From 3f10ee37557d4bc734906269d167ab353e06d4ca Mon Sep 17 00:00:00 2001 From: John Marino Date: Sat, 18 Jul 2015 01:15:16 +0200 Subject: [PATCH] Remove now-unused hostapd source files from contrib --- contrib/hostapd/COPYING | 22 - contrib/hostapd/README | 56 - contrib/hostapd/README.DELETED | 47 - contrib/hostapd/README.DRAGONFLY | 17 - contrib/hostapd/hostapd/ChangeLog | 885 -- contrib/hostapd/hostapd/README | 372 - contrib/hostapd/hostapd/README-WPS | 354 - contrib/hostapd/hostapd/config_file.c | 3030 ---- contrib/hostapd/hostapd/config_file.h | 17 - contrib/hostapd/hostapd/ctrl_iface.c | 1878 --- contrib/hostapd/hostapd/ctrl_iface.h | 39 - contrib/hostapd/hostapd/eap_register.c | 143 - contrib/hostapd/hostapd/eap_register.h | 14 - contrib/hostapd/hostapd/hlr_auc_gw.txt | 104 - contrib/hostapd/hostapd/hostapd_cli.c | 1270 -- contrib/hostapd/hostapd/main.c | 720 - .../openssl-0.9.8-tls-extensions.patch | 429 - .../openssl-0.9.8d-tls-extensions.patch | 429 - .../openssl-0.9.8e-tls-extensions.patch | 353 - .../openssl-0.9.8g-tls-extensions.patch | 330 - .../openssl-0.9.8h-tls-extensions.patch | 344 - .../openssl-0.9.8i-tls-extensions.patch | 404 - .../openssl-0.9.8x-tls-extensions.patch | 396 - .../openssl-0.9.9-session-ticket.patch | 374 - contrib/hostapd/src/ap/accounting.c | 475 - contrib/hostapd/src/ap/accounting.h | 44 - contrib/hostapd/src/ap/acs.c | 802 -- contrib/hostapd/src/ap/acs.h | 27 - contrib/hostapd/src/ap/ap_config.c | 885 -- contrib/hostapd/src/ap/ap_config.h | 582 - contrib/hostapd/src/ap/ap_drv_ops.c | 775 - contrib/hostapd/src/ap/ap_drv_ops.h | 283 - contrib/hostapd/src/ap/ap_list.c | 315 - contrib/hostapd/src/ap/ap_list.h | 53 - contrib/hostapd/src/ap/ap_mlme.c | 178 - contrib/hostapd/src/ap/ap_mlme.h | 34 - contrib/hostapd/src/ap/authsrv.c | 214 - contrib/hostapd/src/ap/authsrv.h | 15 - contrib/hostapd/src/ap/beacon.c | 941 -- contrib/hostapd/src/ap/beacon.h | 25 - contrib/hostapd/src/ap/ctrl_iface_ap.c | 510 - contrib/hostapd/src/ap/ctrl_iface_ap.h | 28 - contrib/hostapd/src/ap/dfs.c | 803 -- contrib/hostapd/src/ap/dfs.h | 25 - contrib/hostapd/src/ap/drv_callbacks.c | 1038 -- contrib/hostapd/src/ap/eap_user_db.c | 270 - contrib/hostapd/src/ap/gas_serv.c | 1199 -- contrib/hostapd/src/ap/gas_serv.h | 72 - contrib/hostapd/src/ap/hostapd.c | 2255 --- contrib/hostapd/src/ap/hostapd.h | 424 - contrib/hostapd/src/ap/hs20.c | 31 - contrib/hostapd/src/ap/hs20.h | 16 - contrib/hostapd/src/ap/hw_features.c | 1031 -- contrib/hostapd/src/ap/hw_features.h | 66 - contrib/hostapd/src/ap/iapp.c | 540 - contrib/hostapd/src/ap/iapp.h | 39 - contrib/hostapd/src/ap/ieee802_11.c | 2266 --- contrib/hostapd/src/ap/ieee802_11.h | 85 - contrib/hostapd/src/ap/ieee802_11_auth.c | 643 - contrib/hostapd/src/ap/ieee802_11_auth.h | 28 - contrib/hostapd/src/ap/ieee802_11_ht.c | 281 - contrib/hostapd/src/ap/ieee802_11_shared.c | 494 - contrib/hostapd/src/ap/ieee802_11_vht.c | 171 - contrib/hostapd/src/ap/ieee802_1x.c | 2145 --- contrib/hostapd/src/ap/ieee802_1x.h | 61 - contrib/hostapd/src/ap/p2p_hostapd.c | 114 - contrib/hostapd/src/ap/p2p_hostapd.h | 35 - contrib/hostapd/src/ap/peerkey_auth.c | 396 - contrib/hostapd/src/ap/pmksa_cache_auth.c | 430 - contrib/hostapd/src/ap/pmksa_cache_auth.h | 61 - contrib/hostapd/src/ap/preauth_auth.c | 273 - contrib/hostapd/src/ap/preauth_auth.h | 52 - contrib/hostapd/src/ap/sta_info.c | 1057 -- contrib/hostapd/src/ap/sta_info.h | 198 - contrib/hostapd/src/ap/tkip_countermeasures.c | 105 - contrib/hostapd/src/ap/tkip_countermeasures.h | 15 - contrib/hostapd/src/ap/utils.c | 85 - contrib/hostapd/src/ap/vlan_init.c | 1100 -- contrib/hostapd/src/ap/vlan_init.h | 53 - contrib/hostapd/src/ap/vlan_util.c | 177 - contrib/hostapd/src/ap/vlan_util.h | 15 - contrib/hostapd/src/ap/wmm.c | 324 - contrib/hostapd/src/ap/wmm.h | 23 - contrib/hostapd/src/ap/wnm_ap.c | 508 - contrib/hostapd/src/ap/wnm_ap.h | 22 - contrib/hostapd/src/ap/wpa_auth.c | 3180 ----- contrib/hostapd/src/ap/wpa_auth.h | 308 - contrib/hostapd/src/ap/wpa_auth_ft.c | 1662 --- contrib/hostapd/src/ap/wpa_auth_glue.c | 628 - contrib/hostapd/src/ap/wpa_auth_glue.h | 16 - contrib/hostapd/src/ap/wpa_auth_i.h | 242 - contrib/hostapd/src/ap/wpa_auth_ie.c | 794 -- contrib/hostapd/src/ap/wpa_auth_ie.h | 54 - contrib/hostapd/src/ap/wps_hostapd.c | 2002 --- contrib/hostapd/src/ap/wps_hostapd.h | 92 - contrib/hostapd/src/common/defs.h | 299 - contrib/hostapd/src/common/eapol_common.h | 81 - contrib/hostapd/src/common/gas.c | 273 - contrib/hostapd/src/common/gas.h | 37 - .../hostapd/src/common/ieee802_11_common.c | 538 - .../hostapd/src/common/ieee802_11_common.h | 98 - contrib/hostapd/src/common/ieee802_11_defs.h | 1193 -- contrib/hostapd/src/common/privsep_commands.h | 69 - contrib/hostapd/src/common/qca-vendor.h | 51 - contrib/hostapd/src/common/sae.c | 1047 -- contrib/hostapd/src/common/sae.h | 64 - contrib/hostapd/src/common/version.h | 10 - contrib/hostapd/src/common/wpa_common.c | 1436 -- contrib/hostapd/src/common/wpa_common.h | 419 - contrib/hostapd/src/common/wpa_ctrl.c | 671 - contrib/hostapd/src/common/wpa_ctrl.h | 376 - contrib/hostapd/src/crypto/aes-cbc.c | 80 - contrib/hostapd/src/crypto/aes-ccm.c | 212 - contrib/hostapd/src/crypto/aes-ctr.c | 55 - contrib/hostapd/src/crypto/aes-eax.c | 145 - contrib/hostapd/src/crypto/aes-encblock.c | 32 - contrib/hostapd/src/crypto/aes-gcm.c | 327 - contrib/hostapd/src/crypto/aes-internal-dec.c | 161 - contrib/hostapd/src/crypto/aes-internal-enc.c | 126 - contrib/hostapd/src/crypto/aes-internal.c | 845 -- contrib/hostapd/src/crypto/aes-omac1.c | 118 - contrib/hostapd/src/crypto/aes-unwrap.c | 73 - contrib/hostapd/src/crypto/aes-wrap.c | 70 - contrib/hostapd/src/crypto/aes.h | 21 - contrib/hostapd/src/crypto/aes_i.h | 125 - contrib/hostapd/src/crypto/aes_wrap.h | 64 - contrib/hostapd/src/crypto/crypto.h | 785 -- contrib/hostapd/src/crypto/crypto_cryptoapi.c | 783 - contrib/hostapd/src/crypto/crypto_gnutls.c | 299 - .../src/crypto/crypto_internal-cipher.c | 243 - .../src/crypto/crypto_internal-modexp.c | 49 - .../hostapd/src/crypto/crypto_internal-rsa.c | 108 - contrib/hostapd/src/crypto/crypto_internal.c | 275 - .../hostapd/src/crypto/crypto_libtomcrypt.c | 726 - contrib/hostapd/src/crypto/crypto_none.c | 23 - contrib/hostapd/src/crypto/crypto_nss.c | 207 - contrib/hostapd/src/crypto/crypto_openssl.c | 1235 -- contrib/hostapd/src/crypto/des-internal.c | 493 - contrib/hostapd/src/crypto/des_i.h | 25 - contrib/hostapd/src/crypto/dh_group5.c | 40 - contrib/hostapd/src/crypto/dh_group5.h | 18 - contrib/hostapd/src/crypto/dh_groups.c | 1271 -- contrib/hostapd/src/crypto/dh_groups.h | 29 - .../hostapd/src/crypto/fips_prf_cryptoapi.c | 19 - contrib/hostapd/src/crypto/fips_prf_gnutls.c | 20 - .../hostapd/src/crypto/fips_prf_internal.c | 69 - contrib/hostapd/src/crypto/fips_prf_nss.c | 19 - contrib/hostapd/src/crypto/fips_prf_openssl.c | 78 - contrib/hostapd/src/crypto/md4-internal.c | 272 - contrib/hostapd/src/crypto/md5-internal.c | 287 - contrib/hostapd/src/crypto/md5.c | 105 - contrib/hostapd/src/crypto/md5.h | 19 - contrib/hostapd/src/crypto/md5_i.h | 23 - contrib/hostapd/src/crypto/milenage.c | 323 - contrib/hostapd/src/crypto/milenage.h | 27 - contrib/hostapd/src/crypto/ms_funcs.c | 526 - contrib/hostapd/src/crypto/ms_funcs.h | 58 - contrib/hostapd/src/crypto/random.c | 446 - contrib/hostapd/src/crypto/random.h | 28 - contrib/hostapd/src/crypto/rc4.c | 54 - contrib/hostapd/src/crypto/sha1-internal.c | 302 - contrib/hostapd/src/crypto/sha1-pbkdf2.c | 92 - contrib/hostapd/src/crypto/sha1-prf.c | 66 - contrib/hostapd/src/crypto/sha1-tlsprf.c | 99 - contrib/hostapd/src/crypto/sha1-tprf.c | 70 - contrib/hostapd/src/crypto/sha1.c | 104 - contrib/hostapd/src/crypto/sha1.h | 27 - contrib/hostapd/src/crypto/sha1_i.h | 23 - contrib/hostapd/src/crypto/sha256-internal.c | 226 - contrib/hostapd/src/crypto/sha256-prf.c | 98 - contrib/hostapd/src/crypto/sha256-tlsprf.c | 66 - contrib/hostapd/src/crypto/sha256.c | 104 - contrib/hostapd/src/crypto/sha256.h | 27 - contrib/hostapd/src/crypto/sha256_i.h | 25 - contrib/hostapd/src/crypto/tls.h | 539 - contrib/hostapd/src/crypto/tls_gnutls.c | 1190 -- contrib/hostapd/src/crypto/tls_internal.c | 630 - contrib/hostapd/src/crypto/tls_none.c | 194 - contrib/hostapd/src/crypto/tls_nss.c | 645 - contrib/hostapd/src/crypto/tls_openssl.c | 3463 ----- contrib/hostapd/src/crypto/tls_schannel.c | 732 - contrib/hostapd/src/drivers/android_drv.h | 56 - contrib/hostapd/src/drivers/driver.h | 3847 ----- contrib/hostapd/src/drivers/driver_atheros.c | 2193 --- contrib/hostapd/src/drivers/driver_bsd.c | 1631 --- contrib/hostapd/src/drivers/driver_common.c | 86 - contrib/hostapd/src/drivers/driver_hostap.c | 1193 -- contrib/hostapd/src/drivers/driver_hostap.h | 210 - contrib/hostapd/src/drivers/driver_madwifi.c | 1309 -- contrib/hostapd/src/drivers/driver_ndis.c | 3218 ----- contrib/hostapd/src/drivers/driver_ndis.h | 59 - contrib/hostapd/src/drivers/driver_ndis_.c | 99 - contrib/hostapd/src/drivers/driver_nl80211.c | 11773 ---------------- contrib/hostapd/src/drivers/driver_none.c | 93 - contrib/hostapd/src/drivers/driver_openbsd.c | 136 - contrib/hostapd/src/drivers/driver_privsep.c | 740 - .../hostapd/src/drivers/driver_roboswitch.c | 474 - contrib/hostapd/src/drivers/driver_test.c | 2678 ---- contrib/hostapd/src/drivers/driver_wext.c | 2338 --- contrib/hostapd/src/drivers/driver_wext.h | 81 - contrib/hostapd/src/drivers/driver_wired.c | 662 - contrib/hostapd/src/drivers/drivers.c | 91 - contrib/hostapd/src/drivers/linux_ioctl.c | 221 - contrib/hostapd/src/drivers/linux_ioctl.h | 22 - contrib/hostapd/src/drivers/linux_wext.h | 45 - contrib/hostapd/src/drivers/ndis_events.c | 802 -- contrib/hostapd/src/drivers/netlink.c | 228 - contrib/hostapd/src/drivers/netlink.h | 28 - contrib/hostapd/src/drivers/nl80211_copy.h | 4040 ------ contrib/hostapd/src/drivers/priv_netlink.h | 108 - contrib/hostapd/src/drivers/rfkill.c | 188 - contrib/hostapd/src/drivers/rfkill.h | 25 - contrib/hostapd/src/eap_common/chap.c | 28 - contrib/hostapd/src/eap_common/chap.h | 17 - contrib/hostapd/src/eap_common/eap_common.c | 205 - contrib/hostapd/src/eap_common/eap_common.h | 23 - contrib/hostapd/src/eap_common/eap_defs.h | 85 - .../hostapd/src/eap_common/eap_eke_common.c | 768 - .../hostapd/src/eap_common/eap_eke_common.h | 114 - .../hostapd/src/eap_common/eap_fast_common.c | 298 - .../hostapd/src/eap_common/eap_fast_common.h | 107 - .../hostapd/src/eap_common/eap_gpsk_common.c | 552 - .../hostapd/src/eap_common/eap_gpsk_common.h | 66 - .../hostapd/src/eap_common/eap_ikev2_common.c | 126 - .../hostapd/src/eap_common/eap_ikev2_common.h | 36 - .../hostapd/src/eap_common/eap_pax_common.c | 144 - .../hostapd/src/eap_common/eap_pax_common.h | 91 - .../hostapd/src/eap_common/eap_peap_common.c | 85 - .../hostapd/src/eap_common/eap_peap_common.h | 16 - .../hostapd/src/eap_common/eap_psk_common.c | 68 - .../hostapd/src/eap_common/eap_psk_common.h | 72 - .../hostapd/src/eap_common/eap_pwd_common.c | 345 - .../hostapd/src/eap_common/eap_pwd_common.h | 67 - .../hostapd/src/eap_common/eap_sake_common.c | 387 - .../hostapd/src/eap_common/eap_sake_common.h | 96 - .../hostapd/src/eap_common/eap_sim_common.c | 1209 -- .../hostapd/src/eap_common/eap_sim_common.h | 229 - .../hostapd/src/eap_common/eap_tlv_common.h | 112 - contrib/hostapd/src/eap_common/eap_ttls.h | 65 - .../hostapd/src/eap_common/eap_wsc_common.c | 33 - .../hostapd/src/eap_common/eap_wsc_common.h | 27 - contrib/hostapd/src/eap_common/ikev2_common.c | 791 -- contrib/hostapd/src/eap_common/ikev2_common.h | 338 - contrib/hostapd/src/eap_peer/eap.c | 2426 ---- contrib/hostapd/src/eap_peer/eap.h | 327 - contrib/hostapd/src/eap_peer/eap_aka.c | 1537 -- contrib/hostapd/src/eap_peer/eap_config.h | 713 - contrib/hostapd/src/eap_peer/eap_eke.c | 765 - contrib/hostapd/src/eap_peer/eap_fast.c | 1761 --- contrib/hostapd/src/eap_peer/eap_fast_pac.c | 921 -- contrib/hostapd/src/eap_peer/eap_fast_pac.h | 50 - contrib/hostapd/src/eap_peer/eap_gpsk.c | 783 - contrib/hostapd/src/eap_peer/eap_gtc.c | 145 - contrib/hostapd/src/eap_peer/eap_i.h | 373 - contrib/hostapd/src/eap_peer/eap_ikev2.c | 536 - contrib/hostapd/src/eap_peer/eap_leap.c | 410 - contrib/hostapd/src/eap_peer/eap_md5.c | 120 - contrib/hostapd/src/eap_peer/eap_methods.c | 369 - contrib/hostapd/src/eap_peer/eap_methods.h | 110 - contrib/hostapd/src/eap_peer/eap_mschapv2.c | 877 -- contrib/hostapd/src/eap_peer/eap_otp.c | 101 - contrib/hostapd/src/eap_peer/eap_pax.c | 525 - contrib/hostapd/src/eap_peer/eap_peap.c | 1248 -- contrib/hostapd/src/eap_peer/eap_proxy.h | 49 - .../hostapd/src/eap_peer/eap_proxy_dummy.c | 77 - contrib/hostapd/src/eap_peer/eap_psk.c | 502 - contrib/hostapd/src/eap_peer/eap_pwd.c | 927 -- contrib/hostapd/src/eap_peer/eap_sake.c | 517 - contrib/hostapd/src/eap_peer/eap_sim.c | 1243 -- contrib/hostapd/src/eap_peer/eap_tls.c | 384 - contrib/hostapd/src/eap_peer/eap_tls_common.c | 1115 -- contrib/hostapd/src/eap_peer/eap_tls_common.h | 131 - contrib/hostapd/src/eap_peer/eap_tnc.c | 427 - contrib/hostapd/src/eap_peer/eap_ttls.c | 1675 --- .../hostapd/src/eap_peer/eap_vendor_test.c | 189 - contrib/hostapd/src/eap_peer/eap_wsc.c | 593 - contrib/hostapd/src/eap_peer/ikev2.c | 1299 -- contrib/hostapd/src/eap_peer/ikev2.h | 59 - contrib/hostapd/src/eap_peer/mschapv2.c | 124 - contrib/hostapd/src/eap_peer/mschapv2.h | 28 - contrib/hostapd/src/eap_peer/tncc.c | 1361 -- contrib/hostapd/src/eap_peer/tncc.h | 36 - contrib/hostapd/src/eap_server/eap.h | 125 - contrib/hostapd/src/eap_server/eap_i.h | 200 - contrib/hostapd/src/eap_server/eap_methods.h | 50 - contrib/hostapd/src/eap_server/eap_server.c | 1419 -- .../hostapd/src/eap_server/eap_server_aka.c | 1352 -- .../hostapd/src/eap_server/eap_server_eke.c | 793 -- .../hostapd/src/eap_server/eap_server_fast.c | 1614 --- .../hostapd/src/eap_server/eap_server_gpsk.c | 620 - .../hostapd/src/eap_server/eap_server_gtc.c | 224 - .../src/eap_server/eap_server_identity.c | 174 - .../hostapd/src/eap_server/eap_server_ikev2.c | 536 - .../hostapd/src/eap_server/eap_server_md5.c | 175 - .../src/eap_server/eap_server_methods.c | 171 - .../src/eap_server/eap_server_mschapv2.c | 571 - .../hostapd/src/eap_server/eap_server_pax.c | 564 - .../hostapd/src/eap_server/eap_server_peap.c | 1255 -- .../hostapd/src/eap_server/eap_server_psk.c | 512 - .../hostapd/src/eap_server/eap_server_pwd.c | 1045 -- .../hostapd/src/eap_server/eap_server_sake.c | 522 - .../hostapd/src/eap_server/eap_server_sim.c | 847 -- .../hostapd/src/eap_server/eap_server_tls.c | 342 - .../src/eap_server/eap_server_tls_common.c | 430 - .../hostapd/src/eap_server/eap_server_tnc.c | 575 - .../hostapd/src/eap_server/eap_server_ttls.c | 1193 -- .../src/eap_server/eap_server_vendor_test.c | 192 - .../hostapd/src/eap_server/eap_server_wsc.c | 512 - contrib/hostapd/src/eap_server/eap_sim_db.c | 1494 -- contrib/hostapd/src/eap_server/eap_sim_db.h | 95 - .../hostapd/src/eap_server/eap_tls_common.h | 90 - contrib/hostapd/src/eap_server/ikev2.c | 1200 -- contrib/hostapd/src/eap_server/ikev2.h | 61 - contrib/hostapd/src/eap_server/tncs.c | 1265 -- contrib/hostapd/src/eap_server/tncs.h | 43 - .../hostapd/src/eapol_auth/eapol_auth_dump.c | 289 - .../hostapd/src/eapol_auth/eapol_auth_sm.c | 1161 -- .../hostapd/src/eapol_auth/eapol_auth_sm.h | 90 - .../hostapd/src/eapol_auth/eapol_auth_sm_i.h | 178 - .../hostapd/src/eapol_supp/eapol_supp_sm.c | 2080 --- .../hostapd/src/eapol_supp/eapol_supp_sm.h | 404 - contrib/hostapd/src/l2_packet/l2_packet.h | 124 - .../hostapd/src/l2_packet/l2_packet_freebsd.c | 310 - .../hostapd/src/l2_packet/l2_packet_linux.c | 204 - .../hostapd/src/l2_packet/l2_packet_ndis.c | 516 - .../hostapd/src/l2_packet/l2_packet_none.c | 117 - .../hostapd/src/l2_packet/l2_packet_pcap.c | 380 - .../hostapd/src/l2_packet/l2_packet_privsep.c | 261 - .../hostapd/src/l2_packet/l2_packet_winpcap.c | 335 - contrib/hostapd/src/p2p/p2p.c | 4598 ------ contrib/hostapd/src/p2p/p2p.h | 1944 --- contrib/hostapd/src/p2p/p2p_build.c | 477 - contrib/hostapd/src/p2p/p2p_dev_disc.c | 325 - contrib/hostapd/src/p2p/p2p_go_neg.c | 1223 -- contrib/hostapd/src/p2p/p2p_group.c | 1015 -- contrib/hostapd/src/p2p/p2p_i.h | 759 - contrib/hostapd/src/p2p/p2p_invitation.c | 605 - contrib/hostapd/src/p2p/p2p_parse.c | 767 - contrib/hostapd/src/p2p/p2p_pd.c | 477 - contrib/hostapd/src/p2p/p2p_sd.c | 879 -- contrib/hostapd/src/p2p/p2p_utils.c | 471 - contrib/hostapd/src/radius/radius.c | 1578 --- contrib/hostapd/src/radius/radius.h | 287 - contrib/hostapd/src/radius/radius_client.c | 1491 -- contrib/hostapd/src/radius/radius_client.h | 259 - contrib/hostapd/src/radius/radius_das.c | 362 - contrib/hostapd/src/radius/radius_das.h | 47 - contrib/hostapd/src/radius/radius_server.c | 1555 -- contrib/hostapd/src/radius/radius_server.h | 220 - contrib/hostapd/src/rsn_supp/peerkey.c | 1157 -- contrib/hostapd/src/rsn_supp/peerkey.h | 80 - contrib/hostapd/src/rsn_supp/pmksa_cache.c | 525 - contrib/hostapd/src/rsn_supp/pmksa_cache.h | 132 - contrib/hostapd/src/rsn_supp/preauth.c | 513 - contrib/hostapd/src/rsn_supp/preauth.h | 79 - contrib/hostapd/src/rsn_supp/tdls.c | 2638 ---- contrib/hostapd/src/rsn_supp/wpa.c | 2786 ---- contrib/hostapd/src/rsn_supp/wpa.h | 402 - contrib/hostapd/src/rsn_supp/wpa_ft.c | 848 -- contrib/hostapd/src/rsn_supp/wpa_i.h | 334 - contrib/hostapd/src/rsn_supp/wpa_ie.c | 477 - contrib/hostapd/src/rsn_supp/wpa_ie.h | 72 - contrib/hostapd/src/tls/asn1.c | 206 - contrib/hostapd/src/tls/asn1.h | 66 - contrib/hostapd/src/tls/bignum.c | 224 - contrib/hostapd/src/tls/bignum.h | 32 - contrib/hostapd/src/tls/libtommath.c | 3401 ----- contrib/hostapd/src/tls/pkcs1.c | 195 - contrib/hostapd/src/tls/pkcs1.h | 22 - contrib/hostapd/src/tls/pkcs5.c | 232 - contrib/hostapd/src/tls/pkcs5.h | 16 - contrib/hostapd/src/tls/pkcs8.c | 187 - contrib/hostapd/src/tls/pkcs8.h | 16 - contrib/hostapd/src/tls/rsa.c | 352 - contrib/hostapd/src/tls/rsa.h | 23 - contrib/hostapd/src/tls/tlsv1_client.c | 794 -- contrib/hostapd/src/tls/tlsv1_client.h | 54 - contrib/hostapd/src/tls/tlsv1_client_i.h | 84 - contrib/hostapd/src/tls/tlsv1_client_read.c | 999 -- contrib/hostapd/src/tls/tlsv1_client_write.c | 866 -- contrib/hostapd/src/tls/tlsv1_common.c | 321 - contrib/hostapd/src/tls/tlsv1_common.h | 261 - contrib/hostapd/src/tls/tlsv1_cred.c | 506 - contrib/hostapd/src/tls/tlsv1_cred.h | 40 - contrib/hostapd/src/tls/tlsv1_record.c | 485 - contrib/hostapd/src/tls/tlsv1_record.h | 71 - contrib/hostapd/src/tls/tlsv1_server.c | 620 - contrib/hostapd/src/tls/tlsv1_server.h | 48 - contrib/hostapd/src/tls/tlsv1_server_i.h | 71 - contrib/hostapd/src/tls/tlsv1_server_read.c | 1253 -- contrib/hostapd/src/tls/tlsv1_server_write.c | 801 -- contrib/hostapd/src/tls/x509v3.c | 1979 --- contrib/hostapd/src/tls/x509v3.h | 123 - contrib/hostapd/src/utils/base64.c | 155 - contrib/hostapd/src/utils/base64.h | 17 - contrib/hostapd/src/utils/bitfield.c | 89 - contrib/hostapd/src/utils/bitfield.h | 21 - contrib/hostapd/src/utils/build_config.h | 50 - contrib/hostapd/src/utils/common.c | 829 -- contrib/hostapd/src/utils/common.h | 557 - contrib/hostapd/src/utils/edit.c | 1174 -- contrib/hostapd/src/utils/edit.h | 21 - contrib/hostapd/src/utils/edit_readline.c | 192 - contrib/hostapd/src/utils/edit_simple.c | 92 - contrib/hostapd/src/utils/eloop.c | 950 -- contrib/hostapd/src/utils/eloop.h | 359 - contrib/hostapd/src/utils/eloop_win.c | 694 - contrib/hostapd/src/utils/ext_password.c | 116 - contrib/hostapd/src/utils/ext_password.h | 33 - contrib/hostapd/src/utils/ext_password_i.h | 23 - contrib/hostapd/src/utils/ext_password_test.c | 90 - contrib/hostapd/src/utils/includes.h | 50 - contrib/hostapd/src/utils/ip_addr.c | 77 - contrib/hostapd/src/utils/ip_addr.h | 28 - contrib/hostapd/src/utils/list.h | 95 - contrib/hostapd/src/utils/os.h | 595 - contrib/hostapd/src/utils/os_internal.c | 494 - contrib/hostapd/src/utils/os_none.c | 231 - contrib/hostapd/src/utils/os_unix.c | 532 - contrib/hostapd/src/utils/os_win32.c | 246 - contrib/hostapd/src/utils/pcsc_funcs.c | 1419 -- contrib/hostapd/src/utils/pcsc_funcs.h | 42 - contrib/hostapd/src/utils/radiotap.c | 287 - contrib/hostapd/src/utils/radiotap.h | 243 - contrib/hostapd/src/utils/radiotap_iter.h | 56 - contrib/hostapd/src/utils/state_machine.h | 138 - contrib/hostapd/src/utils/trace.c | 323 - contrib/hostapd/src/utils/trace.h | 68 - contrib/hostapd/src/utils/uuid.c | 71 - contrib/hostapd/src/utils/uuid.h | 18 - contrib/hostapd/src/utils/wpa_debug.c | 736 - contrib/hostapd/src/utils/wpa_debug.h | 327 - contrib/hostapd/src/utils/wpabuf.c | 303 - contrib/hostapd/src/utils/wpabuf.h | 162 - contrib/hostapd/src/wps/http.h | 29 - contrib/hostapd/src/wps/http_client.c | 368 - contrib/hostapd/src/wps/http_client.h | 40 - contrib/hostapd/src/wps/http_server.c | 310 - contrib/hostapd/src/wps/http_server.h | 33 - contrib/hostapd/src/wps/httpread.c | 826 -- contrib/hostapd/src/wps/httpread.h | 117 - contrib/hostapd/src/wps/ndef.c | 196 - contrib/hostapd/src/wps/upnp_xml.c | 252 - contrib/hostapd/src/wps/upnp_xml.h | 25 - contrib/hostapd/src/wps/wps.c | 669 - contrib/hostapd/src/wps/wps.h | 1031 -- contrib/hostapd/src/wps/wps_attr_build.c | 488 - contrib/hostapd/src/wps/wps_attr_parse.c | 644 - contrib/hostapd/src/wps/wps_attr_parse.h | 108 - contrib/hostapd/src/wps/wps_attr_process.c | 343 - contrib/hostapd/src/wps/wps_common.c | 906 -- contrib/hostapd/src/wps/wps_defs.h | 335 - contrib/hostapd/src/wps/wps_dev_attr.c | 419 - contrib/hostapd/src/wps/wps_dev_attr.h | 39 - contrib/hostapd/src/wps/wps_enrollee.c | 1469 -- contrib/hostapd/src/wps/wps_er.c | 2098 --- contrib/hostapd/src/wps/wps_er.h | 112 - contrib/hostapd/src/wps/wps_er_ssdp.c | 207 - contrib/hostapd/src/wps/wps_i.h | 216 - contrib/hostapd/src/wps/wps_registrar.c | 3654 ----- contrib/hostapd/src/wps/wps_upnp.c | 1196 -- contrib/hostapd/src/wps/wps_upnp.h | 48 - contrib/hostapd/src/wps/wps_upnp_ap.c | 87 - contrib/hostapd/src/wps/wps_upnp_event.c | 423 - contrib/hostapd/src/wps/wps_upnp_i.h | 193 - contrib/hostapd/src/wps/wps_upnp_ssdp.c | 950 -- contrib/hostapd/src/wps/wps_upnp_web.c | 1322 -- contrib/hostapd/src/wps/wps_validate.c | 1975 --- 468 files changed, 246715 deletions(-) delete mode 100644 contrib/hostapd/COPYING delete mode 100644 contrib/hostapd/README delete mode 100644 contrib/hostapd/README.DELETED delete mode 100644 contrib/hostapd/README.DRAGONFLY delete mode 100644 contrib/hostapd/hostapd/ChangeLog delete mode 100644 contrib/hostapd/hostapd/README delete mode 100644 contrib/hostapd/hostapd/README-WPS delete mode 100644 contrib/hostapd/hostapd/config_file.c delete mode 100644 contrib/hostapd/hostapd/config_file.h delete mode 100644 contrib/hostapd/hostapd/ctrl_iface.c delete mode 100644 contrib/hostapd/hostapd/ctrl_iface.h delete mode 100644 contrib/hostapd/hostapd/eap_register.c delete mode 100644 contrib/hostapd/hostapd/eap_register.h delete mode 100644 contrib/hostapd/hostapd/hlr_auc_gw.txt delete mode 100644 contrib/hostapd/hostapd/hostapd_cli.c delete mode 100644 contrib/hostapd/hostapd/main.c delete mode 100644 contrib/hostapd/patches/openssl-0.9.8-tls-extensions.patch delete mode 100644 contrib/hostapd/patches/openssl-0.9.8d-tls-extensions.patch delete mode 100644 contrib/hostapd/patches/openssl-0.9.8e-tls-extensions.patch delete mode 100644 contrib/hostapd/patches/openssl-0.9.8g-tls-extensions.patch delete mode 100644 contrib/hostapd/patches/openssl-0.9.8h-tls-extensions.patch delete mode 100644 contrib/hostapd/patches/openssl-0.9.8i-tls-extensions.patch delete mode 100644 contrib/hostapd/patches/openssl-0.9.8x-tls-extensions.patch delete mode 100644 contrib/hostapd/patches/openssl-0.9.9-session-ticket.patch delete mode 100644 contrib/hostapd/src/ap/accounting.c delete mode 100644 contrib/hostapd/src/ap/accounting.h delete mode 100644 contrib/hostapd/src/ap/acs.c delete mode 100644 contrib/hostapd/src/ap/acs.h delete mode 100644 contrib/hostapd/src/ap/ap_config.c delete mode 100644 contrib/hostapd/src/ap/ap_config.h delete mode 100644 contrib/hostapd/src/ap/ap_drv_ops.c delete mode 100644 contrib/hostapd/src/ap/ap_drv_ops.h delete mode 100644 contrib/hostapd/src/ap/ap_list.c delete mode 100644 contrib/hostapd/src/ap/ap_list.h delete mode 100644 contrib/hostapd/src/ap/ap_mlme.c delete mode 100644 contrib/hostapd/src/ap/ap_mlme.h delete mode 100644 contrib/hostapd/src/ap/authsrv.c delete mode 100644 contrib/hostapd/src/ap/authsrv.h delete mode 100644 contrib/hostapd/src/ap/beacon.c delete mode 100644 contrib/hostapd/src/ap/beacon.h delete mode 100644 contrib/hostapd/src/ap/ctrl_iface_ap.c delete mode 100644 contrib/hostapd/src/ap/ctrl_iface_ap.h delete mode 100644 contrib/hostapd/src/ap/dfs.c delete mode 100644 contrib/hostapd/src/ap/dfs.h delete mode 100644 contrib/hostapd/src/ap/drv_callbacks.c delete mode 100644 contrib/hostapd/src/ap/eap_user_db.c delete mode 100644 contrib/hostapd/src/ap/gas_serv.c delete mode 100644 contrib/hostapd/src/ap/gas_serv.h delete mode 100644 contrib/hostapd/src/ap/hostapd.c delete mode 100644 contrib/hostapd/src/ap/hostapd.h delete mode 100644 contrib/hostapd/src/ap/hs20.c delete mode 100644 contrib/hostapd/src/ap/hs20.h delete mode 100644 contrib/hostapd/src/ap/hw_features.c delete mode 100644 contrib/hostapd/src/ap/hw_features.h delete mode 100644 contrib/hostapd/src/ap/iapp.c delete mode 100644 contrib/hostapd/src/ap/iapp.h delete mode 100644 contrib/hostapd/src/ap/ieee802_11.c delete mode 100644 contrib/hostapd/src/ap/ieee802_11.h delete mode 100644 contrib/hostapd/src/ap/ieee802_11_auth.c delete mode 100644 contrib/hostapd/src/ap/ieee802_11_auth.h delete mode 100644 contrib/hostapd/src/ap/ieee802_11_ht.c delete mode 100644 contrib/hostapd/src/ap/ieee802_11_shared.c delete mode 100644 contrib/hostapd/src/ap/ieee802_11_vht.c delete mode 100644 contrib/hostapd/src/ap/ieee802_1x.c delete mode 100644 contrib/hostapd/src/ap/ieee802_1x.h delete mode 100644 contrib/hostapd/src/ap/p2p_hostapd.c delete mode 100644 contrib/hostapd/src/ap/p2p_hostapd.h delete mode 100644 contrib/hostapd/src/ap/peerkey_auth.c delete mode 100644 contrib/hostapd/src/ap/pmksa_cache_auth.c delete mode 100644 contrib/hostapd/src/ap/pmksa_cache_auth.h delete mode 100644 contrib/hostapd/src/ap/preauth_auth.c delete mode 100644 contrib/hostapd/src/ap/preauth_auth.h delete mode 100644 contrib/hostapd/src/ap/sta_info.c delete mode 100644 contrib/hostapd/src/ap/sta_info.h delete mode 100644 contrib/hostapd/src/ap/tkip_countermeasures.c delete mode 100644 contrib/hostapd/src/ap/tkip_countermeasures.h delete mode 100644 contrib/hostapd/src/ap/utils.c delete mode 100644 contrib/hostapd/src/ap/vlan_init.c delete mode 100644 contrib/hostapd/src/ap/vlan_init.h delete mode 100644 contrib/hostapd/src/ap/vlan_util.c delete mode 100644 contrib/hostapd/src/ap/vlan_util.h delete mode 100644 contrib/hostapd/src/ap/wmm.c delete mode 100644 contrib/hostapd/src/ap/wmm.h delete mode 100644 contrib/hostapd/src/ap/wnm_ap.c delete mode 100644 contrib/hostapd/src/ap/wnm_ap.h delete mode 100644 contrib/hostapd/src/ap/wpa_auth.c delete mode 100644 contrib/hostapd/src/ap/wpa_auth.h delete mode 100644 contrib/hostapd/src/ap/wpa_auth_ft.c delete mode 100644 contrib/hostapd/src/ap/wpa_auth_glue.c delete mode 100644 contrib/hostapd/src/ap/wpa_auth_glue.h delete mode 100644 contrib/hostapd/src/ap/wpa_auth_i.h delete mode 100644 contrib/hostapd/src/ap/wpa_auth_ie.c delete mode 100644 contrib/hostapd/src/ap/wpa_auth_ie.h delete mode 100644 contrib/hostapd/src/ap/wps_hostapd.c delete mode 100644 contrib/hostapd/src/ap/wps_hostapd.h delete mode 100644 contrib/hostapd/src/common/defs.h delete mode 100644 contrib/hostapd/src/common/eapol_common.h delete mode 100644 contrib/hostapd/src/common/gas.c delete mode 100644 contrib/hostapd/src/common/gas.h delete mode 100644 contrib/hostapd/src/common/ieee802_11_common.c delete mode 100644 contrib/hostapd/src/common/ieee802_11_common.h delete mode 100644 contrib/hostapd/src/common/ieee802_11_defs.h delete mode 100644 contrib/hostapd/src/common/privsep_commands.h delete mode 100644 contrib/hostapd/src/common/qca-vendor.h delete mode 100644 contrib/hostapd/src/common/sae.c delete mode 100644 contrib/hostapd/src/common/sae.h delete mode 100644 contrib/hostapd/src/common/version.h delete mode 100644 contrib/hostapd/src/common/wpa_common.c delete mode 100644 contrib/hostapd/src/common/wpa_common.h delete mode 100644 contrib/hostapd/src/common/wpa_ctrl.c delete mode 100644 contrib/hostapd/src/common/wpa_ctrl.h delete mode 100644 contrib/hostapd/src/crypto/aes-cbc.c delete mode 100644 contrib/hostapd/src/crypto/aes-ccm.c delete mode 100644 contrib/hostapd/src/crypto/aes-ctr.c delete mode 100644 contrib/hostapd/src/crypto/aes-eax.c delete mode 100644 contrib/hostapd/src/crypto/aes-encblock.c delete mode 100644 contrib/hostapd/src/crypto/aes-gcm.c delete mode 100644 contrib/hostapd/src/crypto/aes-internal-dec.c delete mode 100644 contrib/hostapd/src/crypto/aes-internal-enc.c delete mode 100644 contrib/hostapd/src/crypto/aes-internal.c delete mode 100644 contrib/hostapd/src/crypto/aes-omac1.c delete mode 100644 contrib/hostapd/src/crypto/aes-unwrap.c delete mode 100644 contrib/hostapd/src/crypto/aes-wrap.c delete mode 100644 contrib/hostapd/src/crypto/aes.h delete mode 100644 contrib/hostapd/src/crypto/aes_i.h delete mode 100644 contrib/hostapd/src/crypto/aes_wrap.h delete mode 100644 contrib/hostapd/src/crypto/crypto.h delete mode 100644 contrib/hostapd/src/crypto/crypto_cryptoapi.c delete mode 100644 contrib/hostapd/src/crypto/crypto_gnutls.c delete mode 100644 contrib/hostapd/src/crypto/crypto_internal-cipher.c delete mode 100644 contrib/hostapd/src/crypto/crypto_internal-modexp.c delete mode 100644 contrib/hostapd/src/crypto/crypto_internal-rsa.c delete mode 100644 contrib/hostapd/src/crypto/crypto_internal.c delete mode 100644 contrib/hostapd/src/crypto/crypto_libtomcrypt.c delete mode 100644 contrib/hostapd/src/crypto/crypto_none.c delete mode 100644 contrib/hostapd/src/crypto/crypto_nss.c delete mode 100644 contrib/hostapd/src/crypto/crypto_openssl.c delete mode 100644 contrib/hostapd/src/crypto/des-internal.c delete mode 100644 contrib/hostapd/src/crypto/des_i.h delete mode 100644 contrib/hostapd/src/crypto/dh_group5.c delete mode 100644 contrib/hostapd/src/crypto/dh_group5.h delete mode 100644 contrib/hostapd/src/crypto/dh_groups.c delete mode 100644 contrib/hostapd/src/crypto/dh_groups.h delete mode 100644 contrib/hostapd/src/crypto/fips_prf_cryptoapi.c delete mode 100644 contrib/hostapd/src/crypto/fips_prf_gnutls.c delete mode 100644 contrib/hostapd/src/crypto/fips_prf_internal.c delete mode 100644 contrib/hostapd/src/crypto/fips_prf_nss.c delete mode 100644 contrib/hostapd/src/crypto/fips_prf_openssl.c delete mode 100644 contrib/hostapd/src/crypto/md4-internal.c delete mode 100644 contrib/hostapd/src/crypto/md5-internal.c delete mode 100644 contrib/hostapd/src/crypto/md5.c delete mode 100644 contrib/hostapd/src/crypto/md5.h delete mode 100644 contrib/hostapd/src/crypto/md5_i.h delete mode 100644 contrib/hostapd/src/crypto/milenage.c delete mode 100644 contrib/hostapd/src/crypto/milenage.h delete mode 100644 contrib/hostapd/src/crypto/ms_funcs.c delete mode 100644 contrib/hostapd/src/crypto/ms_funcs.h delete mode 100644 contrib/hostapd/src/crypto/random.c delete mode 100644 contrib/hostapd/src/crypto/random.h delete mode 100644 contrib/hostapd/src/crypto/rc4.c delete mode 100644 contrib/hostapd/src/crypto/sha1-internal.c delete mode 100644 contrib/hostapd/src/crypto/sha1-pbkdf2.c delete mode 100644 contrib/hostapd/src/crypto/sha1-prf.c delete mode 100644 contrib/hostapd/src/crypto/sha1-tlsprf.c delete mode 100644 contrib/hostapd/src/crypto/sha1-tprf.c delete mode 100644 contrib/hostapd/src/crypto/sha1.c delete mode 100644 contrib/hostapd/src/crypto/sha1.h delete mode 100644 contrib/hostapd/src/crypto/sha1_i.h delete mode 100644 contrib/hostapd/src/crypto/sha256-internal.c delete mode 100644 contrib/hostapd/src/crypto/sha256-prf.c delete mode 100644 contrib/hostapd/src/crypto/sha256-tlsprf.c delete mode 100644 contrib/hostapd/src/crypto/sha256.c delete mode 100644 contrib/hostapd/src/crypto/sha256.h delete mode 100644 contrib/hostapd/src/crypto/sha256_i.h delete mode 100644 contrib/hostapd/src/crypto/tls.h delete mode 100644 contrib/hostapd/src/crypto/tls_gnutls.c delete mode 100644 contrib/hostapd/src/crypto/tls_internal.c delete mode 100644 contrib/hostapd/src/crypto/tls_none.c delete mode 100644 contrib/hostapd/src/crypto/tls_nss.c delete mode 100644 contrib/hostapd/src/crypto/tls_openssl.c delete mode 100644 contrib/hostapd/src/crypto/tls_schannel.c delete mode 100644 contrib/hostapd/src/drivers/android_drv.h delete mode 100644 contrib/hostapd/src/drivers/driver.h delete mode 100644 contrib/hostapd/src/drivers/driver_atheros.c delete mode 100644 contrib/hostapd/src/drivers/driver_bsd.c delete mode 100644 contrib/hostapd/src/drivers/driver_common.c delete mode 100644 contrib/hostapd/src/drivers/driver_hostap.c delete mode 100644 contrib/hostapd/src/drivers/driver_hostap.h delete mode 100644 contrib/hostapd/src/drivers/driver_madwifi.c delete mode 100644 contrib/hostapd/src/drivers/driver_ndis.c delete mode 100644 contrib/hostapd/src/drivers/driver_ndis.h delete mode 100644 contrib/hostapd/src/drivers/driver_ndis_.c delete mode 100644 contrib/hostapd/src/drivers/driver_nl80211.c delete mode 100644 contrib/hostapd/src/drivers/driver_none.c delete mode 100644 contrib/hostapd/src/drivers/driver_openbsd.c delete mode 100644 contrib/hostapd/src/drivers/driver_privsep.c delete mode 100644 contrib/hostapd/src/drivers/driver_roboswitch.c delete mode 100644 contrib/hostapd/src/drivers/driver_test.c delete mode 100644 contrib/hostapd/src/drivers/driver_wext.c delete mode 100644 contrib/hostapd/src/drivers/driver_wext.h delete mode 100644 contrib/hostapd/src/drivers/driver_wired.c delete mode 100644 contrib/hostapd/src/drivers/drivers.c delete mode 100644 contrib/hostapd/src/drivers/linux_ioctl.c delete mode 100644 contrib/hostapd/src/drivers/linux_ioctl.h delete mode 100644 contrib/hostapd/src/drivers/linux_wext.h delete mode 100644 contrib/hostapd/src/drivers/ndis_events.c delete mode 100644 contrib/hostapd/src/drivers/netlink.c delete mode 100644 contrib/hostapd/src/drivers/netlink.h delete mode 100644 contrib/hostapd/src/drivers/nl80211_copy.h delete mode 100644 contrib/hostapd/src/drivers/priv_netlink.h delete mode 100644 contrib/hostapd/src/drivers/rfkill.c delete mode 100644 contrib/hostapd/src/drivers/rfkill.h delete mode 100644 contrib/hostapd/src/eap_common/chap.c delete mode 100644 contrib/hostapd/src/eap_common/chap.h delete mode 100644 contrib/hostapd/src/eap_common/eap_common.c delete mode 100644 contrib/hostapd/src/eap_common/eap_common.h delete mode 100644 contrib/hostapd/src/eap_common/eap_defs.h delete mode 100644 contrib/hostapd/src/eap_common/eap_eke_common.c delete mode 100644 contrib/hostapd/src/eap_common/eap_eke_common.h delete mode 100644 contrib/hostapd/src/eap_common/eap_fast_common.c delete mode 100644 contrib/hostapd/src/eap_common/eap_fast_common.h delete mode 100644 contrib/hostapd/src/eap_common/eap_gpsk_common.c delete mode 100644 contrib/hostapd/src/eap_common/eap_gpsk_common.h delete mode 100644 contrib/hostapd/src/eap_common/eap_ikev2_common.c delete mode 100644 contrib/hostapd/src/eap_common/eap_ikev2_common.h delete mode 100644 contrib/hostapd/src/eap_common/eap_pax_common.c delete mode 100644 contrib/hostapd/src/eap_common/eap_pax_common.h delete mode 100644 contrib/hostapd/src/eap_common/eap_peap_common.c delete mode 100644 contrib/hostapd/src/eap_common/eap_peap_common.h delete mode 100644 contrib/hostapd/src/eap_common/eap_psk_common.c delete mode 100644 contrib/hostapd/src/eap_common/eap_psk_common.h delete mode 100644 contrib/hostapd/src/eap_common/eap_pwd_common.c delete mode 100644 contrib/hostapd/src/eap_common/eap_pwd_common.h delete mode 100644 contrib/hostapd/src/eap_common/eap_sake_common.c delete mode 100644 contrib/hostapd/src/eap_common/eap_sake_common.h delete mode 100644 contrib/hostapd/src/eap_common/eap_sim_common.c delete mode 100644 contrib/hostapd/src/eap_common/eap_sim_common.h delete mode 100644 contrib/hostapd/src/eap_common/eap_tlv_common.h delete mode 100644 contrib/hostapd/src/eap_common/eap_ttls.h delete mode 100644 contrib/hostapd/src/eap_common/eap_wsc_common.c delete mode 100644 contrib/hostapd/src/eap_common/eap_wsc_common.h delete mode 100644 contrib/hostapd/src/eap_common/ikev2_common.c delete mode 100644 contrib/hostapd/src/eap_common/ikev2_common.h delete mode 100644 contrib/hostapd/src/eap_peer/eap.c delete mode 100644 contrib/hostapd/src/eap_peer/eap.h delete mode 100644 contrib/hostapd/src/eap_peer/eap_aka.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_config.h delete mode 100644 contrib/hostapd/src/eap_peer/eap_eke.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_fast.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_fast_pac.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_fast_pac.h delete mode 100644 contrib/hostapd/src/eap_peer/eap_gpsk.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_gtc.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_i.h delete mode 100644 contrib/hostapd/src/eap_peer/eap_ikev2.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_leap.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_md5.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_methods.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_methods.h delete mode 100644 contrib/hostapd/src/eap_peer/eap_mschapv2.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_otp.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_pax.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_peap.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_proxy.h delete mode 100644 contrib/hostapd/src/eap_peer/eap_proxy_dummy.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_psk.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_pwd.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_sake.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_sim.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_tls.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_tls_common.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_tls_common.h delete mode 100644 contrib/hostapd/src/eap_peer/eap_tnc.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_ttls.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_vendor_test.c delete mode 100644 contrib/hostapd/src/eap_peer/eap_wsc.c delete mode 100644 contrib/hostapd/src/eap_peer/ikev2.c delete mode 100644 contrib/hostapd/src/eap_peer/ikev2.h delete mode 100644 contrib/hostapd/src/eap_peer/mschapv2.c delete mode 100644 contrib/hostapd/src/eap_peer/mschapv2.h delete mode 100644 contrib/hostapd/src/eap_peer/tncc.c delete mode 100644 contrib/hostapd/src/eap_peer/tncc.h delete mode 100644 contrib/hostapd/src/eap_server/eap.h delete mode 100644 contrib/hostapd/src/eap_server/eap_i.h delete mode 100644 contrib/hostapd/src/eap_server/eap_methods.h delete mode 100644 contrib/hostapd/src/eap_server/eap_server.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_aka.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_eke.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_fast.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_gpsk.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_gtc.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_identity.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_ikev2.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_md5.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_methods.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_mschapv2.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_pax.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_peap.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_psk.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_pwd.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_sake.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_sim.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_tls.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_tls_common.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_tnc.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_ttls.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_vendor_test.c delete mode 100644 contrib/hostapd/src/eap_server/eap_server_wsc.c delete mode 100644 contrib/hostapd/src/eap_server/eap_sim_db.c delete mode 100644 contrib/hostapd/src/eap_server/eap_sim_db.h delete mode 100644 contrib/hostapd/src/eap_server/eap_tls_common.h delete mode 100644 contrib/hostapd/src/eap_server/ikev2.c delete mode 100644 contrib/hostapd/src/eap_server/ikev2.h delete mode 100644 contrib/hostapd/src/eap_server/tncs.c delete mode 100644 contrib/hostapd/src/eap_server/tncs.h delete mode 100644 contrib/hostapd/src/eapol_auth/eapol_auth_dump.c delete mode 100644 contrib/hostapd/src/eapol_auth/eapol_auth_sm.c delete mode 100644 contrib/hostapd/src/eapol_auth/eapol_auth_sm.h delete mode 100644 contrib/hostapd/src/eapol_auth/eapol_auth_sm_i.h delete mode 100644 contrib/hostapd/src/eapol_supp/eapol_supp_sm.c delete mode 100644 contrib/hostapd/src/eapol_supp/eapol_supp_sm.h delete mode 100644 contrib/hostapd/src/l2_packet/l2_packet.h delete mode 100644 contrib/hostapd/src/l2_packet/l2_packet_freebsd.c delete mode 100644 contrib/hostapd/src/l2_packet/l2_packet_linux.c delete mode 100644 contrib/hostapd/src/l2_packet/l2_packet_ndis.c delete mode 100644 contrib/hostapd/src/l2_packet/l2_packet_none.c delete mode 100644 contrib/hostapd/src/l2_packet/l2_packet_pcap.c delete mode 100644 contrib/hostapd/src/l2_packet/l2_packet_privsep.c delete mode 100644 contrib/hostapd/src/l2_packet/l2_packet_winpcap.c delete mode 100644 contrib/hostapd/src/p2p/p2p.c delete mode 100644 contrib/hostapd/src/p2p/p2p.h delete mode 100644 contrib/hostapd/src/p2p/p2p_build.c delete mode 100644 contrib/hostapd/src/p2p/p2p_dev_disc.c delete mode 100644 contrib/hostapd/src/p2p/p2p_go_neg.c delete mode 100644 contrib/hostapd/src/p2p/p2p_group.c delete mode 100644 contrib/hostapd/src/p2p/p2p_i.h delete mode 100644 contrib/hostapd/src/p2p/p2p_invitation.c delete mode 100644 contrib/hostapd/src/p2p/p2p_parse.c delete mode 100644 contrib/hostapd/src/p2p/p2p_pd.c delete mode 100644 contrib/hostapd/src/p2p/p2p_sd.c delete mode 100644 contrib/hostapd/src/p2p/p2p_utils.c delete mode 100644 contrib/hostapd/src/radius/radius.c delete mode 100644 contrib/hostapd/src/radius/radius.h delete mode 100644 contrib/hostapd/src/radius/radius_client.c delete mode 100644 contrib/hostapd/src/radius/radius_client.h delete mode 100644 contrib/hostapd/src/radius/radius_das.c delete mode 100644 contrib/hostapd/src/radius/radius_das.h delete mode 100644 contrib/hostapd/src/radius/radius_server.c delete mode 100644 contrib/hostapd/src/radius/radius_server.h delete mode 100644 contrib/hostapd/src/rsn_supp/peerkey.c delete mode 100644 contrib/hostapd/src/rsn_supp/peerkey.h delete mode 100644 contrib/hostapd/src/rsn_supp/pmksa_cache.c delete mode 100644 contrib/hostapd/src/rsn_supp/pmksa_cache.h delete mode 100644 contrib/hostapd/src/rsn_supp/preauth.c delete mode 100644 contrib/hostapd/src/rsn_supp/preauth.h delete mode 100644 contrib/hostapd/src/rsn_supp/tdls.c delete mode 100644 contrib/hostapd/src/rsn_supp/wpa.c delete mode 100644 contrib/hostapd/src/rsn_supp/wpa.h delete mode 100644 contrib/hostapd/src/rsn_supp/wpa_ft.c delete mode 100644 contrib/hostapd/src/rsn_supp/wpa_i.h delete mode 100644 contrib/hostapd/src/rsn_supp/wpa_ie.c delete mode 100644 contrib/hostapd/src/rsn_supp/wpa_ie.h delete mode 100644 contrib/hostapd/src/tls/asn1.c delete mode 100644 contrib/hostapd/src/tls/asn1.h delete mode 100644 contrib/hostapd/src/tls/bignum.c delete mode 100644 contrib/hostapd/src/tls/bignum.h delete mode 100644 contrib/hostapd/src/tls/libtommath.c delete mode 100644 contrib/hostapd/src/tls/pkcs1.c delete mode 100644 contrib/hostapd/src/tls/pkcs1.h delete mode 100644 contrib/hostapd/src/tls/pkcs5.c delete mode 100644 contrib/hostapd/src/tls/pkcs5.h delete mode 100644 contrib/hostapd/src/tls/pkcs8.c delete mode 100644 contrib/hostapd/src/tls/pkcs8.h delete mode 100644 contrib/hostapd/src/tls/rsa.c delete mode 100644 contrib/hostapd/src/tls/rsa.h delete mode 100644 contrib/hostapd/src/tls/tlsv1_client.c delete mode 100644 contrib/hostapd/src/tls/tlsv1_client.h delete mode 100644 contrib/hostapd/src/tls/tlsv1_client_i.h delete mode 100644 contrib/hostapd/src/tls/tlsv1_client_read.c delete mode 100644 contrib/hostapd/src/tls/tlsv1_client_write.c delete mode 100644 contrib/hostapd/src/tls/tlsv1_common.c delete mode 100644 contrib/hostapd/src/tls/tlsv1_common.h delete mode 100644 contrib/hostapd/src/tls/tlsv1_cred.c delete mode 100644 contrib/hostapd/src/tls/tlsv1_cred.h delete mode 100644 contrib/hostapd/src/tls/tlsv1_record.c delete mode 100644 contrib/hostapd/src/tls/tlsv1_record.h delete mode 100644 contrib/hostapd/src/tls/tlsv1_server.c delete mode 100644 contrib/hostapd/src/tls/tlsv1_server.h delete mode 100644 contrib/hostapd/src/tls/tlsv1_server_i.h delete mode 100644 contrib/hostapd/src/tls/tlsv1_server_read.c delete mode 100644 contrib/hostapd/src/tls/tlsv1_server_write.c delete mode 100644 contrib/hostapd/src/tls/x509v3.c delete mode 100644 contrib/hostapd/src/tls/x509v3.h delete mode 100644 contrib/hostapd/src/utils/base64.c delete mode 100644 contrib/hostapd/src/utils/base64.h delete mode 100644 contrib/hostapd/src/utils/bitfield.c delete mode 100644 contrib/hostapd/src/utils/bitfield.h delete mode 100644 contrib/hostapd/src/utils/build_config.h delete mode 100644 contrib/hostapd/src/utils/common.c delete mode 100644 contrib/hostapd/src/utils/common.h delete mode 100644 contrib/hostapd/src/utils/edit.c delete mode 100644 contrib/hostapd/src/utils/edit.h delete mode 100644 contrib/hostapd/src/utils/edit_readline.c delete mode 100644 contrib/hostapd/src/utils/edit_simple.c delete mode 100644 contrib/hostapd/src/utils/eloop.c delete mode 100644 contrib/hostapd/src/utils/eloop.h delete mode 100644 contrib/hostapd/src/utils/eloop_win.c delete mode 100644 contrib/hostapd/src/utils/ext_password.c delete mode 100644 contrib/hostapd/src/utils/ext_password.h delete mode 100644 contrib/hostapd/src/utils/ext_password_i.h delete mode 100644 contrib/hostapd/src/utils/ext_password_test.c delete mode 100644 contrib/hostapd/src/utils/includes.h delete mode 100644 contrib/hostapd/src/utils/ip_addr.c delete mode 100644 contrib/hostapd/src/utils/ip_addr.h delete mode 100644 contrib/hostapd/src/utils/list.h delete mode 100644 contrib/hostapd/src/utils/os.h delete mode 100644 contrib/hostapd/src/utils/os_internal.c delete mode 100644 contrib/hostapd/src/utils/os_none.c delete mode 100644 contrib/hostapd/src/utils/os_unix.c delete mode 100644 contrib/hostapd/src/utils/os_win32.c delete mode 100644 contrib/hostapd/src/utils/pcsc_funcs.c delete mode 100644 contrib/hostapd/src/utils/pcsc_funcs.h delete mode 100644 contrib/hostapd/src/utils/radiotap.c delete mode 100644 contrib/hostapd/src/utils/radiotap.h delete mode 100644 contrib/hostapd/src/utils/radiotap_iter.h delete mode 100644 contrib/hostapd/src/utils/state_machine.h delete mode 100644 contrib/hostapd/src/utils/trace.c delete mode 100644 contrib/hostapd/src/utils/trace.h delete mode 100644 contrib/hostapd/src/utils/uuid.c delete mode 100644 contrib/hostapd/src/utils/uuid.h delete mode 100644 contrib/hostapd/src/utils/wpa_debug.c delete mode 100644 contrib/hostapd/src/utils/wpa_debug.h delete mode 100644 contrib/hostapd/src/utils/wpabuf.c delete mode 100644 contrib/hostapd/src/utils/wpabuf.h delete mode 100644 contrib/hostapd/src/wps/http.h delete mode 100644 contrib/hostapd/src/wps/http_client.c delete mode 100644 contrib/hostapd/src/wps/http_client.h delete mode 100644 contrib/hostapd/src/wps/http_server.c delete mode 100644 contrib/hostapd/src/wps/http_server.h delete mode 100644 contrib/hostapd/src/wps/httpread.c delete mode 100644 contrib/hostapd/src/wps/httpread.h delete mode 100644 contrib/hostapd/src/wps/ndef.c delete mode 100644 contrib/hostapd/src/wps/upnp_xml.c delete mode 100644 contrib/hostapd/src/wps/upnp_xml.h delete mode 100644 contrib/hostapd/src/wps/wps.c delete mode 100644 contrib/hostapd/src/wps/wps.h delete mode 100644 contrib/hostapd/src/wps/wps_attr_build.c delete mode 100644 contrib/hostapd/src/wps/wps_attr_parse.c delete mode 100644 contrib/hostapd/src/wps/wps_attr_parse.h delete mode 100644 contrib/hostapd/src/wps/wps_attr_process.c delete mode 100644 contrib/hostapd/src/wps/wps_common.c delete mode 100644 contrib/hostapd/src/wps/wps_defs.h delete mode 100644 contrib/hostapd/src/wps/wps_dev_attr.c delete mode 100644 contrib/hostapd/src/wps/wps_dev_attr.h delete mode 100644 contrib/hostapd/src/wps/wps_enrollee.c delete mode 100644 contrib/hostapd/src/wps/wps_er.c delete mode 100644 contrib/hostapd/src/wps/wps_er.h delete mode 100644 contrib/hostapd/src/wps/wps_er_ssdp.c delete mode 100644 contrib/hostapd/src/wps/wps_i.h delete mode 100644 contrib/hostapd/src/wps/wps_registrar.c delete mode 100644 contrib/hostapd/src/wps/wps_upnp.c delete mode 100644 contrib/hostapd/src/wps/wps_upnp.h delete mode 100644 contrib/hostapd/src/wps/wps_upnp_ap.c delete mode 100644 contrib/hostapd/src/wps/wps_upnp_event.c delete mode 100644 contrib/hostapd/src/wps/wps_upnp_i.h delete mode 100644 contrib/hostapd/src/wps/wps_upnp_ssdp.c delete mode 100644 contrib/hostapd/src/wps/wps_upnp_web.c delete mode 100644 contrib/hostapd/src/wps/wps_validate.c diff --git a/contrib/hostapd/COPYING b/contrib/hostapd/COPYING deleted file mode 100644 index 8a98582c89..0000000000 --- a/contrib/hostapd/COPYING +++ /dev/null @@ -1,22 +0,0 @@ -wpa_supplicant and hostapd --------------------------- - -Copyright (c) 2002-2012, Jouni Malinen and contributors -All Rights Reserved. - - -See the README file for the current license terms. - -This software was previously distributed under BSD/GPL v2 dual license -terms that allowed either of those license alternatives to be -selected. As of February 11, 2012, the project has chosen to use only -the BSD license option for future distribution. As such, the GPL v2 -license option is no longer used. It should be noted that the BSD -license option (the one with advertisement clause removed) is compatible -with GPL and as such, does not prevent use of this software in projects -that use GPL. - -Some of the files may still include pointers to GPL version 2 license -terms. However, such copyright and license notifications are maintained -only for attribution purposes and any distribution of this software -after February 11, 2012 is no longer under the GPL v2 option. diff --git a/contrib/hostapd/README b/contrib/hostapd/README deleted file mode 100644 index 8de14a64fa..0000000000 --- a/contrib/hostapd/README +++ /dev/null @@ -1,56 +0,0 @@ -wpa_supplicant and hostapd --------------------------- - -Copyright (c) 2002-2014, Jouni Malinen and contributors -All Rights Reserved. - -These programs are licensed under the BSD license (the one with -advertisement clause removed). - -If you are submitting changes to the project, please see CONTRIBUTIONS -file for more instructions. - - -This package may include either wpa_supplicant, hostapd, or both. See -README file respective subdirectories (wpa_supplicant/README or -hostapd/README) for more details. - -Source code files were moved around in v0.6.x releases and compared to -earlier releases, the programs are now built by first going to a -subdirectory (wpa_supplicant or hostapd) and creating build -configuration (.config) and running 'make' there (for Linux/BSD/cygwin -builds). - - -License -------- - -This software may be distributed, used, and modified under the terms of -BSD license: - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name(s) of the above-listed copyright holder(s) nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/contrib/hostapd/README.DELETED b/contrib/hostapd/README.DELETED deleted file mode 100644 index c2a92d4a78..0000000000 --- a/contrib/hostapd/README.DELETED +++ /dev/null @@ -1,47 +0,0 @@ -hostapd/Android.mk -hostapd/Makefile -hostapd/android.config -hostapd/defconfig -hostapd/eap_testing.txt -hostapd/hlr_auc_gw.c -hostapd/hlr_auc_gw.milenage_db -hostapd/hostapd.8 -hostapd/hostapd.accept -hostapd/hostapd.conf -hostapd/hostapd.deny -hostapd/hostapd.eap_user -hostapd/hostapd.eap_user_sqlite -hostapd/hostapd.radius_clients -hostapd/hostapd.sim_db -hostapd/hostapd.vlan -hostapd/hostapd.wpa_psk -hostapd/hostapd_cli.1 -hostapd/logwatch/ -hostapd/nt_password_hash.c -hostapd/wired.conf -hostapd/wps-ap-nfc.py -src/Makefile -src/ap/Makefile -src/common/Makefile -src/crypto/.gitignore -src/crypto/Makefile -src/drivers/.gitignore -src/drivers/Makefile -src/drivers/drivers.mak -src/drivers/drivers.mk -src/eap_common/Makefile -src/eap_peer/Makefile -src/eap_server/Makefile -src/eapol_auth/Makefile -src/eapol_supp/Makefile -src/l2_packet/Makefile -src/lib.rules -src/p2p/Makefile -src/radius/.gitignore -src/radius/Makefile -src/rsn_supp/Makefile -src/tls/.gitignore -src/tls/Makefile -src/utils/.gitignore -src/utils/Makefile -src/wps/Makefile diff --git a/contrib/hostapd/README.DRAGONFLY b/contrib/hostapd/README.DRAGONFLY deleted file mode 100644 index 0d5224d25b..0000000000 --- a/contrib/hostapd/README.DRAGONFLY +++ /dev/null @@ -1,17 +0,0 @@ -HOSTAPD 2.1 -=========== - -This directory contains a selected set of files from hostapd-2.1. -Original source can be downloaded from: - - http://hostap.epitest.fi/hostapd/ - -file = hostapd-2.1.tar.gz -date = 23 May 2014 -size = 1490215 -sha1 = 5c1a1ead3ccf89bceb035bd6b5a6e516d44f4b2b - - -The following files have been added or patched: -=============================================== - modified: src/wps/wps_upnp.c diff --git a/contrib/hostapd/hostapd/ChangeLog b/contrib/hostapd/hostapd/ChangeLog deleted file mode 100644 index 5ef96768f8..0000000000 --- a/contrib/hostapd/hostapd/ChangeLog +++ /dev/null @@ -1,885 +0,0 @@ -ChangeLog for hostapd - -2014-02-04 - v2.1 - * added support for simultaneous authentication of equals (SAE) for - stronger password-based authentication with WPA2-Personal - * added nl80211 functionality - - VHT configuration for nl80211 - - support split wiphy dump - - driver-based MAC ACL - - QoS Mapping configuration - * added fully automated regression testing with mac80211_hwsim - * allow ctrl_iface group to be specified on command line (-G) - * allow single hostapd process to control independent WPS interfaces - (wps_independent=1) instead of synchronized operations through all - configured interfaces within a process - * avoid processing received management frames multiple times when using - nl80211 with multiple BSSes - * added support for DFS (processing radar detection events, CAC, channel - re-selection) - * added EAP-EKE server - * added automatic channel selection (ACS) - * added option for using per-BSS (vif) configuration files with - -b: - * extended global control interface ADD/REMOVE commands to allow BSSes - of a radio to be removed individually without having to add/remove all - other BSSes of the radio at the same time - * added support for sending debug info to Linux tracing (-T on command - line) - * replace dump_file functionality with same information being available - through the hostapd control interface - * added support for using Protected Dual of Public Action frames for - GAS/ANQP exchanges when PMF is enabled - * added support for WPS+NFC updates - - improved protocol - - option to fetch and report alternative carrier records for external - NFC operations - * various bug fixes - -2013-01-12 - v2.0 - * added AP-STA-DISCONNECTED ctrl_iface event - * improved debug logging (human readable event names, interface name - included in more entries) - * added number of small changes to make it easier for static analyzers - to understand the implementation - * added a workaround for Windows 7 Michael MIC failure reporting and - use of the Secure bit in EAPOL-Key msg 3/4 - * fixed number of small bugs (see git logs for more details) - * changed OpenSSL to read full certificate chain from server_cert file - * nl80211: number of updates to use new cfg80211/nl80211 functionality - - replace monitor interface with nl80211 commands - - additional information for driver-based AP SME - * EAP-pwd: - - fix KDF for group 21 and zero-padding - - added support for fragmentation - - increased maximum number of hunting-and-pecking iterations - * avoid excessive Probe Response retries for broadcast Probe Request - frames (only with drivers using hostapd SME/MLME) - * added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y) - * fixed WPS operation stopping on dual concurrent AP - * added wps_rf_bands configuration parameter for overriding RF Bands - value for WPS - * added support for getting per-device PSK from RADIUS Tunnel-Password - * added support for libnl 3.2 and newer - * increased initial group key handshake retransmit timeout to 500 ms - * added a workaround for 4-way handshake to update SNonce even after - having sent EAPOL-Key 3/4 to avoid issues with some supplicant - implementations that can change SNonce for each EAP-Key 2/4 - * added a workaround for EAPOL-Key 4/4 using incorrect type value in - WPA2 mode (some deployed stations use WPA type in that message) - * added a WPS workaround for mixed mode AP Settings with Windows 7 - * changed WPS AP PIN disabling mechanism to disable the PIN after 10 - consecutive failures in addition to using the exponential lockout - period - * added support for WFA Hotspot 2.0 - - GAS/ANQP advertisement of network information - - disable_dgaf parameter to disable downstream group-addressed - forwarding - * simplified licensing terms by selecting the BSD license as the only - alternative - * EAP-SIM: fixed re-authentication not to update pseudonym - * EAP-SIM: use Notification round before EAP-Failure - * EAP-AKA: added support for AT_COUNTER_TOO_SMALL - * EAP-AKA: skip AKA/Identity exchange if EAP identity is recognized - * EAP-AKA': fixed identity for MK derivation - * EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this - breaks interoperability with older versions - * EAP-SIM/AKA: allow pseudonym to be used after unknown reauth id - * changed ANonce to be a random number instead of Counter-based - * added support for canceling WPS operations with hostapd_cli wps_cancel - * fixed EAP/WPS to PSK transition on reassociation in cases where - deauthentication is missed - * hlr_auc_gw enhancements: - - a new command line parameter -u can be used to enable updating of - SQN in Milenage file - - use 5 bit IND for SQN updates - - SQLite database can now be used to store Milenage information - * EAP-SIM/AKA DB: added optional use of SQLite database for pseudonyms - and reauth data - * added support for Chargeable-User-Identity (RFC 4372) - * added radius_auth_req_attr and radius_acct_req_attr configuration - parameters to allow adding/overriding of RADIUS attributes in - Access-Request and Accounting-Request packets - * added support for RADIUS dynamic authorization server (RFC 5176) - * added initial support for WNM operations - - BSS max idle period - - WNM-Sleep Mode - * added new WPS NFC ctrl_iface mechanism - - removed obsoleted WPS_OOB command (including support for deprecated - UFD config_method) - * added FT support for drivers that implement MLME internally - * added SA Query support for drivers that implement MLME internally - * removed default ACM=1 from AC_VO and AC_VI - * changed VENDOR-TEST EAP method to use proper private enterprise number - (this will not interoperate with older versions) - * added hostapd.conf parameter vendor_elements to allow arbitrary vendor - specific elements to be added to the Beacon and Probe Response frames - * added support for configuring GCMP cipher for IEEE 802.11ad - * added support for 256-bit AES with internal TLS implementation - * changed EAPOL transmission to use AC_VO if WMM is active - * fixed EAP-TLS/PEAP/TTLS/FAST server to validate TLS Message Length - correctly; invalid messages could have caused the hostapd process to - terminate before this fix [CVE-2012-4445] - * limit number of active wildcard PINs for WPS Registrar to one to avoid - confusing behavior with multiple wildcard PINs - * added a workaround for WPS PBC session overlap detection to avoid - interop issues with deployed station implementations that do not - remove active PBC indication from Probe Request frames properly - * added support for using SQLite for the eap_user database - * added Acct-Session-Id attribute into Access-Request messages - * fixed EAPOL frame transmission to non-QoS STAs with nl80211 - (do not send QoS frames if the STA did not negotiate use of QoS for - this association) - -2012-05-10 - v1.0 - * Add channel selection support in hostapd. See hostapd.conf. - * Add support for IEEE 802.11v Time Advertisement mechanism with UTC - TSF offset. See hostapd.conf for config info. - * Delay STA entry removal until Deauth/Disassoc TX status in AP mode. - This allows the driver to use PS buffering of Deauthentication and - Disassociation frames when the STA is in power save sleep. Only - available with drivers that provide TX status events for Deauth/ - Disassoc frames (nl80211). - * Allow PMKSA caching to be disabled on the Authenticator. See - hostap.conf config parameter disable_pmksa_caching. - * atheros: Add support for IEEE 802.11w configuration. - * bsd: Add support for setting HT values in IFM_MMASK. - * Allow client isolation to be configured with ap_isolate. Client - isolation can be used to prevent low-level bridging of frames - between associated stations in the BSS. By default, this bridging - is allowed. - * Allow coexistance of HT BSSes with WEP/TKIP BSSes. - * Add require_ht config parameter, which can be used to configure - hostapd to reject association with any station that does not support - HT PHY. - * Add support for writing debug log to a file using "-f" option. Also - add relog CLI command to re-open the log file. - * Add bridge handling for WDS STA interfaces. By default they are - added to the configured bridge of the AP interface (if present), - but the user can also specify a separate bridge using cli command - wds_bridge. - * hostapd_cli: - - Add wds_bridge command for specifying bridge for WDS STA - interfaces. - - Add relog command for reopening log file. - - Send AP-STA-DISCONNECTED event when an AP disconnects a station - due to inactivity. - - Add wps_config ctrl_interface command for configuring AP. This - command can be used to configure the AP using the internal WPS - registrar. It works in the same way as new AP settings received - from an ER. - - Many WPS/WPS ER commands - see WPS/WPS ER sections for details. - - Add command get version, that returns hostapd version string. - * WNM: Add BSS Transition Management Request for ESS Disassoc Imminent. - Use hostapd_cli ess_disassoc (STA addr) (URL) to send the - notification to the STA. - * Allow AP mode to disconnect STAs based on low ACK condition (when - the data connection is not working properly, e.g., due to the STA - going outside the range of the AP). Disabled by default, enable by - config option disassoc_low_ack. - * Add WPA_IGNORE_CONFIG_ERRORS build option to continue in case of bad - config file. - * WPS: - - Send AP Settings as a wrapped Credential attribute to ctrl_iface - in WPS-NEW-AP-SETTINGS. - - Dispatch more WPS events through hostapd ctrl_iface. - - Add mechanism for indicating non-standard WPS errors. - - Change concurrent radio AP to use only one WPS UPnP instance. - - Add wps_check_pin command for processing PIN from user input. - UIs can use this command to process a PIN entered by a user and to - validate the checksum digit (if present). - - Add hostap_cli get_config command to display current AP config. - - Add new hostapd_cli command, wps_ap_pin, to manage AP PIN at - runtime and support dynamic AP PIN management. - - Disable AP PIN after 10 consecutive failures. Slow down attacks - on failures up to 10. - - Allow AP to start in Enrollee mode without AP PIN for probing, - to be compatible with Windows 7. - - Add Config Error into WPS-FAIL events to provide more info - to the user on how to resolve the issue. - - When controlling multiple interfaces: - - apply WPS commands to all interfaces configured to use WPS - - apply WPS config changes to all interfaces that use WPS - - when an attack is detected on any interface, disable AP PIN on - all interfaces - * WPS ER: - - Show SetSelectedRegistrar events as ctrl_iface events. - - Add special AP Setup Locked mode to allow read only ER. - ap_setup_locked=2 can now be used to enable a special mode where - WPS ER can learn the current AP settings, but cannot change them. - * WPS 2.0: Add support for WPS 2.0 (CONFIG_WPS2) - - Add build option CONFIG_WPS_EXTENSIBILITY_TESTING to enable tool - for testing protocol extensibility. - - Add build option CONFIG_WPS_STRICT to allow disabling of WPS - workarounds. - - Add support for AuthorizedMACs attribute. - * TDLS: - - Allow TDLS use or TDLS channel switching in the BSS to be - prohibited in the BSS, using config params tdls_prohibit and - tdls_prohibit_chan_switch. - * EAP server: Add support for configuring fragment size (see - fragment_size in hostapd.conf). - * wlantest: Add a tool wlantest for IEEE802.11 protocol testing. - wlantest can be used to capture frames from a monitor interface - for realtime capturing or from pcap files for offline analysis. - * Interworking: Support added for 802.11u. Enable in .config with - CONFIG_INTERWORKING. See hostapd.conf for config parameters for - interworking. - * Android: Add build and runtime support for Android hostapd. - * Add a new debug message level for excessive information. Use - -ddd to enable. - * TLS: Add support for tls_disable_time_checks=1 in client mode. - * Internal TLS: - - Add support for TLS v1.1 (RFC 4346). Enable with build parameter - CONFIG_TLSV11. - - Add domainComponent parser for X.509 names - * Reorder some IEs to get closer to IEEE 802.11 standard. Move - WMM into end of Beacon, Probe Resp and (Re)Assoc Resp frames. - Move HT IEs to be later in (Re)Assoc Resp. - * Many bugfixes. - -2010-04-18 - v0.7.2 - * fix WPS internal Registrar use when an external Registrar is also - active - * bsd: Cleaned up driver wrapper and added various low-level - configuration options - * TNC: fixed issues with fragmentation - * EAP-TNC: add Flags field into fragment acknowledgement (needed to - interoperate with other implementations; may potentially breaks - compatibility with older wpa_supplicant/hostapd versions) - * cleaned up driver wrapper API for multi-BSS operations - * nl80211: fix multi-BSS and VLAN operations - * fix number of issues with IEEE 802.11r/FT; this version is not - backwards compatible with old versions - * add SA Query Request processing in AP mode (IEEE 802.11w) - * fix IGTK PN in group rekeying (IEEE 802.11w) - * fix WPS PBC session overlap detection to use correct attribute - * hostapd_notif_Assoc() can now be called with all IEs to simplify - driver wrappers - * work around interoperability issue with some WPS External Registrar - implementations - * nl80211: fix WPS IE update - * hostapd_cli: add support for action script operations (run a script - on hostapd events) - * fix DH padding with internal crypto code (mainly, for WPS) - * fix WPS association with both WPS IE and WPA/RSN IE present with - driver wrappers that use hostapd MLME (e.g., nl80211) - -2010-01-16 - v0.7.1 - * cleaned up driver wrapper API (struct wpa_driver_ops); the new API - is not fully backwards compatible, so out-of-tree driver wrappers - will need modifications - * cleaned up various module interfaces - * merge hostapd and wpa_supplicant developers' documentation into a - single document - * fixed HT Capabilities IE with nl80211 drivers - * moved generic AP functionality code into src/ap - * WPS: handle Selected Registrar as union of info from all Registrars - * remove obsolte Prism54.org driver wrapper - * added internal debugging mechanism with backtrace support and memory - allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y) - * EAP-FAST server: piggyback Phase 2 start with the end of Phase 1 - * WPS: add support for dynamically selecting whether to provision the - PSK as an ASCII passphrase or PSK - * added support for WDS (4-address frame) mode with per-station virtual - interfaces (wds_sta=1 in config file; only supported with - driver=nl80211 for now) - * fixed WPS Probe Request processing to handle missing required - attribute - * fixed PKCS#12 use with OpenSSL 1.0.0 - * detect bridge interface automatically so that bridge parameter in - hostapd.conf becomes optional (though, it may now be used to - automatically add then WLAN interface into a bridge with - driver=nl80211) - -2009-11-21 - v0.7.0 - * increased hostapd_cli ping interval to 5 seconds and made this - configurable with a new command line options (-G) - * driver_nl80211: use Linux socket filter to improve performance - * added support for external Registrars with WPS (UPnP transport) - * 802.11n: scan for overlapping BSSes before starting 20/40 MHz channel - * driver_nl80211: fixed STA accounting data collection (TX/RX bytes - reported correctly; TX/RX packets not yet available from kernel) - * added support for WPS USBA out-of-band mechanism with USB Flash - Drives (UFD) (CONFIG_WPS_UFD=y) - * fixed EAPOL/EAP reauthentication when using an external RADIUS - authentication server - * fixed TNC with EAP-TTLS - * fixed IEEE 802.11r key derivation function to match with the standard - (note: this breaks interoperability with previous version) [Bug 303] - * fixed SHA-256 based key derivation function to match with the - standard when using CCMP (for IEEE 802.11r and IEEE 802.11w) - (note: this breaks interoperability with previous version) [Bug 307] - * added number of code size optimizations to remove unnecessary - functionality from the program binary based on build configuration - (part of this automatic; part configurable with CONFIG_NO_* build - options) - * use shared driver wrapper files with wpa_supplicant - * driver_nl80211: multiple updates to provide support for new Linux - nl80211/mac80211 functionality - * updated management frame protection to use IEEE Std 802.11w-2009 - * fixed number of small WPS issues and added workarounds to - interoperate with common deployed broken implementations - * added some IEEE 802.11n co-existence rules to disable 40 MHz channels - or modify primary/secondary channels if needed based on neighboring - networks - * added support for NFC out-of-band mechanism with WPS - * added preliminary support for IEEE 802.11r RIC processing - -2009-01-06 - v0.6.7 - * added support for Wi-Fi Protected Setup (WPS) - (hostapd can now be configured to act as an integrated WPS Registrar - and provision credentials for WPS Enrollees using PIN and PBC - methods; external wireless Registrar can configure the AP, but - external WLAN Manager Registrars are not supported); WPS support can - be enabled by adding CONFIG_WPS=y into .config and setting the - runtime configuration variables in hostapd.conf (see WPS section in - the example configuration file); new hostapd_cli commands wps_pin and - wps_pbc are used to configure WPS negotiation; see README-WPS for - more details - * added IEEE 802.11n HT capability configuration (ht_capab) - * added support for generating Country IE based on nl80211 regulatory - information (added if ieee80211d=1 in configuration) - * fixed WEP authentication (both Open System and Shared Key) with - mac80211 - * added support for EAP-AKA' (draft-arkko-eap-aka-kdf) - * added support for using driver_test over UDP socket - * changed EAP-GPSK to use the IANA assigned EAP method type 51 - * updated management frame protection to use IEEE 802.11w/D7.0 - * fixed retransmission of EAP requests if no response is received - -2008-11-23 - v0.6.6 - * added a new configuration option, wpa_ptk_rekey, that can be used to - enforce frequent PTK rekeying, e.g., to mitigate some attacks against - TKIP deficiencies - * updated OpenSSL code for EAP-FAST to use an updated version of the - session ticket overriding API that was included into the upstream - OpenSSL 0.9.9 tree on 2008-11-15 (no additional OpenSSL patch is - needed with that version anymore) - * changed channel flags configuration to read the information from - the driver (e.g., via driver_nl80211 when using mac80211) instead of - using hostapd as the source of the regulatory information (i.e., - information from CRDA is now used with mac80211); this allows 5 GHz - channels to be used with hostapd (if allowed in the current - regulatory domain) - * fixed EAP-TLS message processing for the last TLS message if it is - large enough to require fragmentation (e.g., if a large Session - Ticket data is included) - * fixed listen interval configuration for nl80211 drivers - -2008-11-01 - v0.6.5 - * added support for SHA-256 as X.509 certificate digest when using the - internal X.509/TLSv1 implementation - * fixed EAP-FAST PAC-Opaque padding (0.6.4 broke this for some peer - identity lengths) - * fixed internal TLSv1 implementation for abbreviated handshake (used - by EAP-FAST server) - * added support for setting VLAN ID for STAs based on local MAC ACL - (accept_mac_file) as an alternative for RADIUS server-based - configuration - * updated management frame protection to use IEEE 802.11w/D6.0 - (adds a new association ping to protect against unauthenticated - authenticate or (re)associate request frames dropping association) - * added support for using SHA256-based stronger key derivation for WPA2 - (IEEE 802.11w) - * added new "driver wrapper" for RADIUS-only configuration - (driver=none in hostapd.conf; CONFIG_DRIVER_NONE=y in .config) - * fixed WPA/RSN IE validation to verify that the proto (WPA vs. WPA2) - is enabled in configuration - * changed EAP-FAST configuration to use separate fields for A-ID and - A-ID-Info (eap_fast_a_id_info) to allow A-ID to be set to a fixed - 16-octet len binary value for better interoperability with some peer - implementations; eap_fast_a_id is now configured as a hex string - * driver_nl80211: Updated to match the current Linux mac80211 AP mode - configuration (wireless-testing.git and Linux kernel releases - starting from 2.6.29) - -2008-08-10 - v0.6.4 - * added peer identity into EAP-FAST PAC-Opaque and skip Phase 2 - Identity Request if identity is already known - * added support for EAP Sequences in EAP-FAST Phase 2 - * added support for EAP-TNC (Trusted Network Connect) - (this version implements the EAP-TNC method and EAP-TTLS/EAP-FAST - changes needed to run two methods in sequence (IF-T) and the IF-IMV - and IF-TNCCS interfaces from TNCS) - * added support for optional cryptobinding with PEAPv0 - * added fragmentation support for EAP-TNC - * added support for fragmenting EAP-TTLS/PEAP/FAST Phase 2 (tunneled) - data - * added support for opportunistic key caching (OKC) - -2008-02-22 - v0.6.3 - * fixed Reassociation Response callback processing when using internal - MLME (driver_{hostap,nl80211,test}.c) - * updated FT support to use the latest draft, IEEE 802.11r/D9.0 - * copy optional Proxy-State attributes into RADIUS response when acting - as a RADIUS authentication server - * fixed EAPOL state machine to handle a case in which no response is - received from the RADIUS authentication server; previous version - could have triggered a crash in some cases after a timeout - * fixed EAP-SIM/AKA realm processing to allow decorated usernames to - be used - * added a workaround for EAP-SIM/AKA peers that include incorrect null - termination in the username - * fixed EAP-SIM/AKA protected result indication to include AT_COUNTER - attribute in notification messages only when using fast - reauthentication - * fixed EAP-SIM Start response processing for fast reauthentication - case - * added support for pending EAP processing in EAP-{PEAP,TTLS,FAST} - phase 2 to allow EAP-SIM and EAP-AKA to be used as the Phase 2 method - -2008-01-01 - v0.6.2 - * fixed EAP-SIM and EAP-AKA message parser to validate attribute - lengths properly to avoid potential crash caused by invalid messages - * added data structure for storing allocated buffers (struct wpabuf); - this does not affect hostapd usage, but many of the APIs changed - and various interfaces (e.g., EAP) is not compatible with old - versions - * added support for protecting EAP-AKA/Identity messages with - AT_CHECKCODE (optional feature in RFC 4187) - * added support for protected result indication with AT_RESULT_IND for - EAP-SIM and EAP-AKA (eap_sim_aka_result_ind=1) - * added support for configuring EAP-TTLS phase 2 non-EAP methods in - EAP server configuration; previously all four were enabled for every - phase 2 user, now all four are disabled by default and need to be - enabled with new method names TTLS-PAP, TTLS-CHAP, TTLS-MSCHAP, - TTLS-MSCHAPV2 - * removed old debug printing mechanism and the related 'debug' - parameter in the configuration file; debug verbosity is now set with - -d (or -dd) command line arguments - * added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt); - only shared key/password authentication is supported in this version - -2007-11-24 - v0.6.1 - * added experimental, integrated TLSv1 server implementation with the - needed X.509/ASN.1/RSA/bignum processing (this can be enabled by - setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in - .config); this can be useful, e.g., if the target system does not - have a suitable TLS library and a minimal code size is required - * added support for EAP-FAST server method to the integrated EAP - server - * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest - draft (draft-ietf-emu-eap-gpsk-07.txt) - * added a new configuration parameter, rsn_pairwise, to allow different - pairwise cipher suites to be enabled for WPA and RSN/WPA2 - (note: if wpa_pairwise differs from rsn_pairwise, the driver will - either need to support this or will have to use the WPA/RSN IEs from - hostapd; currently, the included madwifi and bsd driver interfaces do - not have support for this) - * updated FT support to use the latest draft, IEEE 802.11r/D8.0 - -2007-05-28 - v0.6.0 - * added experimental IEEE 802.11r/D6.0 support - * updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48 - * updated EAP-PSK to use the IANA-allocated EAP type 47 - * fixed EAP-PSK bit ordering of the Flags field - * fixed configuration reloading (SIGHUP) to re-initialize WPA PSKs - by reading wpa_psk_file [Bug 181] - * fixed EAP-TTLS AVP parser processing for too short AVP lengths - * fixed IPv6 connection to RADIUS accounting server - * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest - draft (draft-ietf-emu-eap-gpsk-04.txt) - * hlr_auc_gw: read GSM triplet file into memory and rotate through the - entries instead of only using the same three triplets every time - (this does not work properly with tests using multiple clients, but - provides bit better triplet data for testing a single client; anyway, - if a better quality triplets are needed, GSM-Milenage should be used - instead of hardcoded triplet file) - * fixed EAP-MSCHAPv2 server to use a space between S and M parameters - in Success Request [Bug 203] - * added support for sending EAP-AKA Notifications in error cases - * updated to use IEEE 802.11w/D2.0 for management frame protection - (still experimental) - * RADIUS server: added support for processing duplicate messages - (retransmissions from RADIUS client) by replying with the previous - reply - -2006-11-24 - v0.5.6 - * added support for configuring and controlling multiple BSSes per - radio interface (bss= in hostapd.conf); this is only - available with Devicescape and test driver interfaces - * fixed PMKSA cache update in the end of successful RSN - pre-authentication - * added support for dynamic VLAN configuration (i.e., selecting VLAN-ID - for each STA based on RADIUS Access-Accept attributes); this requires - VLAN support from the kernel driver/802.11 stack and this is - currently only available with Devicescape and test driver interfaces - * driver_madwifi: fixed configuration of unencrypted modes (plaintext - and IEEE 802.1X without WEP) - * removed STAKey handshake since PeerKey handshake has replaced it in - IEEE 802.11ma and there are no known deployments of STAKey - * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest - draft (draft-ietf-emu-eap-gpsk-01.txt) - * added preliminary implementation of IEEE 802.11w/D1.0 (management - frame protection) - (Note: this requires driver support to work properly.) - (Note2: IEEE 802.11w is an unapproved draft and subject to change.) - * hlr_auc_gw: added support for GSM-Milenage (for EAP-SIM) - * hlr_auc_gw: added support for reading per-IMSI Milenage keys and - parameters from a text file to make it possible to implement proper - GSM/UMTS authentication server for multiple SIM/USIM cards using - EAP-SIM/EAP-AKA - * fixed session timeout processing with drivers that do not use - ieee802_11.c (e.g., madwifi) - -2006-08-27 - v0.5.5 - * added 'hostapd_cli new_sta ' command for adding a new STA into - hostapd (e.g., to initialize wired network authentication based on an - external signal) - * fixed hostapd to add PMKID KDE into 4-Way Handshake Message 1 when - using WPA2 even if PMKSA caching is not used - * added -P argument for hostapd to write the current process - id into a file - * added support for RADIUS Authentication Server MIB (RFC 2619) - -2006-06-20 - v0.5.4 - * fixed nt_password_hash build [Bug 144] - * added PeerKey handshake implementation for IEEE 802.11e - direct link setup (DLS) to replace STAKey handshake - * added support for EAP Generalized Pre-Shared Key (EAP-GPSK, - draft-clancy-emu-eap-shared-secret-00.txt) - * fixed a segmentation fault when RSN pre-authentication was completed - successfully [Bug 152] - -2006-04-27 - v0.5.3 - * do not build nt_password_hash and hlr_auc_gw by default to avoid - requiring a TLS library for a successful build; these programs can be - build with 'make nt_password_hash' and 'make hlr_auc_gw' - * added a new configuration option, eapol_version, that can be used to - set EAPOL version to 1 (default is 2) to work around broken client - implementations that drop EAPOL frames which use version number 2 - [Bug 89] - * added support for EAP-SAKE (no EAP method number allocated yet, so - this is using the same experimental type 255 as EAP-PSK) - * fixed EAP-MSCHAPv2 message length validation - -2006-03-19 - v0.5.2 - * fixed stdarg use in hostapd_logger(): if both stdout and syslog - logging was enabled, hostapd could trigger a segmentation fault in - vsyslog on some CPU -- C library combinations - * moved HLR/AuC gateway implementation for EAP-SIM/AKA into an external - program to make it easier to use for implementing real SS7 gateway; - eap_sim_db is not anymore used as a file name for GSM authentication - triplets; instead, it is path to UNIX domain socket that will be used - to communicate with the external gateway program (e.g., hlr_auc_gw) - * added example HLR/AuC gateway implementation, hlr_auc_gw, that uses - local information (GSM authentication triplets from a text file and - hardcoded AKA authentication data); this can be used to test EAP-SIM - and EAP-AKA - * added Milenage algorithm (example 3GPP AKA algorithm) to hlr_auc_gw - to make it possible to test EAP-AKA with real USIM cards (this is - disabled by default; define AKA_USE_MILENAGE when building hlr_auc_gw - to enable this) - * driver_madwifi: added support for getting station RSN IE from - madwifi-ng svn r1453 and newer; this fixes RSN that was apparently - broken with earlier change (r1357) in the driver - * changed EAP method registration to use a dynamic list of methods - instead of a static list generated at build time - * fixed WPA message 3/4 not to encrypt Key Data field (WPA IE) - [Bug 125] - * added ap_max_inactivity configuration parameter - -2006-01-29 - v0.5.1 - * driver_test: added better support for multiple APs and STAs by using - a directory with sockets that include MAC address for each device in - the name (test_socket=DIR:/tmp/test) - * added support for EAP expanded type (vendor specific EAP methods) - -2005-12-18 - v0.5.0 (beginning of 0.5.x development releases) - * added experimental STAKey handshake implementation for IEEE 802.11e - direct link setup (DLS); note: this is disabled by default in both - build and runtime configuration (can be enabled with CONFIG_STAKEY=y - and stakey=1) - * added support for EAP methods to use callbacks to external programs - by buffering a pending request and processing it after the EAP method - is ready to continue - * improved EAP-SIM database interface to allow external request to GSM - HLR/AuC without blocking hostapd process - * added support for using EAP-SIM pseudonyms and fast re-authentication - * added support for EAP-AKA in the integrated EAP authenticator - * added support for matching EAP identity prefixes (e.g., "1"*) in EAP - user database to allow EAP-SIM/AKA selection without extra roundtrip - for EAP-Nak negotiation - * added support for storing EAP user password as NtPasswordHash instead - of plaintext password when using MSCHAP or MSCHAPv2 for - authentication (hash:<16-octet hex value>); added nt_password_hash - tool for hashing password to generate NtPasswordHash - -2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases) - * driver_wired: fixed EAPOL sending to optionally use PAE group address - as the destination instead of supplicant MAC address; this is - disabled by default, but should be enabled with use_pae_group_addr=1 - in configuration file if the wired interface is used by only one - device at the time (common switch configuration) - * driver_madwifi: configure driver to use TKIP countermeasures in order - to get correct behavior (IEEE 802.11 association failing; previously, - association succeeded, but hostpad forced disassociation immediately) - * driver_madwifi: added support for madwifi-ng - -2005-10-27 - v0.4.6 - * added support for replacing user identity from EAP with RADIUS - User-Name attribute from Access-Accept message, if that is included, - for the RADIUS accounting messages (e.g., for EAP-PEAP/TTLS to get - tunneled identity into accounting messages when the RADIUS server - does not support better way of doing this with Class attribute) - * driver_madwifi: fixed EAPOL packet receive for configuration where - ath# is part of a bridge interface - * added a configuration file and log analyzer script for logwatch - * fixed EAPOL state machine step function to process all state - transitions before processing new events; this resolves a race - condition in which EAPOL-Start message could trigger hostapd to send - two EAP-Response/Identity frames to the authentication server - -2005-09-25 - v0.4.5 - * added client CA list to the TLS certificate request in order to make - it easier for the client to select which certificate to use - * added experimental support for EAP-PSK - * added support for WE-19 (hostap, madwifi) - -2005-08-21 - v0.4.4 - * fixed build without CONFIG_RSN_PREAUTH - * fixed FreeBSD build - -2005-06-26 - v0.4.3 - * fixed PMKSA caching to copy User-Name and Class attributes so that - RADIUS accounting gets correct information - * start RADIUS accounting only after successful completion of WPA - 4-Way Handshake if WPA-PSK is used - * fixed PMKSA caching for the case where STA (re)associates without - first disassociating - -2005-06-12 - v0.4.2 - * EAP-PAX is now registered as EAP type 46 - * fixed EAP-PAX MAC calculation - * fixed EAP-PAX CK and ICK key derivation - * renamed eap_authenticator configuration variable to eap_server to - better match with RFC 3748 (EAP) terminology - * driver_test: added support for testing hostapd with wpa_supplicant - by using test driver interface without any kernel drivers or network - cards - -2005-05-22 - v0.4.1 - * fixed RADIUS server initialization when only auth or acct server - is configured and the other one is left empty - * driver_madwifi: added support for RADIUS accounting - * driver_madwifi: added preliminary support for compiling against 'BSD' - branch of madwifi CVS tree - * driver_madwifi: fixed pairwise key removal to allow WPA reauth - without disassociation - * added support for reading additional certificates from PKCS#12 files - and adding them to the certificate chain - * fixed RADIUS Class attribute processing to only use Access-Accept - packets to update Class; previously, other RADIUS authentication - packets could have cleared Class attribute - * added support for more than one Class attribute in RADIUS packets - * added support for verifying certificate revocation list (CRL) when - using integrated EAP authenticator for EAP-TLS; new hostapd.conf - options 'check_crl'; CRL must be included in the ca_cert file for now - -2005-04-25 - v0.4.0 (beginning of 0.4.x development releases) - * added support for including network information into - EAP-Request/Identity message (ASCII-0 (nul) in eap_message) - (e.g., to implement draft-adrange-eap-network-discovery-07.txt) - * fixed a bug which caused some RSN pre-authentication cases to use - freed memory and potentially crash hostapd - * fixed private key loading for cases where passphrase is not set - * added support for sending TLS alerts and aborting authentication - when receiving a TLS alert - * fixed WPA2 to add PMKSA cache entry when using integrated EAP - authenticator - * fixed PMKSA caching (EAP authentication was not skipped correctly - with the new state machine changes from IEEE 802.1X draft) - * added support for RADIUS over IPv6; own_ip_addr, auth_server_addr, - and acct_server_addr can now be IPv6 addresses (CONFIG_IPV6=y needs - to be added to .config to include IPv6 support); for RADIUS server, - radius_server_ipv6=1 needs to be set in hostapd.conf and addresses - in RADIUS clients file can then use IPv6 format - * added experimental support for EAP-PAX - * replaced hostapd control interface library (hostapd_ctrl.[ch]) with - the same implementation that wpa_supplicant is using (wpa_ctrl.[ch]) - -2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases) - -2005-01-23 - v0.3.5 - * added support for configuring a forced PEAP version based on the - Phase 1 identity - * fixed PEAPv1 to use tunneled EAP-Success/Failure instead of EAP-TLV - to terminate authentication - * fixed EAP identifier duplicate processing with the new IEEE 802.1X - draft - * clear accounting data in the driver when starting a new accounting - session - * driver_madwifi: filter wireless events based on ifindex to allow more - than one network interface to be used - * fixed WPA message 2/4 processing not to cancel timeout for TimeoutEvt - setting if the packet does not pass MIC verification (e.g., due to - incorrect PSK); previously, message 1/4 was not tried again if an - invalid message 2/4 was received - * fixed reconfiguration of RADIUS client retransmission timer when - adding a new message to the pending list; previously, timer was not - updated at this point and if there was a pending message with long - time for the next retry, the new message needed to wait that long for - its first retry, too - -2005-01-09 - v0.3.4 - * added support for configuring multiple allowed EAP types for Phase 2 - authentication (EAP-PEAP, EAP-TTLS) - * fixed EAPOL-Start processing to trigger WPA reauthentication - (previously, only EAPOL authentication was done) - -2005-01-02 - v0.3.3 - * added support for EAP-PEAP in the integrated EAP authenticator - * added support for EAP-GTC in the integrated EAP authenticator - * added support for configuring list of EAP methods for Phase 1 so that - the integrated EAP authenticator can, e.g., use the wildcard entry - for EAP-TLS and EAP-PEAP - * added support for EAP-TTLS in the integrated EAP authenticator - * added support for EAP-SIM in the integrated EAP authenticator - * added support for using hostapd as a RADIUS authentication server - with the integrated EAP authenticator taking care of EAP - authentication (new hostapd.conf options: radius_server_clients and - radius_server_auth_port); this is not included in default build; use - CONFIG_RADIUS_SERVER=y in .config to include - -2004-12-19 - v0.3.2 - * removed 'daemonize' configuration file option since it has not really - been used at all for more than year - * driver_madwifi: fixed group key setup and added get_ssid method - * added support for EAP-MSCHAPv2 in the integrated EAP authenticator - -2004-12-12 - v0.3.1 - * added support for integrated EAP-TLS authentication (new hostapd.conf - variables: ca_cert, server_cert, private_key, private_key_passwd); - this enabled dynamic keying (WPA2/WPA/IEEE 802.1X/WEP) without - external RADIUS server - * added support for reading PKCS#12 (PFX) files (as a replacement for - PEM/DER) to get certificate and private key (CONFIG_PKCS12) - -2004-12-05 - v0.3.0 (beginning of 0.3.x development releases) - * added support for Acct-{Input,Output}-Gigawords - * added support for Event-Timestamp (in RADIUS Accounting-Requests) - * added support for RADIUS Authentication Client MIB (RFC2618) - * added support for RADIUS Accounting Client MIB (RFC2620) - * made EAP re-authentication period configurable (eap_reauth_period) - * fixed EAPOL reauthentication to trigger WPA/WPA2 reauthentication - * fixed EAPOL state machine to stop if STA is removed during - eapol_sm_step(); this fixes at least one segfault triggering bug with - IEEE 802.11i pre-authentication - * added support for multiple WPA pre-shared keys (e.g., one for each - client MAC address or keys shared by a group of clients); - new hostapd.conf field wpa_psk_file for setting path to a text file - containing PSKs, see hostapd.wpa_psk for an example - * added support for multiple driver interfaces to allow hostapd to be - used with other drivers - * added wired authenticator driver interface (driver=wired in - hostapd.conf, see wired.conf for example configuration) - * added madwifi driver interface (driver=madwifi in hostapd.conf, see - madwifi.conf for example configuration; Note: include files from - madwifi project is needed for building and a configuration file, - .config, needs to be created in hostapd directory with - CONFIG_DRIVER_MADWIFI=y to include this driver interface in hostapd - build) - * fixed an alignment issue that could cause SHA-1 to fail on some - platforms (e.g., Intel ixp425 with a compiler that does not 32-bit - align variables) - * fixed RADIUS reconnection after an error in sending interim - accounting packets - * added hostapd control interface for external programs and an example - CLI, hostapd_cli (like wpa_cli for wpa_supplicant) - * started adding dot11, dot1x, radius MIBs ('hostapd_cli mib', - 'hostapd_cli sta ') - * finished update from IEEE 802.1X-2001 to IEEE 802.1X-REV (now d11) - * added support for strict GTK rekeying (wpa_strict_rekey in - hostapd.conf) - * updated IAPP to use UDP port 3517 and multicast address 224.0.1.178 - (instead of broadcast) for IAPP ADD-notify (moved from draft 3 to - IEEE 802.11F-2003) - * added Prism54 driver interface (driver=prism54 in hostapd.conf; - note: .config needs to be created in hostapd directory with - CONFIG_DRIVER_PRISM54=y to include this driver interface in hostapd - build) - * dual-licensed hostapd (GPLv2 and BSD licenses) - * fixed RADIUS accounting to generate a new session id for cases where - a station reassociates without first being complete deauthenticated - * fixed STA disassociation handler to mark next timeout state to - deauthenticate the station, i.e., skip long wait for inactivity poll - and extra disassociation, if the STA disassociates without - deauthenticating - * added integrated EAP authenticator that can be used instead of - external RADIUS authentication server; currently, only EAP-MD5 is - supported, so this cannot yet be used for key distribution; the EAP - method interface is generic, though, so adding new EAP methods should - be straightforward; new hostapd.conf variables: 'eap_authenticator' - and 'eap_user_file'; this obsoletes "minimal authentication server" - ('minimal_eap' in hostapd.conf) which is now removed - * added support for FreeBSD and driver interface for the BSD net80211 - layer (driver=bsd in hostapd.conf and CONFIG_DRIVER_BSD=y in - .config); please note that some of the required kernel mods have not - yet been committed - -2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases) - * fixed some accounting cases where Accounting-Start was sent when - IEEE 802.1X port was being deauthorized - -2004-06-20 - v0.2.3 - * modified RADIUS client to re-connect the socket in case of certain - error codes that are generated when a network interface state is - changes (e.g., when IP address changes or the interface is set UP) - * fixed couple of cases where EAPOL state for a station was freed - twice causing a segfault for hostapd - * fixed couple of bugs in processing WPA deauthentication (freed data - was used) - -2004-05-31 - v0.2.2 - * fixed WPA/WPA2 group rekeying to use key index correctly (GN/GM) - * fixed group rekeying to send zero TSC in EAPOL-Key messages to fix - cases where STAs dropped multicast frames as replay attacks - * added support for copying RADIUS Attribute 'Class' from - authentication messages into accounting messages - * send canned EAP failure if RADIUS server sends Access-Reject without - EAP message (previously, Supplicant was not notified in this case) - * fixed mixed WPA-PSK and WPA-EAP mode to work with WPA-PSK (i.e., do - not start EAPOL state machines if the STA selected to use WPA-PSK) - -2004-05-06 - v0.2.1 - * added WPA and IEEE 802.11i/RSN (WPA2) Authenticator functionality - - based on IEEE 802.11i/D10.0 but modified to interoperate with WPA - (i.e., IEEE 802.11i/D3.0) - - supports WPA-only, RSN-only, and mixed WPA/RSN mode - - both WPA-PSK and WPA-RADIUS/EAP are supported - - PMKSA caching and pre-authentication - - new hostapd.conf variables: wpa, wpa_psk, wpa_passphrase, - wpa_key_mgmt, wpa_pairwise, wpa_group_rekey, wpa_gmk_rekey, - rsn_preauth, rsn_preauth_interfaces - * fixed interim accounting to remove any pending accounting messages - to the STA before sending a new one - -2004-02-15 - v0.2.0 - * added support for Acct-Interim-Interval: - - draft-ietf-radius-acct-interim-01.txt - - use Acct-Interim-Interval attribute from Access-Accept if local - 'radius_acct_interim_interval' is not set - - allow different update intervals for each STA - * fixed event loop to call signal handlers only after returning from - the real signal handler - * reset sta->timeout_next after successful association to make sure - that the previously registered inactivity timer will not remove the - STA immediately (e.g., if STA deauthenticates and re-associates - before the timer is triggered). - * added new hostapd.conf variable, nas_identifier, that can be used to - add an optional RADIUS Attribute, NAS-Identifier, into authentication - and accounting messages - * added support for Accounting-On and Accounting-Off messages - * fixed accounting session handling to send Accounting-Start only once - per session and not to send Accounting-Stop if the session was not - initialized properly - * fixed Accounting-Stop statistics in cases where the message was - previously sent after the kernel entry for the STA (and/or IEEE - 802.1X data) was removed - - -Note: - -Older changes up to and including v0.1.0 are included in the ChangeLog -of the Host AP driver. diff --git a/contrib/hostapd/hostapd/README b/contrib/hostapd/hostapd/README deleted file mode 100644 index 50868ee1de..0000000000 --- a/contrib/hostapd/hostapd/README +++ /dev/null @@ -1,372 +0,0 @@ -hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP - Authenticator and RADIUS authentication server -================================================================ - -Copyright (c) 2002-2014, Jouni Malinen and contributors -All Rights Reserved. - -This program is licensed under the BSD license (the one with -advertisement clause removed). - -If you are submitting changes to the project, please see CONTRIBUTIONS -file for more instructions. - - - -License -------- - -This software may be distributed, used, and modified under the terms of -BSD license: - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name(s) of the above-listed copyright holder(s) nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - -Introduction -============ - -Originally, hostapd was an optional user space component for Host AP -driver. It adds more features to the basic IEEE 802.11 management -included in the kernel driver: using external RADIUS authentication -server for MAC address based access control, IEEE 802.1X Authenticator -and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN) -Authenticator and dynamic TKIP/CCMP keying. - -The current version includes support for other drivers, an integrated -EAP server (i.e., allow full authentication without requiring -an external RADIUS authentication server), and RADIUS authentication -server for EAP authentication. - - -Requirements ------------- - -Current hardware/software requirements: -- drivers: - Host AP driver for Prism2/2.5/3. - (http://hostap.epitest.fi/) - Please note that station firmware version needs to be 1.7.0 or newer - to work in WPA mode. - - madwifi driver for cards based on Atheros chip set (ar521x) - (http://sourceforge.net/projects/madwifi/) - Please note that you will need to add the correct path for - madwifi driver root directory in .config (see defconfig file for - an example: CFLAGS += -I) - - mac80211-based drivers that support AP mode (with driver=nl80211). - This includes drivers for Atheros (ath9k) and Broadcom (b43) - chipsets. - - Any wired Ethernet driver for wired IEEE 802.1X authentication - (experimental code) - - FreeBSD -current (with some kernel mods that have not yet been - committed when hostapd v0.3.0 was released) - BSD net80211 layer (e.g., Atheros driver) - - -Build configuration -------------------- - -In order to be able to build hostapd, you will need to create a build -time configuration file, .config that selects which optional -components are included. See defconfig file for example configuration -and list of available options. - - - -IEEE 802.1X -=========== - -IEEE Std 802.1X-2001 is a standard for port-based network access -control. In case of IEEE 802.11 networks, a "virtual port" is used -between each associated station and the AP. IEEE 802.11 specifies -minimal authentication mechanism for stations, whereas IEEE 802.1X -introduces a extensible mechanism for authenticating and authorizing -users. - -IEEE 802.1X uses elements called Supplicant, Authenticator, Port -Access Entity, and Authentication Server. Supplicant is a component in -a station and it performs the authentication with the Authentication -Server. An access point includes an Authenticator that relays the packets -between a Supplicant and an Authentication Server. In addition, it has a -Port Access Entity (PAE) with Authenticator functionality for -controlling the virtual port authorization, i.e., whether to accept -packets from or to the station. - -IEEE 802.1X uses Extensible Authentication Protocol (EAP). The frames -between a Supplicant and an Authenticator are sent using EAP over LAN -(EAPOL) and the Authenticator relays these frames to the Authentication -Server (and similarly, relays the messages from the Authentication -Server to the Supplicant). The Authentication Server can be colocated with the -Authenticator, in which case there is no need for additional protocol -for EAP frame transmission. However, a more common configuration is to -use an external Authentication Server and encapsulate EAP frame in the -frames used by that server. RADIUS is suitable for this, but IEEE -802.1X would also allow other mechanisms. - -Host AP driver includes PAE functionality in the kernel driver. It -is a relatively simple mechanism for denying normal frames going to -or coming from an unauthorized port. PAE allows IEEE 802.1X related -frames to be passed between the Supplicant and the Authenticator even -on an unauthorized port. - -User space daemon, hostapd, includes Authenticator functionality. It -receives 802.1X (EAPOL) frames from the Supplicant using the wlan#ap -device that is also used with IEEE 802.11 management frames. The -frames to the Supplicant are sent using the same device. - -The normal configuration of the Authenticator would use an external -Authentication Server. hostapd supports RADIUS encapsulation of EAP -packets, so the Authentication Server should be a RADIUS server, like -FreeRADIUS (http://www.freeradius.org/). The Authenticator in hostapd -relays the frames between the Supplicant and the Authentication -Server. It also controls the PAE functionality in the kernel driver by -controlling virtual port authorization, i.e., station-AP -connection, based on the IEEE 802.1X state. - -When a station would like to use the services of an access point, it -will first perform IEEE 802.11 authentication. This is normally done -with open systems authentication, so there is no security. After -this, IEEE 802.11 association is performed. If IEEE 802.1X is -configured to be used, the virtual port for the station is set in -Unauthorized state and only IEEE 802.1X frames are accepted at this -point. The Authenticator will then ask the Supplicant to authenticate -with the Authentication Server. After this is completed successfully, -the virtual port is set to Authorized state and frames from and to the -station are accepted. - -Host AP configuration for IEEE 802.1X -------------------------------------- - -The user space daemon has its own configuration file that can be used to -define AP options. Distribution package contains an example -configuration file (hostapd/hostapd.conf) that can be used as a basis -for configuration. It includes examples of all supported configuration -options and short description of each option. hostapd should be started -with full path to the configuration file as the command line argument, -e.g., './hostapd /etc/hostapd.conf'. If you have more that one wireless -LAN card, you can use one hostapd process for multiple interfaces by -giving a list of configuration files (one per interface) in the command -line. - -hostapd includes a minimal co-located IEEE 802.1X server which can be -used to test IEEE 802.1X authentication. However, it should not be -used in normal use since it does not provide any security. This can be -configured by setting ieee8021x and minimal_eap options in the -configuration file. - -An external Authentication Server (RADIUS) is configured with -auth_server_{addr,port,shared_secret} options. In addition, -ieee8021x and own_ip_addr must be set for this mode. With such -configuration, the co-located Authentication Server is not used and EAP -frames will be relayed using EAPOL between the Supplicant and the -Authenticator and RADIUS encapsulation between the Authenticator and -the Authentication Server. Other than this, the functionality is similar -to the case with the co-located Authentication Server. - -Authentication Server and Supplicant ------------------------------------- - -Any RADIUS server supporting EAP should be usable as an IEEE 802.1X -Authentication Server with hostapd Authenticator. FreeRADIUS -(http://www.freeradius.org/) has been successfully tested with hostapd -Authenticator and both Xsupplicant (http://www.open1x.org) and Windows -XP Supplicants. EAP/TLS was used with Xsupplicant and -EAP/MD5-Challenge with Windows XP. - -http://www.missl.cs.umd.edu/wireless/eaptls/ has useful information -about using EAP/TLS with FreeRADIUS and Xsupplicant (just replace -Cisco access point with Host AP driver, hostapd daemon, and a Prism2 -card ;-). http://www.freeradius.org/doc/EAP-MD5.html has information -about using EAP/MD5 with FreeRADIUS, including instructions for WinXP -configuration. http://www.denobula.com/EAPTLS.pdf has a HOWTO on -EAP/TLS use with WinXP Supplicant. - -Automatic WEP key configuration -------------------------------- - -EAP/TLS generates a session key that can be used to send WEP keys from -an AP to authenticated stations. The Authenticator in hostapd can be -configured to automatically select a random default/broadcast key -(shared by all authenticated stations) with wep_key_len_broadcast -option (5 for 40-bit WEP or 13 for 104-bit WEP). In addition, -wep_key_len_unicast option can be used to configure individual unicast -keys for stations. This requires support for individual keys in the -station driver. - -WEP keys can be automatically updated by configuring rekeying. This -will improve security of the network since same WEP key will only be -used for a limited period of time. wep_rekey_period option sets the -interval for rekeying in seconds. - - -WPA/WPA2 -======== - -Features --------- - -Supported WPA/IEEE 802.11i features: -- WPA-PSK ("WPA-Personal") -- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise") -- key management for CCMP, TKIP, WEP104, WEP40 -- RSN/WPA2 (IEEE 802.11i), including PMKSA caching and pre-authentication - -WPA ---- - -The original security mechanism of IEEE 802.11 standard was not -designed to be strong and has proved to be insufficient for most -networks that require some kind of security. Task group I (Security) -of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked -to address the flaws of the base standard and has in practice -completed its work in May 2004. The IEEE 802.11i amendment to the IEEE -802.11 standard was approved in June 2004 and this amendment is likely -to be published in July 2004. - -Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the -IEEE 802.11i work (draft 3.0) to define a subset of the security -enhancements that can be implemented with existing wlan hardware. This -is called Wi-Fi Protected Access (WPA). This has now become a -mandatory component of interoperability testing and certification done -by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web -site (http://www.wi-fi.org/OpenSection/protected_access.asp). - -IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm -for protecting wireless networks. WEP uses RC4 with 40-bit keys, -24-bit initialization vector (IV), and CRC32 to protect against packet -forgery. All these choices have proven to be insufficient: key space is -too small against current attacks, RC4 key scheduling is insufficient -(beginning of the pseudorandom stream should be skipped), IV space is -too small and IV reuse makes attacks easier, there is no replay -protection, and non-keyed authentication does not protect against bit -flipping packet data. - -WPA is an intermediate solution for the security issues. It uses -Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a -compromise on strong security and possibility to use existing -hardware. It still uses RC4 for the encryption like WEP, but with -per-packet RC4 keys. In addition, it implements replay protection, -keyed packet authentication mechanism (Michael MIC). - -Keys can be managed using two different mechanisms. WPA can either use -an external authentication server (e.g., RADIUS) and EAP just like -IEEE 802.1X is using or pre-shared keys without need for additional -servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal", -respectively. Both mechanisms will generate a master session key for -the Authenticator (AP) and Supplicant (client station). - -WPA implements a new key handshake (4-Way Handshake and Group Key -Handshake) for generating and exchanging data encryption keys between -the Authenticator and Supplicant. This handshake is also used to -verify that both Authenticator and Supplicant know the master session -key. These handshakes are identical regardless of the selected key -management mechanism (only the method for generating master session -key changes). - - -IEEE 802.11i / WPA2 -------------------- - -The design for parts of IEEE 802.11i that were not included in WPA has -finished (May 2004) and this amendment to IEEE 802.11 was approved in -June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new -version of WPA called WPA2. This includes, e.g., support for more -robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC) -to replace TKIP and optimizations for handoff (reduced number of -messages in initial key handshake, pre-authentication, and PMKSA caching). - -Some wireless LAN vendors are already providing support for CCMP in -their WPA products. There is no "official" interoperability -certification for CCMP and/or mixed modes using both TKIP and CCMP, so -some interoperability issues can be expected even though many -combinations seem to be working with equipment from different vendors. -Testing for WPA2 is likely to start during the second half of 2004. - -hostapd configuration for WPA/WPA2 ----------------------------------- - -TODO - -# Enable WPA. Setting this variable configures the AP to require WPA (either -# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either -# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK. -# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys), -# RADIUS authentication server must be configured, and WPA-EAP must be included -# in wpa_key_mgmt. -# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0) -# and/or WPA2 (full IEEE 802.11i/RSN): -# bit0 = WPA -# bit1 = IEEE 802.11i/RSN (WPA2) -#wpa=1 - -# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit -# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase -# (8..63 characters) that will be converted to PSK. This conversion uses SSID -# so the PSK changes when ASCII passphrase is used and the SSID is changed. -#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef -#wpa_passphrase=secret passphrase - -# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The -# entries are separated with a space. -#wpa_key_mgmt=WPA-PSK WPA-EAP - -# Set of accepted cipher suites (encryption algorithms) for pairwise keys -# (unicast packets). This is a space separated list of algorithms: -# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i] -# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i] -# Group cipher suite (encryption algorithm for broadcast and multicast frames) -# is automatically selected based on this configuration. If only CCMP is -# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise, -# TKIP will be used as the group cipher. -#wpa_pairwise=TKIP CCMP - -# Time interval for rekeying GTK (broadcast/multicast encryption keys) in -# seconds. -#wpa_group_rekey=600 - -# Time interval for rekeying GMK (master key used internally to generate GTKs -# (in seconds). -#wpa_gmk_rekey=86400 - -# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up -# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN -# authentication and key handshake before actually associating with a new AP. -#rsn_preauth=1 -# -# Space separated list of interfaces from which pre-authentication frames are -# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all -# interface that are used for connections to other APs. This could include -# wired interfaces and WDS links. The normal wireless data interface towards -# associated stations (e.g., wlan0) should not be added, since -# pre-authentication is only used with APs other than the currently associated -# one. -#rsn_preauth_interfaces=eth0 diff --git a/contrib/hostapd/hostapd/README-WPS b/contrib/hostapd/hostapd/README-WPS deleted file mode 100644 index 654b5bcec3..0000000000 --- a/contrib/hostapd/hostapd/README-WPS +++ /dev/null @@ -1,354 +0,0 @@ -hostapd and Wi-Fi Protected Setup (WPS) -======================================= - -This document describes how the WPS implementation in hostapd can be -configured and how an external component on an AP (e.g., web UI) is -used to enable enrollment of client devices. - - -Introduction to WPS -------------------- - -Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a -wireless network. It allows automated generation of random keys (WPA -passphrase/PSK) and configuration of an access point and client -devices. WPS includes number of methods for setting up connections -with PIN method and push-button configuration (PBC) being the most -commonly deployed options. - -While WPS can enable more home networks to use encryption in the -wireless network, it should be noted that the use of the PIN and -especially PBC mechanisms for authenticating the initial key setup is -not very secure. As such, use of WPS may not be suitable for -environments that require secure network access without chance for -allowing outsiders to gain access during the setup phase. - -WPS uses following terms to describe the entities participating in the -network setup: -- access point: the WLAN access point -- Registrar: a device that control a network and can authorize - addition of new devices); this may be either in the AP ("internal - Registrar") or in an external device, e.g., a laptop, ("external - Registrar") -- Enrollee: a device that is being authorized to use the network - -It should also be noted that the AP and a client device may change -roles (i.e., AP acts as an Enrollee and client device as a Registrar) -when WPS is used to configure the access point. - - -More information about WPS is available from Wi-Fi Alliance: -http://www.wi-fi.org/wifi-protected-setup - - -hostapd implementation ----------------------- - -hostapd includes an optional WPS component that can be used as an -internal WPS Registrar to manage addition of new WPS enabled clients -to the network. In addition, WPS Enrollee functionality in hostapd can -be used to allow external WPS Registrars to configure the access -point, e.g., for initial network setup. In addition, hostapd can proxy a -WPS registration between a wireless Enrollee and an external Registrar -(e.g., Microsoft Vista or Atheros JumpStart) with UPnP. - - -hostapd configuration ---------------------- - -WPS is an optional component that needs to be enabled in hostapd build -configuration (.config). Here is an example configuration that -includes WPS support and uses madwifi driver interface: - -CONFIG_DRIVER_MADWIFI=y -CFLAGS += -I/usr/src/madwifi-0.9.3 -CONFIG_WPS=y -CONFIG_WPS2=y -CONFIG_WPS_UPNP=y - -Following parameter can be used to enable support for NFC config method: - -CONFIG_WPS_NFC=y - - -Following section shows an example runtime configuration -(hostapd.conf) that enables WPS: - -# Configure the driver and network interface -driver=madwifi -interface=ath0 - -# WPA2-Personal configuration for the AP -ssid=wps-test -wpa=2 -wpa_key_mgmt=WPA-PSK -wpa_pairwise=CCMP -# Default WPA passphrase for legacy (non-WPS) clients -wpa_passphrase=12345678 -# Enable random per-device PSK generation for WPS clients -# Please note that the file has to exists for hostapd to start (i.e., create an -# empty file as a starting point). -wpa_psk_file=/etc/hostapd.psk - -# Enable control interface for PBC/PIN entry -ctrl_interface=/var/run/hostapd - -# Enable internal EAP server for EAP-WSC (part of Wi-Fi Protected Setup) -eap_server=1 - -# WPS configuration (AP configured, do not allow external WPS Registrars) -wps_state=2 -ap_setup_locked=1 -# If UUID is not configured, it will be generated based on local MAC address. -uuid=87654321-9abc-def0-1234-56789abc0000 -wps_pin_requests=/var/run/hostapd.pin-req -device_name=Wireless AP -manufacturer=Company -model_name=WAP -model_number=123 -serial_number=12345 -device_type=6-0050F204-1 -os_version=01020300 -config_methods=label display push_button keypad - -# if external Registrars are allowed, UPnP support could be added: -#upnp_iface=br0 -#friendly_name=WPS Access Point - - -External operations -------------------- - -WPS requires either a device PIN code (usually, 8-digit number) or a -pushbutton event (for PBC) to allow a new WPS Enrollee to join the -network. hostapd uses the control interface as an input channel for -these events. - -The PIN value used in the commands must be processed by an UI to -remove non-digit characters and potentially, to verify the checksum -digit. "hostapd_cli wps_check_pin " can be used to do such -processing. It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if -the checksum digit is incorrect, or the processed PIN (non-digit -characters removed) if the PIN is valid. - -When a client device (WPS Enrollee) connects to hostapd (WPS -Registrar) in order to start PIN mode negotiation for WPS, an -identifier (Enrollee UUID) is sent. hostapd will need to be configured -with a device password (PIN) for this Enrollee. This is an operation -that requires user interaction (assuming there are no pre-configured -PINs on the AP for a set of Enrollee). - -The PIN request with information about the device is appended to the -wps_pin_requests file (/var/run/hostapd.pin-req in this example). In -addition, hostapd control interface event is sent as a notification of -a new device. The AP could use, e.g., a web UI for showing active -Enrollees to the user and request a PIN for an Enrollee. - -The PIN request file has one line for every Enrollee that connected to -the AP, but for which there was no PIN. Following information is -provided for each Enrollee (separated with tabulators): -- timestamp (seconds from 1970-01-01) -- Enrollee UUID -- MAC address -- Device name -- Manufacturer -- Model Name -- Model Number -- Serial Number -- Device category - -Example line in the /var/run/hostapd.pin-req file: -1200188391 53b63a98-d29e-4457-a2ed-094d7e6a669c Intel(R) Centrino(R) Intel Corporation Intel(R) Centrino(R) - - 1-0050F204-1 - -Control interface data: -WPS-PIN-NEEDED [UUID-E|MAC Address|Device Name|Manufacturer|Model Name|Model Number|Serial Number|Device Category] -For example: -<2>WPS-PIN-NEEDED [53b63a98-d29e-4457-a2ed-094d7e6a669c|02:12:34:56:78:9a|Device|Manuf|Model|Model Number|Serial Number|1-0050F204-1] - -When the user enters a PIN for a pending Enrollee, e.g., on the web -UI), hostapd needs to be notified of the new PIN over the control -interface. This can be done either by using the UNIX domain socket --based control interface directly (src/common/wpa_ctrl.c provides -helper functions for using the interface) or by calling hostapd_cli. - -Example command to add a PIN (12345670) for an Enrollee: - -hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c 12345670 - -If the UUID-E is not available (e.g., Enrollee waits for the Registrar -to be selected before connecting), wildcard UUID may be used to allow -the PIN to be used once with any UUID: - -hostapd_cli wps_pin any 12345670 - -To reduce likelihood of PIN being used with other devices or of -forgetting an active PIN available for potential attackers, expiration -time in seconds can be set for the new PIN (value 0 indicates no -expiration): - -hostapd_cli wps_pin any 12345670 300 - -If the MAC address of the enrollee is known, it should be configured -to allow the AP to advertise list of authorized enrollees: - -hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c \ - 12345670 300 00:11:22:33:44:55 - - -After this, the Enrollee can connect to the AP again and complete WPS -negotiation. At that point, a new, random WPA PSK is generated for the -client device and the client can then use that key to connect to the -AP to access the network. - - -If the AP includes a pushbutton, WPS PBC mode can be used. It is -enabled by pushing a button on both the AP and the client at about the -same time (2 minute window). hostapd needs to be notified about the AP -button pushed event over the control interface, e.g., by calling -hostapd_cli: - -hostapd_cli wps_pbc - -At this point, the client has two minutes to complete WPS negotiation -which will generate a new WPA PSK in the same way as the PIN method -described above. - - -When an external Registrar is used, the AP can act as an Enrollee and -use its AP PIN. A static AP PIN (e.g., one one a label in the AP -device) can be configured in hostapd.conf (ap_pin parameter). A more -secure option is to use hostapd_cli wps_ap_pin command to enable the -AP PIN only based on user action (and even better security by using a -random AP PIN for each session, i.e., by using "wps_ap_pin random" -command with a timeout value). Following commands are available for -managing the dynamic AP PIN operations: - -hostapd_cli wps_ap_pin disable -- disable AP PIN (i.e., do not allow external Registrars to use it to - learn the current AP settings or to reconfigure the AP) - -hostapd_cli wps_ap_pin random [timeout] -- generate a random AP PIN and enable it -- if the optional timeout parameter is given, the AP PIN will be enabled - for the specified number of seconds - -hostapd_cli wps_ap_pin get -- fetch the current AP PIN - -hostapd_cli wps_ap_pin set [timeout] -- set the AP PIN and enable it -- if the optional timeout parameter is given, the AP PIN will be enabled - for the specified number of seconds - -hostapd_cli get_config -- display the current configuration - -hostapd_cli wps_config -examples: - hostapd_cli wps_config testing WPA2PSK CCMP 12345678 - hostapd_cli wps_config "no security" OPEN NONE "" - - must be one of the following: OPEN WPAPSK WPA2PSK - must be one of the following: NONE WEP TKIP CCMP - - -Credential generation and configuration changes ------------------------------------------------ - -By default, hostapd generates credentials for Enrollees and processing -AP configuration updates internally. However, it is possible to -control these operations from external programs, if desired. - -The internal credential generation can be disabled with -skip_cred_build=1 option in the configuration. extra_cred option will -then need to be used to provide pre-configured Credential attribute(s) -for hostapd to use. The exact data from this binary file will be sent, -i.e., it will have to include valid WPS attributes. extra_cred can -also be used to add additional networks if the Registrar is used to -configure credentials for multiple networks. - -Processing of received configuration updates can be disabled with -wps_cred_processing=1 option. When this is used, an external program -is responsible for creating hostapd configuration files and processing -configuration updates based on messages received from hostapd over -control interface. This will also include the initial configuration on -first successful registration if the AP is initially set in -unconfigured state. - -Following control interface messages are sent out for external programs: - -WPS-REG-SUCCESS -For example: -<2>WPS-REG-SUCCESS 02:66:a0:ee:17:27 2b7093f1-d6fb-5108-adbb-bea66bb87333 - -This can be used to trigger change from unconfigured to configured -state (random configuration based on the first successful WPS -registration). In addition, this can be used to update AP UI about the -status of WPS registration progress. - - -WPS-NEW-AP-SETTINGS -For example: -<2>WPS-NEW-AP-SETTINGS 10260001011045000c6a6b6d2d7770732d74657374100300020020100f00020008102700403065346230343536633236366665306433396164313535346131663462663731323433376163666462376633393965353466316631623032306164343438623510200006024231cede15101e000844 - -This can be used to update the externally stored AP configuration and -then update hostapd configuration (followed by restarting of hostapd). - - -WPS with NFC ------------- - -WPS can be used with NFC-based configuration method. An NFC tag -containing a password token from the Enrollee can be used to -authenticate the connection instead of the PIN. In addition, an NFC tag -with a configuration token can be used to transfer AP settings without -going through the WPS protocol. - -When the AP acts as an Enrollee, a local NFC tag with a password token -can be used by touching the NFC interface of an external Registrar. The -wps_nfc_token command is used to manage use of the NFC password token -from the AP. "wps_nfc_token enable" enables the use of the AP's NFC -password token (in place of AP PIN) and "wps_nfc_token disable" disables -the NFC password token. - -The NFC password token that is either pre-configured in the -configuration file (wps_nfc_dev_pw_id, wps_nfc_dh_pubkey, -wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with -"wps_nfc_token " command. The nfc_pw_token tool from -wpa_supplicant can be used to generate NFC password tokens during -manufacturing (each AP needs to have its own random keys). - -The "wps_nfc_config_token " command can be used to build an -NFC configuration token. The output value from this command is a hexdump -of the current AP configuration (WPS parameter requests this to include -only the WPS attributes; NDEF parameter requests additional NDEF -encapsulation to be included). This data needs to be written to an NFC -tag with an external program. Once written, the NFC configuration token -can be used to touch an NFC interface on a station to provision the -credentials needed to access the network. - -When the NFC device on the AP reads an NFC tag with a MIME media type -"application/vnd.wfa.wsc", the NDEF message payload (with or without -NDEF encapsulation) can be delivered to hostapd using the -following hostapd_cli command: - -wps_nfc_tag_read - -If the NFC tag contains a password token, the token is added to the -internal Registrar. This allows station Enrollee from which the password -token was received to run through WPS protocol to provision the -credential. - -"nfc_get_handover_sel " command can be used to build the -contents of a Handover Select Message for connection handover when this -does not depend on the contents of the Handover Request Message. The -first argument selects the format of the output data and the second -argument selects which type of connection handover is requested (WPS = -Wi-Fi handover as specified in WSC 2.0). - -"nfc_report_handover WPS -" is used to report completed NFC -connection handover. The first parameter indicates whether the local -device initiated or responded to the connection handover and the carrier -records are the selected carrier from the handover request and select -messages as a hexdump. diff --git a/contrib/hostapd/hostapd/config_file.c b/contrib/hostapd/hostapd/config_file.c deleted file mode 100644 index 54e4af9d38..0000000000 --- a/contrib/hostapd/hostapd/config_file.c +++ /dev/null @@ -1,3030 +0,0 @@ -/* - * hostapd / Configuration file parser - * Copyright (c) 2003-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" -#ifndef CONFIG_NATIVE_WINDOWS -#include -#endif /* CONFIG_NATIVE_WINDOWS */ - -#include "utils/common.h" -#include "utils/uuid.h" -#include "common/ieee802_11_defs.h" -#include "drivers/driver.h" -#include "eap_server/eap.h" -#include "radius/radius_client.h" -#include "ap/wpa_auth.h" -#include "ap/ap_config.h" -#include "config_file.h" - - -#ifndef CONFIG_NO_VLAN -static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss, - const char *fname) -{ - FILE *f; - char buf[128], *pos, *pos2; - int line = 0, vlan_id; - struct hostapd_vlan *vlan; - - f = fopen(fname, "r"); - if (!f) { - wpa_printf(MSG_ERROR, "VLAN file '%s' not readable.", fname); - return -1; - } - - while (fgets(buf, sizeof(buf), f)) { - line++; - - if (buf[0] == '#') - continue; - pos = buf; - while (*pos != '\0') { - if (*pos == '\n') { - *pos = '\0'; - break; - } - pos++; - } - if (buf[0] == '\0') - continue; - - if (buf[0] == '*') { - vlan_id = VLAN_ID_WILDCARD; - pos = buf + 1; - } else { - vlan_id = strtol(buf, &pos, 10); - if (buf == pos || vlan_id < 1 || - vlan_id > MAX_VLAN_ID) { - wpa_printf(MSG_ERROR, "Invalid VLAN ID at " - "line %d in '%s'", line, fname); - fclose(f); - return -1; - } - } - - while (*pos == ' ' || *pos == '\t') - pos++; - pos2 = pos; - while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0') - pos2++; - *pos2 = '\0'; - if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) { - wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d " - "in '%s'", line, fname); - fclose(f); - return -1; - } - - vlan = os_zalloc(sizeof(*vlan)); - if (vlan == NULL) { - wpa_printf(MSG_ERROR, "Out of memory while reading " - "VLAN interfaces from '%s'", fname); - fclose(f); - return -1; - } - - vlan->vlan_id = vlan_id; - os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname)); - vlan->next = bss->vlan; - bss->vlan = vlan; - } - - fclose(f); - - return 0; -} -#endif /* CONFIG_NO_VLAN */ - - -static int hostapd_acl_comp(const void *a, const void *b) -{ - const struct mac_acl_entry *aa = a; - const struct mac_acl_entry *bb = b; - return os_memcmp(aa->addr, bb->addr, sizeof(macaddr)); -} - - -static int hostapd_config_read_maclist(const char *fname, - struct mac_acl_entry **acl, int *num) -{ - FILE *f; - char buf[128], *pos; - int line = 0; - u8 addr[ETH_ALEN]; - struct mac_acl_entry *newacl; - int vlan_id; - - if (!fname) - return 0; - - f = fopen(fname, "r"); - if (!f) { - wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname); - return -1; - } - - while (fgets(buf, sizeof(buf), f)) { - line++; - - if (buf[0] == '#') - continue; - pos = buf; - while (*pos != '\0') { - if (*pos == '\n') { - *pos = '\0'; - break; - } - pos++; - } - if (buf[0] == '\0') - continue; - - if (hwaddr_aton(buf, addr)) { - wpa_printf(MSG_ERROR, "Invalid MAC address '%s' at " - "line %d in '%s'", buf, line, fname); - fclose(f); - return -1; - } - - vlan_id = 0; - pos = buf; - while (*pos != '\0' && *pos != ' ' && *pos != '\t') - pos++; - while (*pos == ' ' || *pos == '\t') - pos++; - if (*pos != '\0') - vlan_id = atoi(pos); - - newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl)); - if (newacl == NULL) { - wpa_printf(MSG_ERROR, "MAC list reallocation failed"); - fclose(f); - return -1; - } - - *acl = newacl; - os_memcpy((*acl)[*num].addr, addr, ETH_ALEN); - (*acl)[*num].vlan_id = vlan_id; - (*num)++; - } - - fclose(f); - - qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp); - - return 0; -} - - -#ifdef EAP_SERVER -static int hostapd_config_read_eap_user(const char *fname, - struct hostapd_bss_config *conf) -{ - FILE *f; - char buf[512], *pos, *start, *pos2; - int line = 0, ret = 0, num_methods; - struct hostapd_eap_user *user, *tail = NULL; - - if (!fname) - return 0; - - if (os_strncmp(fname, "sqlite:", 7) == 0) { - os_free(conf->eap_user_sqlite); - conf->eap_user_sqlite = os_strdup(fname + 7); - return 0; - } - - f = fopen(fname, "r"); - if (!f) { - wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname); - return -1; - } - - /* Lines: "user" METHOD,METHOD2 "password" (password optional) */ - while (fgets(buf, sizeof(buf), f)) { - line++; - - if (buf[0] == '#') - continue; - pos = buf; - while (*pos != '\0') { - if (*pos == '\n') { - *pos = '\0'; - break; - } - pos++; - } - if (buf[0] == '\0') - continue; - - user = NULL; - - if (buf[0] != '"' && buf[0] != '*') { - wpa_printf(MSG_ERROR, "Invalid EAP identity (no \" in " - "start) on line %d in '%s'", line, fname); - goto failed; - } - - user = os_zalloc(sizeof(*user)); - if (user == NULL) { - wpa_printf(MSG_ERROR, "EAP user allocation failed"); - goto failed; - } - user->force_version = -1; - - if (buf[0] == '*') { - pos = buf; - } else { - pos = buf + 1; - start = pos; - while (*pos != '"' && *pos != '\0') - pos++; - if (*pos == '\0') { - wpa_printf(MSG_ERROR, "Invalid EAP identity " - "(no \" in end) on line %d in '%s'", - line, fname); - goto failed; - } - - user->identity = os_malloc(pos - start); - if (user->identity == NULL) { - wpa_printf(MSG_ERROR, "Failed to allocate " - "memory for EAP identity"); - goto failed; - } - os_memcpy(user->identity, start, pos - start); - user->identity_len = pos - start; - - if (pos[0] == '"' && pos[1] == '*') { - user->wildcard_prefix = 1; - pos++; - } - } - pos++; - while (*pos == ' ' || *pos == '\t') - pos++; - - if (*pos == '\0') { - wpa_printf(MSG_ERROR, "No EAP method on line %d in " - "'%s'", line, fname); - goto failed; - } - - start = pos; - while (*pos != ' ' && *pos != '\t' && *pos != '\0') - pos++; - if (*pos == '\0') { - pos = NULL; - } else { - *pos = '\0'; - pos++; - } - num_methods = 0; - while (*start) { - char *pos3 = os_strchr(start, ','); - if (pos3) { - *pos3++ = '\0'; - } - user->methods[num_methods].method = - eap_server_get_type( - start, - &user->methods[num_methods].vendor); - if (user->methods[num_methods].vendor == - EAP_VENDOR_IETF && - user->methods[num_methods].method == EAP_TYPE_NONE) - { - if (os_strcmp(start, "TTLS-PAP") == 0) { - user->ttls_auth |= EAP_TTLS_AUTH_PAP; - goto skip_eap; - } - if (os_strcmp(start, "TTLS-CHAP") == 0) { - user->ttls_auth |= EAP_TTLS_AUTH_CHAP; - goto skip_eap; - } - if (os_strcmp(start, "TTLS-MSCHAP") == 0) { - user->ttls_auth |= - EAP_TTLS_AUTH_MSCHAP; - goto skip_eap; - } - if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) { - user->ttls_auth |= - EAP_TTLS_AUTH_MSCHAPV2; - goto skip_eap; - } - wpa_printf(MSG_ERROR, "Unsupported EAP type " - "'%s' on line %d in '%s'", - start, line, fname); - goto failed; - } - - num_methods++; - if (num_methods >= EAP_MAX_METHODS) - break; - skip_eap: - if (pos3 == NULL) - break; - start = pos3; - } - if (num_methods == 0 && user->ttls_auth == 0) { - wpa_printf(MSG_ERROR, "No EAP types configured on " - "line %d in '%s'", line, fname); - goto failed; - } - - if (pos == NULL) - goto done; - - while (*pos == ' ' || *pos == '\t') - pos++; - if (*pos == '\0') - goto done; - - if (os_strncmp(pos, "[ver=0]", 7) == 0) { - user->force_version = 0; - goto done; - } - - if (os_strncmp(pos, "[ver=1]", 7) == 0) { - user->force_version = 1; - goto done; - } - - if (os_strncmp(pos, "[2]", 3) == 0) { - user->phase2 = 1; - goto done; - } - - if (*pos == '"') { - pos++; - start = pos; - while (*pos != '"' && *pos != '\0') - pos++; - if (*pos == '\0') { - wpa_printf(MSG_ERROR, "Invalid EAP password " - "(no \" in end) on line %d in '%s'", - line, fname); - goto failed; - } - - user->password = os_malloc(pos - start); - if (user->password == NULL) { - wpa_printf(MSG_ERROR, "Failed to allocate " - "memory for EAP password"); - goto failed; - } - os_memcpy(user->password, start, pos - start); - user->password_len = pos - start; - - pos++; - } else if (os_strncmp(pos, "hash:", 5) == 0) { - pos += 5; - pos2 = pos; - while (*pos2 != '\0' && *pos2 != ' ' && - *pos2 != '\t' && *pos2 != '#') - pos2++; - if (pos2 - pos != 32) { - wpa_printf(MSG_ERROR, "Invalid password hash " - "on line %d in '%s'", line, fname); - goto failed; - } - user->password = os_malloc(16); - if (user->password == NULL) { - wpa_printf(MSG_ERROR, "Failed to allocate " - "memory for EAP password hash"); - goto failed; - } - if (hexstr2bin(pos, user->password, 16) < 0) { - wpa_printf(MSG_ERROR, "Invalid hash password " - "on line %d in '%s'", line, fname); - goto failed; - } - user->password_len = 16; - user->password_hash = 1; - pos = pos2; - } else { - pos2 = pos; - while (*pos2 != '\0' && *pos2 != ' ' && - *pos2 != '\t' && *pos2 != '#') - pos2++; - if ((pos2 - pos) & 1) { - wpa_printf(MSG_ERROR, "Invalid hex password " - "on line %d in '%s'", line, fname); - goto failed; - } - user->password = os_malloc((pos2 - pos) / 2); - if (user->password == NULL) { - wpa_printf(MSG_ERROR, "Failed to allocate " - "memory for EAP password"); - goto failed; - } - if (hexstr2bin(pos, user->password, - (pos2 - pos) / 2) < 0) { - wpa_printf(MSG_ERROR, "Invalid hex password " - "on line %d in '%s'", line, fname); - goto failed; - } - user->password_len = (pos2 - pos) / 2; - pos = pos2; - } - - while (*pos == ' ' || *pos == '\t') - pos++; - if (os_strncmp(pos, "[2]", 3) == 0) { - user->phase2 = 1; - } - - done: - if (tail == NULL) { - tail = conf->eap_user = user; - } else { - tail->next = user; - tail = user; - } - continue; - - failed: - if (user) { - os_free(user->password); - os_free(user->identity); - os_free(user); - } - ret = -1; - break; - } - - fclose(f); - - return ret; -} -#endif /* EAP_SERVER */ - - -#ifndef CONFIG_NO_RADIUS -static int -hostapd_config_read_radius_addr(struct hostapd_radius_server **server, - int *num_server, const char *val, int def_port, - struct hostapd_radius_server **curr_serv) -{ - struct hostapd_radius_server *nserv; - int ret; - static int server_index = 1; - - nserv = os_realloc_array(*server, *num_server + 1, sizeof(*nserv)); - if (nserv == NULL) - return -1; - - *server = nserv; - nserv = &nserv[*num_server]; - (*num_server)++; - (*curr_serv) = nserv; - - os_memset(nserv, 0, sizeof(*nserv)); - nserv->port = def_port; - ret = hostapd_parse_ip_addr(val, &nserv->addr); - nserv->index = server_index++; - - return ret; -} - - -static struct hostapd_radius_attr * -hostapd_parse_radius_attr(const char *value) -{ - const char *pos; - char syntax; - struct hostapd_radius_attr *attr; - size_t len; - - attr = os_zalloc(sizeof(*attr)); - if (attr == NULL) - return NULL; - - attr->type = atoi(value); - - pos = os_strchr(value, ':'); - if (pos == NULL) { - attr->val = wpabuf_alloc(1); - if (attr->val == NULL) { - os_free(attr); - return NULL; - } - wpabuf_put_u8(attr->val, 0); - return attr; - } - - pos++; - if (pos[0] == '\0' || pos[1] != ':') { - os_free(attr); - return NULL; - } - syntax = *pos++; - pos++; - - switch (syntax) { - case 's': - attr->val = wpabuf_alloc_copy(pos, os_strlen(pos)); - break; - case 'x': - len = os_strlen(pos); - if (len & 1) - break; - len /= 2; - attr->val = wpabuf_alloc(len); - if (attr->val == NULL) - break; - if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) { - wpabuf_free(attr->val); - os_free(attr); - return NULL; - } - break; - case 'd': - attr->val = wpabuf_alloc(4); - if (attr->val) - wpabuf_put_be32(attr->val, atoi(pos)); - break; - default: - os_free(attr); - return NULL; - } - - if (attr->val == NULL) { - os_free(attr); - return NULL; - } - - return attr; -} - - -static int hostapd_parse_das_client(struct hostapd_bss_config *bss, - const char *val) -{ - char *secret; - - secret = os_strchr(val, ' '); - if (secret == NULL) - return -1; - - secret++; - - if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr)) - return -1; - - os_free(bss->radius_das_shared_secret); - bss->radius_das_shared_secret = (u8 *) os_strdup(secret); - if (bss->radius_das_shared_secret == NULL) - return -1; - bss->radius_das_shared_secret_len = os_strlen(secret); - - return 0; -} -#endif /* CONFIG_NO_RADIUS */ - - -static int hostapd_config_parse_key_mgmt(int line, const char *value) -{ - int val = 0, last; - char *start, *end, *buf; - - buf = os_strdup(value); - if (buf == NULL) - return -1; - start = buf; - - while (*start != '\0') { - while (*start == ' ' || *start == '\t') - start++; - if (*start == '\0') - break; - end = start; - while (*end != ' ' && *end != '\t' && *end != '\0') - end++; - last = *end == '\0'; - *end = '\0'; - if (os_strcmp(start, "WPA-PSK") == 0) - val |= WPA_KEY_MGMT_PSK; - else if (os_strcmp(start, "WPA-EAP") == 0) - val |= WPA_KEY_MGMT_IEEE8021X; -#ifdef CONFIG_IEEE80211R - else if (os_strcmp(start, "FT-PSK") == 0) - val |= WPA_KEY_MGMT_FT_PSK; - else if (os_strcmp(start, "FT-EAP") == 0) - val |= WPA_KEY_MGMT_FT_IEEE8021X; -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - else if (os_strcmp(start, "WPA-PSK-SHA256") == 0) - val |= WPA_KEY_MGMT_PSK_SHA256; - else if (os_strcmp(start, "WPA-EAP-SHA256") == 0) - val |= WPA_KEY_MGMT_IEEE8021X_SHA256; -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_SAE - else if (os_strcmp(start, "SAE") == 0) - val |= WPA_KEY_MGMT_SAE; - else if (os_strcmp(start, "FT-SAE") == 0) - val |= WPA_KEY_MGMT_FT_SAE; -#endif /* CONFIG_SAE */ - else { - wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", - line, start); - os_free(buf); - return -1; - } - - if (last) - break; - start = end + 1; - } - - os_free(buf); - if (val == 0) { - wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values " - "configured.", line); - return -1; - } - - return val; -} - - -static int hostapd_config_parse_cipher(int line, const char *value) -{ - int val = wpa_parse_cipher(value); - if (val < 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.", - line, value); - return -1; - } - if (val == 0) { - wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.", - line); - return -1; - } - return val; -} - - -static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx, - char *val) -{ - size_t len = os_strlen(val); - - if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL) - return -1; - - if (val[0] == '"') { - if (len < 2 || val[len - 1] != '"') - return -1; - len -= 2; - wep->key[keyidx] = os_malloc(len); - if (wep->key[keyidx] == NULL) - return -1; - os_memcpy(wep->key[keyidx], val + 1, len); - wep->len[keyidx] = len; - } else { - if (len & 1) - return -1; - len /= 2; - wep->key[keyidx] = os_malloc(len); - if (wep->key[keyidx] == NULL) - return -1; - wep->len[keyidx] = len; - if (hexstr2bin(val, wep->key[keyidx], len) < 0) - return -1; - } - - wep->keys_set++; - - return 0; -} - - -static int hostapd_parse_intlist(int **int_list, char *val) -{ - int *list; - int count; - char *pos, *end; - - os_free(*int_list); - *int_list = NULL; - - pos = val; - count = 0; - while (*pos != '\0') { - if (*pos == ' ') - count++; - pos++; - } - - list = os_malloc(sizeof(int) * (count + 2)); - if (list == NULL) - return -1; - pos = val; - count = 0; - while (*pos != '\0') { - end = os_strchr(pos, ' '); - if (end) - *end = '\0'; - - list[count++] = atoi(pos); - if (!end) - break; - pos = end + 1; - } - list[count] = -1; - - *int_list = list; - return 0; -} - - -static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname) -{ - struct hostapd_bss_config **all, *bss; - - if (*ifname == '\0') - return -1; - - all = os_realloc_array(conf->bss, conf->num_bss + 1, - sizeof(struct hostapd_bss_config *)); - if (all == NULL) { - wpa_printf(MSG_ERROR, "Failed to allocate memory for " - "multi-BSS entry"); - return -1; - } - conf->bss = all; - - bss = os_zalloc(sizeof(*bss)); - if (bss == NULL) - return -1; - bss->radius = os_zalloc(sizeof(*bss->radius)); - if (bss->radius == NULL) { - wpa_printf(MSG_ERROR, "Failed to allocate memory for " - "multi-BSS RADIUS data"); - os_free(bss); - return -1; - } - - conf->bss[conf->num_bss++] = bss; - conf->last_bss = bss; - - hostapd_config_defaults_bss(bss); - os_strlcpy(bss->iface, ifname, sizeof(bss->iface)); - os_memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1); - - return 0; -} - - -/* convert floats with one decimal place to value*10 int, i.e., - * "1.5" will return 15 */ -static int hostapd_config_read_int10(const char *value) -{ - int i, d; - char *pos; - - i = atoi(value); - pos = os_strchr(value, '.'); - d = 0; - if (pos) { - pos++; - if (*pos >= '0' && *pos <= '9') - d = *pos - '0'; - } - - return i * 10 + d; -} - - -static int valid_cw(int cw) -{ - return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 || - cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023); -} - - -enum { - IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */ - IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */ - IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */ - IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */ -}; - -static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name, - char *val) -{ - int num; - char *pos; - struct hostapd_tx_queue_params *queue; - - /* skip 'tx_queue_' prefix */ - pos = name + 9; - if (os_strncmp(pos, "data", 4) == 0 && - pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') { - num = pos[4] - '0'; - pos += 6; - } else if (os_strncmp(pos, "after_beacon_", 13) == 0 || - os_strncmp(pos, "beacon_", 7) == 0) { - wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name); - return 0; - } else { - wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos); - return -1; - } - - if (num >= NUM_TX_QUEUES) { - /* for backwards compatibility, do not trigger failure */ - wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name); - return 0; - } - - queue = &conf->tx_queue[num]; - - if (os_strcmp(pos, "aifs") == 0) { - queue->aifs = atoi(val); - if (queue->aifs < 0 || queue->aifs > 255) { - wpa_printf(MSG_ERROR, "Invalid AIFS value %d", - queue->aifs); - return -1; - } - } else if (os_strcmp(pos, "cwmin") == 0) { - queue->cwmin = atoi(val); - if (!valid_cw(queue->cwmin)) { - wpa_printf(MSG_ERROR, "Invalid cwMin value %d", - queue->cwmin); - return -1; - } - } else if (os_strcmp(pos, "cwmax") == 0) { - queue->cwmax = atoi(val); - if (!valid_cw(queue->cwmax)) { - wpa_printf(MSG_ERROR, "Invalid cwMax value %d", - queue->cwmax); - return -1; - } - } else if (os_strcmp(pos, "burst") == 0) { - queue->burst = hostapd_config_read_int10(val); - } else { - wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos); - return -1; - } - - return 0; -} - - -#ifdef CONFIG_IEEE80211R -static int add_r0kh(struct hostapd_bss_config *bss, char *value) -{ - struct ft_remote_r0kh *r0kh; - char *pos, *next; - - r0kh = os_zalloc(sizeof(*r0kh)); - if (r0kh == NULL) - return -1; - - /* 02:01:02:03:04:05 a.example.com 000102030405060708090a0b0c0d0e0f */ - pos = value; - next = os_strchr(pos, ' '); - if (next) - *next++ = '\0'; - if (next == NULL || hwaddr_aton(pos, r0kh->addr)) { - wpa_printf(MSG_ERROR, "Invalid R0KH MAC address: '%s'", pos); - os_free(r0kh); - return -1; - } - - pos = next; - next = os_strchr(pos, ' '); - if (next) - *next++ = '\0'; - if (next == NULL || next - pos > FT_R0KH_ID_MAX_LEN) { - wpa_printf(MSG_ERROR, "Invalid R0KH-ID: '%s'", pos); - os_free(r0kh); - return -1; - } - r0kh->id_len = next - pos - 1; - os_memcpy(r0kh->id, pos, r0kh->id_len); - - pos = next; - if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) { - wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos); - os_free(r0kh); - return -1; - } - - r0kh->next = bss->r0kh_list; - bss->r0kh_list = r0kh; - - return 0; -} - - -static int add_r1kh(struct hostapd_bss_config *bss, char *value) -{ - struct ft_remote_r1kh *r1kh; - char *pos, *next; - - r1kh = os_zalloc(sizeof(*r1kh)); - if (r1kh == NULL) - return -1; - - /* 02:01:02:03:04:05 02:01:02:03:04:05 - * 000102030405060708090a0b0c0d0e0f */ - pos = value; - next = os_strchr(pos, ' '); - if (next) - *next++ = '\0'; - if (next == NULL || hwaddr_aton(pos, r1kh->addr)) { - wpa_printf(MSG_ERROR, "Invalid R1KH MAC address: '%s'", pos); - os_free(r1kh); - return -1; - } - - pos = next; - next = os_strchr(pos, ' '); - if (next) - *next++ = '\0'; - if (next == NULL || hwaddr_aton(pos, r1kh->id)) { - wpa_printf(MSG_ERROR, "Invalid R1KH-ID: '%s'", pos); - os_free(r1kh); - return -1; - } - - pos = next; - if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) { - wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos); - os_free(r1kh); - return -1; - } - - r1kh->next = bss->r1kh_list; - bss->r1kh_list = r1kh; - - return 0; -} -#endif /* CONFIG_IEEE80211R */ - - -#ifdef CONFIG_IEEE80211N -static int hostapd_config_ht_capab(struct hostapd_config *conf, - const char *capab) -{ - if (os_strstr(capab, "[LDPC]")) - conf->ht_capab |= HT_CAP_INFO_LDPC_CODING_CAP; - if (os_strstr(capab, "[HT40-]")) { - conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; - conf->secondary_channel = -1; - } - if (os_strstr(capab, "[HT40+]")) { - conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; - conf->secondary_channel = 1; - } - if (os_strstr(capab, "[SMPS-STATIC]")) { - conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK; - conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC; - } - if (os_strstr(capab, "[SMPS-DYNAMIC]")) { - conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK; - conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC; - } - if (os_strstr(capab, "[GF]")) - conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD; - if (os_strstr(capab, "[SHORT-GI-20]")) - conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ; - if (os_strstr(capab, "[SHORT-GI-40]")) - conf->ht_capab |= HT_CAP_INFO_SHORT_GI40MHZ; - if (os_strstr(capab, "[TX-STBC]")) - conf->ht_capab |= HT_CAP_INFO_TX_STBC; - if (os_strstr(capab, "[RX-STBC1]")) { - conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK; - conf->ht_capab |= HT_CAP_INFO_RX_STBC_1; - } - if (os_strstr(capab, "[RX-STBC12]")) { - conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK; - conf->ht_capab |= HT_CAP_INFO_RX_STBC_12; - } - if (os_strstr(capab, "[RX-STBC123]")) { - conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK; - conf->ht_capab |= HT_CAP_INFO_RX_STBC_123; - } - if (os_strstr(capab, "[DELAYED-BA]")) - conf->ht_capab |= HT_CAP_INFO_DELAYED_BA; - if (os_strstr(capab, "[MAX-AMSDU-7935]")) - conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE; - if (os_strstr(capab, "[DSSS_CCK-40]")) - conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ; - if (os_strstr(capab, "[PSMP]")) - conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP; - if (os_strstr(capab, "[LSIG-TXOP-PROT]")) - conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT; - - return 0; -} -#endif /* CONFIG_IEEE80211N */ - - -#ifdef CONFIG_IEEE80211AC -static int hostapd_config_vht_capab(struct hostapd_config *conf, - const char *capab) -{ - if (os_strstr(capab, "[MAX-MPDU-7991]")) - conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_7991; - if (os_strstr(capab, "[MAX-MPDU-11454]")) - conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_11454; - if (os_strstr(capab, "[VHT160]")) - conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; - if (os_strstr(capab, "[VHT160-80PLUS80]")) - conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; - if (os_strstr(capab, "[VHT160-80PLUS80]")) - conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; - if (os_strstr(capab, "[RXLDPC]")) - conf->vht_capab |= VHT_CAP_RXLDPC; - if (os_strstr(capab, "[SHORT-GI-80]")) - conf->vht_capab |= VHT_CAP_SHORT_GI_80; - if (os_strstr(capab, "[SHORT-GI-160]")) - conf->vht_capab |= VHT_CAP_SHORT_GI_160; - if (os_strstr(capab, "[TX-STBC-2BY1]")) - conf->vht_capab |= VHT_CAP_TXSTBC; - if (os_strstr(capab, "[RX-STBC-1]")) - conf->vht_capab |= VHT_CAP_RXSTBC_1; - if (os_strstr(capab, "[RX-STBC-12]")) - conf->vht_capab |= VHT_CAP_RXSTBC_2; - if (os_strstr(capab, "[RX-STBC-123]")) - conf->vht_capab |= VHT_CAP_RXSTBC_3; - if (os_strstr(capab, "[RX-STBC-1234]")) - conf->vht_capab |= VHT_CAP_RXSTBC_4; - if (os_strstr(capab, "[SU-BEAMFORMER]")) - conf->vht_capab |= VHT_CAP_SU_BEAMFORMER_CAPABLE; - if (os_strstr(capab, "[SU-BEAMFORMEE]")) - conf->vht_capab |= VHT_CAP_SU_BEAMFORMEE_CAPABLE; - if (os_strstr(capab, "[BF-ANTENNA-2]") && - (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE)) - conf->vht_capab |= (1 << VHT_CAP_BEAMFORMEE_STS_OFFSET); - if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") && - (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE)) - conf->vht_capab |= (1 << VHT_CAP_SOUNDING_DIMENSION_OFFSET); - if (os_strstr(capab, "[MU-BEAMFORMER]")) - conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE; - if (os_strstr(capab, "[MU-BEAMFORMEE]")) - conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE; - if (os_strstr(capab, "[VHT-TXOP-PS]")) - conf->vht_capab |= VHT_CAP_VHT_TXOP_PS; - if (os_strstr(capab, "[HTC-VHT]")) - conf->vht_capab |= VHT_CAP_HTC_VHT; - if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP0]")) - conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT; - if (os_strstr(capab, "[VHT-LINK-ADAPT2]") && - (conf->vht_capab & VHT_CAP_HTC_VHT)) - conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB; - if (os_strstr(capab, "[VHT-LINK-ADAPT3]") && - (conf->vht_capab & VHT_CAP_HTC_VHT)) - conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB; - if (os_strstr(capab, "[RX-ANTENNA-PATTERN]")) - conf->vht_capab |= VHT_CAP_RX_ANTENNA_PATTERN; - if (os_strstr(capab, "[TX-ANTENNA-PATTERN]")) - conf->vht_capab |= VHT_CAP_TX_ANTENNA_PATTERN; - return 0; -} -#endif /* CONFIG_IEEE80211AC */ - - -#ifdef CONFIG_INTERWORKING -static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos, - int line) -{ - size_t len = os_strlen(pos); - u8 oi[MAX_ROAMING_CONSORTIUM_LEN]; - - struct hostapd_roaming_consortium *rc; - - if ((len & 1) || len < 2 * 3 || len / 2 > MAX_ROAMING_CONSORTIUM_LEN || - hexstr2bin(pos, oi, len / 2)) { - wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortium " - "'%s'", line, pos); - return -1; - } - len /= 2; - - rc = os_realloc_array(bss->roaming_consortium, - bss->roaming_consortium_count + 1, - sizeof(struct hostapd_roaming_consortium)); - if (rc == NULL) - return -1; - - os_memcpy(rc[bss->roaming_consortium_count].oi, oi, len); - rc[bss->roaming_consortium_count].len = len; - - bss->roaming_consortium = rc; - bss->roaming_consortium_count++; - - return 0; -} - - -static int parse_lang_string(struct hostapd_lang_string **array, - unsigned int *count, char *pos) -{ - char *sep, *str = NULL; - size_t clen, nlen, slen; - struct hostapd_lang_string *ls; - int ret = -1; - - if (*pos == '"' || (*pos == 'P' && pos[1] == '"')) { - str = wpa_config_parse_string(pos, &slen); - if (!str) - return -1; - pos = str; - } - - sep = os_strchr(pos, ':'); - if (sep == NULL) - goto fail; - *sep++ = '\0'; - - clen = os_strlen(pos); - if (clen < 2 || clen > sizeof(ls->lang)) - goto fail; - nlen = os_strlen(sep); - if (nlen > 252) - goto fail; - - ls = os_realloc_array(*array, *count + 1, - sizeof(struct hostapd_lang_string)); - if (ls == NULL) - goto fail; - - *array = ls; - ls = &(*array)[*count]; - (*count)++; - - os_memset(ls->lang, 0, sizeof(ls->lang)); - os_memcpy(ls->lang, pos, clen); - ls->name_len = nlen; - os_memcpy(ls->name, sep, nlen); - - ret = 0; -fail: - os_free(str); - return ret; -} - - -static int parse_venue_name(struct hostapd_bss_config *bss, char *pos, - int line) -{ - if (parse_lang_string(&bss->venue_name, &bss->venue_name_count, pos)) { - wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'", - line, pos); - return -1; - } - return 0; -} - - -static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf, - int line) -{ - size_t count; - char *pos; - u8 *info = NULL, *ipos; - - /* format: [;][;...] */ - - count = 1; - for (pos = buf; *pos; pos++) { - if ((*pos < '0' && *pos > '9') && *pos != ';' && *pos != ',') - goto fail; - if (*pos == ';') - count++; - } - if (1 + count * 3 > 0x7f) - goto fail; - - info = os_zalloc(2 + 3 + count * 3); - if (info == NULL) - return -1; - - ipos = info; - *ipos++ = 0; /* GUD - Version 1 */ - *ipos++ = 3 + count * 3; /* User Data Header Length (UDHL) */ - *ipos++ = 0; /* PLMN List IEI */ - /* ext(b8) | Length of PLMN List value contents(b7..1) */ - *ipos++ = 1 + count * 3; - *ipos++ = count; /* Number of PLMNs */ - - pos = buf; - while (pos && *pos) { - char *mcc, *mnc; - size_t mnc_len; - - mcc = pos; - mnc = os_strchr(pos, ','); - if (mnc == NULL) - goto fail; - *mnc++ = '\0'; - pos = os_strchr(mnc, ';'); - if (pos) - *pos++ = '\0'; - - mnc_len = os_strlen(mnc); - if (os_strlen(mcc) != 3 || (mnc_len != 2 && mnc_len != 3)) - goto fail; - - /* BC coded MCC,MNC */ - /* MCC digit 2 | MCC digit 1 */ - *ipos++ = ((mcc[1] - '0') << 4) | (mcc[0] - '0'); - /* MNC digit 3 | MCC digit 3 */ - *ipos++ = (((mnc_len == 2) ? 0xf0 : ((mnc[2] - '0') << 4))) | - (mcc[2] - '0'); - /* MNC digit 2 | MNC digit 1 */ - *ipos++ = ((mnc[1] - '0') << 4) | (mnc[0] - '0'); - } - - os_free(bss->anqp_3gpp_cell_net); - bss->anqp_3gpp_cell_net = info; - bss->anqp_3gpp_cell_net_len = 2 + 3 + 3 * count; - wpa_hexdump(MSG_MSGDUMP, "3GPP Cellular Network information", - bss->anqp_3gpp_cell_net, bss->anqp_3gpp_cell_net_len); - - return 0; - -fail: - wpa_printf(MSG_ERROR, "Line %d: Invalid anqp_3gpp_cell_net: %s", - line, buf); - os_free(info); - return -1; -} - - -static int parse_nai_realm(struct hostapd_bss_config *bss, char *buf, int line) -{ - struct hostapd_nai_realm_data *realm; - size_t i, j, len; - int *offsets; - char *pos, *end, *rpos; - - offsets = os_calloc(bss->nai_realm_count * MAX_NAI_REALMS, - sizeof(int)); - if (offsets == NULL) - return -1; - - for (i = 0; i < bss->nai_realm_count; i++) { - realm = &bss->nai_realm_data[i]; - for (j = 0; j < MAX_NAI_REALMS; j++) { - offsets[i * MAX_NAI_REALMS + j] = - realm->realm[j] ? - realm->realm[j] - realm->realm_buf : -1; - } - } - - realm = os_realloc_array(bss->nai_realm_data, bss->nai_realm_count + 1, - sizeof(struct hostapd_nai_realm_data)); - if (realm == NULL) { - os_free(offsets); - return -1; - } - bss->nai_realm_data = realm; - - /* patch the pointers after realloc */ - for (i = 0; i < bss->nai_realm_count; i++) { - realm = &bss->nai_realm_data[i]; - for (j = 0; j < MAX_NAI_REALMS; j++) { - int offs = offsets[i * MAX_NAI_REALMS + j]; - if (offs >= 0) - realm->realm[j] = realm->realm_buf + offs; - else - realm->realm[j] = NULL; - } - } - os_free(offsets); - - realm = &bss->nai_realm_data[bss->nai_realm_count]; - os_memset(realm, 0, sizeof(*realm)); - - pos = buf; - realm->encoding = atoi(pos); - pos = os_strchr(pos, ','); - if (pos == NULL) - goto fail; - pos++; - - end = os_strchr(pos, ','); - if (end) { - len = end - pos; - *end = '\0'; - } else { - len = os_strlen(pos); - } - - if (len > MAX_NAI_REALMLEN) { - wpa_printf(MSG_ERROR, "Too long a realm string (%d > max %d " - "characters)", (int) len, MAX_NAI_REALMLEN); - goto fail; - } - os_memcpy(realm->realm_buf, pos, len); - - if (end) - pos = end + 1; - else - pos = NULL; - - while (pos && *pos) { - struct hostapd_nai_realm_eap *eap; - - if (realm->eap_method_count >= MAX_NAI_EAP_METHODS) { - wpa_printf(MSG_ERROR, "Too many EAP methods"); - goto fail; - } - - eap = &realm->eap_method[realm->eap_method_count]; - realm->eap_method_count++; - - end = os_strchr(pos, ','); - if (end == NULL) - end = pos + os_strlen(pos); - - eap->eap_method = atoi(pos); - for (;;) { - pos = os_strchr(pos, '['); - if (pos == NULL || pos > end) - break; - pos++; - if (eap->num_auths >= MAX_NAI_AUTH_TYPES) { - wpa_printf(MSG_ERROR, "Too many auth params"); - goto fail; - } - eap->auth_id[eap->num_auths] = atoi(pos); - pos = os_strchr(pos, ':'); - if (pos == NULL || pos > end) - goto fail; - pos++; - eap->auth_val[eap->num_auths] = atoi(pos); - pos = os_strchr(pos, ']'); - if (pos == NULL || pos > end) - goto fail; - pos++; - eap->num_auths++; - } - - if (*end != ',') - break; - - pos = end + 1; - } - - /* Split realm list into null terminated realms */ - rpos = realm->realm_buf; - i = 0; - while (*rpos) { - if (i >= MAX_NAI_REALMS) { - wpa_printf(MSG_ERROR, "Too many realms"); - goto fail; - } - realm->realm[i++] = rpos; - rpos = os_strchr(rpos, ';'); - if (rpos == NULL) - break; - *rpos++ = '\0'; - } - - bss->nai_realm_count++; - - return 0; - -fail: - wpa_printf(MSG_ERROR, "Line %d: invalid nai_realm '%s'", line, buf); - return -1; -} - - -static int parse_qos_map_set(struct hostapd_bss_config *bss, - char *buf, int line) -{ - u8 qos_map_set[16 + 2 * 21], count = 0; - char *pos = buf; - int val; - - for (;;) { - if (count == sizeof(qos_map_set)) { - wpa_printf(MSG_ERROR, "Line %d: Too many qos_map_set " - "parameters '%s'", line, buf); - return -1; - } - - val = atoi(pos); - if (val > 255 || val < 0) { - wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set " - "'%s'", line, buf); - return -1; - } - - qos_map_set[count++] = val; - pos = os_strchr(pos, ','); - if (!pos) - break; - pos++; - } - - if (count < 16 || count & 1) { - wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set '%s'", - line, buf); - return -1; - } - - os_memcpy(bss->qos_map_set, qos_map_set, count); - bss->qos_map_set_len = count; - - return 0; -} - -#endif /* CONFIG_INTERWORKING */ - - -#ifdef CONFIG_HS20 -static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf, - int line) -{ - u8 *conn_cap; - char *pos; - - if (bss->hs20_connection_capability_len >= 0xfff0) - return -1; - - conn_cap = os_realloc(bss->hs20_connection_capability, - bss->hs20_connection_capability_len + 4); - if (conn_cap == NULL) - return -1; - - bss->hs20_connection_capability = conn_cap; - conn_cap += bss->hs20_connection_capability_len; - pos = buf; - conn_cap[0] = atoi(pos); - pos = os_strchr(pos, ':'); - if (pos == NULL) - return -1; - pos++; - WPA_PUT_LE16(conn_cap + 1, atoi(pos)); - pos = os_strchr(pos, ':'); - if (pos == NULL) - return -1; - pos++; - conn_cap[3] = atoi(pos); - bss->hs20_connection_capability_len += 4; - - return 0; -} - - -static int hs20_parse_wan_metrics(struct hostapd_bss_config *bss, char *buf, - int line) -{ - u8 *wan_metrics; - char *pos; - - /* :
:
    :
    :
      : */ - - wan_metrics = os_zalloc(13); - if (wan_metrics == NULL) - return -1; - - pos = buf; - /* WAN Info */ - if (hexstr2bin(pos, wan_metrics, 1) < 0) - goto fail; - pos += 2; - if (*pos != ':') - goto fail; - pos++; - - /* Downlink Speed */ - WPA_PUT_LE32(wan_metrics + 1, atoi(pos)); - pos = os_strchr(pos, ':'); - if (pos == NULL) - goto fail; - pos++; - - /* Uplink Speed */ - WPA_PUT_LE32(wan_metrics + 5, atoi(pos)); - pos = os_strchr(pos, ':'); - if (pos == NULL) - goto fail; - pos++; - - /* Downlink Load */ - wan_metrics[9] = atoi(pos); - pos = os_strchr(pos, ':'); - if (pos == NULL) - goto fail; - pos++; - - /* Uplink Load */ - wan_metrics[10] = atoi(pos); - pos = os_strchr(pos, ':'); - if (pos == NULL) - goto fail; - pos++; - - /* LMD */ - WPA_PUT_LE16(wan_metrics + 11, atoi(pos)); - - os_free(bss->hs20_wan_metrics); - bss->hs20_wan_metrics = wan_metrics; - - return 0; - -fail: - wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_wan_metrics '%s'", - line, pos); - os_free(wan_metrics); - return -1; -} - - -static int hs20_parse_oper_friendly_name(struct hostapd_bss_config *bss, - char *pos, int line) -{ - if (parse_lang_string(&bss->hs20_oper_friendly_name, - &bss->hs20_oper_friendly_name_count, pos)) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "hs20_oper_friendly_name '%s'", line, pos); - return -1; - } - return 0; -} -#endif /* CONFIG_HS20 */ - - -#ifdef CONFIG_WPS_NFC -static struct wpabuf * hostapd_parse_bin(const char *buf) -{ - size_t len; - struct wpabuf *ret; - - len = os_strlen(buf); - if (len & 0x01) - return NULL; - len /= 2; - - ret = wpabuf_alloc(len); - if (ret == NULL) - return NULL; - - if (hexstr2bin(buf, wpabuf_put(ret, len), len)) { - wpabuf_free(ret); - return NULL; - } - - return ret; -} -#endif /* CONFIG_WPS_NFC */ - - -static int hostapd_config_fill(struct hostapd_config *conf, - struct hostapd_bss_config *bss, - char *buf, char *pos, int line) -{ - int errors = 0; - - { - if (os_strcmp(buf, "interface") == 0) { - os_strlcpy(conf->bss[0]->iface, pos, - sizeof(conf->bss[0]->iface)); - } else if (os_strcmp(buf, "bridge") == 0) { - os_strlcpy(bss->bridge, pos, sizeof(bss->bridge)); - } else if (os_strcmp(buf, "vlan_bridge") == 0) { - os_strlcpy(bss->vlan_bridge, pos, - sizeof(bss->vlan_bridge)); - } else if (os_strcmp(buf, "wds_bridge") == 0) { - os_strlcpy(bss->wds_bridge, pos, - sizeof(bss->wds_bridge)); - } else if (os_strcmp(buf, "driver") == 0) { - int j; - /* clear to get error below if setting is invalid */ - conf->driver = NULL; - for (j = 0; wpa_drivers[j]; j++) { - if (os_strcmp(pos, wpa_drivers[j]->name) == 0) - { - conf->driver = wpa_drivers[j]; - break; - } - } - if (conf->driver == NULL) { - wpa_printf(MSG_ERROR, "Line %d: invalid/" - "unknown driver '%s'", line, pos); - errors++; - } - } else if (os_strcmp(buf, "debug") == 0) { - wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' " - "configuration variable is not used " - "anymore", line); - } else if (os_strcmp(buf, "logger_syslog_level") == 0) { - bss->logger_syslog_level = atoi(pos); - } else if (os_strcmp(buf, "logger_stdout_level") == 0) { - bss->logger_stdout_level = atoi(pos); - } else if (os_strcmp(buf, "logger_syslog") == 0) { - bss->logger_syslog = atoi(pos); - } else if (os_strcmp(buf, "logger_stdout") == 0) { - bss->logger_stdout = atoi(pos); - } else if (os_strcmp(buf, "dump_file") == 0) { - wpa_printf(MSG_INFO, "Line %d: DEPRECATED: 'dump_file' configuration variable is not used anymore", - line); - } else if (os_strcmp(buf, "ssid") == 0) { - bss->ssid.ssid_len = os_strlen(pos); - if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN || - bss->ssid.ssid_len < 1) { - wpa_printf(MSG_ERROR, "Line %d: invalid SSID " - "'%s'", line, pos); - errors++; - } else { - os_memcpy(bss->ssid.ssid, pos, - bss->ssid.ssid_len); - bss->ssid.ssid_set = 1; - } - } else if (os_strcmp(buf, "ssid2") == 0) { - size_t slen; - char *str = wpa_config_parse_string(pos, &slen); - if (str == NULL || slen < 1 || - slen > HOSTAPD_MAX_SSID_LEN) { - wpa_printf(MSG_ERROR, "Line %d: invalid SSID " - "'%s'", line, pos); - errors++; - } else { - os_memcpy(bss->ssid.ssid, str, slen); - bss->ssid.ssid_len = slen; - bss->ssid.ssid_set = 1; - } - os_free(str); - } else if (os_strcmp(buf, "utf8_ssid") == 0) { - bss->ssid.utf8_ssid = atoi(pos) > 0; - } else if (os_strcmp(buf, "macaddr_acl") == 0) { - bss->macaddr_acl = atoi(pos); - if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED && - bss->macaddr_acl != DENY_UNLESS_ACCEPTED && - bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) { - wpa_printf(MSG_ERROR, "Line %d: unknown " - "macaddr_acl %d", - line, bss->macaddr_acl); - } - } else if (os_strcmp(buf, "accept_mac_file") == 0) { - if (hostapd_config_read_maclist(pos, &bss->accept_mac, - &bss->num_accept_mac)) - { - wpa_printf(MSG_ERROR, "Line %d: Failed to " - "read accept_mac_file '%s'", - line, pos); - errors++; - } - } else if (os_strcmp(buf, "deny_mac_file") == 0) { - if (hostapd_config_read_maclist(pos, &bss->deny_mac, - &bss->num_deny_mac)) { - wpa_printf(MSG_ERROR, "Line %d: Failed to " - "read deny_mac_file '%s'", - line, pos); - errors++; - } - } else if (os_strcmp(buf, "wds_sta") == 0) { - bss->wds_sta = atoi(pos); - } else if (os_strcmp(buf, "start_disabled") == 0) { - bss->start_disabled = atoi(pos); - } else if (os_strcmp(buf, "ap_isolate") == 0) { - bss->isolate = atoi(pos); - } else if (os_strcmp(buf, "ap_max_inactivity") == 0) { - bss->ap_max_inactivity = atoi(pos); - } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) { - bss->skip_inactivity_poll = atoi(pos); - } else if (os_strcmp(buf, "country_code") == 0) { - os_memcpy(conf->country, pos, 2); - /* FIX: make this configurable */ - conf->country[2] = ' '; - } else if (os_strcmp(buf, "ieee80211d") == 0) { - conf->ieee80211d = atoi(pos); - } else if (os_strcmp(buf, "ieee80211h") == 0) { - conf->ieee80211h = atoi(pos); - } else if (os_strcmp(buf, "ieee8021x") == 0) { - bss->ieee802_1x = atoi(pos); - } else if (os_strcmp(buf, "eapol_version") == 0) { - bss->eapol_version = atoi(pos); - if (bss->eapol_version < 1 || - bss->eapol_version > 2) { - wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL " - "version (%d): '%s'.", - line, bss->eapol_version, pos); - errors++; - } else - wpa_printf(MSG_DEBUG, "eapol_version=%d", - bss->eapol_version); -#ifdef EAP_SERVER - } else if (os_strcmp(buf, "eap_authenticator") == 0) { - bss->eap_server = atoi(pos); - wpa_printf(MSG_ERROR, "Line %d: obsolete " - "eap_authenticator used; this has been " - "renamed to eap_server", line); - } else if (os_strcmp(buf, "eap_server") == 0) { - bss->eap_server = atoi(pos); - } else if (os_strcmp(buf, "eap_user_file") == 0) { - if (hostapd_config_read_eap_user(pos, bss)) - errors++; - } else if (os_strcmp(buf, "ca_cert") == 0) { - os_free(bss->ca_cert); - bss->ca_cert = os_strdup(pos); - } else if (os_strcmp(buf, "server_cert") == 0) { - os_free(bss->server_cert); - bss->server_cert = os_strdup(pos); - } else if (os_strcmp(buf, "private_key") == 0) { - os_free(bss->private_key); - bss->private_key = os_strdup(pos); - } else if (os_strcmp(buf, "private_key_passwd") == 0) { - os_free(bss->private_key_passwd); - bss->private_key_passwd = os_strdup(pos); - } else if (os_strcmp(buf, "check_crl") == 0) { - bss->check_crl = atoi(pos); - } else if (os_strcmp(buf, "ocsp_stapling_response") == 0) { - os_free(bss->ocsp_stapling_response); - bss->ocsp_stapling_response = os_strdup(pos); - } else if (os_strcmp(buf, "dh_file") == 0) { - os_free(bss->dh_file); - bss->dh_file = os_strdup(pos); - } else if (os_strcmp(buf, "fragment_size") == 0) { - bss->fragment_size = atoi(pos); -#ifdef EAP_SERVER_FAST - } else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) { - os_free(bss->pac_opaque_encr_key); - bss->pac_opaque_encr_key = os_malloc(16); - if (bss->pac_opaque_encr_key == NULL) { - wpa_printf(MSG_ERROR, "Line %d: No memory for " - "pac_opaque_encr_key", line); - errors++; - } else if (hexstr2bin(pos, bss->pac_opaque_encr_key, - 16)) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "pac_opaque_encr_key", line); - errors++; - } - } else if (os_strcmp(buf, "eap_fast_a_id") == 0) { - size_t idlen = os_strlen(pos); - if (idlen & 1) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "eap_fast_a_id", line); - errors++; - } else { - os_free(bss->eap_fast_a_id); - bss->eap_fast_a_id = os_malloc(idlen / 2); - if (bss->eap_fast_a_id == NULL || - hexstr2bin(pos, bss->eap_fast_a_id, - idlen / 2)) { - wpa_printf(MSG_ERROR, "Line %d: " - "Failed to parse " - "eap_fast_a_id", line); - errors++; - } else - bss->eap_fast_a_id_len = idlen / 2; - } - } else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) { - os_free(bss->eap_fast_a_id_info); - bss->eap_fast_a_id_info = os_strdup(pos); - } else if (os_strcmp(buf, "eap_fast_prov") == 0) { - bss->eap_fast_prov = atoi(pos); - } else if (os_strcmp(buf, "pac_key_lifetime") == 0) { - bss->pac_key_lifetime = atoi(pos); - } else if (os_strcmp(buf, "pac_key_refresh_time") == 0) { - bss->pac_key_refresh_time = atoi(pos); -#endif /* EAP_SERVER_FAST */ -#ifdef EAP_SERVER_SIM - } else if (os_strcmp(buf, "eap_sim_db") == 0) { - os_free(bss->eap_sim_db); - bss->eap_sim_db = os_strdup(pos); - } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) { - bss->eap_sim_aka_result_ind = atoi(pos); -#endif /* EAP_SERVER_SIM */ -#ifdef EAP_SERVER_TNC - } else if (os_strcmp(buf, "tnc") == 0) { - bss->tnc = atoi(pos); -#endif /* EAP_SERVER_TNC */ -#ifdef EAP_SERVER_PWD - } else if (os_strcmp(buf, "pwd_group") == 0) { - bss->pwd_group = atoi(pos); -#endif /* EAP_SERVER_PWD */ -#endif /* EAP_SERVER */ - } else if (os_strcmp(buf, "eap_message") == 0) { - char *term; - bss->eap_req_id_text = os_strdup(pos); - if (bss->eap_req_id_text == NULL) { - wpa_printf(MSG_ERROR, "Line %d: Failed to " - "allocate memory for " - "eap_req_id_text", line); - errors++; - return errors; - } - bss->eap_req_id_text_len = - os_strlen(bss->eap_req_id_text); - term = os_strstr(bss->eap_req_id_text, "\\0"); - if (term) { - *term++ = '\0'; - os_memmove(term, term + 1, - bss->eap_req_id_text_len - - (term - bss->eap_req_id_text) - 1); - bss->eap_req_id_text_len--; - } - } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) { - bss->default_wep_key_len = atoi(pos); - if (bss->default_wep_key_len > 13) { - wpa_printf(MSG_ERROR, "Line %d: invalid WEP " - "key len %lu (= %lu bits)", line, - (unsigned long) - bss->default_wep_key_len, - (unsigned long) - bss->default_wep_key_len * 8); - errors++; - } - } else if (os_strcmp(buf, "wep_key_len_unicast") == 0) { - bss->individual_wep_key_len = atoi(pos); - if (bss->individual_wep_key_len < 0 || - bss->individual_wep_key_len > 13) { - wpa_printf(MSG_ERROR, "Line %d: invalid WEP " - "key len %d (= %d bits)", line, - bss->individual_wep_key_len, - bss->individual_wep_key_len * 8); - errors++; - } - } else if (os_strcmp(buf, "wep_rekey_period") == 0) { - bss->wep_rekeying_period = atoi(pos); - if (bss->wep_rekeying_period < 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "period %d", - line, bss->wep_rekeying_period); - errors++; - } - } else if (os_strcmp(buf, "eap_reauth_period") == 0) { - bss->eap_reauth_period = atoi(pos); - if (bss->eap_reauth_period < 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "period %d", - line, bss->eap_reauth_period); - errors++; - } - } else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) { - bss->eapol_key_index_workaround = atoi(pos); -#ifdef CONFIG_IAPP - } else if (os_strcmp(buf, "iapp_interface") == 0) { - bss->ieee802_11f = 1; - os_strlcpy(bss->iapp_iface, pos, - sizeof(bss->iapp_iface)); -#endif /* CONFIG_IAPP */ - } else if (os_strcmp(buf, "own_ip_addr") == 0) { - if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) { - wpa_printf(MSG_ERROR, "Line %d: invalid IP " - "address '%s'", line, pos); - errors++; - } - } else if (os_strcmp(buf, "nas_identifier") == 0) { - bss->nas_identifier = os_strdup(pos); -#ifndef CONFIG_NO_RADIUS - } else if (os_strcmp(buf, "auth_server_addr") == 0) { - if (hostapd_config_read_radius_addr( - &bss->radius->auth_servers, - &bss->radius->num_auth_servers, pos, 1812, - &bss->radius->auth_server)) { - wpa_printf(MSG_ERROR, "Line %d: invalid IP " - "address '%s'", line, pos); - errors++; - } - } else if (bss->radius->auth_server && - os_strcmp(buf, "auth_server_port") == 0) { - bss->radius->auth_server->port = atoi(pos); - } else if (bss->radius->auth_server && - os_strcmp(buf, "auth_server_shared_secret") == 0) { - int len = os_strlen(pos); - if (len == 0) { - /* RFC 2865, Ch. 3 */ - wpa_printf(MSG_ERROR, "Line %d: empty shared " - "secret is not allowed.", line); - errors++; - } - bss->radius->auth_server->shared_secret = - (u8 *) os_strdup(pos); - bss->radius->auth_server->shared_secret_len = len; - } else if (os_strcmp(buf, "acct_server_addr") == 0) { - if (hostapd_config_read_radius_addr( - &bss->radius->acct_servers, - &bss->radius->num_acct_servers, pos, 1813, - &bss->radius->acct_server)) { - wpa_printf(MSG_ERROR, "Line %d: invalid IP " - "address '%s'", line, pos); - errors++; - } - } else if (bss->radius->acct_server && - os_strcmp(buf, "acct_server_port") == 0) { - bss->radius->acct_server->port = atoi(pos); - } else if (bss->radius->acct_server && - os_strcmp(buf, "acct_server_shared_secret") == 0) { - int len = os_strlen(pos); - if (len == 0) { - /* RFC 2865, Ch. 3 */ - wpa_printf(MSG_ERROR, "Line %d: empty shared " - "secret is not allowed.", line); - errors++; - } - bss->radius->acct_server->shared_secret = - (u8 *) os_strdup(pos); - bss->radius->acct_server->shared_secret_len = len; - } else if (os_strcmp(buf, "radius_retry_primary_interval") == - 0) { - bss->radius->retry_primary_interval = atoi(pos); - } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0) - { - bss->acct_interim_interval = atoi(pos); - } else if (os_strcmp(buf, "radius_request_cui") == 0) { - bss->radius_request_cui = atoi(pos); - } else if (os_strcmp(buf, "radius_auth_req_attr") == 0) { - struct hostapd_radius_attr *attr, *a; - attr = hostapd_parse_radius_attr(pos); - if (attr == NULL) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "radius_auth_req_attr", line); - errors++; - } else if (bss->radius_auth_req_attr == NULL) { - bss->radius_auth_req_attr = attr; - } else { - a = bss->radius_auth_req_attr; - while (a->next) - a = a->next; - a->next = attr; - } - } else if (os_strcmp(buf, "radius_acct_req_attr") == 0) { - struct hostapd_radius_attr *attr, *a; - attr = hostapd_parse_radius_attr(pos); - if (attr == NULL) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "radius_acct_req_attr", line); - errors++; - } else if (bss->radius_acct_req_attr == NULL) { - bss->radius_acct_req_attr = attr; - } else { - a = bss->radius_acct_req_attr; - while (a->next) - a = a->next; - a->next = attr; - } - } else if (os_strcmp(buf, "radius_das_port") == 0) { - bss->radius_das_port = atoi(pos); - } else if (os_strcmp(buf, "radius_das_client") == 0) { - if (hostapd_parse_das_client(bss, pos) < 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "DAS client", line); - errors++; - } - } else if (os_strcmp(buf, "radius_das_time_window") == 0) { - bss->radius_das_time_window = atoi(pos); - } else if (os_strcmp(buf, "radius_das_require_event_timestamp") - == 0) { - bss->radius_das_require_event_timestamp = atoi(pos); -#endif /* CONFIG_NO_RADIUS */ - } else if (os_strcmp(buf, "auth_algs") == 0) { - bss->auth_algs = atoi(pos); - if (bss->auth_algs == 0) { - wpa_printf(MSG_ERROR, "Line %d: no " - "authentication algorithms allowed", - line); - errors++; - } - } else if (os_strcmp(buf, "max_num_sta") == 0) { - bss->max_num_sta = atoi(pos); - if (bss->max_num_sta < 0 || - bss->max_num_sta > MAX_STA_COUNT) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "max_num_sta=%d; allowed range " - "0..%d", line, bss->max_num_sta, - MAX_STA_COUNT); - errors++; - } - } else if (os_strcmp(buf, "wpa") == 0) { - bss->wpa = atoi(pos); - } else if (os_strcmp(buf, "wpa_group_rekey") == 0) { - bss->wpa_group_rekey = atoi(pos); - } else if (os_strcmp(buf, "wpa_strict_rekey") == 0) { - bss->wpa_strict_rekey = atoi(pos); - } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) { - bss->wpa_gmk_rekey = atoi(pos); - } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) { - bss->wpa_ptk_rekey = atoi(pos); - } else if (os_strcmp(buf, "wpa_passphrase") == 0) { - int len = os_strlen(pos); - if (len < 8 || len > 63) { - wpa_printf(MSG_ERROR, "Line %d: invalid WPA " - "passphrase length %d (expected " - "8..63)", line, len); - errors++; - } else { - os_free(bss->ssid.wpa_passphrase); - bss->ssid.wpa_passphrase = os_strdup(pos); - if (bss->ssid.wpa_passphrase) { - os_free(bss->ssid.wpa_psk); - bss->ssid.wpa_psk = NULL; - bss->ssid.wpa_passphrase_set = 1; - } - } - } else if (os_strcmp(buf, "wpa_psk") == 0) { - os_free(bss->ssid.wpa_psk); - bss->ssid.wpa_psk = - os_zalloc(sizeof(struct hostapd_wpa_psk)); - if (bss->ssid.wpa_psk == NULL) - errors++; - else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk, - PMK_LEN) || - pos[PMK_LEN * 2] != '\0') { - wpa_printf(MSG_ERROR, "Line %d: Invalid PSK " - "'%s'.", line, pos); - errors++; - } else { - bss->ssid.wpa_psk->group = 1; - os_free(bss->ssid.wpa_passphrase); - bss->ssid.wpa_passphrase = NULL; - bss->ssid.wpa_psk_set = 1; - } - } else if (os_strcmp(buf, "wpa_psk_file") == 0) { - os_free(bss->ssid.wpa_psk_file); - bss->ssid.wpa_psk_file = os_strdup(pos); - if (!bss->ssid.wpa_psk_file) { - wpa_printf(MSG_ERROR, "Line %d: allocation " - "failed", line); - errors++; - } - } else if (os_strcmp(buf, "wpa_key_mgmt") == 0) { - bss->wpa_key_mgmt = - hostapd_config_parse_key_mgmt(line, pos); - if (bss->wpa_key_mgmt == -1) - errors++; - } else if (os_strcmp(buf, "wpa_psk_radius") == 0) { - bss->wpa_psk_radius = atoi(pos); - if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED && - bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED && - bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) { - wpa_printf(MSG_ERROR, "Line %d: unknown " - "wpa_psk_radius %d", - line, bss->wpa_psk_radius); - errors++; - } - } else if (os_strcmp(buf, "wpa_pairwise") == 0) { - bss->wpa_pairwise = - hostapd_config_parse_cipher(line, pos); - if (bss->wpa_pairwise == -1 || - bss->wpa_pairwise == 0) - errors++; - else if (bss->wpa_pairwise & - (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | - WPA_CIPHER_WEP104)) { - wpa_printf(MSG_ERROR, "Line %d: unsupported " - "pairwise cipher suite '%s'", - bss->wpa_pairwise, pos); - errors++; - } - } else if (os_strcmp(buf, "rsn_pairwise") == 0) { - bss->rsn_pairwise = - hostapd_config_parse_cipher(line, pos); - if (bss->rsn_pairwise == -1 || - bss->rsn_pairwise == 0) - errors++; - else if (bss->rsn_pairwise & - (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | - WPA_CIPHER_WEP104)) { - wpa_printf(MSG_ERROR, "Line %d: unsupported " - "pairwise cipher suite '%s'", - bss->rsn_pairwise, pos); - errors++; - } -#ifdef CONFIG_RSN_PREAUTH - } else if (os_strcmp(buf, "rsn_preauth") == 0) { - bss->rsn_preauth = atoi(pos); - } else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) { - bss->rsn_preauth_interfaces = os_strdup(pos); -#endif /* CONFIG_RSN_PREAUTH */ -#ifdef CONFIG_PEERKEY - } else if (os_strcmp(buf, "peerkey") == 0) { - bss->peerkey = atoi(pos); -#endif /* CONFIG_PEERKEY */ -#ifdef CONFIG_IEEE80211R - } else if (os_strcmp(buf, "mobility_domain") == 0) { - if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN || - hexstr2bin(pos, bss->mobility_domain, - MOBILITY_DOMAIN_ID_LEN) != 0) { - wpa_printf(MSG_DEBUG, "Line %d: Invalid " - "mobility_domain '%s'", line, pos); - errors++; - return errors; - } - } else if (os_strcmp(buf, "r1_key_holder") == 0) { - if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN || - hexstr2bin(pos, bss->r1_key_holder, - FT_R1KH_ID_LEN) != 0) { - wpa_printf(MSG_DEBUG, "Line %d: Invalid " - "r1_key_holder '%s'", line, pos); - errors++; - return errors; - } - } else if (os_strcmp(buf, "r0_key_lifetime") == 0) { - bss->r0_key_lifetime = atoi(pos); - } else if (os_strcmp(buf, "reassociation_deadline") == 0) { - bss->reassociation_deadline = atoi(pos); - } else if (os_strcmp(buf, "r0kh") == 0) { - if (add_r0kh(bss, pos) < 0) { - wpa_printf(MSG_DEBUG, "Line %d: Invalid " - "r0kh '%s'", line, pos); - errors++; - return errors; - } - } else if (os_strcmp(buf, "r1kh") == 0) { - if (add_r1kh(bss, pos) < 0) { - wpa_printf(MSG_DEBUG, "Line %d: Invalid " - "r1kh '%s'", line, pos); - errors++; - return errors; - } - } else if (os_strcmp(buf, "pmk_r1_push") == 0) { - bss->pmk_r1_push = atoi(pos); - } else if (os_strcmp(buf, "ft_over_ds") == 0) { - bss->ft_over_ds = atoi(pos); -#endif /* CONFIG_IEEE80211R */ -#ifndef CONFIG_NO_CTRL_IFACE - } else if (os_strcmp(buf, "ctrl_interface") == 0) { - os_free(bss->ctrl_interface); - bss->ctrl_interface = os_strdup(pos); - } else if (os_strcmp(buf, "ctrl_interface_group") == 0) { -#ifndef CONFIG_NATIVE_WINDOWS - struct group *grp; - char *endp; - const char *group = pos; - - grp = getgrnam(group); - if (grp) { - bss->ctrl_interface_gid = grp->gr_gid; - bss->ctrl_interface_gid_set = 1; - wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" - " (from group name '%s')", - bss->ctrl_interface_gid, group); - return errors; - } - - /* Group name not found - try to parse this as gid */ - bss->ctrl_interface_gid = strtol(group, &endp, 10); - if (*group == '\0' || *endp != '\0') { - wpa_printf(MSG_DEBUG, "Line %d: Invalid group " - "'%s'", line, group); - errors++; - return errors; - } - bss->ctrl_interface_gid_set = 1; - wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", - bss->ctrl_interface_gid); -#endif /* CONFIG_NATIVE_WINDOWS */ -#endif /* CONFIG_NO_CTRL_IFACE */ -#ifdef RADIUS_SERVER - } else if (os_strcmp(buf, "radius_server_clients") == 0) { - os_free(bss->radius_server_clients); - bss->radius_server_clients = os_strdup(pos); - } else if (os_strcmp(buf, "radius_server_auth_port") == 0) { - bss->radius_server_auth_port = atoi(pos); - } else if (os_strcmp(buf, "radius_server_ipv6") == 0) { - bss->radius_server_ipv6 = atoi(pos); -#endif /* RADIUS_SERVER */ - } else if (os_strcmp(buf, "test_socket") == 0) { - os_free(bss->test_socket); - bss->test_socket = os_strdup(pos); - } else if (os_strcmp(buf, "use_pae_group_addr") == 0) { - bss->use_pae_group_addr = atoi(pos); - } else if (os_strcmp(buf, "hw_mode") == 0) { - if (os_strcmp(pos, "a") == 0) - conf->hw_mode = HOSTAPD_MODE_IEEE80211A; - else if (os_strcmp(pos, "b") == 0) - conf->hw_mode = HOSTAPD_MODE_IEEE80211B; - else if (os_strcmp(pos, "g") == 0) - conf->hw_mode = HOSTAPD_MODE_IEEE80211G; - else if (os_strcmp(pos, "ad") == 0) - conf->hw_mode = HOSTAPD_MODE_IEEE80211AD; - else { - wpa_printf(MSG_ERROR, "Line %d: unknown " - "hw_mode '%s'", line, pos); - errors++; - } - } else if (os_strcmp(buf, "wps_rf_bands") == 0) { - if (os_strcmp(pos, "a") == 0) - bss->wps_rf_bands = WPS_RF_50GHZ; - else if (os_strcmp(pos, "g") == 0 || - os_strcmp(pos, "b") == 0) - bss->wps_rf_bands = WPS_RF_24GHZ; - else if (os_strcmp(pos, "ag") == 0 || - os_strcmp(pos, "ga") == 0) - bss->wps_rf_bands = - WPS_RF_24GHZ | WPS_RF_50GHZ; - else { - wpa_printf(MSG_ERROR, "Line %d: unknown " - "wps_rf_band '%s'", line, pos); - errors++; - } - } else if (os_strcmp(buf, "channel") == 0) { - if (os_strcmp(pos, "acs_survey") == 0) { -#ifndef CONFIG_ACS - wpa_printf(MSG_ERROR, "Line %d: tries to enable ACS but CONFIG_ACS disabled", - line); - errors++; -#endif /* CONFIG_ACS */ - conf->channel = 0; - } else - conf->channel = atoi(pos); - } else if (os_strcmp(buf, "beacon_int") == 0) { - int val = atoi(pos); - /* MIB defines range as 1..65535, but very small values - * cause problems with the current implementation. - * Since it is unlikely that this small numbers are - * useful in real life scenarios, do not allow beacon - * period to be set below 15 TU. */ - if (val < 15 || val > 65535) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "beacon_int %d (expected " - "15..65535)", line, val); - errors++; - } else - conf->beacon_int = val; -#ifdef CONFIG_ACS - } else if (os_strcmp(buf, "acs_num_scans") == 0) { - int val = atoi(pos); - if (val <= 0 || val > 100) { - wpa_printf(MSG_ERROR, "Line %d: invalid acs_num_scans %d (expected 1..100)", - line, val); - errors++; - } else - conf->acs_num_scans = val; -#endif /* CONFIG_ACS */ - } else if (os_strcmp(buf, "dtim_period") == 0) { - bss->dtim_period = atoi(pos); - if (bss->dtim_period < 1 || bss->dtim_period > 255) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "dtim_period %d", - line, bss->dtim_period); - errors++; - } - } else if (os_strcmp(buf, "rts_threshold") == 0) { - conf->rts_threshold = atoi(pos); - if (conf->rts_threshold < 0 || - conf->rts_threshold > 2347) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "rts_threshold %d", - line, conf->rts_threshold); - errors++; - } - } else if (os_strcmp(buf, "fragm_threshold") == 0) { - conf->fragm_threshold = atoi(pos); - if (conf->fragm_threshold < 256 || - conf->fragm_threshold > 2346) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "fragm_threshold %d", - line, conf->fragm_threshold); - errors++; - } - } else if (os_strcmp(buf, "send_probe_response") == 0) { - int val = atoi(pos); - if (val != 0 && val != 1) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "send_probe_response %d (expected " - "0 or 1)", line, val); - } else - conf->send_probe_response = val; - } else if (os_strcmp(buf, "supported_rates") == 0) { - if (hostapd_parse_intlist(&conf->supported_rates, pos)) - { - wpa_printf(MSG_ERROR, "Line %d: invalid rate " - "list", line); - errors++; - } - } else if (os_strcmp(buf, "basic_rates") == 0) { - if (hostapd_parse_intlist(&conf->basic_rates, pos)) { - wpa_printf(MSG_ERROR, "Line %d: invalid rate " - "list", line); - errors++; - } - } else if (os_strcmp(buf, "preamble") == 0) { - if (atoi(pos)) - conf->preamble = SHORT_PREAMBLE; - else - conf->preamble = LONG_PREAMBLE; - } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) { - bss->ignore_broadcast_ssid = atoi(pos); - } else if (os_strcmp(buf, "wep_default_key") == 0) { - bss->ssid.wep.idx = atoi(pos); - if (bss->ssid.wep.idx > 3) { - wpa_printf(MSG_ERROR, "Invalid " - "wep_default_key index %d", - bss->ssid.wep.idx); - errors++; - } - } else if (os_strcmp(buf, "wep_key0") == 0 || - os_strcmp(buf, "wep_key1") == 0 || - os_strcmp(buf, "wep_key2") == 0 || - os_strcmp(buf, "wep_key3") == 0) { - if (hostapd_config_read_wep(&bss->ssid.wep, - buf[7] - '0', pos)) { - wpa_printf(MSG_ERROR, "Line %d: invalid WEP " - "key '%s'", line, buf); - errors++; - } -#ifndef CONFIG_NO_VLAN - } else if (os_strcmp(buf, "dynamic_vlan") == 0) { - bss->ssid.dynamic_vlan = atoi(pos); - } else if (os_strcmp(buf, "vlan_file") == 0) { - if (hostapd_config_read_vlan_file(bss, pos)) { - wpa_printf(MSG_ERROR, "Line %d: failed to " - "read VLAN file '%s'", line, pos); - errors++; - } - } else if (os_strcmp(buf, "vlan_naming") == 0) { - bss->ssid.vlan_naming = atoi(pos); - if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END || - bss->ssid.vlan_naming < 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "naming scheme %d", line, - bss->ssid.vlan_naming); - errors++; - } -#ifdef CONFIG_FULL_DYNAMIC_VLAN - } else if (os_strcmp(buf, "vlan_tagged_interface") == 0) { - bss->ssid.vlan_tagged_interface = os_strdup(pos); -#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -#endif /* CONFIG_NO_VLAN */ - } else if (os_strcmp(buf, "ap_table_max_size") == 0) { - conf->ap_table_max_size = atoi(pos); - } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) { - conf->ap_table_expiration_time = atoi(pos); - } else if (os_strncmp(buf, "tx_queue_", 9) == 0) { - if (hostapd_config_tx_queue(conf, buf, pos)) { - wpa_printf(MSG_ERROR, "Line %d: invalid TX " - "queue item", line); - errors++; - } - } else if (os_strcmp(buf, "wme_enabled") == 0 || - os_strcmp(buf, "wmm_enabled") == 0) { - bss->wmm_enabled = atoi(pos); - } else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) { - bss->wmm_uapsd = atoi(pos); - } else if (os_strncmp(buf, "wme_ac_", 7) == 0 || - os_strncmp(buf, "wmm_ac_", 7) == 0) { - if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf, - pos)) { - wpa_printf(MSG_ERROR, "Line %d: invalid WMM " - "ac item", line); - errors++; - } - } else if (os_strcmp(buf, "bss") == 0) { - if (hostapd_config_bss(conf, pos)) { - wpa_printf(MSG_ERROR, "Line %d: invalid bss " - "item", line); - errors++; - } - } else if (os_strcmp(buf, "bssid") == 0) { - if (hwaddr_aton(pos, bss->bssid)) { - wpa_printf(MSG_ERROR, "Line %d: invalid bssid " - "item", line); - errors++; - } -#ifdef CONFIG_IEEE80211W - } else if (os_strcmp(buf, "ieee80211w") == 0) { - bss->ieee80211w = atoi(pos); - } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) { - bss->assoc_sa_query_max_timeout = atoi(pos); - if (bss->assoc_sa_query_max_timeout == 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "assoc_sa_query_max_timeout", line); - errors++; - } - } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0) - { - bss->assoc_sa_query_retry_timeout = atoi(pos); - if (bss->assoc_sa_query_retry_timeout == 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "assoc_sa_query_retry_timeout", - line); - errors++; - } -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_IEEE80211N - } else if (os_strcmp(buf, "ieee80211n") == 0) { - conf->ieee80211n = atoi(pos); - } else if (os_strcmp(buf, "ht_capab") == 0) { - if (hostapd_config_ht_capab(conf, pos) < 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "ht_capab", line); - errors++; - } - } else if (os_strcmp(buf, "require_ht") == 0) { - conf->require_ht = atoi(pos); - } else if (os_strcmp(buf, "obss_interval") == 0) { - conf->obss_interval = atoi(pos); -#endif /* CONFIG_IEEE80211N */ -#ifdef CONFIG_IEEE80211AC - } else if (os_strcmp(buf, "ieee80211ac") == 0) { - conf->ieee80211ac = atoi(pos); - } else if (os_strcmp(buf, "vht_capab") == 0) { - if (hostapd_config_vht_capab(conf, pos) < 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "vht_capab", line); - errors++; - } - } else if (os_strcmp(buf, "require_vht") == 0) { - conf->require_vht = atoi(pos); - } else if (os_strcmp(buf, "vht_oper_chwidth") == 0) { - conf->vht_oper_chwidth = atoi(pos); - } else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0) - { - conf->vht_oper_centr_freq_seg0_idx = atoi(pos); - } else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0) - { - conf->vht_oper_centr_freq_seg1_idx = atoi(pos); -#endif /* CONFIG_IEEE80211AC */ - } else if (os_strcmp(buf, "max_listen_interval") == 0) { - bss->max_listen_interval = atoi(pos); - } else if (os_strcmp(buf, "disable_pmksa_caching") == 0) { - bss->disable_pmksa_caching = atoi(pos); - } else if (os_strcmp(buf, "okc") == 0) { - bss->okc = atoi(pos); -#ifdef CONFIG_WPS - } else if (os_strcmp(buf, "wps_state") == 0) { - bss->wps_state = atoi(pos); - if (bss->wps_state < 0 || bss->wps_state > 2) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "wps_state", line); - errors++; - } - } else if (os_strcmp(buf, "wps_independent") == 0) { - bss->wps_independent = atoi(pos); - } else if (os_strcmp(buf, "ap_setup_locked") == 0) { - bss->ap_setup_locked = atoi(pos); - } else if (os_strcmp(buf, "uuid") == 0) { - if (uuid_str2bin(pos, bss->uuid)) { - wpa_printf(MSG_ERROR, "Line %d: invalid UUID", - line); - errors++; - } - } else if (os_strcmp(buf, "wps_pin_requests") == 0) { - os_free(bss->wps_pin_requests); - bss->wps_pin_requests = os_strdup(pos); - } else if (os_strcmp(buf, "device_name") == 0) { - if (os_strlen(pos) > 32) { - wpa_printf(MSG_ERROR, "Line %d: Too long " - "device_name", line); - errors++; - } - os_free(bss->device_name); - bss->device_name = os_strdup(pos); - } else if (os_strcmp(buf, "manufacturer") == 0) { - if (os_strlen(pos) > 64) { - wpa_printf(MSG_ERROR, "Line %d: Too long " - "manufacturer", line); - errors++; - } - os_free(bss->manufacturer); - bss->manufacturer = os_strdup(pos); - } else if (os_strcmp(buf, "model_name") == 0) { - if (os_strlen(pos) > 32) { - wpa_printf(MSG_ERROR, "Line %d: Too long " - "model_name", line); - errors++; - } - os_free(bss->model_name); - bss->model_name = os_strdup(pos); - } else if (os_strcmp(buf, "model_number") == 0) { - if (os_strlen(pos) > 32) { - wpa_printf(MSG_ERROR, "Line %d: Too long " - "model_number", line); - errors++; - } - os_free(bss->model_number); - bss->model_number = os_strdup(pos); - } else if (os_strcmp(buf, "serial_number") == 0) { - if (os_strlen(pos) > 32) { - wpa_printf(MSG_ERROR, "Line %d: Too long " - "serial_number", line); - errors++; - } - os_free(bss->serial_number); - bss->serial_number = os_strdup(pos); - } else if (os_strcmp(buf, "device_type") == 0) { - if (wps_dev_type_str2bin(pos, bss->device_type)) - errors++; - } else if (os_strcmp(buf, "config_methods") == 0) { - os_free(bss->config_methods); - bss->config_methods = os_strdup(pos); - } else if (os_strcmp(buf, "os_version") == 0) { - if (hexstr2bin(pos, bss->os_version, 4)) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "os_version", line); - errors++; - } - } else if (os_strcmp(buf, "ap_pin") == 0) { - os_free(bss->ap_pin); - bss->ap_pin = os_strdup(pos); - } else if (os_strcmp(buf, "skip_cred_build") == 0) { - bss->skip_cred_build = atoi(pos); - } else if (os_strcmp(buf, "extra_cred") == 0) { - os_free(bss->extra_cred); - bss->extra_cred = - (u8 *) os_readfile(pos, &bss->extra_cred_len); - if (bss->extra_cred == NULL) { - wpa_printf(MSG_ERROR, "Line %d: could not " - "read Credentials from '%s'", - line, pos); - errors++; - } - } else if (os_strcmp(buf, "wps_cred_processing") == 0) { - bss->wps_cred_processing = atoi(pos); - } else if (os_strcmp(buf, "ap_settings") == 0) { - os_free(bss->ap_settings); - bss->ap_settings = - (u8 *) os_readfile(pos, &bss->ap_settings_len); - if (bss->ap_settings == NULL) { - wpa_printf(MSG_ERROR, "Line %d: could not " - "read AP Settings from '%s'", - line, pos); - errors++; - } - } else if (os_strcmp(buf, "upnp_iface") == 0) { - bss->upnp_iface = os_strdup(pos); - } else if (os_strcmp(buf, "friendly_name") == 0) { - os_free(bss->friendly_name); - bss->friendly_name = os_strdup(pos); - } else if (os_strcmp(buf, "manufacturer_url") == 0) { - os_free(bss->manufacturer_url); - bss->manufacturer_url = os_strdup(pos); - } else if (os_strcmp(buf, "model_description") == 0) { - os_free(bss->model_description); - bss->model_description = os_strdup(pos); - } else if (os_strcmp(buf, "model_url") == 0) { - os_free(bss->model_url); - bss->model_url = os_strdup(pos); - } else if (os_strcmp(buf, "upc") == 0) { - os_free(bss->upc); - bss->upc = os_strdup(pos); - } else if (os_strcmp(buf, "pbc_in_m1") == 0) { - bss->pbc_in_m1 = atoi(pos); - } else if (os_strcmp(buf, "server_id") == 0) { - os_free(bss->server_id); - bss->server_id = os_strdup(pos); -#ifdef CONFIG_WPS_NFC - } else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) { - bss->wps_nfc_dev_pw_id = atoi(pos); - if (bss->wps_nfc_dev_pw_id < 0x10 || - bss->wps_nfc_dev_pw_id > 0xffff) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "wps_nfc_dev_pw_id value", line); - errors++; - } - bss->wps_nfc_pw_from_config = 1; - } else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) { - wpabuf_free(bss->wps_nfc_dh_pubkey); - bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos); - bss->wps_nfc_pw_from_config = 1; - } else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) { - wpabuf_free(bss->wps_nfc_dh_privkey); - bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos); - bss->wps_nfc_pw_from_config = 1; - } else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) { - wpabuf_free(bss->wps_nfc_dev_pw); - bss->wps_nfc_dev_pw = hostapd_parse_bin(pos); - bss->wps_nfc_pw_from_config = 1; -#endif /* CONFIG_WPS_NFC */ -#endif /* CONFIG_WPS */ -#ifdef CONFIG_P2P_MANAGER - } else if (os_strcmp(buf, "manage_p2p") == 0) { - int manage = atoi(pos); - if (manage) - bss->p2p |= P2P_MANAGE; - else - bss->p2p &= ~P2P_MANAGE; - } else if (os_strcmp(buf, "allow_cross_connection") == 0) { - if (atoi(pos)) - bss->p2p |= P2P_ALLOW_CROSS_CONNECTION; - else - bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION; -#endif /* CONFIG_P2P_MANAGER */ - } else if (os_strcmp(buf, "disassoc_low_ack") == 0) { - bss->disassoc_low_ack = atoi(pos); - } else if (os_strcmp(buf, "tdls_prohibit") == 0) { - int val = atoi(pos); - if (val) - bss->tdls |= TDLS_PROHIBIT; - else - bss->tdls &= ~TDLS_PROHIBIT; - } else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) { - int val = atoi(pos); - if (val) - bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH; - else - bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH; -#ifdef CONFIG_RSN_TESTING - } else if (os_strcmp(buf, "rsn_testing") == 0) { - extern int rsn_testing; - rsn_testing = atoi(pos); -#endif /* CONFIG_RSN_TESTING */ - } else if (os_strcmp(buf, "time_advertisement") == 0) { - bss->time_advertisement = atoi(pos); - } else if (os_strcmp(buf, "time_zone") == 0) { - size_t tz_len = os_strlen(pos); - if (tz_len < 4 || tz_len > 255) { - wpa_printf(MSG_DEBUG, "Line %d: invalid " - "time_zone", line); - errors++; - return errors; - } - os_free(bss->time_zone); - bss->time_zone = os_strdup(pos); - if (bss->time_zone == NULL) - errors++; -#ifdef CONFIG_WNM - } else if (os_strcmp(buf, "wnm_sleep_mode") == 0) { - bss->wnm_sleep_mode = atoi(pos); - } else if (os_strcmp(buf, "bss_transition") == 0) { - bss->bss_transition = atoi(pos); -#endif /* CONFIG_WNM */ -#ifdef CONFIG_INTERWORKING - } else if (os_strcmp(buf, "interworking") == 0) { - bss->interworking = atoi(pos); - } else if (os_strcmp(buf, "access_network_type") == 0) { - bss->access_network_type = atoi(pos); - if (bss->access_network_type < 0 || - bss->access_network_type > 15) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "access_network_type", line); - errors++; - } - } else if (os_strcmp(buf, "internet") == 0) { - bss->internet = atoi(pos); - } else if (os_strcmp(buf, "asra") == 0) { - bss->asra = atoi(pos); - } else if (os_strcmp(buf, "esr") == 0) { - bss->esr = atoi(pos); - } else if (os_strcmp(buf, "uesa") == 0) { - bss->uesa = atoi(pos); - } else if (os_strcmp(buf, "venue_group") == 0) { - bss->venue_group = atoi(pos); - bss->venue_info_set = 1; - } else if (os_strcmp(buf, "venue_type") == 0) { - bss->venue_type = atoi(pos); - bss->venue_info_set = 1; - } else if (os_strcmp(buf, "hessid") == 0) { - if (hwaddr_aton(pos, bss->hessid)) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "hessid", line); - errors++; - } - } else if (os_strcmp(buf, "roaming_consortium") == 0) { - if (parse_roaming_consortium(bss, pos, line) < 0) - errors++; - } else if (os_strcmp(buf, "venue_name") == 0) { - if (parse_venue_name(bss, pos, line) < 0) - errors++; - } else if (os_strcmp(buf, "network_auth_type") == 0) { - u8 auth_type; - u16 redirect_url_len; - if (hexstr2bin(pos, &auth_type, 1)) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "network_auth_type '%s'", - line, pos); - errors++; - return errors; - } - if (auth_type == 0 || auth_type == 2) - redirect_url_len = os_strlen(pos + 2); - else - redirect_url_len = 0; - os_free(bss->network_auth_type); - bss->network_auth_type = - os_malloc(redirect_url_len + 3 + 1); - if (bss->network_auth_type == NULL) { - errors++; - return errors; - } - *bss->network_auth_type = auth_type; - WPA_PUT_LE16(bss->network_auth_type + 1, - redirect_url_len); - if (redirect_url_len) - os_memcpy(bss->network_auth_type + 3, - pos + 2, redirect_url_len); - bss->network_auth_type_len = 3 + redirect_url_len; - } else if (os_strcmp(buf, "ipaddr_type_availability") == 0) { - if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1)) - { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "ipaddr_type_availability '%s'", - line, pos); - bss->ipaddr_type_configured = 0; - errors++; - return errors; - } - bss->ipaddr_type_configured = 1; - } else if (os_strcmp(buf, "domain_name") == 0) { - int j, num_domains, domain_len, domain_list_len = 0; - char *tok_start, *tok_prev; - u8 *domain_list, *domain_ptr; - - domain_list_len = os_strlen(pos) + 1; - domain_list = os_malloc(domain_list_len); - if (domain_list == NULL) { - errors++; - return errors; - } - - domain_ptr = domain_list; - tok_prev = pos; - num_domains = 1; - while ((tok_prev = os_strchr(tok_prev, ','))) { - num_domains++; - tok_prev++; - } - tok_prev = pos; - for (j = 0; j < num_domains; j++) { - tok_start = os_strchr(tok_prev, ','); - if (tok_start) { - domain_len = tok_start - tok_prev; - *domain_ptr = domain_len; - os_memcpy(domain_ptr + 1, tok_prev, - domain_len); - domain_ptr += domain_len + 1; - tok_prev = ++tok_start; - } else { - domain_len = os_strlen(tok_prev); - *domain_ptr = domain_len; - os_memcpy(domain_ptr + 1, tok_prev, - domain_len); - domain_ptr += domain_len + 1; - } - } - - os_free(bss->domain_name); - bss->domain_name = domain_list; - bss->domain_name_len = domain_list_len; - } else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) { - if (parse_3gpp_cell_net(bss, pos, line) < 0) - errors++; - } else if (os_strcmp(buf, "nai_realm") == 0) { - if (parse_nai_realm(bss, pos, line) < 0) - errors++; - } else if (os_strcmp(buf, "gas_frag_limit") == 0) { - bss->gas_frag_limit = atoi(pos); - } else if (os_strcmp(buf, "gas_comeback_delay") == 0) { - bss->gas_comeback_delay = atoi(pos); - } else if (os_strcmp(buf, "qos_map_set") == 0) { - if (parse_qos_map_set(bss, pos, line) < 0) - errors++; -#endif /* CONFIG_INTERWORKING */ -#ifdef CONFIG_RADIUS_TEST - } else if (os_strcmp(buf, "dump_msk_file") == 0) { - os_free(bss->dump_msk_file); - bss->dump_msk_file = os_strdup(pos); -#endif /* CONFIG_RADIUS_TEST */ -#ifdef CONFIG_HS20 - } else if (os_strcmp(buf, "hs20") == 0) { - bss->hs20 = atoi(pos); - } else if (os_strcmp(buf, "disable_dgaf") == 0) { - bss->disable_dgaf = atoi(pos); - } else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) { - if (hs20_parse_oper_friendly_name(bss, pos, line) < 0) - errors++; - } else if (os_strcmp(buf, "hs20_wan_metrics") == 0) { - if (hs20_parse_wan_metrics(bss, pos, line) < 0) { - errors++; - return errors; - } - } else if (os_strcmp(buf, "hs20_conn_capab") == 0) { - if (hs20_parse_conn_capab(bss, pos, line) < 0) { - errors++; - return errors; - } - } else if (os_strcmp(buf, "hs20_operating_class") == 0) { - u8 *oper_class; - size_t oper_class_len; - oper_class_len = os_strlen(pos); - if (oper_class_len < 2 || (oper_class_len & 0x01)) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "hs20_operating_class '%s'", - line, pos); - errors++; - return errors; - } - oper_class_len /= 2; - oper_class = os_malloc(oper_class_len); - if (oper_class == NULL) { - errors++; - return errors; - } - if (hexstr2bin(pos, oper_class, oper_class_len)) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "hs20_operating_class '%s'", - line, pos); - os_free(oper_class); - errors++; - return errors; - } - os_free(bss->hs20_operating_class); - bss->hs20_operating_class = oper_class; - bss->hs20_operating_class_len = oper_class_len; -#endif /* CONFIG_HS20 */ -#ifdef CONFIG_TESTING_OPTIONS -#define PARSE_TEST_PROBABILITY(_val) \ - } else if (os_strcmp(buf, #_val) == 0) { \ - char *end; \ - \ - conf->_val = strtod(pos, &end); \ - if (*end || conf->_val < 0.0d || \ - conf->_val > 1.0d) { \ - wpa_printf(MSG_ERROR, \ - "Line %d: Invalid value '%s'", \ - line, pos); \ - errors++; \ - return errors; \ - } - PARSE_TEST_PROBABILITY(ignore_probe_probability) - PARSE_TEST_PROBABILITY(ignore_auth_probability) - PARSE_TEST_PROBABILITY(ignore_assoc_probability) - PARSE_TEST_PROBABILITY(ignore_reassoc_probability) - PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability) - } else if (os_strcmp(buf, "bss_load_test") == 0) { - WPA_PUT_LE16(bss->bss_load_test, atoi(pos)); - pos = os_strchr(pos, ':'); - if (pos == NULL) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "bss_load_test", line); - return 1; - } - pos++; - bss->bss_load_test[2] = atoi(pos); - pos = os_strchr(pos, ':'); - if (pos == NULL) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "bss_load_test", line); - return 1; - } - pos++; - WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos)); - bss->bss_load_test_set = 1; -#endif /* CONFIG_TESTING_OPTIONS */ - } else if (os_strcmp(buf, "vendor_elements") == 0) { - struct wpabuf *elems; - size_t len = os_strlen(pos); - if (len & 0x01) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "vendor_elements '%s'", line, pos); - return 1; - } - len /= 2; - if (len == 0) { - wpabuf_free(bss->vendor_elements); - bss->vendor_elements = NULL; - return 0; - } - - elems = wpabuf_alloc(len); - if (elems == NULL) - return 1; - - if (hexstr2bin(pos, wpabuf_put(elems, len), len)) { - wpabuf_free(elems); - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "vendor_elements '%s'", line, pos); - return 1; - } - - wpabuf_free(bss->vendor_elements); - bss->vendor_elements = elems; - } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) { - bss->sae_anti_clogging_threshold = atoi(pos); - } else if (os_strcmp(buf, "sae_groups") == 0) { - if (hostapd_parse_intlist(&bss->sae_groups, pos)) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "sae_groups value '%s'", line, pos); - return 1; - } - } else { - wpa_printf(MSG_ERROR, "Line %d: unknown configuration " - "item '%s'", line, buf); - errors++; - } - } - - return errors; -} - - -/** - * hostapd_config_read - Read and parse a configuration file - * @fname: Configuration file name (including path, if needed) - * Returns: Allocated configuration data structure - */ -struct hostapd_config * hostapd_config_read(const char *fname) -{ - struct hostapd_config *conf; - struct hostapd_bss_config *bss; - FILE *f; - char buf[512], *pos; - int line = 0; - int errors = 0; - size_t i; - - f = fopen(fname, "r"); - if (f == NULL) { - wpa_printf(MSG_ERROR, "Could not open configuration file '%s' " - "for reading.", fname); - return NULL; - } - - conf = hostapd_config_defaults(); - if (conf == NULL) { - fclose(f); - return NULL; - } - - /* set default driver based on configuration */ - conf->driver = wpa_drivers[0]; - if (conf->driver == NULL) { - wpa_printf(MSG_ERROR, "No driver wrappers registered!"); - hostapd_config_free(conf); - fclose(f); - return NULL; - } - - bss = conf->last_bss = conf->bss[0]; - - while (fgets(buf, sizeof(buf), f)) { - bss = conf->last_bss; - line++; - - if (buf[0] == '#') - continue; - pos = buf; - while (*pos != '\0') { - if (*pos == '\n') { - *pos = '\0'; - break; - } - pos++; - } - if (buf[0] == '\0') - continue; - - pos = os_strchr(buf, '='); - if (pos == NULL) { - wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'", - line, buf); - errors++; - continue; - } - *pos = '\0'; - pos++; - errors += hostapd_config_fill(conf, bss, buf, pos, line); - } - - fclose(f); - - for (i = 0; i < conf->num_bss; i++) - hostapd_set_security_params(conf->bss[i]); - - if (hostapd_config_check(conf, 1)) - errors++; - -#ifndef WPA_IGNORE_CONFIG_ERRORS - if (errors) { - wpa_printf(MSG_ERROR, "%d errors found in configuration file " - "'%s'", errors, fname); - hostapd_config_free(conf); - conf = NULL; - } -#endif /* WPA_IGNORE_CONFIG_ERRORS */ - - return conf; -} - - -int hostapd_set_iface(struct hostapd_config *conf, - struct hostapd_bss_config *bss, char *field, char *value) -{ - int errors; - size_t i; - - errors = hostapd_config_fill(conf, bss, field, value, 0); - if (errors) { - wpa_printf(MSG_INFO, "Failed to set configuration field '%s' " - "to value '%s'", field, value); - return -1; - } - - for (i = 0; i < conf->num_bss; i++) - hostapd_set_security_params(conf->bss[i]); - - if (hostapd_config_check(conf, 0)) { - wpa_printf(MSG_ERROR, "Configuration check failed"); - return -1; - } - - return 0; -} diff --git a/contrib/hostapd/hostapd/config_file.h b/contrib/hostapd/hostapd/config_file.h deleted file mode 100644 index fba57b87ad..0000000000 --- a/contrib/hostapd/hostapd/config_file.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * hostapd / Configuration file parser - * Copyright (c) 2003-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef CONFIG_FILE_H -#define CONFIG_FILE_H - -struct hostapd_config * hostapd_config_read(const char *fname); -int hostapd_set_iface(struct hostapd_config *conf, - struct hostapd_bss_config *bss, char *field, - char *value); - -#endif /* CONFIG_FILE_H */ diff --git a/contrib/hostapd/hostapd/ctrl_iface.c b/contrib/hostapd/hostapd/ctrl_iface.c deleted file mode 100644 index 4a9da5f6a8..0000000000 --- a/contrib/hostapd/hostapd/ctrl_iface.c +++ /dev/null @@ -1,1878 +0,0 @@ -/* - * hostapd / UNIX domain socket -based control interface - * Copyright (c) 2004-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#ifndef CONFIG_NATIVE_WINDOWS - -#include -#include -#include - -#include "utils/common.h" -#include "utils/eloop.h" -#include "common/version.h" -#include "common/ieee802_11_defs.h" -#include "drivers/driver.h" -#include "radius/radius_client.h" -#include "radius/radius_server.h" -#include "ap/hostapd.h" -#include "ap/ap_config.h" -#include "ap/ieee802_1x.h" -#include "ap/wpa_auth.h" -#include "ap/ieee802_11.h" -#include "ap/sta_info.h" -#include "ap/wps_hostapd.h" -#include "ap/ctrl_iface_ap.h" -#include "ap/ap_drv_ops.h" -#include "ap/wnm_ap.h" -#include "ap/wpa_auth.h" -#include "wps/wps_defs.h" -#include "wps/wps.h" -#include "config_file.h" -#include "ctrl_iface.h" - - -struct wpa_ctrl_dst { - struct wpa_ctrl_dst *next; - struct sockaddr_un addr; - socklen_t addrlen; - int debug_level; - int errors; -}; - - -static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, - const char *buf, size_t len); - - -static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd, - struct sockaddr_un *from, - socklen_t fromlen) -{ - struct wpa_ctrl_dst *dst; - - dst = os_zalloc(sizeof(*dst)); - if (dst == NULL) - return -1; - os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); - dst->addrlen = fromlen; - dst->debug_level = MSG_INFO; - dst->next = hapd->ctrl_dst; - hapd->ctrl_dst = dst; - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", - (u8 *) from->sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)); - return 0; -} - - -static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd, - struct sockaddr_un *from, - socklen_t fromlen) -{ - struct wpa_ctrl_dst *dst, *prev = NULL; - - dst = hapd->ctrl_dst; - while (dst) { - if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)) - == 0) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", - (u8 *) from->sun_path, - fromlen - - offsetof(struct sockaddr_un, sun_path)); - if (prev == NULL) - hapd->ctrl_dst = dst->next; - else - prev->next = dst->next; - os_free(dst); - return 0; - } - prev = dst; - dst = dst->next; - } - return -1; -} - - -static int hostapd_ctrl_iface_level(struct hostapd_data *hapd, - struct sockaddr_un *from, - socklen_t fromlen, - char *level) -{ - struct wpa_ctrl_dst *dst; - - wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); - - dst = hapd->ctrl_dst; - while (dst) { - if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)) - == 0) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " - "level", (u8 *) from->sun_path, fromlen - - offsetof(struct sockaddr_un, sun_path)); - dst->debug_level = atoi(level); - return 0; - } - dst = dst->next; - } - - return -1; -} - - -static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd, - const char *txtaddr) -{ - u8 addr[ETH_ALEN]; - struct sta_info *sta; - - wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr); - - if (hwaddr_aton(txtaddr, addr)) - return -1; - - sta = ap_get_sta(hapd, addr); - if (sta) - return 0; - - wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface " - "notification", MAC2STR(addr)); - sta = ap_sta_add(hapd, addr); - if (sta == NULL) - return -1; - - hostapd_new_assoc_sta(hapd, sta, 0); - return 0; -} - - -#ifdef CONFIG_IEEE80211W -#ifdef NEED_AP_MLME -static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd, - const char *txtaddr) -{ - u8 addr[ETH_ALEN]; - u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; - - wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr); - - if (hwaddr_aton(txtaddr, addr) || - os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) - return -1; - - ieee802_11_send_sa_query_req(hapd, addr, trans_id); - - return 0; -} -#endif /* NEED_AP_MLME */ -#endif /* CONFIG_IEEE80211W */ - - -#ifdef CONFIG_WPS -static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt) -{ - char *pin = os_strchr(txt, ' '); - char *timeout_txt; - int timeout; - u8 addr_buf[ETH_ALEN], *addr = NULL; - char *pos; - - if (pin == NULL) - return -1; - *pin++ = '\0'; - - timeout_txt = os_strchr(pin, ' '); - if (timeout_txt) { - *timeout_txt++ = '\0'; - timeout = atoi(timeout_txt); - pos = os_strchr(timeout_txt, ' '); - if (pos) { - *pos++ = '\0'; - if (hwaddr_aton(pos, addr_buf) == 0) - addr = addr_buf; - } - } else - timeout = 0; - - return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout); -} - - -static int hostapd_ctrl_iface_wps_check_pin( - struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen) -{ - char pin[9]; - size_t len; - char *pos; - int ret; - - wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN", - (u8 *) cmd, os_strlen(cmd)); - for (pos = cmd, len = 0; *pos != '\0'; pos++) { - if (*pos < '0' || *pos > '9') - continue; - pin[len++] = *pos; - if (len == 9) { - wpa_printf(MSG_DEBUG, "WPS: Too long PIN"); - return -1; - } - } - if (len != 4 && len != 8) { - wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len); - return -1; - } - pin[len] = '\0'; - - if (len == 8) { - unsigned int pin_val; - pin_val = atoi(pin); - if (!wps_pin_valid(pin_val)) { - wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit"); - ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n"); - if (ret < 0 || (size_t) ret >= buflen) - return -1; - return ret; - } - } - - ret = os_snprintf(buf, buflen, "%s", pin); - if (ret < 0 || (size_t) ret >= buflen) - return -1; - - return ret; -} - - -#ifdef CONFIG_WPS_NFC -static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd, - char *pos) -{ - size_t len; - struct wpabuf *buf; - int ret; - - len = os_strlen(pos); - if (len & 0x01) - return -1; - len /= 2; - - buf = wpabuf_alloc(len); - if (buf == NULL) - return -1; - if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) { - wpabuf_free(buf); - return -1; - } - - ret = hostapd_wps_nfc_tag_read(hapd, buf); - wpabuf_free(buf); - - return ret; -} - - -static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd, - char *cmd, char *reply, - size_t max_len) -{ - int ndef; - struct wpabuf *buf; - int res; - - if (os_strcmp(cmd, "WPS") == 0) - ndef = 0; - else if (os_strcmp(cmd, "NDEF") == 0) - ndef = 1; - else - return -1; - - buf = hostapd_wps_nfc_config_token(hapd, ndef); - if (buf == NULL) - return -1; - - res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), - wpabuf_len(buf)); - reply[res++] = '\n'; - reply[res] = '\0'; - - wpabuf_free(buf); - - return res; -} - - -static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd, - char *reply, size_t max_len, - int ndef) -{ - struct wpabuf *buf; - int res; - - buf = hostapd_wps_nfc_token_gen(hapd, ndef); - if (buf == NULL) - return -1; - - res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), - wpabuf_len(buf)); - reply[res++] = '\n'; - reply[res] = '\0'; - - wpabuf_free(buf); - - return res; -} - - -static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd, - char *cmd, char *reply, - size_t max_len) -{ - if (os_strcmp(cmd, "WPS") == 0) - return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply, - max_len, 0); - - if (os_strcmp(cmd, "NDEF") == 0) - return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply, - max_len, 1); - - if (os_strcmp(cmd, "enable") == 0) - return hostapd_wps_nfc_token_enable(hapd); - - if (os_strcmp(cmd, "disable") == 0) { - hostapd_wps_nfc_token_disable(hapd); - return 0; - } - - return -1; -} - - -static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd, - char *cmd, char *reply, - size_t max_len) -{ - struct wpabuf *buf; - int res; - char *pos; - int ndef; - - pos = os_strchr(cmd, ' '); - if (pos == NULL) - return -1; - *pos++ = '\0'; - - if (os_strcmp(cmd, "WPS") == 0) - ndef = 0; - else if (os_strcmp(cmd, "NDEF") == 0) - ndef = 1; - else - return -1; - - if (os_strcmp(pos, "WPS-CR") == 0) - buf = hostapd_wps_nfc_hs_cr(hapd, ndef); - else - buf = NULL; - if (buf == NULL) - return -1; - - res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), - wpabuf_len(buf)); - reply[res++] = '\n'; - reply[res] = '\0'; - - wpabuf_free(buf); - - return res; -} - - -static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd, - char *cmd) -{ - size_t len; - struct wpabuf *req, *sel; - int ret; - char *pos, *role, *type, *pos2; - - role = cmd; - pos = os_strchr(role, ' '); - if (pos == NULL) - return -1; - *pos++ = '\0'; - - type = pos; - pos = os_strchr(type, ' '); - if (pos == NULL) - return -1; - *pos++ = '\0'; - - pos2 = os_strchr(pos, ' '); - if (pos2 == NULL) - return -1; - *pos2++ = '\0'; - - len = os_strlen(pos); - if (len & 0x01) - return -1; - len /= 2; - - req = wpabuf_alloc(len); - if (req == NULL) - return -1; - if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) { - wpabuf_free(req); - return -1; - } - - len = os_strlen(pos2); - if (len & 0x01) { - wpabuf_free(req); - return -1; - } - len /= 2; - - sel = wpabuf_alloc(len); - if (sel == NULL) { - wpabuf_free(req); - return -1; - } - if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) { - wpabuf_free(req); - wpabuf_free(sel); - return -1; - } - - if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) { - ret = hostapd_wps_nfc_report_handover(hapd, req, sel); - } else { - wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover " - "reported: role=%s type=%s", role, type); - ret = -1; - } - wpabuf_free(req); - wpabuf_free(sel); - - return ret; -} - -#endif /* CONFIG_WPS_NFC */ - - -static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt, - char *buf, size_t buflen) -{ - int timeout = 300; - char *pos; - const char *pin_txt; - - pos = os_strchr(txt, ' '); - if (pos) - *pos++ = '\0'; - - if (os_strcmp(txt, "disable") == 0) { - hostapd_wps_ap_pin_disable(hapd); - return os_snprintf(buf, buflen, "OK\n"); - } - - if (os_strcmp(txt, "random") == 0) { - if (pos) - timeout = atoi(pos); - pin_txt = hostapd_wps_ap_pin_random(hapd, timeout); - if (pin_txt == NULL) - return -1; - return os_snprintf(buf, buflen, "%s", pin_txt); - } - - if (os_strcmp(txt, "get") == 0) { - pin_txt = hostapd_wps_ap_pin_get(hapd); - if (pin_txt == NULL) - return -1; - return os_snprintf(buf, buflen, "%s", pin_txt); - } - - if (os_strcmp(txt, "set") == 0) { - char *pin; - if (pos == NULL) - return -1; - pin = pos; - pos = os_strchr(pos, ' '); - if (pos) { - *pos++ = '\0'; - timeout = atoi(pos); - } - if (os_strlen(pin) > buflen) - return -1; - if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0) - return -1; - return os_snprintf(buf, buflen, "%s", pin); - } - - return -1; -} - - -static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt) -{ - char *pos; - char *ssid, *auth, *encr = NULL, *key = NULL; - - ssid = txt; - pos = os_strchr(txt, ' '); - if (!pos) - return -1; - *pos++ = '\0'; - - auth = pos; - pos = os_strchr(pos, ' '); - if (pos) { - *pos++ = '\0'; - encr = pos; - pos = os_strchr(pos, ' '); - if (pos) { - *pos++ = '\0'; - key = pos; - } - } - - return hostapd_wps_config_ap(hapd, ssid, auth, encr, key); -} - - -static const char * pbc_status_str(enum pbc_status status) -{ - switch (status) { - case WPS_PBC_STATUS_DISABLE: - return "Disabled"; - case WPS_PBC_STATUS_ACTIVE: - return "Active"; - case WPS_PBC_STATUS_TIMEOUT: - return "Timed-out"; - case WPS_PBC_STATUS_OVERLAP: - return "Overlap"; - default: - return "Unknown"; - } -} - - -static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd, - char *buf, size_t buflen) -{ - int ret; - char *pos, *end; - - pos = buf; - end = buf + buflen; - - ret = os_snprintf(pos, end - pos, "PBC Status: %s\n", - pbc_status_str(hapd->wps_stats.pbc_status)); - - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n", - (hapd->wps_stats.status == WPS_STATUS_SUCCESS ? - "Success": - (hapd->wps_stats.status == WPS_STATUS_FAILURE ? - "Failed" : "None"))); - - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - /* If status == Failure - Add possible Reasons */ - if(hapd->wps_stats.status == WPS_STATUS_FAILURE && - hapd->wps_stats.failure_reason > 0) { - ret = os_snprintf(pos, end - pos, - "Failure Reason: %s\n", - wps_ei_str(hapd->wps_stats.failure_reason)); - - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - - if (hapd->wps_stats.status) { - ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n", - MAC2STR(hapd->wps_stats.peer_addr)); - - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - - return pos - buf; -} - -#endif /* CONFIG_WPS */ - - -#ifdef CONFIG_INTERWORKING - -static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd, - const char *cmd) -{ - u8 qos_map_set[16 + 2 * 21], count = 0; - const char *pos = cmd; - int val, ret; - - for (;;) { - if (count == sizeof(qos_map_set)) { - wpa_printf(MSG_ERROR, "Too many qos_map_set parameters"); - return -1; - } - - val = atoi(pos); - if (val < 0 || val > 255) { - wpa_printf(MSG_INFO, "Invalid QoS Map Set"); - return -1; - } - - qos_map_set[count++] = val; - pos = os_strchr(pos, ','); - if (!pos) - break; - pos++; - } - - if (count < 16 || count & 1) { - wpa_printf(MSG_INFO, "Invalid QoS Map Set"); - return -1; - } - - ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count); - if (ret) { - wpa_printf(MSG_INFO, "Failed to set QoS Map Set"); - return -1; - } - - os_memcpy(hapd->conf->qos_map_set, qos_map_set, count); - hapd->conf->qos_map_set_len = count; - - return 0; -} - - -static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd, - const char *cmd) -{ - u8 addr[ETH_ALEN]; - struct sta_info *sta; - struct wpabuf *buf; - u8 *qos_map_set = hapd->conf->qos_map_set; - u8 qos_map_set_len = hapd->conf->qos_map_set_len; - int ret; - - if (!qos_map_set_len) { - wpa_printf(MSG_INFO, "QoS Map Set is not set"); - return -1; - } - - if (hwaddr_aton(cmd, addr)) - return -1; - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Station " MACSTR " not found " - "for QoS Map Configuration message", - MAC2STR(addr)); - return -1; - } - - if (!sta->qos_map_enabled) { - wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate " - "support for QoS Map", MAC2STR(addr)); - return -1; - } - - buf = wpabuf_alloc(2 + 2 + qos_map_set_len); - if (buf == NULL) - return -1; - - wpabuf_put_u8(buf, WLAN_ACTION_QOS); - wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG); - - /* QoS Map Set Element */ - wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET); - wpabuf_put_u8(buf, qos_map_set_len); - wpabuf_put_data(buf, qos_map_set, qos_map_set_len); - - ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, - wpabuf_head(buf), wpabuf_len(buf)); - wpabuf_free(buf); - - return ret; -} - -#endif /* CONFIG_INTERWORKING */ - - -#ifdef CONFIG_WNM - -static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, - const char *cmd) -{ - u8 addr[ETH_ALEN]; - int disassoc_timer; - struct sta_info *sta; - - if (hwaddr_aton(cmd, addr)) - return -1; - if (cmd[17] != ' ') - return -1; - disassoc_timer = atoi(cmd + 17); - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Station " MACSTR - " not found for disassociation imminent message", - MAC2STR(addr)); - return -1; - } - - return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer); -} - - -static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, - const char *cmd) -{ - u8 addr[ETH_ALEN]; - const char *url, *timerstr; - int disassoc_timer; - struct sta_info *sta; - - if (hwaddr_aton(cmd, addr)) - return -1; - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Station " MACSTR - " not found for ESS disassociation imminent message", - MAC2STR(addr)); - return -1; - } - - timerstr = cmd + 17; - if (*timerstr != ' ') - return -1; - timerstr++; - disassoc_timer = atoi(timerstr); - if (disassoc_timer < 0 || disassoc_timer > 65535) - return -1; - - url = os_strchr(timerstr, ' '); - if (url == NULL) - return -1; - url++; - - return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer); -} - -#endif /* CONFIG_WNM */ - - -static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, - char *buf, size_t buflen) -{ - int ret; - char *pos, *end; - - pos = buf; - end = buf + buflen; - - ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n" - "ssid=%s\n", - MAC2STR(hapd->own_addr), - wpa_ssid_txt(hapd->conf->ssid.ssid, - hapd->conf->ssid.ssid_len)); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - -#ifdef CONFIG_WPS - ret = os_snprintf(pos, end - pos, "wps_state=%s\n", - hapd->conf->wps_state == 0 ? "disabled" : - (hapd->conf->wps_state == 1 ? "not configured" : - "configured")); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - if (hapd->conf->wps_state && hapd->conf->wpa && - hapd->conf->ssid.wpa_passphrase) { - ret = os_snprintf(pos, end - pos, "passphrase=%s\n", - hapd->conf->ssid.wpa_passphrase); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - - if (hapd->conf->wps_state && hapd->conf->wpa && - hapd->conf->ssid.wpa_psk && - hapd->conf->ssid.wpa_psk->group) { - char hex[PMK_LEN * 2 + 1]; - wpa_snprintf_hex(hex, sizeof(hex), - hapd->conf->ssid.wpa_psk->psk, PMK_LEN); - ret = os_snprintf(pos, end - pos, "psk=%s\n", hex); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } -#endif /* CONFIG_WPS */ - - if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) { - ret = os_snprintf(pos, end - pos, "key_mgmt="); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { - ret = os_snprintf(pos, end - pos, "WPA-PSK "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { - ret = os_snprintf(pos, end - pos, "WPA-EAP "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } -#ifdef CONFIG_IEEE80211R - if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { - ret = os_snprintf(pos, end - pos, "FT-PSK "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { - ret = os_snprintf(pos, end - pos, "FT-EAP "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { - ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { - ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } -#endif /* CONFIG_IEEE80211W */ - - ret = os_snprintf(pos, end - pos, "\n"); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - - if (hapd->conf->wpa) { - ret = os_snprintf(pos, end - pos, "group_cipher=%s\n", - wpa_cipher_txt(hapd->conf->wpa_group)); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - - if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) { - ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher="); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise, - " "); - if (ret < 0) - return pos - buf; - pos += ret; - - ret = os_snprintf(pos, end - pos, "\n"); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - - if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) { - ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher="); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise, - " "); - if (ret < 0) - return pos - buf; - pos += ret; - - ret = os_snprintf(pos, end - pos, "\n"); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - - return pos - buf; -} - - -static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) -{ - char *value; - int ret = 0; - - value = os_strchr(cmd, ' '); - if (value == NULL) - return -1; - *value++ = '\0'; - - wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value); - if (0) { -#ifdef CONFIG_WPS_TESTING - } else if (os_strcasecmp(cmd, "wps_version_number") == 0) { - long int val; - val = strtol(value, NULL, 0); - if (val < 0 || val > 0xff) { - ret = -1; - wpa_printf(MSG_DEBUG, "WPS: Invalid " - "wps_version_number %ld", val); - } else { - wps_version_number = val; - wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS " - "version %u.%u", - (wps_version_number & 0xf0) >> 4, - wps_version_number & 0x0f); - hostapd_wps_update_ie(hapd); - } - } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) { - wps_testing_dummy_cred = atoi(value); - wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d", - wps_testing_dummy_cred); - } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) { - wps_corrupt_pkhash = atoi(value); - wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d", - wps_corrupt_pkhash); -#endif /* CONFIG_WPS_TESTING */ -#ifdef CONFIG_INTERWORKING - } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) { - int val = atoi(value); - if (val <= 0) - ret = -1; - else - hapd->gas_frag_limit = val; -#endif /* CONFIG_INTERWORKING */ -#ifdef CONFIG_TESTING_OPTIONS - } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) { - hapd->ext_mgmt_frame_handling = atoi(value); -#endif /* CONFIG_TESTING_OPTIONS */ - } else { - ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value); - } - - return ret; -} - - -static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd, - char *buf, size_t buflen) -{ - int res; - - wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd); - - if (os_strcmp(cmd, "version") == 0) { - res = os_snprintf(buf, buflen, "%s", VERSION_STR); - if (res < 0 || (unsigned int) res >= buflen) - return -1; - return res; - } - - return -1; -} - - -static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface) -{ - if (hostapd_enable_iface(iface) < 0) { - wpa_printf(MSG_ERROR, "Enabling of interface failed"); - return -1; - } - return 0; -} - - -static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface) -{ - if (hostapd_reload_iface(iface) < 0) { - wpa_printf(MSG_ERROR, "Reloading of interface failed"); - return -1; - } - return 0; -} - - -static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface) -{ - if (hostapd_disable_iface(iface) < 0) { - wpa_printf(MSG_ERROR, "Disabling of interface failed"); - return -1; - } - return 0; -} - - -#ifdef CONFIG_TESTING_OPTIONS - -static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd) -{ - union wpa_event_data data; - char *pos, *param; - enum wpa_event_type event; - - wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd); - - os_memset(&data, 0, sizeof(data)); - - param = os_strchr(cmd, ' '); - if (param == NULL) - return -1; - *param++ = '\0'; - - if (os_strcmp(cmd, "DETECTED") == 0) - event = EVENT_DFS_RADAR_DETECTED; - else if (os_strcmp(cmd, "CAC-FINISHED") == 0) - event = EVENT_DFS_CAC_FINISHED; - else if (os_strcmp(cmd, "CAC-ABORTED") == 0) - event = EVENT_DFS_CAC_ABORTED; - else if (os_strcmp(cmd, "NOP-FINISHED") == 0) - event = EVENT_DFS_NOP_FINISHED; - else { - wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s", - cmd); - return -1; - } - - pos = os_strstr(param, "freq="); - if (pos) - data.dfs_event.freq = atoi(pos + 5); - - pos = os_strstr(param, "ht_enabled=1"); - if (pos) - data.dfs_event.ht_enabled = 1; - - pos = os_strstr(param, "chan_offset="); - if (pos) - data.dfs_event.chan_offset = atoi(pos + 12); - - pos = os_strstr(param, "chan_width="); - if (pos) - data.dfs_event.chan_width = atoi(pos + 11); - - pos = os_strstr(param, "cf1="); - if (pos) - data.dfs_event.cf1 = atoi(pos + 4); - - pos = os_strstr(param, "cf2="); - if (pos) - data.dfs_event.cf2 = atoi(pos + 4); - - wpa_supplicant_event(hapd, event, &data); - - return 0; -} - - -static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd) -{ - size_t len; - u8 *buf; - int res; - - wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd); - - len = os_strlen(cmd); - if (len & 1) - return -1; - len /= 2; - - buf = os_malloc(len); - if (buf == NULL) - return -1; - - if (hexstr2bin(cmd, buf, len) < 0) { - os_free(buf); - return -1; - } - - res = hostapd_drv_send_mlme(hapd, buf, len, 0); - os_free(buf); - return res; -} - -#endif /* CONFIG_TESTING_OPTIONS */ - - -static int hostapd_ctrl_iface_chan_switch(struct hostapd_data *hapd, char *pos) -{ -#ifdef NEED_AP_MLME - struct csa_settings settings; - int ret = hostapd_parse_csa_settings(pos, &settings); - - if (ret) - return ret; - - return hostapd_switch_channel(hapd, &settings); -#else /* NEED_AP_MLME */ - return -1; -#endif /* NEED_AP_MLME */ -} - - -static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply, - int reply_size, const char *param) -{ -#ifdef RADIUS_SERVER - if (os_strcmp(param, "radius_server") == 0) { - return radius_server_get_mib(hapd->radius_srv, reply, - reply_size); - } -#endif /* RADIUS_SERVER */ - return -1; -} - - -static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, - void *sock_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - char buf[4096]; - int res; - struct sockaddr_un from; - socklen_t fromlen = sizeof(from); - char *reply; - const int reply_size = 4096; - int reply_len; - int level = MSG_DEBUG; - - res = recvfrom(sock, buf, sizeof(buf) - 1, 0, - (struct sockaddr *) &from, &fromlen); - if (res < 0) { - perror("recvfrom(ctrl_iface)"); - return; - } - buf[res] = '\0'; - if (os_strcmp(buf, "PING") == 0) - level = MSG_EXCESSIVE; - wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res); - - reply = os_malloc(reply_size); - if (reply == NULL) { - sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, - fromlen); - return; - } - - os_memcpy(reply, "OK\n", 3); - reply_len = 3; - - if (os_strcmp(buf, "PING") == 0) { - os_memcpy(reply, "PONG\n", 5); - reply_len = 5; - } else if (os_strncmp(buf, "RELOG", 5) == 0) { - if (wpa_debug_reopen_file() < 0) - reply_len = -1; - } else if (os_strcmp(buf, "STATUS") == 0) { - reply_len = hostapd_ctrl_iface_status(hapd, reply, - reply_size); - } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) { - reply_len = hostapd_drv_status(hapd, reply, reply_size); - } else if (os_strcmp(buf, "MIB") == 0) { - reply_len = ieee802_11_get_mib(hapd, reply, reply_size); - if (reply_len >= 0) { - res = wpa_get_mib(hapd->wpa_auth, reply + reply_len, - reply_size - reply_len); - if (res < 0) - reply_len = -1; - else - reply_len += res; - } - if (reply_len >= 0) { - res = ieee802_1x_get_mib(hapd, reply + reply_len, - reply_size - reply_len); - if (res < 0) - reply_len = -1; - else - reply_len += res; - } -#ifndef CONFIG_NO_RADIUS - if (reply_len >= 0) { - res = radius_client_get_mib(hapd->radius, - reply + reply_len, - reply_size - reply_len); - if (res < 0) - reply_len = -1; - else - reply_len += res; - } -#endif /* CONFIG_NO_RADIUS */ - } else if (os_strncmp(buf, "MIB ", 4) == 0) { - reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size, - buf + 4); - } else if (os_strcmp(buf, "STA-FIRST") == 0) { - reply_len = hostapd_ctrl_iface_sta_first(hapd, reply, - reply_size); - } else if (os_strncmp(buf, "STA ", 4) == 0) { - reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply, - reply_size); - } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { - reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply, - reply_size); - } else if (os_strcmp(buf, "ATTACH") == 0) { - if (hostapd_ctrl_iface_attach(hapd, &from, fromlen)) - reply_len = -1; - } else if (os_strcmp(buf, "DETACH") == 0) { - if (hostapd_ctrl_iface_detach(hapd, &from, fromlen)) - reply_len = -1; - } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { - if (hostapd_ctrl_iface_level(hapd, &from, fromlen, - buf + 6)) - reply_len = -1; - } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) { - if (hostapd_ctrl_iface_new_sta(hapd, buf + 8)) - reply_len = -1; - } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) { - if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15)) - reply_len = -1; - } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) { - if (hostapd_ctrl_iface_disassociate(hapd, buf + 13)) - reply_len = -1; -#ifdef CONFIG_IEEE80211W -#ifdef NEED_AP_MLME - } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) { - if (hostapd_ctrl_iface_sa_query(hapd, buf + 9)) - reply_len = -1; -#endif /* NEED_AP_MLME */ -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WPS - } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { - if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8)) - reply_len = -1; - } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) { - reply_len = hostapd_ctrl_iface_wps_check_pin( - hapd, buf + 14, reply, reply_size); - } else if (os_strcmp(buf, "WPS_PBC") == 0) { - if (hostapd_wps_button_pushed(hapd, NULL)) - reply_len = -1; - } else if (os_strcmp(buf, "WPS_CANCEL") == 0) { - if (hostapd_wps_cancel(hapd)) - reply_len = -1; - } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) { - reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11, - reply, reply_size); - } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) { - if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0) - reply_len = -1; - } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) { - reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply, - reply_size); -#ifdef CONFIG_WPS_NFC - } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) { - if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17)) - reply_len = -1; - } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) { - reply_len = hostapd_ctrl_iface_wps_nfc_config_token( - hapd, buf + 21, reply, reply_size); - } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) { - reply_len = hostapd_ctrl_iface_wps_nfc_token( - hapd, buf + 14, reply, reply_size); - } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) { - reply_len = hostapd_ctrl_iface_nfc_get_handover_sel( - hapd, buf + 21, reply, reply_size); - } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) { - if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20)) - reply_len = -1; -#endif /* CONFIG_WPS_NFC */ -#endif /* CONFIG_WPS */ -#ifdef CONFIG_INTERWORKING - } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) { - if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16)) - reply_len = -1; - } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) { - if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18)) - reply_len = -1; -#endif /* CONFIG_INTERWORKING */ -#ifdef CONFIG_WNM - } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) { - if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18)) - reply_len = -1; - } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) { - if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13)) - reply_len = -1; -#endif /* CONFIG_WNM */ - } else if (os_strcmp(buf, "GET_CONFIG") == 0) { - reply_len = hostapd_ctrl_iface_get_config(hapd, reply, - reply_size); - } else if (os_strncmp(buf, "SET ", 4) == 0) { - if (hostapd_ctrl_iface_set(hapd, buf + 4)) - reply_len = -1; - } else if (os_strncmp(buf, "GET ", 4) == 0) { - reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply, - reply_size); - } else if (os_strncmp(buf, "ENABLE", 6) == 0) { - if (hostapd_ctrl_iface_enable(hapd->iface)) - reply_len = -1; - } else if (os_strncmp(buf, "RELOAD", 6) == 0) { - if (hostapd_ctrl_iface_reload(hapd->iface)) - reply_len = -1; - } else if (os_strncmp(buf, "DISABLE", 7) == 0) { - if (hostapd_ctrl_iface_disable(hapd->iface)) - reply_len = -1; -#ifdef CONFIG_TESTING_OPTIONS - } else if (os_strncmp(buf, "RADAR ", 6) == 0) { - if (hostapd_ctrl_iface_radar(hapd, buf + 6)) - reply_len = -1; - } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) { - if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8)) - reply_len = -1; -#endif /* CONFIG_TESTING_OPTIONS */ - } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { - if (hostapd_ctrl_iface_chan_switch(hapd, buf + 12)) - reply_len = -1; - } else { - os_memcpy(reply, "UNKNOWN COMMAND\n", 16); - reply_len = 16; - } - - if (reply_len < 0) { - os_memcpy(reply, "FAIL\n", 5); - reply_len = 5; - } - sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); - os_free(reply); -} - - -static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) -{ - char *buf; - size_t len; - - if (hapd->conf->ctrl_interface == NULL) - return NULL; - - len = os_strlen(hapd->conf->ctrl_interface) + - os_strlen(hapd->conf->iface) + 2; - buf = os_malloc(len); - if (buf == NULL) - return NULL; - - os_snprintf(buf, len, "%s/%s", - hapd->conf->ctrl_interface, hapd->conf->iface); - buf[len - 1] = '\0'; - return buf; -} - - -static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global, - const char *txt, size_t len) -{ - struct hostapd_data *hapd = ctx; - if (hapd == NULL) - return; - hostapd_ctrl_iface_send(hapd, level, txt, len); -} - - -int hostapd_ctrl_iface_init(struct hostapd_data *hapd) -{ - struct sockaddr_un addr; - int s = -1; - char *fname = NULL; - - if (hapd->ctrl_sock > -1) { - wpa_printf(MSG_DEBUG, "ctrl_iface already exists!"); - return 0; - } - - if (hapd->conf->ctrl_interface == NULL) - return 0; - - if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { - if (errno == EEXIST) { - wpa_printf(MSG_DEBUG, "Using existing control " - "interface directory."); - } else { - perror("mkdir[ctrl_interface]"); - goto fail; - } - } - - if (hapd->conf->ctrl_interface_gid_set && - chown(hapd->conf->ctrl_interface, -1, - hapd->conf->ctrl_interface_gid) < 0) { - perror("chown[ctrl_interface]"); - return -1; - } - - if (!hapd->conf->ctrl_interface_gid_set && - hapd->iface->interfaces->ctrl_iface_group && - chown(hapd->conf->ctrl_interface, -1, - hapd->iface->interfaces->ctrl_iface_group) < 0) { - perror("chown[ctrl_interface]"); - return -1; - } - -#ifdef ANDROID - /* - * Android is using umask 0077 which would leave the control interface - * directory without group access. This breaks things since Wi-Fi - * framework assumes that this directory can be accessed by other - * applications in the wifi group. Fix this by adding group access even - * if umask value would prevent this. - */ - if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { - wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s", - strerror(errno)); - /* Try to continue anyway */ - } -#endif /* ANDROID */ - - if (os_strlen(hapd->conf->ctrl_interface) + 1 + - os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path)) - goto fail; - - s = socket(PF_UNIX, SOCK_DGRAM, 0); - if (s < 0) { - perror("socket(PF_UNIX)"); - goto fail; - } - - os_memset(&addr, 0, sizeof(addr)); -#ifdef __FreeBSD__ - addr.sun_len = sizeof(addr); -#endif /* __FreeBSD__ */ - addr.sun_family = AF_UNIX; - fname = hostapd_ctrl_iface_path(hapd); - if (fname == NULL) - goto fail; - os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", - strerror(errno)); - if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" - " allow connections - assuming it was left" - "over from forced program termination"); - if (unlink(fname) < 0) { - perror("unlink[ctrl_iface]"); - wpa_printf(MSG_ERROR, "Could not unlink " - "existing ctrl_iface socket '%s'", - fname); - goto fail; - } - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < - 0) { - perror("hostapd-ctrl-iface: bind(PF_UNIX)"); - goto fail; - } - wpa_printf(MSG_DEBUG, "Successfully replaced leftover " - "ctrl_iface socket '%s'", fname); - } else { - wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " - "be in use - cannot override it"); - wpa_printf(MSG_INFO, "Delete '%s' manually if it is " - "not used anymore", fname); - os_free(fname); - fname = NULL; - goto fail; - } - } - - if (hapd->conf->ctrl_interface_gid_set && - chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) { - perror("chown[ctrl_interface/ifname]"); - goto fail; - } - - if (!hapd->conf->ctrl_interface_gid_set && - hapd->iface->interfaces->ctrl_iface_group && - chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) { - perror("chown[ctrl_interface/ifname]"); - goto fail; - } - - if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { - perror("chmod[ctrl_interface/ifname]"); - goto fail; - } - os_free(fname); - - hapd->ctrl_sock = s; - eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd, - NULL); - hapd->msg_ctx = hapd; - wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb); - - return 0; - -fail: - if (s >= 0) - close(s); - if (fname) { - unlink(fname); - os_free(fname); - } - return -1; -} - - -void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) -{ - struct wpa_ctrl_dst *dst, *prev; - - if (hapd->ctrl_sock > -1) { - char *fname; - eloop_unregister_read_sock(hapd->ctrl_sock); - close(hapd->ctrl_sock); - hapd->ctrl_sock = -1; - fname = hostapd_ctrl_iface_path(hapd); - if (fname) - unlink(fname); - os_free(fname); - - if (hapd->conf->ctrl_interface && - rmdir(hapd->conf->ctrl_interface) < 0) { - if (errno == ENOTEMPTY) { - wpa_printf(MSG_DEBUG, "Control interface " - "directory not empty - leaving it " - "behind"); - } else { - wpa_printf(MSG_ERROR, - "rmdir[ctrl_interface=%s]: %s", - hapd->conf->ctrl_interface, - strerror(errno)); - } - } - } - - dst = hapd->ctrl_dst; - while (dst) { - prev = dst; - dst = dst->next; - os_free(prev); - } -} - - -static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces, - char *buf) -{ - if (hostapd_add_iface(interfaces, buf) < 0) { - wpa_printf(MSG_ERROR, "Adding interface %s failed", buf); - return -1; - } - return 0; -} - - -static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces, - char *buf) -{ - if (hostapd_remove_iface(interfaces, buf) < 0) { - wpa_printf(MSG_ERROR, "Removing interface %s failed", buf); - return -1; - } - return 0; -} - - -static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces) -{ -#ifdef CONFIG_WPS_TESTING - wps_version_number = 0x20; - wps_testing_dummy_cred = 0; - wps_corrupt_pkhash = 0; -#endif /* CONFIG_WPS_TESTING */ -} - - -static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, - void *sock_ctx) -{ - void *interfaces = eloop_ctx; - char buf[256]; - int res; - struct sockaddr_un from; - socklen_t fromlen = sizeof(from); - char reply[24]; - int reply_len; - - res = recvfrom(sock, buf, sizeof(buf) - 1, 0, - (struct sockaddr *) &from, &fromlen); - if (res < 0) { - perror("recvfrom(ctrl_iface)"); - return; - } - buf[res] = '\0'; - wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf); - - os_memcpy(reply, "OK\n", 3); - reply_len = 3; - - if (os_strcmp(buf, "PING") == 0) { - os_memcpy(reply, "PONG\n", 5); - reply_len = 5; - } else if (os_strncmp(buf, "RELOG", 5) == 0) { - if (wpa_debug_reopen_file() < 0) - reply_len = -1; - } else if (os_strcmp(buf, "FLUSH") == 0) { - hostapd_ctrl_iface_flush(interfaces); - } else if (os_strncmp(buf, "ADD ", 4) == 0) { - if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0) - reply_len = -1; - } else if (os_strncmp(buf, "REMOVE ", 7) == 0) { - if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0) - reply_len = -1; - } else { - wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command " - "ignored"); - reply_len = -1; - } - - if (reply_len < 0) { - os_memcpy(reply, "FAIL\n", 5); - reply_len = 5; - } - - sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); -} - - -static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface) -{ - char *buf; - size_t len; - - if (interface->global_iface_path == NULL) - return NULL; - - len = os_strlen(interface->global_iface_path) + - os_strlen(interface->global_iface_name) + 2; - buf = os_malloc(len); - if (buf == NULL) - return NULL; - - os_snprintf(buf, len, "%s/%s", interface->global_iface_path, - interface->global_iface_name); - buf[len - 1] = '\0'; - return buf; -} - - -int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface) -{ - struct sockaddr_un addr; - int s = -1; - char *fname = NULL; - - if (interface->global_iface_path == NULL) { - wpa_printf(MSG_DEBUG, "ctrl_iface not configured!"); - return 0; - } - - if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) { - if (errno == EEXIST) { - wpa_printf(MSG_DEBUG, "Using existing control " - "interface directory."); - } else { - perror("mkdir[ctrl_interface]"); - goto fail; - } - } else if (interface->ctrl_iface_group && - chown(interface->global_iface_path, -1, - interface->ctrl_iface_group) < 0) { - perror("chown[ctrl_interface]"); - goto fail; - } - - if (os_strlen(interface->global_iface_path) + 1 + - os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path)) - goto fail; - - s = socket(PF_UNIX, SOCK_DGRAM, 0); - if (s < 0) { - perror("socket(PF_UNIX)"); - goto fail; - } - - os_memset(&addr, 0, sizeof(addr)); -#ifdef __FreeBSD__ - addr.sun_len = sizeof(addr); -#endif /* __FreeBSD__ */ - addr.sun_family = AF_UNIX; - fname = hostapd_global_ctrl_iface_path(interface); - if (fname == NULL) - goto fail; - os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", - strerror(errno)); - if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" - " allow connections - assuming it was left" - "over from forced program termination"); - if (unlink(fname) < 0) { - perror("unlink[ctrl_iface]"); - wpa_printf(MSG_ERROR, "Could not unlink " - "existing ctrl_iface socket '%s'", - fname); - goto fail; - } - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < - 0) { - perror("bind(PF_UNIX)"); - goto fail; - } - wpa_printf(MSG_DEBUG, "Successfully replaced leftover " - "ctrl_iface socket '%s'", fname); - } else { - wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " - "be in use - cannot override it"); - wpa_printf(MSG_INFO, "Delete '%s' manually if it is " - "not used anymore", fname); - os_free(fname); - fname = NULL; - goto fail; - } - } - - if (interface->ctrl_iface_group && - chown(fname, -1, interface->ctrl_iface_group) < 0) { - perror("chown[ctrl_interface]"); - goto fail; - } - - if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { - perror("chmod[ctrl_interface/ifname]"); - goto fail; - } - os_free(fname); - - interface->global_ctrl_sock = s; - eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive, - interface, NULL); - - return 0; - -fail: - if (s >= 0) - close(s); - if (fname) { - unlink(fname); - os_free(fname); - } - return -1; -} - - -void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces) -{ - char *fname = NULL; - - if (interfaces->global_ctrl_sock > -1) { - eloop_unregister_read_sock(interfaces->global_ctrl_sock); - close(interfaces->global_ctrl_sock); - interfaces->global_ctrl_sock = -1; - fname = hostapd_global_ctrl_iface_path(interfaces); - if (fname) { - unlink(fname); - os_free(fname); - } - - if (interfaces->global_iface_path && - rmdir(interfaces->global_iface_path) < 0) { - if (errno == ENOTEMPTY) { - wpa_printf(MSG_DEBUG, "Control interface " - "directory not empty - leaving it " - "behind"); - } else { - wpa_printf(MSG_ERROR, - "rmdir[ctrl_interface=%s]: %s", - interfaces->global_iface_path, - strerror(errno)); - } - } - os_free(interfaces->global_iface_path); - interfaces->global_iface_path = NULL; - } -} - - -static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, - const char *buf, size_t len) -{ - struct wpa_ctrl_dst *dst, *next; - struct msghdr msg; - int idx; - struct iovec io[2]; - char levelstr[10]; - - dst = hapd->ctrl_dst; - if (hapd->ctrl_sock < 0 || dst == NULL) - return; - - os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); - io[0].iov_base = levelstr; - io[0].iov_len = os_strlen(levelstr); - io[1].iov_base = (char *) buf; - io[1].iov_len = len; - os_memset(&msg, 0, sizeof(msg)); - msg.msg_iov = io; - msg.msg_iovlen = 2; - - idx = 0; - while (dst) { - next = dst->next; - if (level >= dst->debug_level) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", - (u8 *) dst->addr.sun_path, dst->addrlen - - offsetof(struct sockaddr_un, sun_path)); - msg.msg_name = &dst->addr; - msg.msg_namelen = dst->addrlen; - if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) { - int _errno = errno; - wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: " - "%d - %s", - idx, errno, strerror(errno)); - dst->errors++; - if (dst->errors > 10 || _errno == ENOENT) { - hostapd_ctrl_iface_detach( - hapd, &dst->addr, - dst->addrlen); - } - } else - dst->errors = 0; - } - idx++; - dst = next; - } -} - -#endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/contrib/hostapd/hostapd/ctrl_iface.h b/contrib/hostapd/hostapd/ctrl_iface.h deleted file mode 100644 index 3341a66bdc..0000000000 --- a/contrib/hostapd/hostapd/ctrl_iface.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * hostapd / UNIX domain socket -based control interface - * Copyright (c) 2004, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef CTRL_IFACE_H -#define CTRL_IFACE_H - -#ifndef CONFIG_NO_CTRL_IFACE -int hostapd_ctrl_iface_init(struct hostapd_data *hapd); -void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd); -int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface); -void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface); -#else /* CONFIG_NO_CTRL_IFACE */ -static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd) -{ - return 0; -} - -static inline void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) -{ -} - -static inline int -hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface) -{ - return 0; -} - -static inline void -hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface) -{ -} -#endif /* CONFIG_NO_CTRL_IFACE */ - -#endif /* CTRL_IFACE_H */ diff --git a/contrib/hostapd/hostapd/eap_register.c b/contrib/hostapd/hostapd/eap_register.c deleted file mode 100644 index 981e53946a..0000000000 --- a/contrib/hostapd/hostapd/eap_register.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * EAP method registration - * Copyright (c) 2004-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_server/eap_methods.h" -#include "eap_register.h" - - -/** - * eap_server_register_methods - Register statically linked EAP server methods - * Returns: 0 on success, -1 or -2 on failure - * - * This function is called at program initialization to register all EAP - * methods that were linked in statically. - */ -int eap_server_register_methods(void) -{ - int ret = 0; - -#ifdef EAP_SERVER_IDENTITY - if (ret == 0) - ret = eap_server_identity_register(); -#endif /* EAP_SERVER_IDENTITY */ - -#ifdef EAP_SERVER_MD5 - if (ret == 0) - ret = eap_server_md5_register(); -#endif /* EAP_SERVER_MD5 */ - -#ifdef EAP_SERVER_TLS - if (ret == 0) - ret = eap_server_tls_register(); -#endif /* EAP_SERVER_TLS */ - -#ifdef EAP_SERVER_UNAUTH_TLS - if (ret == 0) - ret = eap_server_unauth_tls_register(); -#endif /* EAP_SERVER_TLS */ - -#ifdef EAP_SERVER_MSCHAPV2 - if (ret == 0) - ret = eap_server_mschapv2_register(); -#endif /* EAP_SERVER_MSCHAPV2 */ - -#ifdef EAP_SERVER_PEAP - if (ret == 0) - ret = eap_server_peap_register(); -#endif /* EAP_SERVER_PEAP */ - -#ifdef EAP_SERVER_TLV - if (ret == 0) - ret = eap_server_tlv_register(); -#endif /* EAP_SERVER_TLV */ - -#ifdef EAP_SERVER_GTC - if (ret == 0) - ret = eap_server_gtc_register(); -#endif /* EAP_SERVER_GTC */ - -#ifdef EAP_SERVER_TTLS - if (ret == 0) - ret = eap_server_ttls_register(); -#endif /* EAP_SERVER_TTLS */ - -#ifdef EAP_SERVER_SIM - if (ret == 0) - ret = eap_server_sim_register(); -#endif /* EAP_SERVER_SIM */ - -#ifdef EAP_SERVER_AKA - if (ret == 0) - ret = eap_server_aka_register(); -#endif /* EAP_SERVER_AKA */ - -#ifdef EAP_SERVER_AKA_PRIME - if (ret == 0) - ret = eap_server_aka_prime_register(); -#endif /* EAP_SERVER_AKA_PRIME */ - -#ifdef EAP_SERVER_PAX - if (ret == 0) - ret = eap_server_pax_register(); -#endif /* EAP_SERVER_PAX */ - -#ifdef EAP_SERVER_PSK - if (ret == 0) - ret = eap_server_psk_register(); -#endif /* EAP_SERVER_PSK */ - -#ifdef EAP_SERVER_SAKE - if (ret == 0) - ret = eap_server_sake_register(); -#endif /* EAP_SERVER_SAKE */ - -#ifdef EAP_SERVER_GPSK - if (ret == 0) - ret = eap_server_gpsk_register(); -#endif /* EAP_SERVER_GPSK */ - -#ifdef EAP_SERVER_VENDOR_TEST - if (ret == 0) - ret = eap_server_vendor_test_register(); -#endif /* EAP_SERVER_VENDOR_TEST */ - -#ifdef EAP_SERVER_FAST - if (ret == 0) - ret = eap_server_fast_register(); -#endif /* EAP_SERVER_FAST */ - -#ifdef EAP_SERVER_WSC - if (ret == 0) - ret = eap_server_wsc_register(); -#endif /* EAP_SERVER_WSC */ - -#ifdef EAP_SERVER_IKEV2 - if (ret == 0) - ret = eap_server_ikev2_register(); -#endif /* EAP_SERVER_IKEV2 */ - -#ifdef EAP_SERVER_TNC - if (ret == 0) - ret = eap_server_tnc_register(); -#endif /* EAP_SERVER_TNC */ - -#ifdef EAP_SERVER_PWD - if (ret == 0) - ret = eap_server_pwd_register(); -#endif /* EAP_SERVER_PWD */ - -#ifdef EAP_SERVER_EKE - if (ret == 0) - ret = eap_server_eke_register(); -#endif /* EAP_SERVER_EKE */ - - return ret; -} diff --git a/contrib/hostapd/hostapd/eap_register.h b/contrib/hostapd/hostapd/eap_register.h deleted file mode 100644 index c342351a1a..0000000000 --- a/contrib/hostapd/hostapd/eap_register.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * EAP method registration - * Copyright (c) 2004-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_REGISTER_H -#define EAP_REGISTER_H - -int eap_server_register_methods(void); - -#endif /* EAP_REGISTER_H */ diff --git a/contrib/hostapd/hostapd/hlr_auc_gw.txt b/contrib/hostapd/hostapd/hlr_auc_gw.txt deleted file mode 100644 index 097bbce362..0000000000 --- a/contrib/hostapd/hostapd/hlr_auc_gw.txt +++ /dev/null @@ -1,104 +0,0 @@ -HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator - -hlr_auc_gw is an example implementation of the EAP-SIM/AKA/AKA' -database/authentication gateway interface to HLR/AuC. It could be -replaced with an implementation of SS7 gateway to GSM/UMTS -authentication center (HLR/AuC). hostapd will send SIM/AKA -authentication queries over a UNIX domain socket to and external -program, e.g., hlr_auc_gw. - -hlr_auc_gw can be configured with GSM and UMTS authentication data with -text files: GSM triplet file (see hostapd.sim_db) and Milenage file (see -hlr_auc_gw.milenage_db). Milenage parameters can be used to generate -dynamic authentication data for EAP-SIM, EAP-AKA, and EAP-AKA' while the -GSM triplet data is used for a more static configuration (e.g., triplets -extracted from a SIM card). - -Alternatively, hlr_auc_gw can be built with support for an SQLite -database for more dynamic operations. This is enabled by adding -"CONFIG_SQLITE=y" into hostapd/.config before building hlr_auc_gw ("make -clean; make hlr_auc_gw" in this directory). - -hostapd is configured to use hlr_auc_gw with the eap_sim_db parameter in -hostapd.conf (e.g., "eap_sim_db=unix:/tmp/hlr_auc_gw.sock"). hlr_auc_gw -is configured with command line parameters: - -hlr_auc_gw [-hu] [-s] [-g] [-m] \ - [-D] [-i] - -options: - -h = show this usage help - -u = update SQN in Milenage file on exit - -s = path for UNIX domain socket - (default: /tmp/hlr_auc_gw.sock) - -g = path for GSM authentication triplets - -m = path for Milenage keys - -D = path to SQLite database - -i = IND length for SQN (default: 5) - - -The SQLite database can be initialized with sqlite, e.g., by running -following commands in "sqlite3 /path/to/hlr_auc_gw.db": - -CREATE TABLE milenage( - imsi INTEGER PRIMARY KEY NOT NULL, - ki CHAR(32) NOT NULL, - opc CHAR(32) NOT NULL, - amf CHAR(4) NOT NULL, - sqn CHAR(12) NOT NULL -); -INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES( - 232010000000000, - '90dca4eda45b53cf0f12d7c9c3bc6a89', - 'cb9cccc4b9258e6dca4760379fb82581', - '61df', - '000000000000' -); -INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES( - 555444333222111, - '5122250214c33e723a5dd523fc145fc0', - '981d464c7c52eb6e5036234984ad0bcf', - 'c3ab', - '16f3b3f70fc1' -); - - -hostapd (EAP server) can also be configured to store the EAP-SIM/AKA -pseudonyms and reauth information into a SQLite database. This is -configured with the db parameter within the eap_sim_db configuration -option. - - -"hlr_auc_gw -D /path/to/hlr_auc_gw.db" can then be used to fetch -Milenage parameters based on IMSI from the database. The database can be -updated dynamically while hlr_auc_gw is running to add/remove/modify -entries. - - -Example configuration files for hostapd to operate as a RADIUS -authentication server for EAP-SIM/AKA/AKA': - -hostapd.conf: - -driver=none -radius_server_clients=hostapd.radius_clients -eap_server=1 -eap_user_file=hostapd.eap_user -eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/eap_sim.db -eap_sim_aka_result_ind=1 - -hostapd.radius_clients: - -0.0.0.0/0 radius - -hostapd.eap_user: - -"0"* AKA -"1"* SIM -"2"* AKA -"3"* SIM -"4"* AKA -"5"* SIM -"6"* AKA' -"7"* AKA' -"8"* AKA' diff --git a/contrib/hostapd/hostapd/hostapd_cli.c b/contrib/hostapd/hostapd/hostapd_cli.c deleted file mode 100644 index eee85041b6..0000000000 --- a/contrib/hostapd/hostapd/hostapd_cli.c +++ /dev/null @@ -1,1270 +0,0 @@ -/* - * hostapd - command line interface for hostapd daemon - * Copyright (c) 2004-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common/wpa_ctrl.h" -#include "utils/common.h" -#include "utils/eloop.h" -#include "utils/edit.h" -#include "common/version.h" - - -static const char *hostapd_cli_version = -"hostapd_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2014, Jouni Malinen and contributors"; - - -static const char *hostapd_cli_license = -"This software may be distributed under the terms of the BSD license.\n" -"See README for more details.\n"; - -static const char *hostapd_cli_full_license = -"This software may be distributed under the terms of the BSD license.\n" -"\n" -"Redistribution and use in source and binary forms, with or without\n" -"modification, are permitted provided that the following conditions are\n" -"met:\n" -"\n" -"1. Redistributions of source code must retain the above copyright\n" -" notice, this list of conditions and the following disclaimer.\n" -"\n" -"2. Redistributions in binary form must reproduce the above copyright\n" -" notice, this list of conditions and the following disclaimer in the\n" -" documentation and/or other materials provided with the distribution.\n" -"\n" -"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n" -" names of its contributors may be used to endorse or promote products\n" -" derived from this software without specific prior written permission.\n" -"\n" -"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" -"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" -"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" -"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" -"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" -"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" -"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" -"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" -"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" -"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" -"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" -"\n"; - -static const char *commands_help = -"Commands:\n" -" mib get MIB variables (dot1x, dot11, radius)\n" -" sta get MIB variables for one station\n" -" all_sta get MIB variables for all stations\n" -" new_sta add a new station\n" -" deauthenticate deauthenticate a station\n" -" disassociate disassociate a station\n" -#ifdef CONFIG_IEEE80211W -" sa_query send SA Query to a station\n" -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WPS -" wps_pin [timeout] [addr] add WPS Enrollee PIN\n" -" wps_check_pin verify PIN checksum\n" -" wps_pbc indicate button pushed to initiate PBC\n" -" wps_cancel cancel the pending WPS operation\n" -#ifdef CONFIG_WPS_NFC -" wps_nfc_tag_read report read NFC tag with WPS data\n" -" wps_nfc_config_token build NFC configuration token\n" -" wps_nfc_token manager NFC password token\n" -#endif /* CONFIG_WPS_NFC */ -" wps_ap_pin [params..] enable/disable AP PIN\n" -" wps_config configure AP\n" -" wps_get_status show current WPS status\n" -#endif /* CONFIG_WPS */ -" get_config show current configuration\n" -" help show this usage help\n" -" interface [ifname] show interfaces/select interface\n" -" level change debug level\n" -" license show full hostapd_cli license\n" -" quit exit hostapd_cli\n"; - -static struct wpa_ctrl *ctrl_conn; -static int hostapd_cli_quit = 0; -static int hostapd_cli_attached = 0; - -#ifndef CONFIG_CTRL_IFACE_DIR -#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd" -#endif /* CONFIG_CTRL_IFACE_DIR */ -static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR; - -static char *ctrl_ifname = NULL; -static const char *pid_file = NULL; -static const char *action_file = NULL; -static int ping_interval = 5; -static int interactive = 0; - - -static void usage(void) -{ - fprintf(stderr, "%s\n", hostapd_cli_version); - fprintf(stderr, - "\n" - "usage: hostapd_cli [-p] [-i] [-hvB] " - "[-a] \\\n" - " [-G] [command..]\n" - "\n" - "Options:\n" - " -h help (show this usage text)\n" - " -v shown version information\n" - " -p path to find control sockets (default: " - "/var/run/hostapd)\n" - " -a run in daemon mode executing the action file " - "based on events\n" - " from hostapd\n" - " -B run a daemon in the background\n" - " -i Interface to listen on (default: first " - "interface found in the\n" - " socket path)\n\n" - "%s", - commands_help); -} - - -static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname) -{ - char *cfile; - int flen; - - if (ifname == NULL) - return NULL; - - flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2; - cfile = malloc(flen); - if (cfile == NULL) - return NULL; - snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname); - - ctrl_conn = wpa_ctrl_open(cfile); - free(cfile); - return ctrl_conn; -} - - -static void hostapd_cli_close_connection(void) -{ - if (ctrl_conn == NULL) - return; - - if (hostapd_cli_attached) { - wpa_ctrl_detach(ctrl_conn); - hostapd_cli_attached = 0; - } - wpa_ctrl_close(ctrl_conn); - ctrl_conn = NULL; -} - - -static void hostapd_cli_msg_cb(char *msg, size_t len) -{ - printf("%s\n", msg); -} - - -static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print) -{ - char buf[4096]; - size_t len; - int ret; - - if (ctrl_conn == NULL) { - printf("Not connected to hostapd - command dropped.\n"); - return -1; - } - len = sizeof(buf) - 1; - ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, - hostapd_cli_msg_cb); - if (ret == -2) { - printf("'%s' command timed out.\n", cmd); - return -2; - } else if (ret < 0) { - printf("'%s' command failed.\n", cmd); - return -1; - } - if (print) { - buf[len] = '\0'; - printf("%s", buf); - } - return 0; -} - - -static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd) -{ - return _wpa_ctrl_command(ctrl, cmd, 1); -} - - -static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "PING"); -} - - -static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "RELOG"); -} - - -static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - if (argc > 0 && os_strcmp(argv[0], "driver") == 0) - return wpa_ctrl_command(ctrl, "STATUS-DRIVER"); - return wpa_ctrl_command(ctrl, "STATUS"); -} - - -static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - if (argc > 0) { - char buf[100]; - os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]); - return wpa_ctrl_command(ctrl, buf); - } - return wpa_ctrl_command(ctrl, "MIB"); -} - - -static int hostapd_cli_exec(const char *program, const char *arg1, - const char *arg2) -{ - char *cmd; - size_t len; - int res; - int ret = 0; - - len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3; - cmd = os_malloc(len); - if (cmd == NULL) - return -1; - res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2); - if (res < 0 || (size_t) res >= len) { - os_free(cmd); - return -1; - } - cmd[len - 1] = '\0'; -#ifndef _WIN32_WCE - if (system(cmd) < 0) - ret = -1; -#endif /* _WIN32_WCE */ - os_free(cmd); - - return ret; -} - - -static void hostapd_cli_action_process(char *msg, size_t len) -{ - const char *pos; - - pos = msg; - if (*pos == '<') { - pos = os_strchr(pos, '>'); - if (pos) - pos++; - else - pos = msg; - } - - hostapd_cli_exec(action_file, ctrl_ifname, pos); -} - - -static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char buf[64]; - if (argc < 1) { - printf("Invalid 'sta' command - at least one argument, STA " - "address, is required.\n"); - return -1; - } - if (argc > 1) - snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]); - else - snprintf(buf, sizeof(buf), "STA %s", argv[0]); - return wpa_ctrl_command(ctrl, buf); -} - - -static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char buf[64]; - if (argc != 1) { - printf("Invalid 'new_sta' command - exactly one argument, STA " - "address, is required.\n"); - return -1; - } - snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]); - return wpa_ctrl_command(ctrl, buf); -} - - -static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char buf[64]; - if (argc < 1) { - printf("Invalid 'deauthenticate' command - exactly one " - "argument, STA address, is required.\n"); - return -1; - } - if (argc > 1) - os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s", - argv[0], argv[1]); - else - os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]); - return wpa_ctrl_command(ctrl, buf); -} - - -static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char buf[64]; - if (argc < 1) { - printf("Invalid 'disassociate' command - exactly one " - "argument, STA address, is required.\n"); - return -1; - } - if (argc > 1) - os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s", - argv[0], argv[1]); - else - os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]); - return wpa_ctrl_command(ctrl, buf); -} - - -#ifdef CONFIG_IEEE80211W -static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char buf[64]; - if (argc != 1) { - printf("Invalid 'sa_query' command - exactly one argument, " - "STA address, is required.\n"); - return -1; - } - snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]); - return wpa_ctrl_command(ctrl, buf); -} -#endif /* CONFIG_IEEE80211W */ - - -#ifdef CONFIG_WPS -static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char buf[256]; - if (argc < 2) { - printf("Invalid 'wps_pin' command - at least two arguments, " - "UUID and PIN, are required.\n"); - return -1; - } - if (argc > 3) - snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s", - argv[0], argv[1], argv[2], argv[3]); - else if (argc > 2) - snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s", - argv[0], argv[1], argv[2]); - else - snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]); - return wpa_ctrl_command(ctrl, buf); -} - - -static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char cmd[256]; - int res; - - if (argc != 1 && argc != 2) { - printf("Invalid WPS_CHECK_PIN command: needs one argument:\n" - "- PIN to be verified\n"); - return -1; - } - - if (argc == 2) - res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s", - argv[0], argv[1]); - else - res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s", - argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_CHECK_PIN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); -} - - -static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "WPS_PBC"); -} - - -static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "WPS_CANCEL"); -} - - -#ifdef CONFIG_WPS_NFC -static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - int ret; - char *buf; - size_t buflen; - - if (argc != 1) { - printf("Invalid 'wps_nfc_tag_read' command - one argument " - "is required.\n"); - return -1; - } - - buflen = 18 + os_strlen(argv[0]); - buf = os_malloc(buflen); - if (buf == NULL) - return -1; - os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]); - - ret = wpa_ctrl_command(ctrl, buf); - os_free(buf); - - return ret; -} - - -static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, - int argc, char *argv[]) -{ - char cmd[64]; - int res; - - if (argc != 1) { - printf("Invalid 'wps_nfc_config_token' command - one argument " - "is required.\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s", - argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_NFC_CONFIG_TOKEN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); -} - - -static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, - int argc, char *argv[]) -{ - char cmd[64]; - int res; - - if (argc != 1) { - printf("Invalid 'wps_nfc_token' command - one argument is " - "required.\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long WPS_NFC_TOKEN command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); -} - - -static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, - int argc, char *argv[]) -{ - char cmd[64]; - int res; - - if (argc != 2) { - printf("Invalid 'nfc_get_handover_sel' command - two arguments " - "are required.\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s", - argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long NFC_GET_HANDOVER_SEL command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); -} - -#endif /* CONFIG_WPS_NFC */ - - -static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char buf[64]; - if (argc < 1) { - printf("Invalid 'wps_ap_pin' command - at least one argument " - "is required.\n"); - return -1; - } - if (argc > 2) - snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s", - argv[0], argv[1], argv[2]); - else if (argc > 1) - snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s", - argv[0], argv[1]); - else - snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]); - return wpa_ctrl_command(ctrl, buf); -} - - -static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "WPS_GET_STATUS"); -} - - -static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char buf[256]; - char ssid_hex[2 * 32 + 1]; - char key_hex[2 * 64 + 1]; - int i; - - if (argc < 1) { - printf("Invalid 'wps_config' command - at least two arguments " - "are required.\n"); - return -1; - } - - ssid_hex[0] = '\0'; - for (i = 0; i < 32; i++) { - if (argv[0][i] == '\0') - break; - os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]); - } - - key_hex[0] = '\0'; - if (argc > 3) { - for (i = 0; i < 64; i++) { - if (argv[3][i] == '\0') - break; - os_snprintf(&key_hex[i * 2], 3, "%02x", - argv[3][i]); - } - } - - if (argc > 3) - snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s", - ssid_hex, argv[1], argv[2], key_hex); - else if (argc > 2) - snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s", - ssid_hex, argv[1], argv[2]); - else - snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s", - ssid_hex, argv[1]); - return wpa_ctrl_command(ctrl, buf); -} -#endif /* CONFIG_WPS */ - - -static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char buf[300]; - int res; - - if (argc < 2) { - printf("Invalid 'disassoc_imminent' command - two arguments " - "(STA addr and Disassociation Timer) are needed\n"); - return -1; - } - - res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s", - argv[0], argv[1]); - if (res < 0 || res >= (int) sizeof(buf)) - return -1; - return wpa_ctrl_command(ctrl, buf); -} - - -static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char buf[300]; - int res; - - if (argc < 3) { - printf("Invalid 'ess_disassoc' command - three arguments (STA " - "addr, disassoc timer, and URL) are needed\n"); - return -1; - } - - res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s", - argv[0], argv[1], argv[2]); - if (res < 0 || res >= (int) sizeof(buf)) - return -1; - return wpa_ctrl_command(ctrl, buf); -} - - -static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "GET_CONFIG"); -} - - -static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd, - char *addr, size_t addr_len) -{ - char buf[4096], *pos; - size_t len; - int ret; - - if (ctrl_conn == NULL) { - printf("Not connected to hostapd - command dropped.\n"); - return -1; - } - len = sizeof(buf) - 1; - ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, - hostapd_cli_msg_cb); - if (ret == -2) { - printf("'%s' command timed out.\n", cmd); - return -2; - } else if (ret < 0) { - printf("'%s' command failed.\n", cmd); - return -1; - } - - buf[len] = '\0'; - if (memcmp(buf, "FAIL", 4) == 0) - return -1; - printf("%s", buf); - - pos = buf; - while (*pos != '\0' && *pos != '\n') - pos++; - *pos = '\0'; - os_strlcpy(addr, buf, addr_len); - return 0; -} - - -static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char addr[32], cmd[64]; - - if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr))) - return 0; - do { - snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); - } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0); - - return -1; -} - - -static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - printf("%s", commands_help); - return 0; -} - - -static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license); - return 0; -} - - -static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl, - int argc, char *argv[]) -{ - char buf[200]; - int res; - - if (argc != 1) { - printf("Invalid 'set_qos_map_set' command - " - "one argument (comma delimited QoS map set) " - "is needed\n"); - return -1; - } - - res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]); - if (res < 0 || res >= (int) sizeof(buf)) - return -1; - return wpa_ctrl_command(ctrl, buf); -} - - -static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl, - int argc, char *argv[]) -{ - char buf[50]; - int res; - - if (argc != 1) { - printf("Invalid 'send_qos_map_conf' command - " - "one argument (STA addr) is needed\n"); - return -1; - } - - res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]); - if (res < 0 || res >= (int) sizeof(buf)) - return -1; - return wpa_ctrl_command(ctrl, buf); -} - - -static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - hostapd_cli_quit = 1; - if (interactive) - eloop_terminate(); - return 0; -} - - -static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char cmd[256]; - if (argc != 1) { - printf("Invalid LEVEL command: needs one argument (debug " - "level)\n"); - return 0; - } - snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]); - return wpa_ctrl_command(ctrl, cmd); -} - - -static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl) -{ - struct dirent *dent; - DIR *dir; - - dir = opendir(ctrl_iface_dir); - if (dir == NULL) { - printf("Control interface directory '%s' could not be " - "openned.\n", ctrl_iface_dir); - return; - } - - printf("Available interfaces:\n"); - while ((dent = readdir(dir))) { - if (strcmp(dent->d_name, ".") == 0 || - strcmp(dent->d_name, "..") == 0) - continue; - printf("%s\n", dent->d_name); - } - closedir(dir); -} - - -static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc < 1) { - hostapd_cli_list_interfaces(ctrl); - return 0; - } - - hostapd_cli_close_connection(); - free(ctrl_ifname); - ctrl_ifname = strdup(argv[0]); - - if (hostapd_cli_open_connection(ctrl_ifname)) { - printf("Connected to interface '%s.\n", ctrl_ifname); - if (wpa_ctrl_attach(ctrl_conn) == 0) { - hostapd_cli_attached = 1; - } else { - printf("Warning: Failed to attach to " - "hostapd.\n"); - } - } else { - printf("Could not connect to interface '%s' - re-trying\n", - ctrl_ifname); - } - return 0; -} - - -static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char cmd[256]; - int res; - - if (argc != 2) { - printf("Invalid SET command: needs two arguments (variable " - "name and value)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long SET command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); -} - - -static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char cmd[256]; - int res; - - if (argc != 1) { - printf("Invalid GET command: needs one argument (variable " - "name)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long GET command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); -} - - -static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl, - int argc, char *argv[]) -{ - char cmd[256]; - int res; - int i; - char *tmp; - int total; - - if (argc < 2) { - printf("Invalid chan_switch command: needs at least two " - "arguments (count and freq)\n" - "usage: [sec_channel_offset=] " - "[center_freq1=] [center_freq2=] [bandwidth=] " - "[blocktx] [ht|vht]\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s", - argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { - printf("Too long CHAN_SWITCH command.\n"); - return -1; - } - - total = res; - for (i = 2; i < argc; i++) { - tmp = cmd + total; - res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]); - if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) { - printf("Too long CHAN_SWITCH command.\n"); - return -1; - } - total += res; - } - return wpa_ctrl_command(ctrl, cmd); -} - - -struct hostapd_cli_cmd { - const char *cmd; - int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); -}; - -static struct hostapd_cli_cmd hostapd_cli_commands[] = { - { "ping", hostapd_cli_cmd_ping }, - { "mib", hostapd_cli_cmd_mib }, - { "relog", hostapd_cli_cmd_relog }, - { "status", hostapd_cli_cmd_status }, - { "sta", hostapd_cli_cmd_sta }, - { "all_sta", hostapd_cli_cmd_all_sta }, - { "new_sta", hostapd_cli_cmd_new_sta }, - { "deauthenticate", hostapd_cli_cmd_deauthenticate }, - { "disassociate", hostapd_cli_cmd_disassociate }, -#ifdef CONFIG_IEEE80211W - { "sa_query", hostapd_cli_cmd_sa_query }, -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WPS - { "wps_pin", hostapd_cli_cmd_wps_pin }, - { "wps_check_pin", hostapd_cli_cmd_wps_check_pin }, - { "wps_pbc", hostapd_cli_cmd_wps_pbc }, - { "wps_cancel", hostapd_cli_cmd_wps_cancel }, -#ifdef CONFIG_WPS_NFC - { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read }, - { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token }, - { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token }, - { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel }, -#endif /* CONFIG_WPS_NFC */ - { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin }, - { "wps_config", hostapd_cli_cmd_wps_config }, - { "wps_get_status", hostapd_cli_cmd_wps_get_status }, -#endif /* CONFIG_WPS */ - { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent }, - { "ess_disassoc", hostapd_cli_cmd_ess_disassoc }, - { "get_config", hostapd_cli_cmd_get_config }, - { "help", hostapd_cli_cmd_help }, - { "interface", hostapd_cli_cmd_interface }, - { "level", hostapd_cli_cmd_level }, - { "license", hostapd_cli_cmd_license }, - { "quit", hostapd_cli_cmd_quit }, - { "set", hostapd_cli_cmd_set }, - { "get", hostapd_cli_cmd_get }, - { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set }, - { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf }, - { "chan_switch", hostapd_cli_cmd_chan_switch }, - { NULL, NULL } -}; - - -static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - struct hostapd_cli_cmd *cmd, *match = NULL; - int count; - - count = 0; - cmd = hostapd_cli_commands; - while (cmd->cmd) { - if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) { - match = cmd; - if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { - /* we have an exact match */ - count = 1; - break; - } - count++; - } - cmd++; - } - - if (count > 1) { - printf("Ambiguous command '%s'; possible commands:", argv[0]); - cmd = hostapd_cli_commands; - while (cmd->cmd) { - if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == - 0) { - printf(" %s", cmd->cmd); - } - cmd++; - } - printf("\n"); - } else if (count == 0) { - printf("Unknown command '%s'\n", argv[0]); - } else { - match->handler(ctrl, argc - 1, &argv[1]); - } -} - - -static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, - int action_monitor) -{ - int first = 1; - if (ctrl_conn == NULL) - return; - while (wpa_ctrl_pending(ctrl)) { - char buf[256]; - size_t len = sizeof(buf) - 1; - if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { - buf[len] = '\0'; - if (action_monitor) - hostapd_cli_action_process(buf, len); - else { - if (in_read && first) - printf("\n"); - first = 0; - printf("%s\n", buf); - } - } else { - printf("Could not read pending message.\n"); - break; - } - } -} - - -#define max_args 10 - -static int tokenize_cmd(char *cmd, char *argv[]) -{ - char *pos; - int argc = 0; - - pos = cmd; - for (;;) { - while (*pos == ' ') - pos++; - if (*pos == '\0') - break; - argv[argc] = pos; - argc++; - if (argc == max_args) - break; - if (*pos == '"') { - char *pos2 = os_strrchr(pos, '"'); - if (pos2) - pos = pos2 + 1; - } - while (*pos != '\0' && *pos != ' ') - pos++; - if (*pos == ' ') - *pos++ = '\0'; - } - - return argc; -} - - -static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx) -{ - if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) { - printf("Connection to hostapd lost - trying to reconnect\n"); - hostapd_cli_close_connection(); - } - if (!ctrl_conn) { - ctrl_conn = hostapd_cli_open_connection(ctrl_ifname); - if (ctrl_conn) { - printf("Connection to hostapd re-established\n"); - if (wpa_ctrl_attach(ctrl_conn) == 0) { - hostapd_cli_attached = 1; - } else { - printf("Warning: Failed to attach to " - "hostapd.\n"); - } - } - } - if (ctrl_conn) - hostapd_cli_recv_pending(ctrl_conn, 1, 0); - eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); -} - - -static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx) -{ - eloop_terminate(); -} - - -static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd) -{ - char *argv[max_args]; - int argc; - argc = tokenize_cmd(cmd, argv); - if (argc) - wpa_request(ctrl_conn, argc, argv); -} - - -static void hostapd_cli_edit_eof_cb(void *ctx) -{ - eloop_terminate(); -} - - -static void hostapd_cli_interactive(void) -{ - printf("\nInteractive mode\n\n"); - - eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL); - edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb, - NULL, NULL, NULL, NULL); - eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); - - eloop_run(); - - edit_deinit(NULL, NULL); - eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL); -} - - -static void hostapd_cli_cleanup(void) -{ - hostapd_cli_close_connection(); - if (pid_file) - os_daemonize_terminate(pid_file); - - os_program_deinit(); -} - - -static void hostapd_cli_action(struct wpa_ctrl *ctrl) -{ - fd_set rfds; - int fd, res; - struct timeval tv; - char buf[256]; - size_t len; - - fd = wpa_ctrl_get_fd(ctrl); - - while (!hostapd_cli_quit) { - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - tv.tv_sec = ping_interval; - tv.tv_usec = 0; - res = select(fd + 1, &rfds, NULL, NULL, &tv); - if (res < 0 && errno != EINTR) { - perror("select"); - break; - } - - if (FD_ISSET(fd, &rfds)) - hostapd_cli_recv_pending(ctrl, 0, 1); - else { - len = sizeof(buf) - 1; - if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, - hostapd_cli_action_process) < 0 || - len < 4 || os_memcmp(buf, "PONG", 4) != 0) { - printf("hostapd did not reply to PING " - "command - exiting\n"); - break; - } - } - } -} - - -int main(int argc, char *argv[]) -{ - int warning_displayed = 0; - int c; - int daemonize = 0; - - if (os_program_init()) - return -1; - - for (;;) { - c = getopt(argc, argv, "a:BhG:i:p:v"); - if (c < 0) - break; - switch (c) { - case 'a': - action_file = optarg; - break; - case 'B': - daemonize = 1; - break; - case 'G': - ping_interval = atoi(optarg); - break; - case 'h': - usage(); - return 0; - case 'v': - printf("%s\n", hostapd_cli_version); - return 0; - case 'i': - os_free(ctrl_ifname); - ctrl_ifname = os_strdup(optarg); - break; - case 'p': - ctrl_iface_dir = optarg; - break; - default: - usage(); - return -1; - } - } - - interactive = (argc == optind) && (action_file == NULL); - - if (interactive) { - printf("%s\n\n%s\n\n", hostapd_cli_version, - hostapd_cli_license); - } - - if (eloop_init()) - return -1; - - for (;;) { - if (ctrl_ifname == NULL) { - struct dirent *dent; - DIR *dir = opendir(ctrl_iface_dir); - if (dir) { - while ((dent = readdir(dir))) { - if (os_strcmp(dent->d_name, ".") == 0 - || - os_strcmp(dent->d_name, "..") == 0) - continue; - printf("Selected interface '%s'\n", - dent->d_name); - ctrl_ifname = os_strdup(dent->d_name); - break; - } - closedir(dir); - } - } - ctrl_conn = hostapd_cli_open_connection(ctrl_ifname); - if (ctrl_conn) { - if (warning_displayed) - printf("Connection established.\n"); - break; - } - - if (!interactive) { - perror("Failed to connect to hostapd - " - "wpa_ctrl_open"); - return -1; - } - - if (!warning_displayed) { - printf("Could not connect to hostapd - re-trying\n"); - warning_displayed = 1; - } - os_sleep(1, 0); - continue; - } - - if (interactive || action_file) { - if (wpa_ctrl_attach(ctrl_conn) == 0) { - hostapd_cli_attached = 1; - } else { - printf("Warning: Failed to attach to hostapd.\n"); - if (action_file) - return -1; - } - } - - if (daemonize && os_daemonize(pid_file)) - return -1; - - if (interactive) - hostapd_cli_interactive(); - else if (action_file) - hostapd_cli_action(ctrl_conn); - else - wpa_request(ctrl_conn, argc - optind, &argv[optind]); - - os_free(ctrl_ifname); - eloop_destroy(); - hostapd_cli_cleanup(); - return 0; -} diff --git a/contrib/hostapd/hostapd/main.c b/contrib/hostapd/hostapd/main.c deleted file mode 100644 index 5a1b0a9e92..0000000000 --- a/contrib/hostapd/hostapd/main.c +++ /dev/null @@ -1,720 +0,0 @@ -/* - * hostapd / main() - * Copyright (c) 2002-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" -#ifndef CONFIG_NATIVE_WINDOWS -#include -#include -#endif /* CONFIG_NATIVE_WINDOWS */ - -#include "utils/common.h" -#include "utils/eloop.h" -#include "crypto/random.h" -#include "crypto/tls.h" -#include "common/version.h" -#include "drivers/driver.h" -#include "eap_server/eap.h" -#include "eap_server/tncs.h" -#include "ap/hostapd.h" -#include "ap/ap_config.h" -#include "ap/ap_drv_ops.h" -#include "config_file.h" -#include "eap_register.h" -#include "ctrl_iface.h" - - -struct hapd_global { - void **drv_priv; - size_t drv_count; -}; - -static struct hapd_global global; - - -#ifndef CONFIG_NO_HOSTAPD_LOGGER -static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, - int level, const char *txt, size_t len) -{ - struct hostapd_data *hapd = ctx; - char *format, *module_str; - int maxlen; - int conf_syslog_level, conf_stdout_level; - unsigned int conf_syslog, conf_stdout; - - maxlen = len + 100; - format = os_malloc(maxlen); - if (!format) - return; - - if (hapd && hapd->conf) { - conf_syslog_level = hapd->conf->logger_syslog_level; - conf_stdout_level = hapd->conf->logger_stdout_level; - conf_syslog = hapd->conf->logger_syslog; - conf_stdout = hapd->conf->logger_stdout; - } else { - conf_syslog_level = conf_stdout_level = 0; - conf_syslog = conf_stdout = (unsigned int) -1; - } - - switch (module) { - case HOSTAPD_MODULE_IEEE80211: - module_str = "IEEE 802.11"; - break; - case HOSTAPD_MODULE_IEEE8021X: - module_str = "IEEE 802.1X"; - break; - case HOSTAPD_MODULE_RADIUS: - module_str = "RADIUS"; - break; - case HOSTAPD_MODULE_WPA: - module_str = "WPA"; - break; - case HOSTAPD_MODULE_DRIVER: - module_str = "DRIVER"; - break; - case HOSTAPD_MODULE_IAPP: - module_str = "IAPP"; - break; - case HOSTAPD_MODULE_MLME: - module_str = "MLME"; - break; - default: - module_str = NULL; - break; - } - - if (hapd && hapd->conf && addr) - os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s", - hapd->conf->iface, MAC2STR(addr), - module_str ? " " : "", module_str, txt); - else if (hapd && hapd->conf) - os_snprintf(format, maxlen, "%s:%s%s %s", - hapd->conf->iface, module_str ? " " : "", - module_str, txt); - else if (addr) - os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s", - MAC2STR(addr), module_str ? " " : "", - module_str, txt); - else - os_snprintf(format, maxlen, "%s%s%s", - module_str, module_str ? ": " : "", txt); - - if ((conf_stdout & module) && level >= conf_stdout_level) { - wpa_debug_print_timestamp(); - wpa_printf(MSG_INFO, "%s", format); - } - -#ifndef CONFIG_NATIVE_WINDOWS - if ((conf_syslog & module) && level >= conf_syslog_level) { - int priority; - switch (level) { - case HOSTAPD_LEVEL_DEBUG_VERBOSE: - case HOSTAPD_LEVEL_DEBUG: - priority = LOG_DEBUG; - break; - case HOSTAPD_LEVEL_INFO: - priority = LOG_INFO; - break; - case HOSTAPD_LEVEL_NOTICE: - priority = LOG_NOTICE; - break; - case HOSTAPD_LEVEL_WARNING: - priority = LOG_WARNING; - break; - default: - priority = LOG_INFO; - break; - } - syslog(priority, "%s", format); - } -#endif /* CONFIG_NATIVE_WINDOWS */ - - os_free(format); -} -#endif /* CONFIG_NO_HOSTAPD_LOGGER */ - - -/** - * hostapd_driver_init - Preparate driver interface - */ -static int hostapd_driver_init(struct hostapd_iface *iface) -{ - struct wpa_init_params params; - size_t i; - struct hostapd_data *hapd = iface->bss[0]; - struct hostapd_bss_config *conf = hapd->conf; - u8 *b = conf->bssid; - struct wpa_driver_capa capa; - - if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) { - wpa_printf(MSG_ERROR, "No hostapd driver wrapper available"); - return -1; - } - - /* Initialize the driver interface */ - if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5])) - b = NULL; - - os_memset(¶ms, 0, sizeof(params)); - for (i = 0; wpa_drivers[i]; i++) { - if (wpa_drivers[i] != hapd->driver) - continue; - - if (global.drv_priv[i] == NULL && - wpa_drivers[i]->global_init) { - global.drv_priv[i] = wpa_drivers[i]->global_init(); - if (global.drv_priv[i] == NULL) { - wpa_printf(MSG_ERROR, "Failed to initialize " - "driver '%s'", - wpa_drivers[i]->name); - return -1; - } - } - - params.global_priv = global.drv_priv[i]; - break; - } - params.bssid = b; - params.ifname = hapd->conf->iface; - params.ssid = hapd->conf->ssid.ssid; - params.ssid_len = hapd->conf->ssid.ssid_len; - params.test_socket = hapd->conf->test_socket; - params.use_pae_group_addr = hapd->conf->use_pae_group_addr; - - params.num_bridge = hapd->iface->num_bss; - params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *)); - if (params.bridge == NULL) - return -1; - for (i = 0; i < hapd->iface->num_bss; i++) { - struct hostapd_data *bss = hapd->iface->bss[i]; - if (bss->conf->bridge[0]) - params.bridge[i] = bss->conf->bridge; - } - - params.own_addr = hapd->own_addr; - - hapd->drv_priv = hapd->driver->hapd_init(hapd, ¶ms); - os_free(params.bridge); - if (hapd->drv_priv == NULL) { - wpa_printf(MSG_ERROR, "%s driver initialization failed.", - hapd->driver->name); - hapd->driver = NULL; - return -1; - } - - if (hapd->driver->get_capa && - hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) { - iface->drv_flags = capa.flags; - iface->probe_resp_offloads = capa.probe_resp_offloads; - iface->extended_capa = capa.extended_capa; - iface->extended_capa_mask = capa.extended_capa_mask; - iface->extended_capa_len = capa.extended_capa_len; - iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs; - } - - return 0; -} - - -/** - * hostapd_interface_init - Read configuration file and init BSS data - * - * This function is used to parse configuration file for a full interface (one - * or more BSSes sharing the same radio) and allocate memory for the BSS - * interfaces. No actiual driver operations are started. - */ -static struct hostapd_iface * -hostapd_interface_init(struct hapd_interfaces *interfaces, - const char *config_fname, int debug) -{ - struct hostapd_iface *iface; - int k; - - wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname); - iface = hostapd_init(interfaces, config_fname); - if (!iface) - return NULL; - iface->interfaces = interfaces; - - for (k = 0; k < debug; k++) { - if (iface->bss[0]->conf->logger_stdout_level > 0) - iface->bss[0]->conf->logger_stdout_level--; - } - - if (iface->conf->bss[0]->iface[0] == '\0' && - !hostapd_drv_none(iface->bss[0])) { - wpa_printf(MSG_ERROR, "Interface name not specified in %s", - config_fname); - hostapd_interface_deinit_free(iface); - return NULL; - } - - return iface; -} - - -/** - * handle_term - SIGINT and SIGTERM handler to terminate hostapd process - */ -static void handle_term(int sig, void *signal_ctx) -{ - wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig); - eloop_terminate(); -} - - -#ifndef CONFIG_NATIVE_WINDOWS - -static int handle_reload_iface(struct hostapd_iface *iface, void *ctx) -{ - if (hostapd_reload_config(iface) < 0) { - wpa_printf(MSG_WARNING, "Failed to read new configuration " - "file - continuing with old."); - } - return 0; -} - - -/** - * handle_reload - SIGHUP handler to reload configuration - */ -static void handle_reload(int sig, void *signal_ctx) -{ - struct hapd_interfaces *interfaces = signal_ctx; - wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration", - sig); - hostapd_for_each_interface(interfaces, handle_reload_iface, NULL); -} - - -static void handle_dump_state(int sig, void *signal_ctx) -{ - /* Not used anymore - ignore signal */ -} -#endif /* CONFIG_NATIVE_WINDOWS */ - - -static int hostapd_global_init(struct hapd_interfaces *interfaces, - const char *entropy_file) -{ - int i; - - os_memset(&global, 0, sizeof(global)); - - hostapd_logger_register_cb(hostapd_logger_cb); - - if (eap_server_register_methods()) { - wpa_printf(MSG_ERROR, "Failed to register EAP methods"); - return -1; - } - - if (eloop_init()) { - wpa_printf(MSG_ERROR, "Failed to initialize event loop"); - return -1; - } - - random_init(entropy_file); - -#ifndef CONFIG_NATIVE_WINDOWS - eloop_register_signal(SIGHUP, handle_reload, interfaces); - eloop_register_signal(SIGUSR1, handle_dump_state, interfaces); -#endif /* CONFIG_NATIVE_WINDOWS */ - eloop_register_signal_terminate(handle_term, interfaces); - -#ifndef CONFIG_NATIVE_WINDOWS - openlog("hostapd", 0, LOG_DAEMON); -#endif /* CONFIG_NATIVE_WINDOWS */ - - for (i = 0; wpa_drivers[i]; i++) - global.drv_count++; - if (global.drv_count == 0) { - wpa_printf(MSG_ERROR, "No drivers enabled"); - return -1; - } - global.drv_priv = os_calloc(global.drv_count, sizeof(void *)); - if (global.drv_priv == NULL) - return -1; - - return 0; -} - - -static void hostapd_global_deinit(const char *pid_file) -{ - int i; - - for (i = 0; wpa_drivers[i] && global.drv_priv; i++) { - if (!global.drv_priv[i]) - continue; - wpa_drivers[i]->global_deinit(global.drv_priv[i]); - } - os_free(global.drv_priv); - global.drv_priv = NULL; - -#ifdef EAP_SERVER_TNC - tncs_global_deinit(); -#endif /* EAP_SERVER_TNC */ - - random_deinit(); - - eloop_destroy(); - -#ifndef CONFIG_NATIVE_WINDOWS - closelog(); -#endif /* CONFIG_NATIVE_WINDOWS */ - - eap_server_unregister_methods(); - - os_daemonize_terminate(pid_file); -} - - -static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, - const char *pid_file) -{ -#ifdef EAP_SERVER_TNC - int tnc = 0; - size_t i, k; - - for (i = 0; !tnc && i < ifaces->count; i++) { - for (k = 0; k < ifaces->iface[i]->num_bss; k++) { - if (ifaces->iface[i]->bss[0]->conf->tnc) { - tnc++; - break; - } - } - } - - if (tnc && tncs_global_init() < 0) { - wpa_printf(MSG_ERROR, "Failed to initialize TNCS"); - return -1; - } -#endif /* EAP_SERVER_TNC */ - - if (daemonize && os_daemonize(pid_file)) { - perror("daemon"); - return -1; - } - - eloop_run(); - - return 0; -} - - -static void show_version(void) -{ - fprintf(stderr, - "hostapd v" VERSION_STR "\n" - "User space daemon for IEEE 802.11 AP management,\n" - "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" - "Copyright (c) 2002-2014, Jouni Malinen " - "and contributors\n"); -} - - -static void usage(void) -{ - show_version(); - fprintf(stderr, - "\n" - "usage: hostapd [-hdBKtv] [-P ] [-e ] " - "\\\n" - " [-g ] [-G ] \\\n" - " \n" - "\n" - "options:\n" - " -h show this usage\n" - " -d show more debug messages (-dd for even more)\n" - " -B run daemon in the background\n" - " -e entropy file\n" - " -g global control interface path\n" - " -G group for control interfaces\n" - " -P PID file\n" - " -K include key data in debug messages\n" -#ifdef CONFIG_DEBUG_FILE - " -f log output to debug file instead of stdout\n" -#endif /* CONFIG_DEBUG_FILE */ -#ifdef CONFIG_DEBUG_LINUX_TRACING - " -T = record to Linux tracing in addition to logging\n" - " (records all messages regardless of debug verbosity)\n" -#endif /* CONFIG_DEBUG_LINUX_TRACING */ - " -t include timestamps in some debug messages\n" - " -v show hostapd version\n"); - - exit(1); -} - - -static const char * hostapd_msg_ifname_cb(void *ctx) -{ - struct hostapd_data *hapd = ctx; - if (hapd && hapd->iconf && hapd->iconf->bss && - hapd->iconf->num_bss > 0 && hapd->iconf->bss[0]) - return hapd->iconf->bss[0]->iface; - return NULL; -} - - -static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces, - const char *path) -{ - char *pos; - os_free(interfaces->global_iface_path); - interfaces->global_iface_path = os_strdup(path); - if (interfaces->global_iface_path == NULL) - return -1; - pos = os_strrchr(interfaces->global_iface_path, '/'); - if (pos == NULL) { - wpa_printf(MSG_ERROR, "No '/' in the global control interface " - "file"); - os_free(interfaces->global_iface_path); - interfaces->global_iface_path = NULL; - return -1; - } - - *pos = '\0'; - interfaces->global_iface_name = pos + 1; - - return 0; -} - - -static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces, - const char *group) -{ -#ifndef CONFIG_NATIVE_WINDOWS - struct group *grp; - grp = getgrnam(group); - if (grp == NULL) { - wpa_printf(MSG_ERROR, "Unknown group '%s'", group); - return -1; - } - interfaces->ctrl_iface_group = grp->gr_gid; -#endif /* CONFIG_NATIVE_WINDOWS */ - return 0; -} - - -int main(int argc, char *argv[]) -{ - struct hapd_interfaces interfaces; - int ret = 1; - size_t i, j; - int c, debug = 0, daemonize = 0; - char *pid_file = NULL; - const char *log_file = NULL; - const char *entropy_file = NULL; - char **bss_config = NULL, **tmp_bss; - size_t num_bss_configs = 0; -#ifdef CONFIG_DEBUG_LINUX_TRACING - int enable_trace_dbg = 0; -#endif /* CONFIG_DEBUG_LINUX_TRACING */ - - if (os_program_init()) - return -1; - - os_memset(&interfaces, 0, sizeof(interfaces)); - interfaces.reload_config = hostapd_reload_config; - interfaces.config_read_cb = hostapd_config_read; - interfaces.for_each_interface = hostapd_for_each_interface; - interfaces.ctrl_iface_init = hostapd_ctrl_iface_init; - interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit; - interfaces.driver_init = hostapd_driver_init; - interfaces.global_iface_path = NULL; - interfaces.global_iface_name = NULL; - interfaces.global_ctrl_sock = -1; - - for (;;) { - c = getopt(argc, argv, "b:Bde:f:hKP:Ttvg:G:"); - if (c < 0) - break; - switch (c) { - case 'h': - usage(); - break; - case 'd': - debug++; - if (wpa_debug_level > 0) - wpa_debug_level--; - break; - case 'B': - daemonize++; - break; - case 'e': - entropy_file = optarg; - break; - case 'f': - log_file = optarg; - break; - case 'K': - wpa_debug_show_keys++; - break; - case 'P': - os_free(pid_file); - pid_file = os_rel2abs_path(optarg); - break; - case 't': - wpa_debug_timestamp++; - break; -#ifdef CONFIG_DEBUG_LINUX_TRACING - case 'T': - enable_trace_dbg = 1; - break; -#endif /* CONFIG_DEBUG_LINUX_TRACING */ - case 'v': - show_version(); - exit(1); - break; - case 'g': - if (hostapd_get_global_ctrl_iface(&interfaces, optarg)) - return -1; - break; - case 'G': - if (hostapd_get_ctrl_iface_group(&interfaces, optarg)) - return -1; - break; - case 'b': - tmp_bss = os_realloc_array(bss_config, - num_bss_configs + 1, - sizeof(char *)); - if (tmp_bss == NULL) - goto out; - bss_config = tmp_bss; - bss_config[num_bss_configs++] = optarg; - break; - default: - usage(); - break; - } - } - - if (optind == argc && interfaces.global_iface_path == NULL && - num_bss_configs == 0) - usage(); - - wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb); - - if (log_file) - wpa_debug_open_file(log_file); -#ifdef CONFIG_DEBUG_LINUX_TRACING - if (enable_trace_dbg) { - int tret = wpa_debug_open_linux_tracing(); - if (tret) { - wpa_printf(MSG_ERROR, "Failed to enable trace logging"); - return -1; - } - } -#endif /* CONFIG_DEBUG_LINUX_TRACING */ - - interfaces.count = argc - optind; - if (interfaces.count || num_bss_configs) { - interfaces.iface = os_calloc(interfaces.count + num_bss_configs, - sizeof(struct hostapd_iface *)); - if (interfaces.iface == NULL) { - wpa_printf(MSG_ERROR, "malloc failed"); - return -1; - } - } - - if (hostapd_global_init(&interfaces, entropy_file)) { - wpa_printf(MSG_ERROR, "Failed to initilize global context"); - return -1; - } - - /* Allocate and parse configuration for full interface files */ - for (i = 0; i < interfaces.count; i++) { - interfaces.iface[i] = hostapd_interface_init(&interfaces, - argv[optind + i], - debug); - if (!interfaces.iface[i]) { - wpa_printf(MSG_ERROR, "Failed to initialize interface"); - goto out; - } - } - - /* Allocate and parse configuration for per-BSS files */ - for (i = 0; i < num_bss_configs; i++) { - struct hostapd_iface *iface; - char *fname; - - wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]); - fname = os_strchr(bss_config[i], ':'); - if (fname == NULL) { - wpa_printf(MSG_ERROR, - "Invalid BSS config identifier '%s'", - bss_config[i]); - goto out; - } - *fname++ = '\0'; - iface = hostapd_interface_init_bss(&interfaces, bss_config[i], - fname, debug); - if (iface == NULL) - goto out; - for (j = 0; j < interfaces.count; j++) { - if (interfaces.iface[j] == iface) - break; - } - if (j == interfaces.count) { - struct hostapd_iface **tmp; - tmp = os_realloc_array(interfaces.iface, - interfaces.count + 1, - sizeof(struct hostapd_iface *)); - if (tmp == NULL) { - hostapd_interface_deinit_free(iface); - goto out; - } - interfaces.iface = tmp; - interfaces.iface[interfaces.count++] = iface; - } - } - - /* - * Enable configured interfaces. Depending on channel configuration, - * this may complete full initialization before returning or use a - * callback mechanism to complete setup in case of operations like HT - * co-ex scans, ACS, or DFS are needed to determine channel parameters. - * In such case, the interface will be enabled from eloop context within - * hostapd_global_run(). - */ - interfaces.terminate_on_error = interfaces.count; - for (i = 0; i < interfaces.count; i++) { - if (hostapd_driver_init(interfaces.iface[i]) || - hostapd_setup_interface(interfaces.iface[i])) - goto out; - } - - hostapd_global_ctrl_iface_init(&interfaces); - - if (hostapd_global_run(&interfaces, daemonize, pid_file)) { - wpa_printf(MSG_ERROR, "Failed to start eloop"); - goto out; - } - - ret = 0; - - out: - hostapd_global_ctrl_iface_deinit(&interfaces); - /* Deinitialize all interfaces */ - for (i = 0; i < interfaces.count; i++) - hostapd_interface_deinit_free(interfaces.iface[i]); - os_free(interfaces.iface); - - hostapd_global_deinit(pid_file); - os_free(pid_file); - - if (log_file) - wpa_debug_close_file(); - wpa_debug_close_linux_tracing(); - - os_free(bss_config); - - os_program_deinit(); - - return ret; -} diff --git a/contrib/hostapd/patches/openssl-0.9.8-tls-extensions.patch b/contrib/hostapd/patches/openssl-0.9.8-tls-extensions.patch deleted file mode 100644 index 44490cca22..0000000000 --- a/contrib/hostapd/patches/openssl-0.9.8-tls-extensions.patch +++ /dev/null @@ -1,429 +0,0 @@ -This patch is adding support for TLS hello extensions and externally -generated pre-shared key material to OpenSSL 0.9.8. This is -based on the patch from Alexey Kobozev -(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). - - - -diff -uprN openssl-0.9.8.orig/include/openssl/ssl.h openssl-0.9.8/include/openssl/ssl.h ---- openssl-0.9.8.orig/include/openssl/ssl.h 2005-06-10 12:51:16.000000000 -0700 -+++ openssl-0.9.8/include/openssl/ssl.h 2005-07-19 20:02:15.000000000 -0700 -@@ -340,6 +340,7 @@ extern "C" { - * 'struct ssl_st *' function parameters used to prototype callbacks - * in SSL_CTX. */ - typedef struct ssl_st *ssl_crock_st; -+typedef struct tls_extension_st TLS_EXTENSION; - - /* used to hold info on the particular ciphers used */ - typedef struct ssl_cipher_st -@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER) - typedef struct ssl_st SSL; - typedef struct ssl_ctx_st SSL_CTX; - -+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); -+ - /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ - typedef struct ssl_method_st - { -@@ -968,6 +971,15 @@ struct ssl_st - int first_packet; - int client_version; /* what was passed, used for - * SSLv3/TLS rollback check */ -+ -+ /* TLS externsions */ -+ TLS_EXTENSION *tls_extension; -+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg); -+ void *tls_extension_cb_arg; -+ -+ /* TLS pre-shared secret session resumption */ -+ tls_session_secret_cb_fn tls_session_secret_cb; -+ void *tls_session_secret_cb_arg; - }; - - #ifdef __cplusplus -@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v - int SSL_COMP_add_compression_method(int id,void *cm); - #endif - -+/* TLS extensions functions */ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); -+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg); -+ -+/* Pre-shared secret session resumption functions */ -+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); -+ - /* BEGIN ERROR CODES */ - /* The following lines are auto generated by the script mkerr.pl. Any changes - * made after this point may be overwritten when the script is next run. -@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void); - #define SSL_F_TLS1_ENC 210 - #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 - #define SSL_F_WRITE_PENDING 212 -+#define SSL_F_SSL_SET_HELLO_EXTENSION 213 - - /* Reason codes. */ - #define SSL_R_APP_DATA_IN_HANDSHAKE 100 -diff -uprN openssl-0.9.8.orig/include/openssl/tls1.h openssl-0.9.8/include/openssl/tls1.h ---- openssl-0.9.8.orig/include/openssl/tls1.h 2003-07-22 05:34:21.000000000 -0700 -+++ openssl-0.9.8/include/openssl/tls1.h 2005-07-19 20:02:15.000000000 -0700 -@@ -282,6 +282,14 @@ extern "C" { - #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ - #endif - -+/* TLS extension struct */ -+struct tls_extension_st -+{ -+ unsigned short type; -+ unsigned short length; -+ void *data; -+}; -+ - #ifdef __cplusplus - } - #endif -diff -uprN openssl-0.9.8.orig/ssl/Makefile openssl-0.9.8/ssl/Makefile ---- openssl-0.9.8.orig/ssl/Makefile 2005-05-30 16:20:30.000000000 -0700 -+++ openssl-0.9.8/ssl/Makefile 2005-07-19 20:02:15.000000000 -0700 -@@ -24,7 +24,7 @@ LIBSRC= \ - s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \ - s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \ - s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \ -- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \ -+ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \ - d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \ - d1_both.c d1_enc.c \ - ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \ -@@ -35,7 +35,7 @@ LIBOBJ= \ - s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \ - s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \ - s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \ -- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \ -+ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \ - d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \ - d1_both.o d1_enc.o \ - ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \ -@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h .. - t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h - t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h - t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c -+t1_ext.o: t1_ext.c ssl_locl.h -diff -uprN openssl-0.9.8.orig/ssl/s3_clnt.c openssl-0.9.8/ssl/s3_clnt.c ---- openssl-0.9.8.orig/ssl/s3_clnt.c 2005-05-16 03:11:03.000000000 -0700 -+++ openssl-0.9.8/ssl/s3_clnt.c 2005-07-19 20:02:15.000000000 -0700 -@@ -606,6 +606,20 @@ int ssl3_client_hello(SSL *s) - } - *(p++)=0; /* Add the NULL method */ - -+ /* send client hello extensions if any */ -+ if (s->version >= TLS1_VERSION && s->tls_extension) -+ { -+ // set the total extensions length -+ s2n(s->tls_extension->length + 4, p); -+ -+ // put the extensions with type and length -+ s2n(s->tls_extension->type, p); -+ s2n(s->tls_extension->length, p); -+ -+ memcpy(p, s->tls_extension->data, s->tls_extension->length); -+ p+=s->tls_extension->length; -+ } -+ - l=(p-d); - d=buf; - *(d++)=SSL3_MT_CLIENT_HELLO; -@@ -628,7 +642,7 @@ int ssl3_get_server_hello(SSL *s) - STACK_OF(SSL_CIPHER) *sk; - SSL_CIPHER *c; - unsigned char *p,*d; -- int i,al,ok; -+ int i,al,ok,pre_shared; - unsigned int j; - long n; - SSL_COMP *comp; -@@ -693,7 +707,24 @@ int ssl3_get_server_hello(SSL *s) - goto f_err; - } - -- if (j != 0 && j == s->session->session_id_length -+ /* check if we want to resume the session based on external pre-shared secret */ -+ pre_shared = 0; -+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ NULL, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->hit=1; -+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j); -+ s->session->session_id_length = j; -+ memcpy(s->session->session_id, p, j); -+ pre_shared = 1; -+ } -+ } -+ -+ if ((pre_shared || j != 0) && j == s->session->session_id_length - && memcmp(p,s->session->session_id,j) == 0) - { - if(s->sid_ctx_length != s->session->sid_ctx_length -diff -uprN openssl-0.9.8.orig/ssl/s3_srvr.c openssl-0.9.8/ssl/s3_srvr.c ---- openssl-0.9.8.orig/ssl/s3_srvr.c 2005-05-22 17:32:55.000000000 -0700 -+++ openssl-0.9.8/ssl/s3_srvr.c 2005-07-19 20:02:15.000000000 -0700 -@@ -955,6 +955,75 @@ int ssl3_get_client_hello(SSL *s) - } - #endif - -+ /* Check for TLS client hello extension here */ -+ if (p < (d+n) && s->version >= TLS1_VERSION) -+ { -+ if (s->tls_extension_cb) -+ { -+ TLS_EXTENSION tls_ext; -+ unsigned short ext_total_len; -+ -+ n2s(p, ext_total_len); -+ n2s(p, tls_ext.type); -+ n2s(p, tls_ext.length); -+ -+ // sanity check in TLS extension len -+ if (tls_ext.length > (d+n) - p) -+ { -+ // just cut the lenth to packet border -+ tls_ext.length = (d+n) - p; -+ } -+ -+ tls_ext.data = p; -+ -+ // returns an alert code or 0 -+ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg); -+ if (al != 0) -+ { -+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR); -+ goto f_err; -+ } -+ } -+ } -+ -+ /* Check if we want to use external pre-shared secret for this handshake */ -+ /* for not reused session only */ -+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->hit=1; -+ s->session->ciphers=ciphers; -+ s->session->verify_result=X509_V_OK; -+ -+ ciphers=NULL; -+ -+ /* check if some cipher was preferred by call back */ -+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); -+ if (pref_cipher == NULL) -+ { -+ al=SSL_AD_HANDSHAKE_FAILURE; -+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); -+ goto f_err; -+ } -+ -+ s->session->cipher=pref_cipher; -+ -+ if (s->cipher_list) -+ sk_SSL_CIPHER_free(s->cipher_list); -+ -+ if (s->cipher_list_by_id) -+ sk_SSL_CIPHER_free(s->cipher_list_by_id); -+ -+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); -+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); -+ } -+ } -+ - /* Given s->session->ciphers and SSL_get_ciphers, we must - * pick a cipher */ - -diff -uprN openssl-0.9.8.orig/ssl/ssl_err.c openssl-0.9.8/ssl/ssl_err.c ---- openssl-0.9.8.orig/ssl/ssl_err.c 2005-06-10 12:51:16.000000000 -0700 -+++ openssl-0.9.8/ssl/ssl_err.c 2005-07-19 20:02:15.000000000 -0700 -@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]= - {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, - {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, - {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, -+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"}, - {0,NULL} - }; - -diff -uprN openssl-0.9.8.orig/ssl/ssl.h openssl-0.9.8/ssl/ssl.h ---- openssl-0.9.8.orig/ssl/ssl.h 2005-06-10 12:51:16.000000000 -0700 -+++ openssl-0.9.8/ssl/ssl.h 2005-07-19 20:02:15.000000000 -0700 -@@ -340,6 +340,7 @@ extern "C" { - * 'struct ssl_st *' function parameters used to prototype callbacks - * in SSL_CTX. */ - typedef struct ssl_st *ssl_crock_st; -+typedef struct tls_extension_st TLS_EXTENSION; - - /* used to hold info on the particular ciphers used */ - typedef struct ssl_cipher_st -@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER) - typedef struct ssl_st SSL; - typedef struct ssl_ctx_st SSL_CTX; - -+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); -+ - /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ - typedef struct ssl_method_st - { -@@ -968,6 +971,15 @@ struct ssl_st - int first_packet; - int client_version; /* what was passed, used for - * SSLv3/TLS rollback check */ -+ -+ /* TLS externsions */ -+ TLS_EXTENSION *tls_extension; -+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg); -+ void *tls_extension_cb_arg; -+ -+ /* TLS pre-shared secret session resumption */ -+ tls_session_secret_cb_fn tls_session_secret_cb; -+ void *tls_session_secret_cb_arg; - }; - - #ifdef __cplusplus -@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v - int SSL_COMP_add_compression_method(int id,void *cm); - #endif - -+/* TLS extensions functions */ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); -+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg); -+ -+/* Pre-shared secret session resumption functions */ -+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); -+ - /* BEGIN ERROR CODES */ - /* The following lines are auto generated by the script mkerr.pl. Any changes - * made after this point may be overwritten when the script is next run. -@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void); - #define SSL_F_TLS1_ENC 210 - #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 - #define SSL_F_WRITE_PENDING 212 -+#define SSL_F_SSL_SET_HELLO_EXTENSION 213 - - /* Reason codes. */ - #define SSL_R_APP_DATA_IN_HANDSHAKE 100 -diff -uprN openssl-0.9.8.orig/ssl/ssl_sess.c openssl-0.9.8/ssl/ssl_sess.c ---- openssl-0.9.8.orig/ssl/ssl_sess.c 2005-04-29 13:10:06.000000000 -0700 -+++ openssl-0.9.8/ssl/ssl_sess.c 2005-07-19 20:02:15.000000000 -0700 -@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX * - return(s->session_timeout); - } - -+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, -+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) -+{ -+ if (s == NULL) return(0); -+ s->tls_session_secret_cb = tls_session_secret_cb; -+ s->tls_session_secret_cb_arg = arg; -+ return(1); -+} -+ - typedef struct timeout_param_st - { - SSL_CTX *ctx; -diff -uprN openssl-0.9.8.orig/ssl/t1_ext.c openssl-0.9.8/ssl/t1_ext.c ---- openssl-0.9.8.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800 -+++ openssl-0.9.8/ssl/t1_ext.c 2005-07-19 20:03:29.000000000 -0700 -@@ -0,0 +1,48 @@ -+ -+#include -+#include "ssl_locl.h" -+ -+ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len) -+{ -+ if(s->version >= TLS1_VERSION) -+ { -+ if(s->tls_extension) -+ { -+ OPENSSL_free(s->tls_extension); -+ s->tls_extension = NULL; -+ } -+ -+ if(ext_data) -+ { -+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len); -+ if(!s->tls_extension) -+ { -+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE); -+ return 0; -+ } -+ -+ s->tls_extension->type = ext_type; -+ s->tls_extension->length = ext_len; -+ s->tls_extension->data = s->tls_extension + 1; -+ memcpy(s->tls_extension->data, ext_data, ext_len); -+ } -+ -+ return 1; -+ } -+ -+ return 0; -+} -+ -+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg) -+{ -+ if(s->version >= TLS1_VERSION) -+ { -+ s->tls_extension_cb = cb; -+ s->tls_extension_cb_arg = arg; -+ -+ return 1; -+ } -+ -+ return 0; -+} -diff -uprN openssl-0.9.8.orig/ssl/t1_lib.c openssl-0.9.8/ssl/t1_lib.c ---- openssl-0.9.8.orig/ssl/t1_lib.c 2005-04-26 09:02:40.000000000 -0700 -+++ openssl-0.9.8/ssl/t1_lib.c 2005-07-19 20:02:15.000000000 -0700 -@@ -131,6 +131,10 @@ int tls1_new(SSL *s) - - void tls1_free(SSL *s) - { -+ if(s->tls_extension) -+ { -+ OPENSSL_free(s->tls_extension); -+ } - ssl3_free(s); - } - -diff -uprN openssl-0.9.8.orig/ssl/tls1.h openssl-0.9.8/ssl/tls1.h ---- openssl-0.9.8.orig/ssl/tls1.h 2003-07-22 05:34:21.000000000 -0700 -+++ openssl-0.9.8/ssl/tls1.h 2005-07-19 20:02:15.000000000 -0700 -@@ -282,6 +282,14 @@ extern "C" { - #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ - #endif - -+/* TLS extension struct */ -+struct tls_extension_st -+{ -+ unsigned short type; -+ unsigned short length; -+ void *data; -+}; -+ - #ifdef __cplusplus - } - #endif -diff -uprN openssl-0.9.8.orig/util/ssleay.num openssl-0.9.8/util/ssleay.num ---- openssl-0.9.8.orig/util/ssleay.num 2005-05-08 17:22:02.000000000 -0700 -+++ openssl-0.9.8/util/ssleay.num 2005-07-19 20:02:15.000000000 -0700 -@@ -226,3 +226,6 @@ DTLSv1_server_method - SSL_COMP_get_compression_methods 276 EXIST:!VMS:FUNCTION:COMP - SSL_COMP_get_compress_methods 276 EXIST:VMS:FUNCTION:COMP - SSL_SESSION_get_id 277 EXIST::FUNCTION: -+SSL_set_hello_extension 278 EXIST::FUNCTION: -+SSL_set_hello_extension_cb 279 EXIST::FUNCTION: -+SSL_set_session_secret_cb 280 EXIST::FUNCTION: diff --git a/contrib/hostapd/patches/openssl-0.9.8d-tls-extensions.patch b/contrib/hostapd/patches/openssl-0.9.8d-tls-extensions.patch deleted file mode 100644 index eec6db8a13..0000000000 --- a/contrib/hostapd/patches/openssl-0.9.8d-tls-extensions.patch +++ /dev/null @@ -1,429 +0,0 @@ -This patch is adding support for TLS hello extensions and externally -generated pre-shared key material to OpenSSL 0.9.8d. This is -based on the patch from Alexey Kobozev -(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). - - - -diff -uprN openssl-0.9.8d.orig/include/openssl/ssl.h openssl-0.9.8d/include/openssl/ssl.h ---- openssl-0.9.8d.orig/include/openssl/ssl.h 2006-06-14 06:52:49.000000000 -0700 -+++ openssl-0.9.8d/include/openssl/ssl.h 2006-12-10 08:20:02.000000000 -0800 -@@ -345,6 +345,7 @@ extern "C" { - * 'struct ssl_st *' function parameters used to prototype callbacks - * in SSL_CTX. */ - typedef struct ssl_st *ssl_crock_st; -+typedef struct tls_extension_st TLS_EXTENSION; - - /* used to hold info on the particular ciphers used */ - typedef struct ssl_cipher_st -@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER) - typedef struct ssl_st SSL; - typedef struct ssl_ctx_st SSL_CTX; - -+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); -+ - /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ - typedef struct ssl_method_st - { -@@ -973,6 +976,15 @@ struct ssl_st - int first_packet; - int client_version; /* what was passed, used for - * SSLv3/TLS rollback check */ -+ -+ /* TLS externsions */ -+ TLS_EXTENSION *tls_extension; -+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg); -+ void *tls_extension_cb_arg; -+ -+ /* TLS pre-shared secret session resumption */ -+ tls_session_secret_cb_fn tls_session_secret_cb; -+ void *tls_session_secret_cb_arg; - }; - - #ifdef __cplusplus -@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v - int SSL_COMP_add_compression_method(int id,void *cm); - #endif - -+/* TLS extensions functions */ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); -+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg); -+ -+/* Pre-shared secret session resumption functions */ -+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); -+ - /* BEGIN ERROR CODES */ - /* The following lines are auto generated by the script mkerr.pl. Any changes - * made after this point may be overwritten when the script is next run. -@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void); - #define SSL_F_TLS1_ENC 210 - #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 - #define SSL_F_WRITE_PENDING 212 -+#define SSL_F_SSL_SET_HELLO_EXTENSION 213 - - /* Reason codes. */ - #define SSL_R_APP_DATA_IN_HANDSHAKE 100 -diff -uprN openssl-0.9.8d.orig/include/openssl/tls1.h openssl-0.9.8d/include/openssl/tls1.h ---- openssl-0.9.8d.orig/include/openssl/tls1.h 2006-06-14 10:52:01.000000000 -0700 -+++ openssl-0.9.8d/include/openssl/tls1.h 2006-12-10 08:20:02.000000000 -0800 -@@ -296,6 +296,14 @@ extern "C" { - #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ - #endif - -+/* TLS extension struct */ -+struct tls_extension_st -+{ -+ unsigned short type; -+ unsigned short length; -+ void *data; -+}; -+ - #ifdef __cplusplus - } - #endif -diff -uprN openssl-0.9.8d.orig/ssl/Makefile openssl-0.9.8d/ssl/Makefile ---- openssl-0.9.8d.orig/ssl/Makefile 2006-02-03 17:49:35.000000000 -0800 -+++ openssl-0.9.8d/ssl/Makefile 2006-12-10 08:20:02.000000000 -0800 -@@ -24,7 +24,7 @@ LIBSRC= \ - s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \ - s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \ - s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \ -- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \ -+ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \ - d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \ - d1_both.c d1_enc.c \ - ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \ -@@ -35,7 +35,7 @@ LIBOBJ= \ - s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \ - s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \ - s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \ -- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \ -+ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \ - d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \ - d1_both.o d1_enc.o \ - ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \ -@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h .. - t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h - t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h - t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c -+t1_ext.o: t1_ext.c ssl_locl.h -diff -uprN openssl-0.9.8d.orig/ssl/s3_clnt.c openssl-0.9.8d/ssl/s3_clnt.c ---- openssl-0.9.8d.orig/ssl/s3_clnt.c 2005-12-12 23:41:46.000000000 -0800 -+++ openssl-0.9.8d/ssl/s3_clnt.c 2006-12-10 08:20:02.000000000 -0800 -@@ -601,6 +601,20 @@ int ssl3_client_hello(SSL *s) - #endif - *(p++)=0; /* Add the NULL method */ - -+ /* send client hello extensions if any */ -+ if (s->version >= TLS1_VERSION && s->tls_extension) -+ { -+ // set the total extensions length -+ s2n(s->tls_extension->length + 4, p); -+ -+ // put the extensions with type and length -+ s2n(s->tls_extension->type, p); -+ s2n(s->tls_extension->length, p); -+ -+ memcpy(p, s->tls_extension->data, s->tls_extension->length); -+ p+=s->tls_extension->length; -+ } -+ - l=(p-d); - d=buf; - *(d++)=SSL3_MT_CLIENT_HELLO; -@@ -623,7 +637,7 @@ int ssl3_get_server_hello(SSL *s) - STACK_OF(SSL_CIPHER) *sk; - SSL_CIPHER *c; - unsigned char *p,*d; -- int i,al,ok; -+ int i,al,ok,pre_shared; - unsigned int j; - long n; - #ifndef OPENSSL_NO_COMP -@@ -690,7 +704,24 @@ int ssl3_get_server_hello(SSL *s) - goto f_err; - } - -- if (j != 0 && j == s->session->session_id_length -+ /* check if we want to resume the session based on external pre-shared secret */ -+ pre_shared = 0; -+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ NULL, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->hit=1; -+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j); -+ s->session->session_id_length = j; -+ memcpy(s->session->session_id, p, j); -+ pre_shared = 1; -+ } -+ } -+ -+ if ((pre_shared || j != 0) && j == s->session->session_id_length - && memcmp(p,s->session->session_id,j) == 0) - { - if(s->sid_ctx_length != s->session->sid_ctx_length -diff -uprN openssl-0.9.8d.orig/ssl/s3_srvr.c openssl-0.9.8d/ssl/s3_srvr.c ---- openssl-0.9.8d.orig/ssl/s3_srvr.c 2006-09-28 04:29:03.000000000 -0700 -+++ openssl-0.9.8d/ssl/s3_srvr.c 2006-12-10 08:20:02.000000000 -0800 -@@ -943,6 +943,75 @@ int ssl3_get_client_hello(SSL *s) - } - #endif - -+ /* Check for TLS client hello extension here */ -+ if (p < (d+n) && s->version >= TLS1_VERSION) -+ { -+ if (s->tls_extension_cb) -+ { -+ TLS_EXTENSION tls_ext; -+ unsigned short ext_total_len; -+ -+ n2s(p, ext_total_len); -+ n2s(p, tls_ext.type); -+ n2s(p, tls_ext.length); -+ -+ // sanity check in TLS extension len -+ if (tls_ext.length > (d+n) - p) -+ { -+ // just cut the lenth to packet border -+ tls_ext.length = (d+n) - p; -+ } -+ -+ tls_ext.data = p; -+ -+ // returns an alert code or 0 -+ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg); -+ if (al != 0) -+ { -+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR); -+ goto f_err; -+ } -+ } -+ } -+ -+ /* Check if we want to use external pre-shared secret for this handshake */ -+ /* for not reused session only */ -+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->hit=1; -+ s->session->ciphers=ciphers; -+ s->session->verify_result=X509_V_OK; -+ -+ ciphers=NULL; -+ -+ /* check if some cipher was preferred by call back */ -+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); -+ if (pref_cipher == NULL) -+ { -+ al=SSL_AD_HANDSHAKE_FAILURE; -+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); -+ goto f_err; -+ } -+ -+ s->session->cipher=pref_cipher; -+ -+ if (s->cipher_list) -+ sk_SSL_CIPHER_free(s->cipher_list); -+ -+ if (s->cipher_list_by_id) -+ sk_SSL_CIPHER_free(s->cipher_list_by_id); -+ -+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); -+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); -+ } -+ } -+ - /* Given s->session->ciphers and SSL_get_ciphers, we must - * pick a cipher */ - -diff -uprN openssl-0.9.8d.orig/ssl/ssl.h openssl-0.9.8d/ssl/ssl.h ---- openssl-0.9.8d.orig/ssl/ssl.h 2006-06-14 06:52:49.000000000 -0700 -+++ openssl-0.9.8d/ssl/ssl.h 2006-12-10 08:20:02.000000000 -0800 -@@ -345,6 +345,7 @@ extern "C" { - * 'struct ssl_st *' function parameters used to prototype callbacks - * in SSL_CTX. */ - typedef struct ssl_st *ssl_crock_st; -+typedef struct tls_extension_st TLS_EXTENSION; - - /* used to hold info on the particular ciphers used */ - typedef struct ssl_cipher_st -@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER) - typedef struct ssl_st SSL; - typedef struct ssl_ctx_st SSL_CTX; - -+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); -+ - /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ - typedef struct ssl_method_st - { -@@ -973,6 +976,15 @@ struct ssl_st - int first_packet; - int client_version; /* what was passed, used for - * SSLv3/TLS rollback check */ -+ -+ /* TLS externsions */ -+ TLS_EXTENSION *tls_extension; -+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg); -+ void *tls_extension_cb_arg; -+ -+ /* TLS pre-shared secret session resumption */ -+ tls_session_secret_cb_fn tls_session_secret_cb; -+ void *tls_session_secret_cb_arg; - }; - - #ifdef __cplusplus -@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v - int SSL_COMP_add_compression_method(int id,void *cm); - #endif - -+/* TLS extensions functions */ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); -+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg); -+ -+/* Pre-shared secret session resumption functions */ -+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); -+ - /* BEGIN ERROR CODES */ - /* The following lines are auto generated by the script mkerr.pl. Any changes - * made after this point may be overwritten when the script is next run. -@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void); - #define SSL_F_TLS1_ENC 210 - #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 - #define SSL_F_WRITE_PENDING 212 -+#define SSL_F_SSL_SET_HELLO_EXTENSION 213 - - /* Reason codes. */ - #define SSL_R_APP_DATA_IN_HANDSHAKE 100 -diff -uprN openssl-0.9.8d.orig/ssl/ssl_err.c openssl-0.9.8d/ssl/ssl_err.c ---- openssl-0.9.8d.orig/ssl/ssl_err.c 2006-01-08 13:52:46.000000000 -0800 -+++ openssl-0.9.8d/ssl/ssl_err.c 2006-12-10 08:20:02.000000000 -0800 -@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]= - {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, - {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, - {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, -+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"}, - {0,NULL} - }; - -diff -uprN openssl-0.9.8d.orig/ssl/ssl_sess.c openssl-0.9.8d/ssl/ssl_sess.c ---- openssl-0.9.8d.orig/ssl/ssl_sess.c 2005-12-30 15:51:57.000000000 -0800 -+++ openssl-0.9.8d/ssl/ssl_sess.c 2006-12-10 08:20:02.000000000 -0800 -@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX * - return(s->session_timeout); - } - -+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, -+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) -+{ -+ if (s == NULL) return(0); -+ s->tls_session_secret_cb = tls_session_secret_cb; -+ s->tls_session_secret_cb_arg = arg; -+ return(1); -+} -+ - typedef struct timeout_param_st - { - SSL_CTX *ctx; -diff -uprN openssl-0.9.8d.orig/ssl/t1_ext.c openssl-0.9.8d/ssl/t1_ext.c ---- openssl-0.9.8d.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800 -+++ openssl-0.9.8d/ssl/t1_ext.c 2006-12-10 08:20:02.000000000 -0800 -@@ -0,0 +1,48 @@ -+ -+#include -+#include "ssl_locl.h" -+ -+ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len) -+{ -+ if(s->version >= TLS1_VERSION) -+ { -+ if(s->tls_extension) -+ { -+ OPENSSL_free(s->tls_extension); -+ s->tls_extension = NULL; -+ } -+ -+ if(ext_data) -+ { -+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len); -+ if(!s->tls_extension) -+ { -+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE); -+ return 0; -+ } -+ -+ s->tls_extension->type = ext_type; -+ s->tls_extension->length = ext_len; -+ s->tls_extension->data = s->tls_extension + 1; -+ memcpy(s->tls_extension->data, ext_data, ext_len); -+ } -+ -+ return 1; -+ } -+ -+ return 0; -+} -+ -+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg) -+{ -+ if(s->version >= TLS1_VERSION) -+ { -+ s->tls_extension_cb = cb; -+ s->tls_extension_cb_arg = arg; -+ -+ return 1; -+ } -+ -+ return 0; -+} -diff -uprN openssl-0.9.8d.orig/ssl/t1_lib.c openssl-0.9.8d/ssl/t1_lib.c ---- openssl-0.9.8d.orig/ssl/t1_lib.c 2005-08-05 16:52:07.000000000 -0700 -+++ openssl-0.9.8d/ssl/t1_lib.c 2006-12-10 08:20:02.000000000 -0800 -@@ -97,6 +97,10 @@ int tls1_new(SSL *s) - - void tls1_free(SSL *s) - { -+ if(s->tls_extension) -+ { -+ OPENSSL_free(s->tls_extension); -+ } - ssl3_free(s); - } - -diff -uprN openssl-0.9.8d.orig/ssl/tls1.h openssl-0.9.8d/ssl/tls1.h ---- openssl-0.9.8d.orig/ssl/tls1.h 2006-06-14 10:52:01.000000000 -0700 -+++ openssl-0.9.8d/ssl/tls1.h 2006-12-10 08:20:02.000000000 -0800 -@@ -296,6 +296,14 @@ extern "C" { - #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ - #endif - -+/* TLS extension struct */ -+struct tls_extension_st -+{ -+ unsigned short type; -+ unsigned short length; -+ void *data; -+}; -+ - #ifdef __cplusplus - } - #endif -diff -uprN openssl-0.9.8d.orig/util/ssleay.num openssl-0.9.8d/util/ssleay.num ---- openssl-0.9.8d.orig/util/ssleay.num 2005-05-08 17:22:02.000000000 -0700 -+++ openssl-0.9.8d/util/ssleay.num 2006-12-10 08:20:02.000000000 -0800 -@@ -226,3 +226,6 @@ DTLSv1_server_method - SSL_COMP_get_compression_methods 276 EXIST:!VMS:FUNCTION:COMP - SSL_COMP_get_compress_methods 276 EXIST:VMS:FUNCTION:COMP - SSL_SESSION_get_id 277 EXIST::FUNCTION: -+SSL_set_hello_extension 278 EXIST::FUNCTION: -+SSL_set_hello_extension_cb 279 EXIST::FUNCTION: -+SSL_set_session_secret_cb 280 EXIST::FUNCTION: diff --git a/contrib/hostapd/patches/openssl-0.9.8e-tls-extensions.patch b/contrib/hostapd/patches/openssl-0.9.8e-tls-extensions.patch deleted file mode 100644 index ede053f779..0000000000 --- a/contrib/hostapd/patches/openssl-0.9.8e-tls-extensions.patch +++ /dev/null @@ -1,353 +0,0 @@ -This patch is adding support for TLS hello extensions and externally -generated pre-shared key material to OpenSSL 0.9.8e. This is -based on the patch from Alexey Kobozev -(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). - - - -diff -uprN openssl-0.9.8e.orig/ssl/Makefile openssl-0.9.8e/ssl/Makefile ---- openssl-0.9.8e.orig/ssl/Makefile 2006-02-03 17:49:35.000000000 -0800 -+++ openssl-0.9.8e/ssl/Makefile 2007-03-22 20:23:19.000000000 -0700 -@@ -24,7 +24,7 @@ LIBSRC= \ - s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \ - s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \ - s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \ -- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \ -+ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \ - d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \ - d1_both.c d1_enc.c \ - ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \ -@@ -35,7 +35,7 @@ LIBOBJ= \ - s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \ - s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \ - s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \ -- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \ -+ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \ - d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \ - d1_both.o d1_enc.o \ - ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \ -@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h .. - t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h - t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h - t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c -+t1_ext.o: t1_ext.c ssl_locl.h -diff -uprN openssl-0.9.8e.orig/ssl/s3_clnt.c openssl-0.9.8e/ssl/s3_clnt.c ---- openssl-0.9.8e.orig/ssl/s3_clnt.c 2006-09-28 05:23:15.000000000 -0700 -+++ openssl-0.9.8e/ssl/s3_clnt.c 2007-03-22 20:23:19.000000000 -0700 -@@ -601,6 +601,20 @@ int ssl3_client_hello(SSL *s) - #endif - *(p++)=0; /* Add the NULL method */ - -+ /* send client hello extensions if any */ -+ if (s->version >= TLS1_VERSION && s->tls_extension) -+ { -+ // set the total extensions length -+ s2n(s->tls_extension->length + 4, p); -+ -+ // put the extensions with type and length -+ s2n(s->tls_extension->type, p); -+ s2n(s->tls_extension->length, p); -+ -+ memcpy(p, s->tls_extension->data, s->tls_extension->length); -+ p+=s->tls_extension->length; -+ } -+ - l=(p-d); - d=buf; - *(d++)=SSL3_MT_CLIENT_HELLO; -@@ -623,7 +637,7 @@ int ssl3_get_server_hello(SSL *s) - STACK_OF(SSL_CIPHER) *sk; - SSL_CIPHER *c; - unsigned char *p,*d; -- int i,al,ok; -+ int i,al,ok,pre_shared; - unsigned int j; - long n; - #ifndef OPENSSL_NO_COMP -@@ -690,7 +704,24 @@ int ssl3_get_server_hello(SSL *s) - goto f_err; - } - -- if (j != 0 && j == s->session->session_id_length -+ /* check if we want to resume the session based on external pre-shared secret */ -+ pre_shared = 0; -+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ NULL, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->hit=1; -+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j); -+ s->session->session_id_length = j; -+ memcpy(s->session->session_id, p, j); -+ pre_shared = 1; -+ } -+ } -+ -+ if ((pre_shared || j != 0) && j == s->session->session_id_length - && memcmp(p,s->session->session_id,j) == 0) - { - if(s->sid_ctx_length != s->session->sid_ctx_length -diff -uprN openssl-0.9.8e.orig/ssl/s3_srvr.c openssl-0.9.8e/ssl/s3_srvr.c ---- openssl-0.9.8e.orig/ssl/s3_srvr.c 2007-02-07 12:36:40.000000000 -0800 -+++ openssl-0.9.8e/ssl/s3_srvr.c 2007-03-22 20:23:19.000000000 -0700 -@@ -945,6 +945,75 @@ int ssl3_get_client_hello(SSL *s) - } - #endif - -+ /* Check for TLS client hello extension here */ -+ if (p < (d+n) && s->version >= TLS1_VERSION) -+ { -+ if (s->tls_extension_cb) -+ { -+ TLS_EXTENSION tls_ext; -+ unsigned short ext_total_len; -+ -+ n2s(p, ext_total_len); -+ n2s(p, tls_ext.type); -+ n2s(p, tls_ext.length); -+ -+ // sanity check in TLS extension len -+ if (tls_ext.length > (d+n) - p) -+ { -+ // just cut the lenth to packet border -+ tls_ext.length = (d+n) - p; -+ } -+ -+ tls_ext.data = p; -+ -+ // returns an alert code or 0 -+ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg); -+ if (al != 0) -+ { -+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR); -+ goto f_err; -+ } -+ } -+ } -+ -+ /* Check if we want to use external pre-shared secret for this handshake */ -+ /* for not reused session only */ -+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->hit=1; -+ s->session->ciphers=ciphers; -+ s->session->verify_result=X509_V_OK; -+ -+ ciphers=NULL; -+ -+ /* check if some cipher was preferred by call back */ -+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); -+ if (pref_cipher == NULL) -+ { -+ al=SSL_AD_HANDSHAKE_FAILURE; -+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); -+ goto f_err; -+ } -+ -+ s->session->cipher=pref_cipher; -+ -+ if (s->cipher_list) -+ sk_SSL_CIPHER_free(s->cipher_list); -+ -+ if (s->cipher_list_by_id) -+ sk_SSL_CIPHER_free(s->cipher_list_by_id); -+ -+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); -+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); -+ } -+ } -+ - /* Given s->session->ciphers and SSL_get_ciphers, we must - * pick a cipher */ - -diff -uprN openssl-0.9.8e.orig/ssl/ssl.h openssl-0.9.8e/ssl/ssl.h ---- openssl-0.9.8e.orig/ssl/ssl.h 2007-02-19 09:55:07.000000000 -0800 -+++ openssl-0.9.8e/ssl/ssl.h 2007-03-22 20:23:19.000000000 -0700 -@@ -345,6 +345,7 @@ extern "C" { - * 'struct ssl_st *' function parameters used to prototype callbacks - * in SSL_CTX. */ - typedef struct ssl_st *ssl_crock_st; -+typedef struct tls_extension_st TLS_EXTENSION; - - /* used to hold info on the particular ciphers used */ - typedef struct ssl_cipher_st -@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER) - typedef struct ssl_st SSL; - typedef struct ssl_ctx_st SSL_CTX; - -+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); -+ - /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ - typedef struct ssl_method_st - { -@@ -973,6 +976,15 @@ struct ssl_st - int first_packet; - int client_version; /* what was passed, used for - * SSLv3/TLS rollback check */ -+ -+ /* TLS externsions */ -+ TLS_EXTENSION *tls_extension; -+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg); -+ void *tls_extension_cb_arg; -+ -+ /* TLS pre-shared secret session resumption */ -+ tls_session_secret_cb_fn tls_session_secret_cb; -+ void *tls_session_secret_cb_arg; - }; - - #ifdef __cplusplus -@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v - int SSL_COMP_add_compression_method(int id,void *cm); - #endif - -+/* TLS extensions functions */ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); -+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg); -+ -+/* Pre-shared secret session resumption functions */ -+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); -+ - /* BEGIN ERROR CODES */ - /* The following lines are auto generated by the script mkerr.pl. Any changes - * made after this point may be overwritten when the script is next run. -@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void); - #define SSL_F_TLS1_ENC 210 - #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 - #define SSL_F_WRITE_PENDING 212 -+#define SSL_F_SSL_SET_HELLO_EXTENSION 213 - - /* Reason codes. */ - #define SSL_R_APP_DATA_IN_HANDSHAKE 100 -diff -uprN openssl-0.9.8e.orig/ssl/ssl_err.c openssl-0.9.8e/ssl/ssl_err.c ---- openssl-0.9.8e.orig/ssl/ssl_err.c 2006-11-21 12:14:46.000000000 -0800 -+++ openssl-0.9.8e/ssl/ssl_err.c 2007-03-22 20:23:19.000000000 -0700 -@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]= - {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, - {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, - {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, -+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"}, - {0,NULL} - }; - -diff -uprN openssl-0.9.8e.orig/ssl/ssl_sess.c openssl-0.9.8e/ssl/ssl_sess.c ---- openssl-0.9.8e.orig/ssl/ssl_sess.c 2007-02-10 02:40:24.000000000 -0800 -+++ openssl-0.9.8e/ssl/ssl_sess.c 2007-03-22 20:23:19.000000000 -0700 -@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX * - return(s->session_timeout); - } - -+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, -+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) -+{ -+ if (s == NULL) return(0); -+ s->tls_session_secret_cb = tls_session_secret_cb; -+ s->tls_session_secret_cb_arg = arg; -+ return(1); -+} -+ - typedef struct timeout_param_st - { - SSL_CTX *ctx; -diff -uprN openssl-0.9.8e.orig/ssl/t1_ext.c openssl-0.9.8e/ssl/t1_ext.c ---- openssl-0.9.8e.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800 -+++ openssl-0.9.8e/ssl/t1_ext.c 2007-03-22 20:23:19.000000000 -0700 -@@ -0,0 +1,48 @@ -+ -+#include -+#include "ssl_locl.h" -+ -+ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len) -+{ -+ if(s->version >= TLS1_VERSION) -+ { -+ if(s->tls_extension) -+ { -+ OPENSSL_free(s->tls_extension); -+ s->tls_extension = NULL; -+ } -+ -+ if(ext_data) -+ { -+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len); -+ if(!s->tls_extension) -+ { -+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE); -+ return 0; -+ } -+ -+ s->tls_extension->type = ext_type; -+ s->tls_extension->length = ext_len; -+ s->tls_extension->data = s->tls_extension + 1; -+ memcpy(s->tls_extension->data, ext_data, ext_len); -+ } -+ -+ return 1; -+ } -+ -+ return 0; -+} -+ -+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg) -+{ -+ if(s->version >= TLS1_VERSION) -+ { -+ s->tls_extension_cb = cb; -+ s->tls_extension_cb_arg = arg; -+ -+ return 1; -+ } -+ -+ return 0; -+} -diff -uprN openssl-0.9.8e.orig/ssl/t1_lib.c openssl-0.9.8e/ssl/t1_lib.c ---- openssl-0.9.8e.orig/ssl/t1_lib.c 2007-01-21 08:07:25.000000000 -0800 -+++ openssl-0.9.8e/ssl/t1_lib.c 2007-03-22 20:23:19.000000000 -0700 -@@ -97,6 +97,10 @@ int tls1_new(SSL *s) - - void tls1_free(SSL *s) - { -+ if(s->tls_extension) -+ { -+ OPENSSL_free(s->tls_extension); -+ } - ssl3_free(s); - } - -diff -uprN openssl-0.9.8e.orig/ssl/tls1.h openssl-0.9.8e/ssl/tls1.h ---- openssl-0.9.8e.orig/ssl/tls1.h 2006-06-14 10:52:01.000000000 -0700 -+++ openssl-0.9.8e/ssl/tls1.h 2007-03-22 20:23:19.000000000 -0700 -@@ -296,6 +296,14 @@ extern "C" { - #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ - #endif - -+/* TLS extension struct */ -+struct tls_extension_st -+{ -+ unsigned short type; -+ unsigned short length; -+ void *data; -+}; -+ - #ifdef __cplusplus - } - #endif -diff -uprN openssl-0.9.8e.orig/util/ssleay.num openssl-0.9.8e/util/ssleay.num ---- openssl-0.9.8e.orig/util/ssleay.num 2006-11-30 05:04:43.000000000 -0800 -+++ openssl-0.9.8e/util/ssleay.num 2007-03-22 20:24:07.000000000 -0700 -@@ -238,3 +238,6 @@ SSL_CTX_set_info_callback - SSL_CTX_sess_get_new_cb 287 EXIST::FUNCTION: - SSL_CTX_get_client_cert_cb 288 EXIST::FUNCTION: - SSL_CTX_sess_get_remove_cb 289 EXIST::FUNCTION: -+SSL_set_hello_extension 290 EXIST::FUNCTION: -+SSL_set_hello_extension_cb 291 EXIST::FUNCTION: -+SSL_set_session_secret_cb 292 EXIST::FUNCTION: diff --git a/contrib/hostapd/patches/openssl-0.9.8g-tls-extensions.patch b/contrib/hostapd/patches/openssl-0.9.8g-tls-extensions.patch deleted file mode 100644 index 8ccbfaa29d..0000000000 --- a/contrib/hostapd/patches/openssl-0.9.8g-tls-extensions.patch +++ /dev/null @@ -1,330 +0,0 @@ -This patch adds support for TLS SessionTicket extension (RFC 5077) for -the parts used by EAP-FAST (RFC 4851). - -This is based on the patch from Alexey Kobozev -(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). - -OpenSSL 0.9.8g does not enable TLS extension support by default, so it -will need to be enabled by adding enable-tlsext to config script -command line. - - -diff -upr openssl-0.9.8g.orig/ssl/s3_clnt.c openssl-0.9.8g/ssl/s3_clnt.c ---- openssl-0.9.8g.orig/ssl/s3_clnt.c 2007-08-31 03:28:51.000000000 +0300 -+++ openssl-0.9.8g/ssl/s3_clnt.c 2008-04-15 17:11:46.000000000 +0300 -@@ -727,6 +727,20 @@ int ssl3_get_server_hello(SSL *s) - goto f_err; - } - -+#ifndef OPENSSL_NO_TLSEXT -+ /* check if we want to resume the session based on external pre-shared secret */ -+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ NULL, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j); -+ } -+ } -+#endif /* OPENSSL_NO_TLSEXT */ -+ - if (j != 0 && j == s->session->session_id_length - && memcmp(p,s->session->session_id,j) == 0) - { -diff -upr openssl-0.9.8g.orig/ssl/s3_srvr.c openssl-0.9.8g/ssl/s3_srvr.c ---- openssl-0.9.8g.orig/ssl/s3_srvr.c 2007-09-30 21:55:59.000000000 +0300 -+++ openssl-0.9.8g/ssl/s3_srvr.c 2008-04-15 17:10:37.000000000 +0300 -@@ -928,6 +928,59 @@ int ssl3_get_client_hello(SSL *s) - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); - goto err; - } -+ -+ /* Check if we want to use external pre-shared secret for this -+ * handshake for not reused session only. We need to generate -+ * server_random before calling tls_session_secret_cb in order to allow -+ * SessionTicket processing to use it in key derivation. */ -+ { -+ unsigned long Time; -+ unsigned char *pos; -+ Time=(unsigned long)time(NULL); /* Time */ -+ pos=s->s3->server_random; -+ l2n(Time,pos); -+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0) -+ { -+ al=SSL_AD_INTERNAL_ERROR; -+ goto f_err; -+ } -+ } -+ -+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->hit=1; -+ s->session->ciphers=ciphers; -+ s->session->verify_result=X509_V_OK; -+ -+ ciphers=NULL; -+ -+ /* check if some cipher was preferred by call back */ -+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); -+ if (pref_cipher == NULL) -+ { -+ al=SSL_AD_HANDSHAKE_FAILURE; -+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); -+ goto f_err; -+ } -+ -+ s->session->cipher=pref_cipher; -+ -+ if (s->cipher_list) -+ sk_SSL_CIPHER_free(s->cipher_list); -+ -+ if (s->cipher_list_by_id) -+ sk_SSL_CIPHER_free(s->cipher_list_by_id); -+ -+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); -+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); -+ } -+ } - #endif - /* Worst case, we will use the NULL compression, but if we have other - * options, we will now look for them. We have i-1 compression -@@ -1066,16 +1119,22 @@ int ssl3_send_server_hello(SSL *s) - unsigned char *buf; - unsigned char *p,*d; - int i,sl; -- unsigned long l,Time; -+ unsigned long l; -+#ifdef OPENSSL_NO_TLSEXT -+ unsigned long Time; -+#endif - - if (s->state == SSL3_ST_SW_SRVR_HELLO_A) - { - buf=(unsigned char *)s->init_buf->data; -+#ifdef OPENSSL_NO_TLSEXT - p=s->s3->server_random; -+ /* Generate server_random if it was not needed previously */ - Time=(unsigned long)time(NULL); /* Time */ - l2n(Time,p); - if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) - return -1; -+#endif - /* Do the message type and length last */ - d=p= &(buf[4]); - -diff -upr openssl-0.9.8g.orig/ssl/ssl.h openssl-0.9.8g/ssl/ssl.h ---- openssl-0.9.8g.orig/ssl/ssl.h 2007-10-19 10:42:38.000000000 +0300 -+++ openssl-0.9.8g/ssl/ssl.h 2008-04-15 17:10:37.000000000 +0300 -@@ -342,6 +342,7 @@ extern "C" { - * 'struct ssl_st *' function parameters used to prototype callbacks - * in SSL_CTX. */ - typedef struct ssl_st *ssl_crock_st; -+typedef struct tls_extension_st TLS_EXTENSION; - - /* used to hold info on the particular ciphers used */ - typedef struct ssl_cipher_st -@@ -363,6 +364,8 @@ DECLARE_STACK_OF(SSL_CIPHER) - typedef struct ssl_st SSL; - typedef struct ssl_ctx_st SSL_CTX; - -+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); -+ - /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ - typedef struct ssl_method_st - { -@@ -1004,6 +1007,14 @@ struct ssl_st - */ - /* RFC4507 session ticket expected to be received or sent */ - int tlsext_ticket_expected; -+ -+ /* TLS extensions */ -+ TLS_EXTENSION *tls_extension; -+ -+ /* TLS pre-shared secret session resumption */ -+ tls_session_secret_cb_fn tls_session_secret_cb; -+ void *tls_session_secret_cb_arg; -+ - SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */ - #define session_ctx initial_ctx - #else -@@ -1589,6 +1600,12 @@ void *SSL_COMP_get_compression_methods(v - int SSL_COMP_add_compression_method(int id,void *cm); - #endif - -+/* TLS extensions functions */ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); -+ -+/* Pre-shared secret session resumption functions */ -+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); -+ - /* BEGIN ERROR CODES */ - /* The following lines are auto generated by the script mkerr.pl. Any changes - * made after this point may be overwritten when the script is next run. -@@ -1778,6 +1795,7 @@ void ERR_load_SSL_strings(void); - #define SSL_F_TLS1_ENC 210 - #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 - #define SSL_F_WRITE_PENDING 212 -+#define SSL_F_SSL_SET_HELLO_EXTENSION 213 - - /* Reason codes. */ - #define SSL_R_APP_DATA_IN_HANDSHAKE 100 -diff -upr openssl-0.9.8g.orig/ssl/ssl_err.c openssl-0.9.8g/ssl/ssl_err.c ---- openssl-0.9.8g.orig/ssl/ssl_err.c 2007-10-11 17:36:59.000000000 +0300 -+++ openssl-0.9.8g/ssl/ssl_err.c 2008-04-15 17:10:37.000000000 +0300 -@@ -250,6 +250,7 @@ static ERR_STRING_DATA SSL_str_functs[]= - {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, - {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, - {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, -+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"}, - {0,NULL} - }; - -diff -upr openssl-0.9.8g.orig/ssl/ssl_sess.c openssl-0.9.8g/ssl/ssl_sess.c ---- openssl-0.9.8g.orig/ssl/ssl_sess.c 2007-10-19 10:36:34.000000000 +0300 -+++ openssl-0.9.8g/ssl/ssl_sess.c 2008-04-15 17:10:37.000000000 +0300 -@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX * - return(s->session_timeout); - } - -+#ifndef OPENSSL_NO_TLSEXT -+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, -+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) -+{ -+ if (s == NULL) return(0); -+ s->tls_session_secret_cb = tls_session_secret_cb; -+ s->tls_session_secret_cb_arg = arg; -+ return(1); -+} -+ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len) -+{ -+ if(s->version >= TLS1_VERSION) -+ { -+ if(s->tls_extension) -+ { -+ OPENSSL_free(s->tls_extension); -+ s->tls_extension = NULL; -+ } -+ -+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len); -+ if(!s->tls_extension) -+ { -+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE); -+ return 0; -+ } -+ -+ s->tls_extension->type = ext_type; -+ -+ if(ext_data) -+ { -+ s->tls_extension->length = ext_len; -+ s->tls_extension->data = s->tls_extension + 1; -+ memcpy(s->tls_extension->data, ext_data, ext_len); -+ } else { -+ s->tls_extension->length = 0; -+ s->tls_extension->data = NULL; -+ } -+ -+ return 1; -+ } -+ -+ return 0; -+} -+#endif /* OPENSSL_NO_TLSEXT */ -+ - typedef struct timeout_param_st - { - SSL_CTX *ctx; -diff -upr openssl-0.9.8g.orig/ssl/t1_lib.c openssl-0.9.8g/ssl/t1_lib.c ---- openssl-0.9.8g.orig/ssl/t1_lib.c 2007-10-19 10:44:10.000000000 +0300 -+++ openssl-0.9.8g/ssl/t1_lib.c 2008-04-15 17:10:37.000000000 +0300 -@@ -105,6 +105,12 @@ int tls1_new(SSL *s) - - void tls1_free(SSL *s) - { -+#ifndef OPENSSL_NO_TLSEXT -+ if(s->tls_extension) -+ { -+ OPENSSL_free(s->tls_extension); -+ } -+#endif - ssl3_free(s); - } - -@@ -174,8 +180,24 @@ unsigned char *ssl_add_clienthello_tlsex - int ticklen; - if (s->session && s->session->tlsext_tick) - ticklen = s->session->tlsext_ticklen; -+ else if (s->session && s->tls_extension && -+ s->tls_extension->type == TLSEXT_TYPE_session_ticket && -+ s->tls_extension->data) -+ { -+ ticklen = s->tls_extension->length; -+ s->session->tlsext_tick = OPENSSL_malloc(ticklen); -+ if (!s->session->tlsext_tick) -+ return NULL; -+ memcpy(s->session->tlsext_tick, s->tls_extension->data, -+ ticklen); -+ s->session->tlsext_ticklen = ticklen; -+ } - else - ticklen = 0; -+ if (ticklen == 0 && s->tls_extension && -+ s->tls_extension->type == TLSEXT_TYPE_session_ticket && -+ s->tls_extension->data == NULL) -+ goto skip_ext; - /* Check for enough room 2 for extension type, 2 for len - * rest for ticket - */ -@@ -189,6 +211,7 @@ unsigned char *ssl_add_clienthello_tlsex - ret += ticklen; - } - } -+ skip_ext: - - if ((extdatalen = ret-p-2)== 0) - return p; -@@ -543,6 +566,8 @@ int tls1_process_ticket(SSL *s, unsigned - s->tlsext_ticket_expected = 1; - return 0; /* Cache miss */ - } -+ if (s->tls_session_secret_cb) -+ return 0; - return tls_decrypt_ticket(s, p, size, session_id, len, - ret); - } -diff -upr openssl-0.9.8g.orig/ssl/tls1.h openssl-0.9.8g/ssl/tls1.h ---- openssl-0.9.8g.orig/ssl/tls1.h 2007-08-28 04:12:44.000000000 +0300 -+++ openssl-0.9.8g/ssl/tls1.h 2008-04-15 17:10:37.000000000 +0300 -@@ -365,6 +365,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SER - #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ - #endif - -+/* TLS extension struct */ -+struct tls_extension_st -+{ -+ unsigned short type; -+ unsigned short length; -+ void *data; -+}; -+ - #ifdef __cplusplus - } - #endif -diff -upr openssl-0.9.8g.orig/util/ssleay.num openssl-0.9.8g/util/ssleay.num ---- openssl-0.9.8g.orig/util/ssleay.num 2007-08-13 01:31:16.000000000 +0300 -+++ openssl-0.9.8g/util/ssleay.num 2008-04-15 17:10:37.000000000 +0300 -@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb - SSL_set_SSL_CTX 290 EXIST::FUNCTION: - SSL_get_servername 291 EXIST::FUNCTION:TLSEXT - SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT -+SSL_set_hello_extension 305 EXIST::FUNCTION:TLSEXT -+SSL_set_session_secret_cb 306 EXIST::FUNCTION:TLSEXT diff --git a/contrib/hostapd/patches/openssl-0.9.8h-tls-extensions.patch b/contrib/hostapd/patches/openssl-0.9.8h-tls-extensions.patch deleted file mode 100644 index c68f2279b7..0000000000 --- a/contrib/hostapd/patches/openssl-0.9.8h-tls-extensions.patch +++ /dev/null @@ -1,344 +0,0 @@ -This patch adds support for TLS SessionTicket extension (RFC 5077) for -the parts used by EAP-FAST (RFC 4851). - -This is based on the patch from Alexey Kobozev -(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). - -OpenSSL 0.9.8h does not enable TLS extension support by default, so it -will need to be enabled by adding enable-tlsext to config script -command line. - - -diff -upr openssl-0.9.8h.orig/ssl/s3_clnt.c openssl-0.9.8h/ssl/s3_clnt.c ---- openssl-0.9.8h.orig/ssl/s3_clnt.c 2008-05-28 10:29:27.000000000 +0300 -+++ openssl-0.9.8h/ssl/s3_clnt.c 2008-05-29 10:44:25.000000000 +0300 -@@ -752,6 +752,20 @@ int ssl3_get_server_hello(SSL *s) - goto f_err; - } - -+#ifndef OPENSSL_NO_TLSEXT -+ /* check if we want to resume the session based on external pre-shared secret */ -+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ NULL, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j); -+ } -+ } -+#endif /* OPENSSL_NO_TLSEXT */ -+ - if (j != 0 && j == s->session->session_id_length - && memcmp(p,s->session->session_id,j) == 0) - { -@@ -2693,11 +2707,8 @@ static int ssl3_check_finished(SSL *s) - { - int ok; - long n; -- /* If we have no ticket or session ID is non-zero length (a match of -- * a non-zero session length would never reach here) it cannot be a -- * resumed session. -- */ -- if (!s->session->tlsext_tick || s->session->session_id_length) -+ /* If we have no ticket it cannot be a resumed session. */ -+ if (!s->session->tlsext_tick) - return 1; - /* this function is called when we really expect a Certificate - * message, so permit appropriate message length */ -diff -upr openssl-0.9.8h.orig/ssl/s3_srvr.c openssl-0.9.8h/ssl/s3_srvr.c ---- openssl-0.9.8h.orig/ssl/s3_srvr.c 2008-04-30 19:11:32.000000000 +0300 -+++ openssl-0.9.8h/ssl/s3_srvr.c 2008-05-28 18:49:34.000000000 +0300 -@@ -959,6 +959,59 @@ int ssl3_get_client_hello(SSL *s) - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); - goto err; - } -+ -+ /* Check if we want to use external pre-shared secret for this -+ * handshake for not reused session only. We need to generate -+ * server_random before calling tls_session_secret_cb in order to allow -+ * SessionTicket processing to use it in key derivation. */ -+ { -+ unsigned long Time; -+ unsigned char *pos; -+ Time=(unsigned long)time(NULL); /* Time */ -+ pos=s->s3->server_random; -+ l2n(Time,pos); -+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0) -+ { -+ al=SSL_AD_INTERNAL_ERROR; -+ goto f_err; -+ } -+ } -+ -+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->hit=1; -+ s->session->ciphers=ciphers; -+ s->session->verify_result=X509_V_OK; -+ -+ ciphers=NULL; -+ -+ /* check if some cipher was preferred by call back */ -+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); -+ if (pref_cipher == NULL) -+ { -+ al=SSL_AD_HANDSHAKE_FAILURE; -+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); -+ goto f_err; -+ } -+ -+ s->session->cipher=pref_cipher; -+ -+ if (s->cipher_list) -+ sk_SSL_CIPHER_free(s->cipher_list); -+ -+ if (s->cipher_list_by_id) -+ sk_SSL_CIPHER_free(s->cipher_list_by_id); -+ -+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); -+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); -+ } -+ } - #endif - /* Worst case, we will use the NULL compression, but if we have other - * options, we will now look for them. We have i-1 compression -@@ -1097,16 +1150,22 @@ int ssl3_send_server_hello(SSL *s) - unsigned char *buf; - unsigned char *p,*d; - int i,sl; -- unsigned long l,Time; -+ unsigned long l; -+#ifdef OPENSSL_NO_TLSEXT -+ unsigned long Time; -+#endif - - if (s->state == SSL3_ST_SW_SRVR_HELLO_A) - { - buf=(unsigned char *)s->init_buf->data; -+#ifdef OPENSSL_NO_TLSEXT - p=s->s3->server_random; -+ /* Generate server_random if it was not needed previously */ - Time=(unsigned long)time(NULL); /* Time */ - l2n(Time,p); - if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) - return -1; -+#endif - /* Do the message type and length last */ - d=p= &(buf[4]); - -diff -upr openssl-0.9.8h.orig/ssl/ssl.h openssl-0.9.8h/ssl/ssl.h ---- openssl-0.9.8h.orig/ssl/ssl.h 2008-04-30 19:11:32.000000000 +0300 -+++ openssl-0.9.8h/ssl/ssl.h 2008-05-28 18:49:34.000000000 +0300 -@@ -343,6 +343,7 @@ extern "C" { - * 'struct ssl_st *' function parameters used to prototype callbacks - * in SSL_CTX. */ - typedef struct ssl_st *ssl_crock_st; -+typedef struct tls_extension_st TLS_EXTENSION; - - /* used to hold info on the particular ciphers used */ - typedef struct ssl_cipher_st -@@ -364,6 +365,8 @@ DECLARE_STACK_OF(SSL_CIPHER) - typedef struct ssl_st SSL; - typedef struct ssl_ctx_st SSL_CTX; - -+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); -+ - /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ - typedef struct ssl_method_st - { -@@ -1027,6 +1030,14 @@ struct ssl_st - - /* RFC4507 session ticket expected to be received or sent */ - int tlsext_ticket_expected; -+ -+ /* TLS extensions */ -+ TLS_EXTENSION *tls_extension; -+ -+ /* TLS pre-shared secret session resumption */ -+ tls_session_secret_cb_fn tls_session_secret_cb; -+ void *tls_session_secret_cb_arg; -+ - SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */ - #define session_ctx initial_ctx - #else -@@ -1625,6 +1636,12 @@ void *SSL_COMP_get_compression_methods(v - int SSL_COMP_add_compression_method(int id,void *cm); - #endif - -+/* TLS extensions functions */ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); -+ -+/* Pre-shared secret session resumption functions */ -+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); -+ - /* BEGIN ERROR CODES */ - /* The following lines are auto generated by the script mkerr.pl. Any changes - * made after this point may be overwritten when the script is next run. -@@ -1815,6 +1832,7 @@ void ERR_load_SSL_strings(void); - #define SSL_F_TLS1_ENC 210 - #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 - #define SSL_F_WRITE_PENDING 212 -+#define SSL_F_SSL_SET_HELLO_EXTENSION 213 - - /* Reason codes. */ - #define SSL_R_APP_DATA_IN_HANDSHAKE 100 -diff -upr openssl-0.9.8h.orig/ssl/ssl_err.c openssl-0.9.8h/ssl/ssl_err.c ---- openssl-0.9.8h.orig/ssl/ssl_err.c 2007-10-12 03:00:30.000000000 +0300 -+++ openssl-0.9.8h/ssl/ssl_err.c 2008-05-28 18:49:34.000000000 +0300 -@@ -251,6 +251,7 @@ static ERR_STRING_DATA SSL_str_functs[]= - {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, - {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, - {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, -+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"}, - {0,NULL} - }; - -diff -upr openssl-0.9.8h.orig/ssl/ssl_sess.c openssl-0.9.8h/ssl/ssl_sess.c ---- openssl-0.9.8h.orig/ssl/ssl_sess.c 2007-10-17 20:30:15.000000000 +0300 -+++ openssl-0.9.8h/ssl/ssl_sess.c 2008-05-28 18:49:34.000000000 +0300 -@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX * - return(s->session_timeout); - } - -+#ifndef OPENSSL_NO_TLSEXT -+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, -+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) -+{ -+ if (s == NULL) return(0); -+ s->tls_session_secret_cb = tls_session_secret_cb; -+ s->tls_session_secret_cb_arg = arg; -+ return(1); -+} -+ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len) -+{ -+ if(s->version >= TLS1_VERSION) -+ { -+ if(s->tls_extension) -+ { -+ OPENSSL_free(s->tls_extension); -+ s->tls_extension = NULL; -+ } -+ -+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len); -+ if(!s->tls_extension) -+ { -+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE); -+ return 0; -+ } -+ -+ s->tls_extension->type = ext_type; -+ -+ if(ext_data) -+ { -+ s->tls_extension->length = ext_len; -+ s->tls_extension->data = s->tls_extension + 1; -+ memcpy(s->tls_extension->data, ext_data, ext_len); -+ } else { -+ s->tls_extension->length = 0; -+ s->tls_extension->data = NULL; -+ } -+ -+ return 1; -+ } -+ -+ return 0; -+} -+#endif /* OPENSSL_NO_TLSEXT */ -+ - typedef struct timeout_param_st - { - SSL_CTX *ctx; -diff -upr openssl-0.9.8h.orig/ssl/t1_lib.c openssl-0.9.8h/ssl/t1_lib.c ---- openssl-0.9.8h.orig/ssl/t1_lib.c 2008-05-28 10:26:33.000000000 +0300 -+++ openssl-0.9.8h/ssl/t1_lib.c 2008-05-28 18:49:34.000000000 +0300 -@@ -106,6 +106,12 @@ int tls1_new(SSL *s) - - void tls1_free(SSL *s) - { -+#ifndef OPENSSL_NO_TLSEXT -+ if(s->tls_extension) -+ { -+ OPENSSL_free(s->tls_extension); -+ } -+#endif - ssl3_free(s); - } - -@@ -175,8 +181,24 @@ unsigned char *ssl_add_clienthello_tlsex - int ticklen; - if (s->session && s->session->tlsext_tick) - ticklen = s->session->tlsext_ticklen; -+ else if (s->session && s->tls_extension && -+ s->tls_extension->type == TLSEXT_TYPE_session_ticket && -+ s->tls_extension->data) -+ { -+ ticklen = s->tls_extension->length; -+ s->session->tlsext_tick = OPENSSL_malloc(ticklen); -+ if (!s->session->tlsext_tick) -+ return NULL; -+ memcpy(s->session->tlsext_tick, s->tls_extension->data, -+ ticklen); -+ s->session->tlsext_ticklen = ticklen; -+ } - else - ticklen = 0; -+ if (ticklen == 0 && s->tls_extension && -+ s->tls_extension->type == TLSEXT_TYPE_session_ticket && -+ s->tls_extension->data == NULL) -+ goto skip_ext; - /* Check for enough room 2 for extension type, 2 for len - * rest for ticket - */ -@@ -190,6 +212,7 @@ unsigned char *ssl_add_clienthello_tlsex - ret += ticklen; - } - } -+ skip_ext: - - if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) - { -@@ -774,6 +797,8 @@ int tls1_process_ticket(SSL *s, unsigned - s->tlsext_ticket_expected = 1; - return 0; /* Cache miss */ - } -+ if (s->tls_session_secret_cb) -+ return 0; - return tls_decrypt_ticket(s, p, size, session_id, len, - ret); - } -diff -upr openssl-0.9.8h.orig/ssl/tls1.h openssl-0.9.8h/ssl/tls1.h ---- openssl-0.9.8h.orig/ssl/tls1.h 2008-04-30 19:11:33.000000000 +0300 -+++ openssl-0.9.8h/ssl/tls1.h 2008-05-28 18:49:34.000000000 +0300 -@@ -398,6 +398,14 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T - #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ - #endif - -+/* TLS extension struct */ -+struct tls_extension_st -+{ -+ unsigned short type; -+ unsigned short length; -+ void *data; -+}; -+ - #ifdef __cplusplus - } - #endif -diff -upr openssl-0.9.8h.orig/util/ssleay.num openssl-0.9.8h/util/ssleay.num ---- openssl-0.9.8h.orig/util/ssleay.num 2007-08-13 01:31:16.000000000 +0300 -+++ openssl-0.9.8h/util/ssleay.num 2008-05-28 18:49:34.000000000 +0300 -@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb - SSL_set_SSL_CTX 290 EXIST::FUNCTION: - SSL_get_servername 291 EXIST::FUNCTION:TLSEXT - SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT -+SSL_set_hello_extension 305 EXIST::FUNCTION:TLSEXT -+SSL_set_session_secret_cb 306 EXIST::FUNCTION:TLSEXT diff --git a/contrib/hostapd/patches/openssl-0.9.8i-tls-extensions.patch b/contrib/hostapd/patches/openssl-0.9.8i-tls-extensions.patch deleted file mode 100644 index 90bff544eb..0000000000 --- a/contrib/hostapd/patches/openssl-0.9.8i-tls-extensions.patch +++ /dev/null @@ -1,404 +0,0 @@ -This patch adds support for TLS SessionTicket extension (RFC 5077) for -the parts used by EAP-FAST (RFC 4851). - -This is based on the patch from Alexey Kobozev -(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). - -OpenSSL 0.9.8i does not enable TLS extension support by default, so it -will need to be enabled by adding enable-tlsext to config script -command line. - - -Index: openssl-0.9.8i/ssl/s3_clnt.c -=================================================================== ---- openssl-0.9.8i.orig/ssl/s3_clnt.c 2008-06-16 19:56:41.000000000 +0300 -+++ openssl-0.9.8i/ssl/s3_clnt.c 2008-11-23 20:39:40.000000000 +0200 -@@ -759,6 +759,21 @@ - goto f_err; - } - -+#ifndef OPENSSL_NO_TLSEXT -+ /* check if we want to resume the session based on external pre-shared secret */ -+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ NULL, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->session->cipher=pref_cipher ? -+ pref_cipher : ssl_get_cipher_by_char(s,p+j); -+ } -+ } -+#endif /* OPENSSL_NO_TLSEXT */ -+ - if (j != 0 && j == s->session->session_id_length - && memcmp(p,s->session->session_id,j) == 0) - { -@@ -2701,11 +2716,8 @@ - { - int ok; - long n; -- /* If we have no ticket or session ID is non-zero length (a match of -- * a non-zero session length would never reach here) it cannot be a -- * resumed session. -- */ -- if (!s->session->tlsext_tick || s->session->session_id_length) -+ /* If we have no ticket it cannot be a resumed session. */ -+ if (!s->session->tlsext_tick) - return 1; - /* this function is called when we really expect a Certificate - * message, so permit appropriate message length */ -Index: openssl-0.9.8i/ssl/s3_srvr.c -=================================================================== ---- openssl-0.9.8i.orig/ssl/s3_srvr.c 2008-09-14 21:16:09.000000000 +0300 -+++ openssl-0.9.8i/ssl/s3_srvr.c 2008-11-23 20:37:40.000000000 +0200 -@@ -959,6 +959,59 @@ - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); - goto err; - } -+ -+ /* Check if we want to use external pre-shared secret for this -+ * handshake for not reused session only. We need to generate -+ * server_random before calling tls_session_secret_cb in order to allow -+ * SessionTicket processing to use it in key derivation. */ -+ { -+ unsigned long Time; -+ unsigned char *pos; -+ Time=(unsigned long)time(NULL); /* Time */ -+ pos=s->s3->server_random; -+ l2n(Time,pos); -+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0) -+ { -+ al=SSL_AD_INTERNAL_ERROR; -+ goto f_err; -+ } -+ } -+ -+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->hit=1; -+ s->session->ciphers=ciphers; -+ s->session->verify_result=X509_V_OK; -+ -+ ciphers=NULL; -+ -+ /* check if some cipher was preferred by call back */ -+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); -+ if (pref_cipher == NULL) -+ { -+ al=SSL_AD_HANDSHAKE_FAILURE; -+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); -+ goto f_err; -+ } -+ -+ s->session->cipher=pref_cipher; -+ -+ if (s->cipher_list) -+ sk_SSL_CIPHER_free(s->cipher_list); -+ -+ if (s->cipher_list_by_id) -+ sk_SSL_CIPHER_free(s->cipher_list_by_id); -+ -+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); -+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); -+ } -+ } - #endif - /* Worst case, we will use the NULL compression, but if we have other - * options, we will now look for them. We have i-1 compression -@@ -1097,16 +1150,22 @@ - unsigned char *buf; - unsigned char *p,*d; - int i,sl; -- unsigned long l,Time; -+ unsigned long l; -+#ifdef OPENSSL_NO_TLSEXT -+ unsigned long Time; -+#endif - - if (s->state == SSL3_ST_SW_SRVR_HELLO_A) - { - buf=(unsigned char *)s->init_buf->data; -+#ifdef OPENSSL_NO_TLSEXT - p=s->s3->server_random; -+ /* Generate server_random if it was not needed previously */ - Time=(unsigned long)time(NULL); /* Time */ - l2n(Time,p); - if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) - return -1; -+#endif - /* Do the message type and length last */ - d=p= &(buf[4]); - -Index: openssl-0.9.8i/ssl/ssl_err.c -=================================================================== ---- openssl-0.9.8i.orig/ssl/ssl_err.c 2008-08-13 22:44:44.000000000 +0300 -+++ openssl-0.9.8i/ssl/ssl_err.c 2008-11-23 20:33:43.000000000 +0200 -@@ -253,6 +253,7 @@ - {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, - {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, - {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, -+{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"}, - {0,NULL} - }; - -Index: openssl-0.9.8i/ssl/ssl.h -=================================================================== ---- openssl-0.9.8i.orig/ssl/ssl.h 2008-08-13 22:44:44.000000000 +0300 -+++ openssl-0.9.8i/ssl/ssl.h 2008-11-23 20:35:41.000000000 +0200 -@@ -344,6 +344,7 @@ - * 'struct ssl_st *' function parameters used to prototype callbacks - * in SSL_CTX. */ - typedef struct ssl_st *ssl_crock_st; -+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT; - - /* used to hold info on the particular ciphers used */ - typedef struct ssl_cipher_st -@@ -362,6 +363,9 @@ - - DECLARE_STACK_OF(SSL_CIPHER) - -+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg); -+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); -+ - /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ - typedef struct ssl_method_st - { -@@ -1034,6 +1038,18 @@ - - /* RFC4507 session ticket expected to be received or sent */ - int tlsext_ticket_expected; -+ -+ /* TLS Session Ticket extension override */ -+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket; -+ -+ /* TLS Session Ticket extension callback */ -+ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb; -+ void *tls_session_ticket_ext_cb_arg; -+ -+ /* TLS pre-shared secret session resumption */ -+ tls_session_secret_cb_fn tls_session_secret_cb; -+ void *tls_session_secret_cb_arg; -+ - SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */ - #define session_ctx initial_ctx - #else -@@ -1632,6 +1648,15 @@ - int SSL_COMP_add_compression_method(int id,void *cm); - #endif - -+/* TLS extensions functions */ -+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len); -+ -+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb, -+ void *arg); -+ -+/* Pre-shared secret session resumption functions */ -+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); -+ - /* BEGIN ERROR CODES */ - /* The following lines are auto generated by the script mkerr.pl. Any changes - * made after this point may be overwritten when the script is next run. -@@ -1824,6 +1849,7 @@ - #define SSL_F_TLS1_ENC 210 - #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 - #define SSL_F_WRITE_PENDING 212 -+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213 - - /* Reason codes. */ - #define SSL_R_APP_DATA_IN_HANDSHAKE 100 -Index: openssl-0.9.8i/ssl/ssl_sess.c -=================================================================== ---- openssl-0.9.8i.orig/ssl/ssl_sess.c 2008-06-04 21:35:27.000000000 +0300 -+++ openssl-0.9.8i/ssl/ssl_sess.c 2008-11-23 20:32:24.000000000 +0200 -@@ -707,6 +707,61 @@ - return(s->session_timeout); - } - -+#ifndef OPENSSL_NO_TLSEXT -+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, -+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) -+ { -+ if (s == NULL) return(0); -+ s->tls_session_secret_cb = tls_session_secret_cb; -+ s->tls_session_secret_cb_arg = arg; -+ return(1); -+ } -+ -+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb, -+ void *arg) -+ { -+ if (s == NULL) return(0); -+ s->tls_session_ticket_ext_cb = cb; -+ s->tls_session_ticket_ext_cb_arg = arg; -+ return(1); -+ } -+ -+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len) -+ { -+ if (s->version >= TLS1_VERSION) -+ { -+ if (s->tlsext_session_ticket) -+ { -+ OPENSSL_free(s->tlsext_session_ticket); -+ s->tlsext_session_ticket = NULL; -+ } -+ -+ s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len); -+ if (!s->tlsext_session_ticket) -+ { -+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE); -+ return 0; -+ } -+ -+ if (ext_data) -+ { -+ s->tlsext_session_ticket->length = ext_len; -+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1; -+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len); -+ } -+ else -+ { -+ s->tlsext_session_ticket->length = 0; -+ s->tlsext_session_ticket->data = NULL; -+ } -+ -+ return 1; -+ } -+ -+ return 0; -+ } -+#endif /* OPENSSL_NO_TLSEXT */ -+ - typedef struct timeout_param_st - { - SSL_CTX *ctx; -Index: openssl-0.9.8i/ssl/t1_lib.c -=================================================================== ---- openssl-0.9.8i.orig/ssl/t1_lib.c 2008-09-04 01:13:04.000000000 +0300 -+++ openssl-0.9.8i/ssl/t1_lib.c 2008-11-23 20:31:20.000000000 +0200 -@@ -106,6 +106,12 @@ - - void tls1_free(SSL *s) - { -+#ifndef OPENSSL_NO_TLSEXT -+ if (s->tlsext_session_ticket) -+ { -+ OPENSSL_free(s->tlsext_session_ticket); -+ } -+#endif - ssl3_free(s); - } - -@@ -175,8 +181,23 @@ - int ticklen; - if (s->session && s->session->tlsext_tick) - ticklen = s->session->tlsext_ticklen; -+ else if (s->session && s->tlsext_session_ticket && -+ s->tlsext_session_ticket->data) -+ { -+ ticklen = s->tlsext_session_ticket->length; -+ s->session->tlsext_tick = OPENSSL_malloc(ticklen); -+ if (!s->session->tlsext_tick) -+ return NULL; -+ memcpy(s->session->tlsext_tick, -+ s->tlsext_session_ticket->data, -+ ticklen); -+ s->session->tlsext_ticklen = ticklen; -+ } - else - ticklen = 0; -+ if (ticklen == 0 && s->tlsext_session_ticket && -+ s->tlsext_session_ticket->data == NULL) -+ goto skip_ext; - /* Check for enough room 2 for extension type, 2 for len - * rest for ticket - */ -@@ -190,6 +211,7 @@ - ret += ticklen; - } - } -+ skip_ext: - - if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) - { -@@ -407,6 +429,15 @@ - } - - } -+ else if (type == TLSEXT_TYPE_session_ticket) -+ { -+ if (s->tls_session_ticket_ext_cb && -+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg)) -+ { -+ *al = TLS1_AD_INTERNAL_ERROR; -+ return 0; -+ } -+ } - else if (type == TLSEXT_TYPE_status_request - && s->ctx->tlsext_status_cb) - { -@@ -553,6 +584,12 @@ - } - else if (type == TLSEXT_TYPE_session_ticket) - { -+ if (s->tls_session_ticket_ext_cb && -+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg)) -+ { -+ *al = TLS1_AD_INTERNAL_ERROR; -+ return 0; -+ } - if ((SSL_get_options(s) & SSL_OP_NO_TICKET) - || (size > 0)) - { -@@ -776,6 +813,15 @@ - s->tlsext_ticket_expected = 1; - return 0; /* Cache miss */ - } -+ if (s->tls_session_secret_cb) -+ { -+ /* Indicate cache miss here and instead of -+ * generating the session from ticket now, -+ * trigger abbreviated handshake based on -+ * external mechanism to calculate the master -+ * secret later. */ -+ return 0; -+ } - return tls_decrypt_ticket(s, p, size, session_id, len, - ret); - } -Index: openssl-0.9.8i/ssl/tls1.h -=================================================================== ---- openssl-0.9.8i.orig/ssl/tls1.h 2008-04-30 19:11:33.000000000 +0300 -+++ openssl-0.9.8i/ssl/tls1.h 2008-11-23 20:22:38.000000000 +0200 -@@ -398,6 +398,13 @@ - #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ - #endif - -+/* TLS extension struct */ -+struct tls_session_ticket_ext_st -+ { -+ unsigned short length; -+ void *data; -+ }; -+ - #ifdef __cplusplus - } - #endif -Index: openssl-0.9.8i/util/ssleay.num -=================================================================== ---- openssl-0.9.8i.orig/util/ssleay.num 2008-06-05 13:57:21.000000000 +0300 -+++ openssl-0.9.8i/util/ssleay.num 2008-11-23 20:22:05.000000000 +0200 -@@ -242,3 +242,5 @@ - SSL_get_servername 291 EXIST::FUNCTION:TLSEXT - SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT - SSL_CTX_set_client_cert_engine 293 EXIST::FUNCTION:ENGINE -+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT -+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT diff --git a/contrib/hostapd/patches/openssl-0.9.8x-tls-extensions.patch b/contrib/hostapd/patches/openssl-0.9.8x-tls-extensions.patch deleted file mode 100644 index d1c0dbe6c3..0000000000 --- a/contrib/hostapd/patches/openssl-0.9.8x-tls-extensions.patch +++ /dev/null @@ -1,396 +0,0 @@ -This patch adds support for TLS SessionTicket extension (RFC 5077) for -the parts used by EAP-FAST (RFC 4851). - -This is based on the patch from Alexey Kobozev -(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). - -OpenSSL 0.9.8x does not enable TLS extension support by default, so it -will need to be enabled by adding enable-tlsext to config script -command line. - - -diff -upr openssl-0.9.8x.orig/ssl/s3_clnt.c openssl-0.9.8x/ssl/s3_clnt.c ---- openssl-0.9.8x.orig/ssl/s3_clnt.c 2011-12-26 21:38:28.000000000 +0200 -+++ openssl-0.9.8x/ssl/s3_clnt.c 2012-07-07 10:46:31.501140621 +0300 -@@ -757,6 +757,21 @@ int ssl3_get_server_hello(SSL *s) - goto f_err; - } - -+#ifndef OPENSSL_NO_TLSEXT -+ /* check if we want to resume the session based on external pre-shared secret */ -+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ NULL, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->session->cipher=pref_cipher ? -+ pref_cipher : ssl_get_cipher_by_char(s,p+j); -+ } -+ } -+#endif /* OPENSSL_NO_TLSEXT */ -+ - if (j != 0 && j == s->session->session_id_length - && memcmp(p,s->session->session_id,j) == 0) - { -@@ -2725,11 +2740,8 @@ int ssl3_check_finished(SSL *s) - { - int ok; - long n; -- /* If we have no ticket or session ID is non-zero length (a match of -- * a non-zero session length would never reach here) it cannot be a -- * resumed session. -- */ -- if (!s->session->tlsext_tick || s->session->session_id_length) -+ /* If we have no ticket it cannot be a resumed session. */ -+ if (!s->session->tlsext_tick) - return 1; - /* this function is called when we really expect a Certificate - * message, so permit appropriate message length */ -diff -upr openssl-0.9.8x.orig/ssl/s3_srvr.c openssl-0.9.8x/ssl/s3_srvr.c ---- openssl-0.9.8x.orig/ssl/s3_srvr.c 2012-02-16 17:21:17.000000000 +0200 -+++ openssl-0.9.8x/ssl/s3_srvr.c 2012-07-07 10:46:31.501140621 +0300 -@@ -1009,6 +1009,59 @@ int ssl3_get_client_hello(SSL *s) - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); - goto err; - } -+ -+ /* Check if we want to use external pre-shared secret for this -+ * handshake for not reused session only. We need to generate -+ * server_random before calling tls_session_secret_cb in order to allow -+ * SessionTicket processing to use it in key derivation. */ -+ { -+ unsigned long Time; -+ unsigned char *pos; -+ Time=(unsigned long)time(NULL); /* Time */ -+ pos=s->s3->server_random; -+ l2n(Time,pos); -+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0) -+ { -+ al=SSL_AD_INTERNAL_ERROR; -+ goto f_err; -+ } -+ } -+ -+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->hit=1; -+ s->session->ciphers=ciphers; -+ s->session->verify_result=X509_V_OK; -+ -+ ciphers=NULL; -+ -+ /* check if some cipher was preferred by call back */ -+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); -+ if (pref_cipher == NULL) -+ { -+ al=SSL_AD_HANDSHAKE_FAILURE; -+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); -+ goto f_err; -+ } -+ -+ s->session->cipher=pref_cipher; -+ -+ if (s->cipher_list) -+ sk_SSL_CIPHER_free(s->cipher_list); -+ -+ if (s->cipher_list_by_id) -+ sk_SSL_CIPHER_free(s->cipher_list_by_id); -+ -+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); -+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); -+ } -+ } - #endif - /* Worst case, we will use the NULL compression, but if we have other - * options, we will now look for them. We have i-1 compression -@@ -1147,16 +1200,22 @@ int ssl3_send_server_hello(SSL *s) - unsigned char *buf; - unsigned char *p,*d; - int i,sl; -- unsigned long l,Time; -+ unsigned long l; -+#ifdef OPENSSL_NO_TLSEXT -+ unsigned long Time; -+#endif - - if (s->state == SSL3_ST_SW_SRVR_HELLO_A) - { - buf=(unsigned char *)s->init_buf->data; -+#ifdef OPENSSL_NO_TLSEXT - p=s->s3->server_random; -+ /* Generate server_random if it was not needed previously */ - Time=(unsigned long)time(NULL); /* Time */ - l2n(Time,p); - if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) - return -1; -+#endif - /* Do the message type and length last */ - d=p= &(buf[4]); - -diff -upr openssl-0.9.8x.orig/ssl/ssl_err.c openssl-0.9.8x/ssl/ssl_err.c ---- openssl-0.9.8x.orig/ssl/ssl_err.c 2012-03-12 16:50:55.000000000 +0200 -+++ openssl-0.9.8x/ssl/ssl_err.c 2012-07-07 10:46:31.501140621 +0300 -@@ -264,6 +264,7 @@ static ERR_STRING_DATA SSL_str_functs[]= - {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, - {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, - {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, -+{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"}, - {0,NULL} - }; - -diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h ---- openssl-0.9.8x.orig/ssl/ssl.h 2012-03-12 16:50:55.000000000 +0200 -+++ openssl-0.9.8x/ssl/ssl.h 2012-07-07 10:46:31.501140621 +0300 -@@ -344,6 +344,7 @@ extern "C" { - * 'struct ssl_st *' function parameters used to prototype callbacks - * in SSL_CTX. */ - typedef struct ssl_st *ssl_crock_st; -+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT; - - /* used to hold info on the particular ciphers used */ - typedef struct ssl_cipher_st -@@ -362,6 +363,9 @@ typedef struct ssl_cipher_st - - DECLARE_STACK_OF(SSL_CIPHER) - -+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg); -+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); -+ - /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ - typedef struct ssl_method_st - { -@@ -1050,6 +1054,18 @@ struct ssl_st - - /* RFC4507 session ticket expected to be received or sent */ - int tlsext_ticket_expected; -+ -+ /* TLS Session Ticket extension override */ -+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket; -+ -+ /* TLS Session Ticket extension callback */ -+ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb; -+ void *tls_session_ticket_ext_cb_arg; -+ -+ /* TLS pre-shared secret session resumption */ -+ tls_session_secret_cb_fn tls_session_secret_cb; -+ void *tls_session_secret_cb_arg; -+ - SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */ - #define session_ctx initial_ctx - #else -@@ -1663,6 +1679,15 @@ void *SSL_COMP_get_compression_methods(v - int SSL_COMP_add_compression_method(int id,void *cm); - #endif - -+/* TLS extensions functions */ -+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len); -+ -+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb, -+ void *arg); -+ -+/* Pre-shared secret session resumption functions */ -+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); -+ - /* BEGIN ERROR CODES */ - /* The following lines are auto generated by the script mkerr.pl. Any changes - * made after this point may be overwritten when the script is next run. -@@ -1866,6 +1891,7 @@ void ERR_load_SSL_strings(void); - #define SSL_F_TLS1_ENC 210 - #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 - #define SSL_F_WRITE_PENDING 212 -+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213 - - /* Reason codes. */ - #define SSL_R_APP_DATA_IN_HANDSHAKE 100 -diff -upr openssl-0.9.8x.orig/ssl/ssl_sess.c openssl-0.9.8x/ssl/ssl_sess.c ---- openssl-0.9.8x.orig/ssl/ssl_sess.c 2010-02-01 18:48:40.000000000 +0200 -+++ openssl-0.9.8x/ssl/ssl_sess.c 2012-07-07 10:46:31.501140621 +0300 -@@ -712,6 +712,61 @@ long SSL_CTX_get_timeout(const SSL_CTX * - return(s->session_timeout); - } - -+#ifndef OPENSSL_NO_TLSEXT -+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, -+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) -+ { -+ if (s == NULL) return(0); -+ s->tls_session_secret_cb = tls_session_secret_cb; -+ s->tls_session_secret_cb_arg = arg; -+ return(1); -+ } -+ -+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb, -+ void *arg) -+ { -+ if (s == NULL) return(0); -+ s->tls_session_ticket_ext_cb = cb; -+ s->tls_session_ticket_ext_cb_arg = arg; -+ return(1); -+ } -+ -+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len) -+ { -+ if (s->version >= TLS1_VERSION) -+ { -+ if (s->tlsext_session_ticket) -+ { -+ OPENSSL_free(s->tlsext_session_ticket); -+ s->tlsext_session_ticket = NULL; -+ } -+ -+ s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len); -+ if (!s->tlsext_session_ticket) -+ { -+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE); -+ return 0; -+ } -+ -+ if (ext_data) -+ { -+ s->tlsext_session_ticket->length = ext_len; -+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1; -+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len); -+ } -+ else -+ { -+ s->tlsext_session_ticket->length = 0; -+ s->tlsext_session_ticket->data = NULL; -+ } -+ -+ return 1; -+ } -+ -+ return 0; -+ } -+#endif /* OPENSSL_NO_TLSEXT */ -+ - typedef struct timeout_param_st - { - SSL_CTX *ctx; -diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c ---- openssl-0.9.8x.orig/ssl/t1_lib.c 2012-01-04 16:25:10.000000000 +0200 -+++ openssl-0.9.8x/ssl/t1_lib.c 2012-07-07 10:47:31.153140501 +0300 -@@ -106,6 +106,12 @@ int tls1_new(SSL *s) - - void tls1_free(SSL *s) - { -+#ifndef OPENSSL_NO_TLSEXT -+ if (s->tlsext_session_ticket) -+ { -+ OPENSSL_free(s->tlsext_session_ticket); -+ } -+#endif - ssl3_free(s); - } - -@@ -206,8 +212,23 @@ unsigned char *ssl_add_clienthello_tlsex - int ticklen; - if (!s->new_session && s->session && s->session->tlsext_tick) - ticklen = s->session->tlsext_ticklen; -+ else if (s->session && s->tlsext_session_ticket && -+ s->tlsext_session_ticket->data) -+ { -+ ticklen = s->tlsext_session_ticket->length; -+ s->session->tlsext_tick = OPENSSL_malloc(ticklen); -+ if (!s->session->tlsext_tick) -+ return NULL; -+ memcpy(s->session->tlsext_tick, -+ s->tlsext_session_ticket->data, -+ ticklen); -+ s->session->tlsext_ticklen = ticklen; -+ } - else - ticklen = 0; -+ if (ticklen == 0 && s->tlsext_session_ticket && -+ s->tlsext_session_ticket->data == NULL) -+ goto skip_ext; - /* Check for enough room 2 for extension type, 2 for len - * rest for ticket - */ -@@ -221,6 +242,7 @@ unsigned char *ssl_add_clienthello_tlsex - ret += ticklen; - } - } -+ skip_ext: - - if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp && - s->version != DTLS1_VERSION) -@@ -486,6 +508,15 @@ int ssl_parse_clienthello_tlsext(SSL *s, - return 0; - renegotiate_seen = 1; - } -+ else if (type == TLSEXT_TYPE_session_ticket) -+ { -+ if (s->tls_session_ticket_ext_cb && -+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg)) -+ { -+ *al = TLS1_AD_INTERNAL_ERROR; -+ return 0; -+ } -+ } - else if (type == TLSEXT_TYPE_status_request && - s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb) - { -@@ -663,6 +694,12 @@ int ssl_parse_serverhello_tlsext(SSL *s, - } - else if (type == TLSEXT_TYPE_session_ticket) - { -+ if (s->tls_session_ticket_ext_cb && -+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg)) -+ { -+ *al = TLS1_AD_INTERNAL_ERROR; -+ return 0; -+ } - if ((SSL_get_options(s) & SSL_OP_NO_TICKET) - || (size > 0)) - { -@@ -920,6 +957,15 @@ int tls1_process_ticket(SSL *s, unsigned - s->tlsext_ticket_expected = 1; - return 0; /* Cache miss */ - } -+ if (s->tls_session_secret_cb) -+ { -+ /* Indicate cache miss here and instead of -+ * generating the session from ticket now, -+ * trigger abbreviated handshake based on -+ * external mechanism to calculate the master -+ * secret later. */ -+ return 0; -+ } - return tls_decrypt_ticket(s, p, size, session_id, len, - ret); - } -diff -upr openssl-0.9.8x.orig/ssl/tls1.h openssl-0.9.8x/ssl/tls1.h ---- openssl-0.9.8x.orig/ssl/tls1.h 2009-11-08 16:51:54.000000000 +0200 -+++ openssl-0.9.8x/ssl/tls1.h 2012-07-07 10:46:31.501140621 +0300 -@@ -401,6 +401,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T - #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ - #endif - -+/* TLS extension struct */ -+struct tls_session_ticket_ext_st -+ { -+ unsigned short length; -+ void *data; -+ }; -+ - #ifdef __cplusplus - } - #endif -diff -upr openssl-0.9.8x.orig/util/ssleay.num openssl-0.9.8x/util/ssleay.num ---- openssl-0.9.8x.orig/util/ssleay.num 2008-06-05 13:57:21.000000000 +0300 -+++ openssl-0.9.8x/util/ssleay.num 2012-07-07 10:46:31.505140623 +0300 -@@ -242,3 +242,5 @@ SSL_set_SSL_CTX - SSL_get_servername 291 EXIST::FUNCTION:TLSEXT - SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT - SSL_CTX_set_client_cert_engine 293 EXIST::FUNCTION:ENGINE -+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT -+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT diff --git a/contrib/hostapd/patches/openssl-0.9.9-session-ticket.patch b/contrib/hostapd/patches/openssl-0.9.9-session-ticket.patch deleted file mode 100644 index 3afa639ad8..0000000000 --- a/contrib/hostapd/patches/openssl-0.9.9-session-ticket.patch +++ /dev/null @@ -1,374 +0,0 @@ -This patch adds support for TLS SessionTicket extension (RFC 5077) for -the parts used by EAP-FAST (RFC 4851). - -This is based on the patch from Alexey Kobozev -(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). - -NOTE: This patch (without SSL_set_hello_extension() wrapper) was -merged into the upstream OpenSSL 0.9.9 tree and as such, an external -patch for EAP-FAST support is not needed anymore. - - - -Index: openssl-SNAP-20081111/ssl/s3_clnt.c -=================================================================== ---- openssl-SNAP-20081111.orig/ssl/s3_clnt.c -+++ openssl-SNAP-20081111/ssl/s3_clnt.c -@@ -788,6 +788,23 @@ int ssl3_get_server_hello(SSL *s) - goto f_err; - } - -+#ifndef OPENSSL_NO_TLSEXT -+ /* check if we want to resume the session based on external pre-shared secret */ -+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if (s->tls_session_secret_cb(s, s->session->master_key, -+ &s->session->master_key_length, -+ NULL, &pref_cipher, -+ s->tls_session_secret_cb_arg)) -+ { -+ s->session->cipher = pref_cipher ? -+ pref_cipher : ssl_get_cipher_by_char(s, p+j); -+ } -+ } -+#endif /* OPENSSL_NO_TLSEXT */ -+ - if (j != 0 && j == s->session->session_id_length - && memcmp(p,s->session->session_id,j) == 0) - { -@@ -2927,11 +2944,8 @@ static int ssl3_check_finished(SSL *s) - { - int ok; - long n; -- /* If we have no ticket or session ID is non-zero length (a match of -- * a non-zero session length would never reach here) it cannot be a -- * resumed session. -- */ -- if (!s->session->tlsext_tick || s->session->session_id_length) -+ /* If we have no ticket it cannot be a resumed session. */ -+ if (!s->session->tlsext_tick) - return 1; - /* this function is called when we really expect a Certificate - * message, so permit appropriate message length */ -Index: openssl-SNAP-20081111/ssl/s3_srvr.c -=================================================================== ---- openssl-SNAP-20081111.orig/ssl/s3_srvr.c -+++ openssl-SNAP-20081111/ssl/s3_srvr.c -@@ -1010,6 +1010,59 @@ int ssl3_get_client_hello(SSL *s) - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); - goto err; - } -+ -+ /* Check if we want to use external pre-shared secret for this -+ * handshake for not reused session only. We need to generate -+ * server_random before calling tls_session_secret_cb in order to allow -+ * SessionTicket processing to use it in key derivation. */ -+ { -+ unsigned long Time; -+ unsigned char *pos; -+ Time=(unsigned long)time(NULL); /* Time */ -+ pos=s->s3->server_random; -+ l2n(Time,pos); -+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0) -+ { -+ al=SSL_AD_INTERNAL_ERROR; -+ goto f_err; -+ } -+ } -+ -+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) -+ { -+ SSL_CIPHER *pref_cipher=NULL; -+ -+ s->session->master_key_length=sizeof(s->session->master_key); -+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, -+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) -+ { -+ s->hit=1; -+ s->session->ciphers=ciphers; -+ s->session->verify_result=X509_V_OK; -+ -+ ciphers=NULL; -+ -+ /* check if some cipher was preferred by call back */ -+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); -+ if (pref_cipher == NULL) -+ { -+ al=SSL_AD_HANDSHAKE_FAILURE; -+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); -+ goto f_err; -+ } -+ -+ s->session->cipher=pref_cipher; -+ -+ if (s->cipher_list) -+ sk_SSL_CIPHER_free(s->cipher_list); -+ -+ if (s->cipher_list_by_id) -+ sk_SSL_CIPHER_free(s->cipher_list_by_id); -+ -+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); -+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); -+ } -+ } - #endif - - /* Worst case, we will use the NULL compression, but if we have other -@@ -1134,16 +1187,22 @@ int ssl3_send_server_hello(SSL *s) - unsigned char *buf; - unsigned char *p,*d; - int i,sl; -- unsigned long l,Time; -+ unsigned long l; -+#ifdef OPENSSL_NO_TLSEXT -+ unsigned long Time; -+#endif - - if (s->state == SSL3_ST_SW_SRVR_HELLO_A) - { - buf=(unsigned char *)s->init_buf->data; -+#ifdef OPENSSL_NO_TLSEXT - p=s->s3->server_random; -+ /* Generate server_random if it was not needed previously */ - Time=(unsigned long)time(NULL); /* Time */ - l2n(Time,p); - if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) - return -1; -+#endif - /* Do the message type and length last */ - d=p= &(buf[4]); - -Index: openssl-SNAP-20081111/ssl/ssl_err.c -=================================================================== ---- openssl-SNAP-20081111.orig/ssl/ssl_err.c -+++ openssl-SNAP-20081111/ssl/ssl_err.c -@@ -263,6 +263,7 @@ static ERR_STRING_DATA SSL_str_functs[]= - {ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"}, - {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, - {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, -+{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"}, - {0,NULL} - }; - -Index: openssl-SNAP-20081111/ssl/ssl.h -=================================================================== ---- openssl-SNAP-20081111.orig/ssl/ssl.h -+++ openssl-SNAP-20081111/ssl/ssl.h -@@ -355,6 +355,7 @@ extern "C" { - * 'struct ssl_st *' function parameters used to prototype callbacks - * in SSL_CTX. */ - typedef struct ssl_st *ssl_crock_st; -+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT; - - /* used to hold info on the particular ciphers used */ - typedef struct ssl_cipher_st -@@ -378,6 +379,8 @@ typedef struct ssl_cipher_st - - DECLARE_STACK_OF(SSL_CIPHER) - -+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); -+ - /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ - typedef struct ssl_method_st - { -@@ -1145,6 +1148,13 @@ struct ssl_st - void *tlsext_opaque_prf_input; - size_t tlsext_opaque_prf_input_len; - -+ /* TLS Session Ticket extension override */ -+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket; -+ -+ /* TLS pre-shared secret session resumption */ -+ tls_session_secret_cb_fn tls_session_secret_cb; -+ void *tls_session_secret_cb_arg; -+ - SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */ - #define session_ctx initial_ctx - #else -@@ -1746,6 +1756,16 @@ void *SSL_COMP_get_compression_methods(v - int SSL_COMP_add_compression_method(int id,void *cm); - #endif - -+/* NOTE: This function will be removed; it is only here for backwards -+ * compatibility for the API during testing. */ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); -+ -+/* TLS extensions functions */ -+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len); -+ -+/* Pre-shared secret session resumption functions */ -+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); -+ - /* BEGIN ERROR CODES */ - /* The following lines are auto generated by the script mkerr.pl. Any changes - * made after this point may be overwritten when the script is next run. -@@ -1948,6 +1968,7 @@ void ERR_load_SSL_strings(void); - #define SSL_F_TLS1_PRF 284 - #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 - #define SSL_F_WRITE_PENDING 212 -+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213 - - /* Reason codes. */ - #define SSL_R_APP_DATA_IN_HANDSHAKE 100 -Index: openssl-SNAP-20081111/ssl/ssl_sess.c -=================================================================== ---- openssl-SNAP-20081111.orig/ssl/ssl_sess.c -+++ openssl-SNAP-20081111/ssl/ssl_sess.c -@@ -834,6 +834,62 @@ long SSL_CTX_get_timeout(const SSL_CTX * - return(s->session_timeout); - } - -+#ifndef OPENSSL_NO_TLSEXT -+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, -+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) -+ { -+ if (s == NULL) return(0); -+ s->tls_session_secret_cb = tls_session_secret_cb; -+ s->tls_session_secret_cb_arg = arg; -+ return(1); -+ } -+ -+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len) -+ { -+ if (s->version >= TLS1_VERSION) -+ { -+ if (s->tlsext_session_ticket) -+ { -+ OPENSSL_free(s->tlsext_session_ticket); -+ s->tlsext_session_ticket = NULL; -+ } -+ -+ s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len); -+ if (!s->tlsext_session_ticket) -+ { -+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE); -+ return 0; -+ } -+ -+ if (ext_data) -+ { -+ s->tlsext_session_ticket->length = ext_len; -+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1; -+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len); -+ } -+ else -+ { -+ s->tlsext_session_ticket->length = 0; -+ s->tlsext_session_ticket->data = NULL; -+ } -+ -+ return 1; -+ } -+ -+ return 0; -+ } -+ -+/* NOTE: This function will be removed; it is only here for backwards -+ * compatibility for the API during testing. */ -+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len) -+ { -+ if (ext_type != TLSEXT_TYPE_session_ticket) -+ return 0; -+ -+ return SSL_set_session_ticket_ext(s, ext_data, ext_len); -+ } -+#endif /* OPENSSL_NO_TLSEXT */ -+ - typedef struct timeout_param_st - { - SSL_CTX *ctx; -Index: openssl-SNAP-20081111/ssl/t1_lib.c -=================================================================== ---- openssl-SNAP-20081111.orig/ssl/t1_lib.c -+++ openssl-SNAP-20081111/ssl/t1_lib.c -@@ -154,6 +154,12 @@ int tls1_new(SSL *s) - - void tls1_free(SSL *s) - { -+#ifndef OPENSSL_NO_TLSEXT -+ if (s->tlsext_session_ticket) -+ { -+ OPENSSL_free(s->tlsext_session_ticket); -+ } -+#endif /* OPENSSL_NO_TLSEXT */ - ssl3_free(s); - } - -@@ -357,8 +363,23 @@ unsigned char *ssl_add_clienthello_tlsex - int ticklen; - if (s->session && s->session->tlsext_tick) - ticklen = s->session->tlsext_ticklen; -+ else if (s->session && s->tlsext_session_ticket && -+ s->tlsext_session_ticket->data) -+ { -+ ticklen = s->tlsext_session_ticket->length; -+ s->session->tlsext_tick = OPENSSL_malloc(ticklen); -+ if (!s->session->tlsext_tick) -+ return NULL; -+ memcpy(s->session->tlsext_tick, -+ s->tlsext_session_ticket->data, -+ ticklen); -+ s->session->tlsext_ticklen = ticklen; -+ } - else - ticklen = 0; -+ if (ticklen == 0 && s->tlsext_session_ticket && -+ s->tlsext_session_ticket->data == NULL) -+ goto skip_ext; - /* Check for enough room 2 for extension type, 2 for len - * rest for ticket - */ -@@ -371,6 +392,7 @@ unsigned char *ssl_add_clienthello_tlsex - ret += ticklen; - } - } -+ skip_ext: - - #ifdef TLSEXT_TYPE_opaque_prf_input - if (s->s3->client_opaque_prf_input != NULL) -@@ -1435,6 +1457,15 @@ int tls1_process_ticket(SSL *s, unsigned - s->tlsext_ticket_expected = 1; - return 0; /* Cache miss */ - } -+ if (s->tls_session_secret_cb) -+ { -+ /* Indicate cache miss here and instead of -+ * generating the session from ticket now, -+ * trigger abbreviated handshake based on -+ * external mechanism to calculate the master -+ * secret later. */ -+ return 0; -+ } - return tls_decrypt_ticket(s, p, size, session_id, len, - ret); - } -Index: openssl-SNAP-20081111/ssl/tls1.h -=================================================================== ---- openssl-SNAP-20081111.orig/ssl/tls1.h -+++ openssl-SNAP-20081111/ssl/tls1.h -@@ -512,6 +512,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T - #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ - #endif - -+/* TLS Session Ticket extension struct */ -+struct tls_session_ticket_ext_st -+ { -+ unsigned short length; -+ void *data; -+ }; -+ - #ifdef __cplusplus - } - #endif -Index: openssl-SNAP-20081111/util/ssleay.num -=================================================================== ---- openssl-SNAP-20081111.orig/util/ssleay.num -+++ openssl-SNAP-20081111/util/ssleay.num -@@ -254,3 +254,5 @@ PEM_read_bio_SSL_SESSION - SSL_CTX_set_psk_server_callback 303 EXIST::FUNCTION:PSK - SSL_get_psk_identity 304 EXIST::FUNCTION:PSK - PEM_write_SSL_SESSION 305 EXIST:!WIN16:FUNCTION: -+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT -+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT diff --git a/contrib/hostapd/src/ap/accounting.c b/contrib/hostapd/src/ap/accounting.c deleted file mode 100644 index 6290d3f397..0000000000 --- a/contrib/hostapd/src/ap/accounting.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - * hostapd / RADIUS Accounting - * Copyright (c) 2002-2009, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "radius/radius.h" -#include "radius/radius_client.h" -#include "hostapd.h" -#include "ieee802_1x.h" -#include "ap_config.h" -#include "sta_info.h" -#include "ap_drv_ops.h" -#include "accounting.h" - - -/* Default interval in seconds for polling TX/RX octets from the driver if - * STA is not using interim accounting. This detects wrap arounds for - * input/output octets and updates Acct-{Input,Output}-Gigawords. */ -#define ACCT_DEFAULT_UPDATE_INTERVAL 300 - -static void accounting_sta_interim(struct hostapd_data *hapd, - struct sta_info *sta); - - -static struct radius_msg * accounting_msg(struct hostapd_data *hapd, - struct sta_info *sta, - int status_type) -{ - struct radius_msg *msg; - char buf[128]; - u8 *val; - size_t len; - int i; - struct wpabuf *b; - - msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST, - radius_client_get_id(hapd->radius)); - if (msg == NULL) { - wpa_printf(MSG_INFO, "Could not create new RADIUS packet"); - return NULL; - } - - if (sta) { - radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta)); - - os_snprintf(buf, sizeof(buf), "%08X-%08X", - sta->acct_session_id_hi, sta->acct_session_id_lo); - if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, - (u8 *) buf, os_strlen(buf))) { - wpa_printf(MSG_INFO, "Could not add Acct-Session-Id"); - goto fail; - } - } else { - radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd)); - } - - if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE, - status_type)) { - wpa_printf(MSG_INFO, "Could not add Acct-Status-Type"); - goto fail; - } - - if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr, - RADIUS_ATTR_ACCT_AUTHENTIC) && - !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC, - hapd->conf->ieee802_1x ? - RADIUS_ACCT_AUTHENTIC_RADIUS : - RADIUS_ACCT_AUTHENTIC_LOCAL)) { - wpa_printf(MSG_INFO, "Could not add Acct-Authentic"); - goto fail; - } - - if (sta) { - /* Use 802.1X identity if available */ - val = ieee802_1x_get_identity(sta->eapol_sm, &len); - - /* Use RADIUS ACL identity if 802.1X provides no identity */ - if (!val && sta->identity) { - val = (u8 *) sta->identity; - len = os_strlen(sta->identity); - } - - /* Use STA MAC if neither 802.1X nor RADIUS ACL provided - * identity */ - if (!val) { - os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, - MAC2STR(sta->addr)); - val = (u8 *) buf; - len = os_strlen(buf); - } - - if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val, - len)) { - wpa_printf(MSG_INFO, "Could not add User-Name"); - goto fail; - } - } - - if (add_common_radius_attr(hapd, hapd->conf->radius_acct_req_attr, sta, - msg) < 0) - goto fail; - - if (sta) { - for (i = 0; ; i++) { - val = ieee802_1x_get_radius_class(sta->eapol_sm, &len, - i); - if (val == NULL) - break; - - if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS, - val, len)) { - wpa_printf(MSG_INFO, "Could not add Class"); - goto fail; - } - } - - b = ieee802_1x_get_radius_cui(sta->eapol_sm); - if (b && - !radius_msg_add_attr(msg, - RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, - wpabuf_head(b), wpabuf_len(b))) { - wpa_printf(MSG_ERROR, "Could not add CUI"); - goto fail; - } - - if (!b && sta->radius_cui && - !radius_msg_add_attr(msg, - RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, - (u8 *) sta->radius_cui, - os_strlen(sta->radius_cui))) { - wpa_printf(MSG_ERROR, "Could not add CUI from ACL"); - goto fail; - } - } - - return msg; - - fail: - radius_msg_free(msg); - return NULL; -} - - -static int accounting_sta_update_stats(struct hostapd_data *hapd, - struct sta_info *sta, - struct hostap_sta_driver_data *data) -{ - if (hostapd_drv_read_sta_data(hapd, data, sta->addr)) - return -1; - - if (sta->last_rx_bytes > data->rx_bytes) - sta->acct_input_gigawords++; - if (sta->last_tx_bytes > data->tx_bytes) - sta->acct_output_gigawords++; - sta->last_rx_bytes = data->rx_bytes; - sta->last_tx_bytes = data->tx_bytes; - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: " - "Acct-Input-Octets=%lu Acct-Input-Gigawords=%u " - "Acct-Output-Octets=%lu Acct-Output-Gigawords=%u", - sta->last_rx_bytes, sta->acct_input_gigawords, - sta->last_tx_bytes, sta->acct_output_gigawords); - - return 0; -} - - -static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - struct sta_info *sta = timeout_ctx; - int interval; - - if (sta->acct_interim_interval) { - accounting_sta_interim(hapd, sta); - interval = sta->acct_interim_interval; - } else { - struct hostap_sta_driver_data data; - accounting_sta_update_stats(hapd, sta, &data); - interval = ACCT_DEFAULT_UPDATE_INTERVAL; - } - - eloop_register_timeout(interval, 0, accounting_interim_update, - hapd, sta); -} - - -/** - * accounting_sta_start - Start STA accounting - * @hapd: hostapd BSS data - * @sta: The station - */ -void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) -{ - struct radius_msg *msg; - int interval; - - if (sta->acct_session_started) - return; - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_INFO, - "starting accounting session %08X-%08X", - sta->acct_session_id_hi, sta->acct_session_id_lo); - - os_get_reltime(&sta->acct_session_start); - 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); - - if (!hapd->conf->radius->acct_server) - return; - - if (sta->acct_interim_interval) - interval = sta->acct_interim_interval; - else - interval = ACCT_DEFAULT_UPDATE_INTERVAL; - eloop_register_timeout(interval, 0, accounting_interim_update, - hapd, sta); - - msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START); - if (msg && - radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr) < 0) - radius_msg_free(msg); - - sta->acct_session_started = 1; -} - - -static void accounting_sta_report(struct hostapd_data *hapd, - struct sta_info *sta, int stop) -{ - struct radius_msg *msg; - int cause = sta->acct_terminate_cause; - struct hostap_sta_driver_data data; - struct os_reltime now_r, diff; - struct os_time now; - u32 gigawords; - - if (!hapd->conf->radius->acct_server) - return; - - msg = accounting_msg(hapd, sta, - stop ? RADIUS_ACCT_STATUS_TYPE_STOP : - RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE); - if (!msg) { - wpa_printf(MSG_INFO, "Could not create RADIUS Accounting message"); - return; - } - - os_get_reltime(&now_r); - os_get_time(&now); - os_reltime_sub(&now_r, &sta->acct_session_start, &diff); - if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME, - diff.sec)) { - wpa_printf(MSG_INFO, "Could not add Acct-Session-Time"); - goto fail; - } - - if (accounting_sta_update_stats(hapd, sta, &data) == 0) { - if (!radius_msg_add_attr_int32(msg, - RADIUS_ATTR_ACCT_INPUT_PACKETS, - data.rx_packets)) { - wpa_printf(MSG_INFO, "Could not add Acct-Input-Packets"); - goto fail; - } - if (!radius_msg_add_attr_int32(msg, - RADIUS_ATTR_ACCT_OUTPUT_PACKETS, - data.tx_packets)) { - wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets"); - goto fail; - } - if (!radius_msg_add_attr_int32(msg, - RADIUS_ATTR_ACCT_INPUT_OCTETS, - data.rx_bytes)) { - wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets"); - goto fail; - } - gigawords = sta->acct_input_gigawords; -#if __WORDSIZE == 64 - gigawords += data.rx_bytes >> 32; -#endif - if (gigawords && - !radius_msg_add_attr_int32( - msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, - gigawords)) { - wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords"); - goto fail; - } - if (!radius_msg_add_attr_int32(msg, - RADIUS_ATTR_ACCT_OUTPUT_OCTETS, - data.tx_bytes)) { - wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets"); - goto fail; - } - gigawords = sta->acct_output_gigawords; -#if __WORDSIZE == 64 - gigawords += data.tx_bytes >> 32; -#endif - if (gigawords && - !radius_msg_add_attr_int32( - msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, - gigawords)) { - wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords"); - goto fail; - } - } - - if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP, - now.sec)) { - wpa_printf(MSG_INFO, "Could not add Event-Timestamp"); - goto fail; - } - - if (eloop_terminated()) - cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT; - - if (stop && cause && - !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE, - cause)) { - wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause"); - goto fail; - } - - if (radius_client_send(hapd->radius, msg, - stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM, - sta->addr) < 0) - goto fail; - return; - - fail: - radius_msg_free(msg); -} - - -/** - * accounting_sta_interim - Send a interim STA accounting report - * @hapd: hostapd BSS data - * @sta: The station - */ -static void accounting_sta_interim(struct hostapd_data *hapd, - struct sta_info *sta) -{ - if (sta->acct_session_started) - accounting_sta_report(hapd, sta, 0); -} - - -/** - * accounting_sta_stop - Stop STA accounting - * @hapd: hostapd BSS data - * @sta: The station - */ -void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta) -{ - if (sta->acct_session_started) { - accounting_sta_report(hapd, sta, 1); - eloop_cancel_timeout(accounting_interim_update, hapd, sta); - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_INFO, - "stopped accounting session %08X-%08X", - sta->acct_session_id_hi, - sta->acct_session_id_lo); - sta->acct_session_started = 0; - } -} - - -void accounting_sta_get_id(struct hostapd_data *hapd, - struct sta_info *sta) -{ - sta->acct_session_id_lo = hapd->acct_session_id_lo++; - if (hapd->acct_session_id_lo == 0) { - hapd->acct_session_id_hi++; - } - sta->acct_session_id_hi = hapd->acct_session_id_hi; -} - - -/** - * accounting_receive - Process the RADIUS frames from Accounting Server - * @msg: RADIUS response message - * @req: RADIUS request message - * @shared_secret: RADIUS shared secret - * @shared_secret_len: Length of shared_secret in octets - * @data: Context data (struct hostapd_data *) - * Returns: Processing status - */ -static RadiusRxResult -accounting_receive(struct radius_msg *msg, struct radius_msg *req, - const u8 *shared_secret, size_t shared_secret_len, - void *data) -{ - if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) { - wpa_printf(MSG_INFO, "Unknown RADIUS message code"); - return RADIUS_RX_UNKNOWN; - } - - if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) { - wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Authenticator - dropped"); - return RADIUS_RX_INVALID_AUTHENTICATOR; - } - - return RADIUS_RX_PROCESSED; -} - - -static void accounting_report_state(struct hostapd_data *hapd, int on) -{ - struct radius_msg *msg; - - if (!hapd->conf->radius->acct_server || hapd->radius == NULL) - return; - - /* Inform RADIUS server that accounting will start/stop so that the - * server can close old accounting sessions. */ - msg = accounting_msg(hapd, NULL, - on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON : - RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF); - if (!msg) - return; - - if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE, - RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT)) - { - wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause"); - radius_msg_free(msg); - return; - } - - if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0) - radius_msg_free(msg); -} - - -/** - * accounting_init: Initialize accounting - * @hapd: hostapd BSS data - * Returns: 0 on success, -1 on failure - */ -int accounting_init(struct hostapd_data *hapd) -{ - struct os_time now; - - /* Acct-Session-Id should be unique over reboots. If reliable clock is - * not available, this could be replaced with reboot counter, etc. */ - os_get_time(&now); - hapd->acct_session_id_hi = now.sec; - - if (radius_client_register(hapd->radius, RADIUS_ACCT, - accounting_receive, hapd)) - return -1; - - accounting_report_state(hapd, 1); - - return 0; -} - - -/** - * accounting_deinit: Deinitilize accounting - * @hapd: hostapd BSS data - */ -void accounting_deinit(struct hostapd_data *hapd) -{ - accounting_report_state(hapd, 0); -} diff --git a/contrib/hostapd/src/ap/accounting.h b/contrib/hostapd/src/ap/accounting.h deleted file mode 100644 index dcc54ee94b..0000000000 --- a/contrib/hostapd/src/ap/accounting.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * hostapd / RADIUS Accounting - * Copyright (c) 2002-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef ACCOUNTING_H -#define ACCOUNTING_H - -#ifdef CONFIG_NO_ACCOUNTING -static inline void accounting_sta_get_id(struct hostapd_data *hapd, - struct sta_info *sta) -{ -} - -static inline void accounting_sta_start(struct hostapd_data *hapd, - struct sta_info *sta) -{ -} - -static inline void accounting_sta_stop(struct hostapd_data *hapd, - struct sta_info *sta) -{ -} - -static inline int accounting_init(struct hostapd_data *hapd) -{ - return 0; -} - -static inline void accounting_deinit(struct hostapd_data *hapd) -{ -} -#else /* CONFIG_NO_ACCOUNTING */ -void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta); -void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta); -void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta); -int accounting_init(struct hostapd_data *hapd); -void accounting_deinit(struct hostapd_data *hapd); -#endif /* CONFIG_NO_ACCOUNTING */ - -#endif /* ACCOUNTING_H */ diff --git a/contrib/hostapd/src/ap/acs.c b/contrib/hostapd/src/ap/acs.c deleted file mode 100644 index f58b091e09..0000000000 --- a/contrib/hostapd/src/ap/acs.c +++ /dev/null @@ -1,802 +0,0 @@ -/* - * ACS - Automatic Channel Selection module - * Copyright (c) 2011, Atheros Communications - * Copyright (c) 2013, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" -#include - -#include "utils/common.h" -#include "utils/list.h" -#include "common/ieee802_11_defs.h" -#include "common/wpa_ctrl.h" -#include "drivers/driver.h" -#include "hostapd.h" -#include "ap_drv_ops.h" -#include "ap_config.h" -#include "hw_features.h" -#include "acs.h" - -/* - * Automatic Channel Selection - * =========================== - * - * More info at - * ------------ - * http://wireless.kernel.org/en/users/Documentation/acs - * - * How to use - * ---------- - * - make sure you have CONFIG_ACS=y in hostapd's .config - * - use channel=0 or channel=acs to enable ACS - * - * How does it work - * ---------------- - * 1. passive scans are used to collect survey data - * (it is assumed that scan trigger collection of survey data in driver) - * 2. interference factor is calculated for each channel - * 3. ideal channel is picked depending on channel width by using adjacent - * channel interference factors - * - * Known limitations - * ----------------- - * - Current implementation depends heavily on the amount of time willing to - * spend gathering survey data during hostapd startup. Short traffic bursts - * may be missed and a suboptimal channel may be picked. - * - Ideal channel may end up overlapping a channel with 40 MHz intolerant BSS - * - * Todo / Ideas - * ------------ - * - implement other interference computation methods - * - BSS/RSSI based - * - spectral scan based - * (should be possibly to hook this up with current ACS scans) - * - add wpa_supplicant support (for P2P) - * - collect a histogram of interference over time allowing more educated - * guess about an ideal channel (perhaps CSA could be used to migrate AP to a - * new "better" channel while running) - * - include neighboring BSS scan to avoid conflicts with 40 MHz intolerant BSSs - * when choosing the ideal channel - * - * Survey interference factor implementation details - * ------------------------------------------------- - * Generic interference_factor in struct hostapd_channel_data is used. - * - * The survey interference factor is defined as the ratio of the - * observed busy time over the time we spent on the channel, - * this value is then amplified by the observed noise floor on - * the channel in comparison to the lowest noise floor observed - * on the entire band. - * - * This corresponds to: - * --- - * (busy time - tx time) / (active time - tx time) * 2^(chan_nf + band_min_nf) - * --- - * - * The coefficient of 2 reflects the way power in "far-field" - * radiation decreases as the square of distance from the antenna [1]. - * What this does is it decreases the observed busy time ratio if the - * noise observed was low but increases it if the noise was high, - * proportionally to the way "far field" radiation changes over - * distance. - * - * If channel busy time is not available the fallback is to use channel RX time. - * - * Since noise floor is in dBm it is necessary to convert it into Watts so that - * combined channel interference (e.g., HT40, which uses two channels) can be - * calculated easily. - * --- - * (busy time - tx time) / (active time - tx time) * - * 2^(10^(chan_nf/10) + 10^(band_min_nf/10)) - * --- - * - * However to account for cases where busy/rx time is 0 (channel load is then - * 0%) channel noise floor signal power is combined into the equation so a - * channel with lower noise floor is preferred. The equation becomes: - * --- - * 10^(chan_nf/5) + (busy time - tx time) / (active time - tx time) * - * 2^(10^(chan_nf/10) + 10^(band_min_nf/10)) - * --- - * - * All this "interference factor" is purely subjective and only time - * will tell how usable this is. By using the minimum noise floor we - * remove any possible issues due to card calibration. The computation - * of the interference factor then is dependent on what the card itself - * picks up as the minimum noise, not an actual real possible card - * noise value. - * - * Total interference computation details - * -------------------------------------- - * The above channel interference factor is calculated with no respect to - * target operational bandwidth. - * - * To find an ideal channel the above data is combined by taking into account - * the target operational bandwidth and selected band. E.g., on 2.4 GHz channels - * overlap with 20 MHz bandwidth, but there is no overlap for 20 MHz bandwidth - * on 5 GHz. - * - * Each valid and possible channel spec (i.e., channel + width) is taken and its - * interference factor is computed by summing up interferences of each channel - * it overlaps. The one with least total interference is picked up. - * - * Note: This implies base channel interference factor must be non-negative - * allowing easy summing up. - * - * Example ACS analysis printout - * ----------------------------- - * - * ACS: Trying survey-based ACS - * ACS: Survey analysis for channel 1 (2412 MHz) - * ACS: 1: min_nf=-113 interference_factor=0.0802469 nf=-113 time=162 busy=0 rx=13 - * ACS: 2: min_nf=-113 interference_factor=0.0745342 nf=-113 time=161 busy=0 rx=12 - * ACS: 3: min_nf=-113 interference_factor=0.0679012 nf=-113 time=162 busy=0 rx=11 - * ACS: 4: min_nf=-113 interference_factor=0.0310559 nf=-113 time=161 busy=0 rx=5 - * ACS: 5: min_nf=-113 interference_factor=0.0248447 nf=-113 time=161 busy=0 rx=4 - * ACS: * interference factor average: 0.0557166 - * ACS: Survey analysis for channel 2 (2417 MHz) - * ACS: 1: min_nf=-113 interference_factor=0.0185185 nf=-113 time=162 busy=0 rx=3 - * ACS: 2: min_nf=-113 interference_factor=0.0246914 nf=-113 time=162 busy=0 rx=4 - * ACS: 3: min_nf=-113 interference_factor=0.037037 nf=-113 time=162 busy=0 rx=6 - * ACS: 4: min_nf=-113 interference_factor=0.149068 nf=-113 time=161 busy=0 rx=24 - * ACS: 5: min_nf=-113 interference_factor=0.0248447 nf=-113 time=161 busy=0 rx=4 - * ACS: * interference factor average: 0.050832 - * ACS: Survey analysis for channel 3 (2422 MHz) - * ACS: 1: min_nf=-113 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0 - * ACS: 2: min_nf=-113 interference_factor=0.0185185 nf=-113 time=162 busy=0 rx=3 - * ACS: 3: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3 - * ACS: 4: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3 - * ACS: 5: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3 - * ACS: * interference factor average: 0.0148838 - * ACS: Survey analysis for channel 4 (2427 MHz) - * ACS: 1: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0 - * ACS: 2: min_nf=-114 interference_factor=0.0555556 nf=-114 time=162 busy=0 rx=9 - * ACS: 3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0 - * ACS: 4: min_nf=-114 interference_factor=0.0186335 nf=-114 time=161 busy=0 rx=3 - * ACS: 5: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1 - * ACS: * interference factor average: 0.0160801 - * ACS: Survey analysis for channel 5 (2432 MHz) - * ACS: 1: min_nf=-114 interference_factor=0.409938 nf=-113 time=161 busy=0 rx=66 - * ACS: 2: min_nf=-114 interference_factor=0.0432099 nf=-113 time=162 busy=0 rx=7 - * ACS: 3: min_nf=-114 interference_factor=0.0124224 nf=-113 time=161 busy=0 rx=2 - * ACS: 4: min_nf=-114 interference_factor=0.677019 nf=-113 time=161 busy=0 rx=109 - * ACS: 5: min_nf=-114 interference_factor=0.0186335 nf=-114 time=161 busy=0 rx=3 - * ACS: * interference factor average: 0.232244 - * ACS: Survey analysis for channel 6 (2437 MHz) - * ACS: 1: min_nf=-113 interference_factor=0.552795 nf=-113 time=161 busy=0 rx=89 - * ACS: 2: min_nf=-113 interference_factor=0.0807453 nf=-112 time=161 busy=0 rx=13 - * ACS: 3: min_nf=-113 interference_factor=0.0310559 nf=-113 time=161 busy=0 rx=5 - * ACS: 4: min_nf=-113 interference_factor=0.434783 nf=-112 time=161 busy=0 rx=70 - * ACS: 5: min_nf=-113 interference_factor=0.0621118 nf=-113 time=161 busy=0 rx=10 - * ACS: * interference factor average: 0.232298 - * ACS: Survey analysis for channel 7 (2442 MHz) - * ACS: 1: min_nf=-113 interference_factor=0.440994 nf=-112 time=161 busy=0 rx=71 - * ACS: 2: min_nf=-113 interference_factor=0.385093 nf=-113 time=161 busy=0 rx=62 - * ACS: 3: min_nf=-113 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6 - * ACS: 4: min_nf=-113 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6 - * ACS: 5: min_nf=-113 interference_factor=0.0745342 nf=-113 time=161 busy=0 rx=12 - * ACS: * interference factor average: 0.195031 - * ACS: Survey analysis for channel 8 (2447 MHz) - * ACS: 1: min_nf=-114 interference_factor=0.0496894 nf=-112 time=161 busy=0 rx=8 - * ACS: 2: min_nf=-114 interference_factor=0.0496894 nf=-114 time=161 busy=0 rx=8 - * ACS: 3: min_nf=-114 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6 - * ACS: 4: min_nf=-114 interference_factor=0.12963 nf=-113 time=162 busy=0 rx=21 - * ACS: 5: min_nf=-114 interference_factor=0.166667 nf=-114 time=162 busy=0 rx=27 - * ACS: * interference factor average: 0.0865885 - * ACS: Survey analysis for channel 9 (2452 MHz) - * ACS: 1: min_nf=-114 interference_factor=0.0124224 nf=-114 time=161 busy=0 rx=2 - * ACS: 2: min_nf=-114 interference_factor=0.0310559 nf=-114 time=161 busy=0 rx=5 - * ACS: 3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0 - * ACS: 4: min_nf=-114 interference_factor=0.00617284 nf=-114 time=162 busy=0 rx=1 - * ACS: 5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0 - * ACS: * interference factor average: 0.00993022 - * ACS: Survey analysis for channel 10 (2457 MHz) - * ACS: 1: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1 - * ACS: 2: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1 - * ACS: 3: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1 - * ACS: 4: min_nf=-114 interference_factor=0.0493827 nf=-114 time=162 busy=0 rx=8 - * ACS: 5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0 - * ACS: * interference factor average: 0.0136033 - * ACS: Survey analysis for channel 11 (2462 MHz) - * ACS: 1: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0 - * ACS: 2: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=161 busy=0 rx=0 - * ACS: 3: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=161 busy=0 rx=0 - * ACS: 4: min_nf=-114 interference_factor=0.0432099 nf=-114 time=162 busy=0 rx=7 - * ACS: 5: min_nf=-114 interference_factor=0.0925926 nf=-114 time=162 busy=0 rx=15 - * ACS: * interference factor average: 0.0271605 - * ACS: Survey analysis for channel 12 (2467 MHz) - * ACS: 1: min_nf=-114 interference_factor=0.0621118 nf=-113 time=161 busy=0 rx=10 - * ACS: 2: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1 - * ACS: 3: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0 - * ACS: 4: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0 - * ACS: 5: min_nf=-114 interference_factor=0.00617284 nf=-113 time=162 busy=0 rx=1 - * ACS: * interference factor average: 0.0148992 - * ACS: Survey analysis for channel 13 (2472 MHz) - * ACS: 1: min_nf=-114 interference_factor=0.0745342 nf=-114 time=161 busy=0 rx=12 - * ACS: 2: min_nf=-114 interference_factor=0.0555556 nf=-114 time=162 busy=0 rx=9 - * ACS: 3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0 - * ACS: 4: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0 - * ACS: 5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0 - * ACS: * interference factor average: 0.0260179 - * ACS: Survey analysis for selected bandwidth 20MHz - * ACS: * channel 1: total interference = 0.121432 - * ACS: * channel 2: total interference = 0.137512 - * ACS: * channel 3: total interference = 0.369757 - * ACS: * channel 4: total interference = 0.546338 - * ACS: * channel 5: total interference = 0.690538 - * ACS: * channel 6: total interference = 0.762242 - * ACS: * channel 7: total interference = 0.756092 - * ACS: * channel 8: total interference = 0.537451 - * ACS: * channel 9: total interference = 0.332313 - * ACS: * channel 10: total interference = 0.152182 - * ACS: * channel 11: total interference = 0.0916111 - * ACS: * channel 12: total interference = 0.0816809 - * ACS: * channel 13: total interference = 0.0680776 - * ACS: Ideal channel is 13 (2472 MHz) with total interference factor of 0.0680776 - * - * [1] http://en.wikipedia.org/wiki/Near_and_far_field - */ - - -static int acs_request_scan(struct hostapd_iface *iface); - - -static void acs_clean_chan_surveys(struct hostapd_channel_data *chan) -{ - struct freq_survey *survey, *tmp; - - if (dl_list_empty(&chan->survey_list)) - return; - - dl_list_for_each_safe(survey, tmp, &chan->survey_list, - struct freq_survey, list) { - dl_list_del(&survey->list); - os_free(survey); - } -} - - -static void acs_cleanup(struct hostapd_iface *iface) -{ - int i; - struct hostapd_channel_data *chan; - - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - - if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED) - acs_clean_chan_surveys(chan); - - dl_list_init(&chan->survey_list); - chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED; - chan->min_nf = 0; - } - - iface->chans_surveyed = 0; - iface->acs_num_completed_scans = 0; -} - - -static void acs_fail(struct hostapd_iface *iface) -{ - wpa_printf(MSG_ERROR, "ACS: Failed to start"); - acs_cleanup(iface); -} - - -static long double -acs_survey_interference_factor(struct freq_survey *survey, s8 min_nf) -{ - long double factor, busy, total; - - if (survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) - busy = survey->channel_time_busy; - else if (survey->filled & SURVEY_HAS_CHAN_TIME_RX) - busy = survey->channel_time_rx; - else { - /* This shouldn't really happen as survey data is checked in - * acs_sanity_check() */ - wpa_printf(MSG_ERROR, "ACS: Survey data missing"); - return 0; - } - - total = survey->channel_time; - - if (survey->filled & SURVEY_HAS_CHAN_TIME_TX) { - busy -= survey->channel_time_tx; - total -= survey->channel_time_tx; - } - - /* TODO: figure out the best multiplier for noise floor base */ - factor = pow(10, survey->nf / 5.0L) + - (busy / total) * - pow(2, pow(10, (long double) survey->nf / 10.0L) - - pow(10, (long double) min_nf / 10.0L)); - - return factor; -} - - -static void -acs_survey_chan_interference_factor(struct hostapd_iface *iface, - struct hostapd_channel_data *chan) -{ - struct freq_survey *survey; - unsigned int i = 0; - long double int_factor = 0; - - if (dl_list_empty(&chan->survey_list)) - return; - - if (chan->flag & HOSTAPD_CHAN_DISABLED) - return; - - chan->interference_factor = 0; - - dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list) - { - int_factor = acs_survey_interference_factor(survey, - iface->lowest_nf); - chan->interference_factor += int_factor; - wpa_printf(MSG_DEBUG, "ACS: %d: min_nf=%d interference_factor=%Lg nf=%d time=%lu busy=%lu rx=%lu", - ++i, chan->min_nf, int_factor, - survey->nf, (unsigned long) survey->channel_time, - (unsigned long) survey->channel_time_busy, - (unsigned long) survey->channel_time_rx); - } - - chan->interference_factor = chan->interference_factor / - dl_list_len(&chan->survey_list); -} - - -static int acs_usable_ht40_chan(struct hostapd_channel_data *chan) -{ - const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, - 157, 184, 192 }; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(allowed); i++) - if (chan->chan == allowed[i]) - return 1; - - return 0; -} - - -static int acs_survey_is_sufficient(struct freq_survey *survey) -{ - if (!(survey->filled & SURVEY_HAS_NF)) { - wpa_printf(MSG_ERROR, "ACS: Survey is missing noise floor"); - return 0; - } - - if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) { - wpa_printf(MSG_ERROR, "ACS: Survey is missing channel time"); - return 0; - } - - if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) && - !(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) { - wpa_printf(MSG_ERROR, "ACS: Survey is missing RX and busy time (at least one is required)"); - return 0; - } - - return 1; -} - - -static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan) -{ - struct freq_survey *survey; - - dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list) - { - if (!acs_survey_is_sufficient(survey)) { - wpa_printf(MSG_ERROR, "ACS: Channel %d has insufficient survey data", - chan->chan); - return 0; - } - } - - return 1; - -} - - -static int acs_surveys_are_sufficient(struct hostapd_iface *iface) -{ - int i; - struct hostapd_channel_data *chan; - int valid = 0; - - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - if (chan->flag & HOSTAPD_CHAN_DISABLED) - continue; - - if (!acs_survey_list_is_sufficient(chan)) - continue; - - valid++; - } - - /* We need at least survey data for one channel */ - return !!valid; -} - - -static int acs_usable_chan(struct hostapd_channel_data *chan) -{ - if (dl_list_empty(&chan->survey_list)) - return 0; - if (chan->flag & HOSTAPD_CHAN_DISABLED) - return 0; - if (!acs_survey_list_is_sufficient(chan)) - return 0; - return 1; -} - - -static void acs_survey_all_chans_intereference_factor( - struct hostapd_iface *iface) -{ - int i; - struct hostapd_channel_data *chan; - - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - - if (!acs_usable_chan(chan)) - continue; - - wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)", - chan->chan, chan->freq); - - acs_survey_chan_interference_factor(iface, chan); - - wpa_printf(MSG_DEBUG, "ACS: * interference factor average: %Lg", - chan->interference_factor); - } -} - - -static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface, - int freq) -{ - struct hostapd_channel_data *chan; - int i; - - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - - if (chan->flag & HOSTAPD_CHAN_DISABLED) - continue; - - if (chan->freq == freq) - return chan; - } - - return NULL; -} - - -/* - * At this point it's assumed chan->interface_factor has been computed. - * This function should be reusable regardless of interference computation - * option (survey, BSS, spectral, ...). chan->interference factor must be - * summable (i.e., must be always greater than zero). - */ -static struct hostapd_channel_data * -acs_find_ideal_chan(struct hostapd_iface *iface) -{ - struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL, - *rand_chan = NULL; - long double factor, ideal_factor = 0; - int i, j; - int n_chans = 1; - - /* TODO: HT40- support */ - - if (iface->conf->ieee80211n && - iface->conf->secondary_channel == -1) { - wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+"); - return NULL; - } - - if (iface->conf->ieee80211n && - iface->conf->secondary_channel) - n_chans = 2; - - if (iface->conf->ieee80211ac && - iface->conf->vht_oper_chwidth == 1) - n_chans = 4; - - /* TODO: VHT80+80, VHT160. Update acs_adjust_vht_center_freq() too. */ - - wpa_printf(MSG_DEBUG, "ACS: Survey analysis for selected bandwidth %d MHz", - n_chans == 1 ? 20 : - n_chans == 2 ? 40 : - n_chans == 4 ? 80 : - -1); - - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - - if (chan->flag & HOSTAPD_CHAN_DISABLED) - continue; - - - /* HT40 on 5 GHz has a limited set of primary channels as per - * 11n Annex J */ - if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && - iface->conf->ieee80211n && - iface->conf->secondary_channel && - !acs_usable_ht40_chan(chan)) { - wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for HT40", - chan->chan); - continue; - } - - factor = 0; - if (acs_usable_chan(chan)) - factor = chan->interference_factor; - - for (j = 1; j < n_chans; j++) { - adj_chan = acs_find_chan(iface, chan->freq + (j * 20)); - if (!adj_chan) - break; - - if (acs_usable_chan(adj_chan)) - factor += adj_chan->interference_factor; - } - - if (j != n_chans) { - wpa_printf(MSG_DEBUG, "ACS: Channel %d: not enough bandwidth", - chan->chan); - continue; - } - - /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent - * channel interference factor. */ - if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B || - iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) { - for (j = 0; j < n_chans; j++) { - /* TODO: perhaps a multiplier should be used - * here? */ - - adj_chan = acs_find_chan(iface, chan->freq + - (j * 20) - 5); - if (adj_chan && acs_usable_chan(adj_chan)) - factor += adj_chan->interference_factor; - - adj_chan = acs_find_chan(iface, chan->freq + - (j * 20) - 10); - if (adj_chan && acs_usable_chan(adj_chan)) - factor += adj_chan->interference_factor; - - adj_chan = acs_find_chan(iface, chan->freq + - (j * 20) + 5); - if (adj_chan && acs_usable_chan(adj_chan)) - factor += adj_chan->interference_factor; - - adj_chan = acs_find_chan(iface, chan->freq + - (j * 20) + 10); - if (adj_chan && acs_usable_chan(adj_chan)) - factor += adj_chan->interference_factor; - } - } - - wpa_printf(MSG_DEBUG, "ACS: * channel %d: total interference = %Lg", - chan->chan, factor); - - if (acs_usable_chan(chan) && - (!ideal_chan || factor < ideal_factor)) { - ideal_factor = factor; - ideal_chan = chan; - } - - /* This channel would at least be usable */ - if (!rand_chan) - rand_chan = chan; - } - - if (ideal_chan) { - wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg", - ideal_chan->chan, ideal_chan->freq, ideal_factor); - return ideal_chan; - } - - return rand_chan; -} - - -static void acs_adjust_vht_center_freq(struct hostapd_iface *iface) -{ - wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency"); - - switch (iface->conf->vht_oper_chwidth) { - case VHT_CHANWIDTH_USE_HT: - iface->conf->vht_oper_centr_freq_seg0_idx = - iface->conf->channel + 2; - break; - case VHT_CHANWIDTH_80MHZ: - iface->conf->vht_oper_centr_freq_seg0_idx = - iface->conf->channel + 6; - break; - default: - /* TODO: How can this be calculated? Adjust - * acs_find_ideal_chan() */ - wpa_printf(MSG_INFO, "ACS: Only VHT20/40/80 is supported now"); - break; - } -} - - -static int acs_study_survey_based(struct hostapd_iface *iface) -{ - wpa_printf(MSG_DEBUG, "ACS: Trying survey-based ACS"); - - if (!iface->chans_surveyed) { - wpa_printf(MSG_ERROR, "ACS: Unable to collect survey data"); - return -1; - } - - if (!acs_surveys_are_sufficient(iface)) { - wpa_printf(MSG_ERROR, "ACS: Surveys have insufficient data"); - return -1; - } - - acs_survey_all_chans_intereference_factor(iface); - return 0; -} - - -static int acs_study_options(struct hostapd_iface *iface) -{ - int err; - - err = acs_study_survey_based(iface); - if (err == 0) - return 0; - - /* TODO: If no surveys are available/sufficient this is a good - * place to fallback to BSS-based ACS */ - - return -1; -} - - -static void acs_study(struct hostapd_iface *iface) -{ - struct hostapd_channel_data *ideal_chan; - int err; - - err = acs_study_options(iface); - if (err < 0) { - wpa_printf(MSG_ERROR, "ACS: All study options have failed"); - goto fail; - } - - ideal_chan = acs_find_ideal_chan(iface); - if (!ideal_chan) { - wpa_printf(MSG_ERROR, "ACS: Failed to compute ideal channel"); - err = -1; - goto fail; - } - - iface->conf->channel = ideal_chan->chan; - - if (iface->conf->ieee80211ac) - acs_adjust_vht_center_freq(iface); - - err = 0; -fail: - /* - * hostapd_setup_interface_complete() will return -1 on failure, - * 0 on success and 0 is HOSTAPD_CHAN_VALID :) - */ - if (hostapd_acs_completed(iface, err) == HOSTAPD_CHAN_VALID) { - acs_cleanup(iface); - return; - } - - /* This can possibly happen if channel parameters (secondary - * channel, center frequencies) are misconfigured */ - wpa_printf(MSG_ERROR, "ACS: Possibly channel configuration is invalid, please report this along with your config file."); - acs_fail(iface); -} - - -static void acs_scan_complete(struct hostapd_iface *iface) -{ - int err; - - iface->scan_cb = NULL; - - wpa_printf(MSG_DEBUG, "ACS: Using survey based algorithm (acs_num_scans=%d)", - iface->conf->acs_num_scans); - - err = hostapd_drv_get_survey(iface->bss[0], 0); - if (err) { - wpa_printf(MSG_ERROR, "ACS: Failed to get survey data"); - acs_fail(iface); - } - - if (++iface->acs_num_completed_scans < iface->conf->acs_num_scans) { - err = acs_request_scan(iface); - if (err) { - wpa_printf(MSG_ERROR, "ACS: Failed to request scan"); - goto fail; - } - - return; - } - - acs_study(iface); - return; -fail: - hostapd_acs_completed(iface, 1); - acs_fail(iface); -} - - -static int acs_request_scan(struct hostapd_iface *iface) -{ - struct wpa_driver_scan_params params; - struct hostapd_channel_data *chan; - int i, *freq; - - os_memset(¶ms, 0, sizeof(params)); - params.freqs = os_calloc(iface->current_mode->num_channels + 1, - sizeof(params.freqs[0])); - if (params.freqs == NULL) - return -1; - - freq = params.freqs; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - if (chan->flag & HOSTAPD_CHAN_DISABLED) - continue; - - *freq++ = chan->freq; - } - *freq = 0; - - iface->scan_cb = acs_scan_complete; - - wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d", - iface->acs_num_completed_scans + 1, - iface->conf->acs_num_scans); - - if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) { - wpa_printf(MSG_ERROR, "ACS: Failed to request initial scan"); - acs_cleanup(iface); - return -1; - } - - os_free(params.freqs); - return 0; -} - - -enum hostapd_chan_status acs_init(struct hostapd_iface *iface) -{ - int err; - - wpa_printf(MSG_INFO, "ACS: Automatic channel selection started, this may take a bit"); - - acs_cleanup(iface); - - err = acs_request_scan(iface); - if (err < 0) - return HOSTAPD_CHAN_INVALID; - - hostapd_set_state(iface, HAPD_IFACE_ACS); - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_STARTED); - - return HOSTAPD_CHAN_ACS; -} diff --git a/contrib/hostapd/src/ap/acs.h b/contrib/hostapd/src/ap/acs.h deleted file mode 100644 index fc85259e85..0000000000 --- a/contrib/hostapd/src/ap/acs.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * ACS - Automatic Channel Selection module - * Copyright (c) 2011, Atheros Communications - * Copyright (c) 2013, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef ACS_H -#define ACS_H - -#ifdef CONFIG_ACS - -enum hostapd_chan_status acs_init(struct hostapd_iface *iface); - -#else /* CONFIG_ACS */ - -static inline enum hostapd_chan_status acs_init(struct hostapd_iface *iface) -{ - wpa_printf(MSG_ERROR, "ACS was disabled on your build, rebuild hostapd with CONFIG_ACS=y or set channel"); - return HOSTAPD_CHAN_INVALID; -} - -#endif /* CONFIG_ACS */ - -#endif /* ACS_H */ diff --git a/contrib/hostapd/src/ap/ap_config.c b/contrib/hostapd/src/ap/ap_config.c deleted file mode 100644 index 368b2020e8..0000000000 --- a/contrib/hostapd/src/ap/ap_config.c +++ /dev/null @@ -1,885 +0,0 @@ -/* - * hostapd / Configuration helper functions - * Copyright (c) 2003-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "crypto/sha1.h" -#include "radius/radius_client.h" -#include "common/ieee802_11_defs.h" -#include "common/eapol_common.h" -#include "eap_common/eap_wsc_common.h" -#include "eap_server/eap.h" -#include "wpa_auth.h" -#include "sta_info.h" -#include "ap_config.h" - - -static void hostapd_config_free_vlan(struct hostapd_bss_config *bss) -{ - struct hostapd_vlan *vlan, *prev; - - vlan = bss->vlan; - prev = NULL; - while (vlan) { - prev = vlan; - vlan = vlan->next; - os_free(prev); - } - - bss->vlan = NULL; -} - - -void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) -{ - bss->logger_syslog_level = HOSTAPD_LEVEL_INFO; - bss->logger_stdout_level = HOSTAPD_LEVEL_INFO; - bss->logger_syslog = (unsigned int) -1; - bss->logger_stdout = (unsigned int) -1; - - bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED; - - bss->wep_rekeying_period = 300; - /* use key0 in individual key and key1 in broadcast key */ - bss->broadcast_key_idx_min = 1; - bss->broadcast_key_idx_max = 2; - bss->eap_reauth_period = 3600; - - bss->wpa_group_rekey = 600; - bss->wpa_gmk_rekey = 86400; - bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK; - bss->wpa_pairwise = WPA_CIPHER_TKIP; - bss->wpa_group = WPA_CIPHER_TKIP; - bss->rsn_pairwise = 0; - - bss->max_num_sta = MAX_STA_COUNT; - - bss->dtim_period = 2; - - bss->radius_server_auth_port = 1812; - bss->ap_max_inactivity = AP_MAX_INACTIVITY; - bss->eapol_version = EAPOL_VERSION; - - bss->max_listen_interval = 65535; - - bss->pwd_group = 19; /* ECC: GF(p=256) */ - -#ifdef CONFIG_IEEE80211W - bss->assoc_sa_query_max_timeout = 1000; - bss->assoc_sa_query_retry_timeout = 201; -#endif /* CONFIG_IEEE80211W */ -#ifdef EAP_SERVER_FAST - /* both anonymous and authenticated provisioning */ - bss->eap_fast_prov = 3; - bss->pac_key_lifetime = 7 * 24 * 60 * 60; - bss->pac_key_refresh_time = 1 * 24 * 60 * 60; -#endif /* EAP_SERVER_FAST */ - - /* Set to -1 as defaults depends on HT in setup */ - bss->wmm_enabled = -1; - -#ifdef CONFIG_IEEE80211R - bss->ft_over_ds = 1; -#endif /* CONFIG_IEEE80211R */ - - bss->radius_das_time_window = 300; - - bss->sae_anti_clogging_threshold = 5; -} - - -struct hostapd_config * hostapd_config_defaults(void) -{ -#define ecw2cw(ecw) ((1 << (ecw)) - 1) - - struct hostapd_config *conf; - struct hostapd_bss_config *bss; - const int aCWmin = 4, aCWmax = 10; - const struct hostapd_wmm_ac_params ac_bk = - { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */ - const struct hostapd_wmm_ac_params ac_be = - { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */ - const struct hostapd_wmm_ac_params ac_vi = /* video traffic */ - { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 }; - const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */ - { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 }; - const struct hostapd_tx_queue_params txq_bk = - { 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 }; - const struct hostapd_tx_queue_params txq_be = - { 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0}; - const struct hostapd_tx_queue_params txq_vi = - { 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30}; - const struct hostapd_tx_queue_params txq_vo = - { 1, (ecw2cw(aCWmin) + 1) / 4 - 1, - (ecw2cw(aCWmin) + 1) / 2 - 1, 15}; - -#undef ecw2cw - - conf = os_zalloc(sizeof(*conf)); - bss = os_zalloc(sizeof(*bss)); - if (conf == NULL || bss == NULL) { - wpa_printf(MSG_ERROR, "Failed to allocate memory for " - "configuration data."); - os_free(conf); - os_free(bss); - return NULL; - } - conf->bss = os_calloc(1, sizeof(struct hostapd_bss_config *)); - if (conf->bss == NULL) { - os_free(conf); - os_free(bss); - return NULL; - } - conf->bss[0] = bss; - - bss->radius = os_zalloc(sizeof(*bss->radius)); - if (bss->radius == NULL) { - os_free(conf->bss); - os_free(conf); - os_free(bss); - return NULL; - } - - hostapd_config_defaults_bss(bss); - - conf->num_bss = 1; - - conf->beacon_int = 100; - conf->rts_threshold = -1; /* use driver default: 2347 */ - conf->fragm_threshold = -1; /* user driver default: 2346 */ - conf->send_probe_response = 1; - - conf->wmm_ac_params[0] = ac_be; - conf->wmm_ac_params[1] = ac_bk; - conf->wmm_ac_params[2] = ac_vi; - conf->wmm_ac_params[3] = ac_vo; - - conf->tx_queue[0] = txq_vo; - conf->tx_queue[1] = txq_vi; - conf->tx_queue[2] = txq_be; - conf->tx_queue[3] = txq_bk; - - conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED; - - conf->ap_table_max_size = 255; - conf->ap_table_expiration_time = 60; - -#ifdef CONFIG_TESTING_OPTIONS - conf->ignore_probe_probability = 0.0d; - conf->ignore_auth_probability = 0.0d; - conf->ignore_assoc_probability = 0.0d; - conf->ignore_reassoc_probability = 0.0d; - conf->corrupt_gtk_rekey_mic_probability = 0.0d; -#endif /* CONFIG_TESTING_OPTIONS */ - -#ifdef CONFIG_ACS - conf->acs_num_scans = 5; -#endif /* CONFIG_ACS */ - - return conf; -} - - -int hostapd_mac_comp(const void *a, const void *b) -{ - return os_memcmp(a, b, sizeof(macaddr)); -} - - -int hostapd_mac_comp_empty(const void *a) -{ - macaddr empty = { 0 }; - return os_memcmp(a, empty, sizeof(macaddr)); -} - - -static int hostapd_config_read_wpa_psk(const char *fname, - struct hostapd_ssid *ssid) -{ - FILE *f; - char buf[128], *pos; - int line = 0, ret = 0, len, ok; - u8 addr[ETH_ALEN]; - struct hostapd_wpa_psk *psk; - - if (!fname) - return 0; - - f = fopen(fname, "r"); - if (!f) { - wpa_printf(MSG_ERROR, "WPA PSK file '%s' not found.", fname); - return -1; - } - - while (fgets(buf, sizeof(buf), f)) { - line++; - - if (buf[0] == '#') - continue; - pos = buf; - while (*pos != '\0') { - if (*pos == '\n') { - *pos = '\0'; - break; - } - pos++; - } - if (buf[0] == '\0') - continue; - - if (hwaddr_aton(buf, addr)) { - wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on " - "line %d in '%s'", buf, line, fname); - ret = -1; - break; - } - - psk = os_zalloc(sizeof(*psk)); - if (psk == NULL) { - wpa_printf(MSG_ERROR, "WPA PSK allocation failed"); - ret = -1; - break; - } - if (is_zero_ether_addr(addr)) - psk->group = 1; - else - os_memcpy(psk->addr, addr, ETH_ALEN); - - pos = buf + 17; - if (*pos == '\0') { - wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'", - line, fname); - os_free(psk); - ret = -1; - break; - } - pos++; - - ok = 0; - len = os_strlen(pos); - if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0) - ok = 1; - else if (len >= 8 && len < 64) { - pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len, - 4096, psk->psk, PMK_LEN); - ok = 1; - } - if (!ok) { - wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in " - "'%s'", pos, line, fname); - os_free(psk); - ret = -1; - break; - } - - psk->next = ssid->wpa_psk; - ssid->wpa_psk = psk; - } - - fclose(f); - - return ret; -} - - -static int hostapd_derive_psk(struct hostapd_ssid *ssid) -{ - ssid->wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk)); - if (ssid->wpa_psk == NULL) { - wpa_printf(MSG_ERROR, "Unable to alloc space for PSK"); - return -1; - } - wpa_hexdump_ascii(MSG_DEBUG, "SSID", - (u8 *) ssid->ssid, ssid->ssid_len); - wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)", - (u8 *) ssid->wpa_passphrase, - os_strlen(ssid->wpa_passphrase)); - pbkdf2_sha1(ssid->wpa_passphrase, - ssid->ssid, ssid->ssid_len, - 4096, ssid->wpa_psk->psk, PMK_LEN); - wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)", - ssid->wpa_psk->psk, PMK_LEN); - return 0; -} - - -int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf) -{ - struct hostapd_ssid *ssid = &conf->ssid; - - if (ssid->wpa_passphrase != NULL) { - if (ssid->wpa_psk != NULL) { - wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK " - "instead of passphrase"); - } else { - wpa_printf(MSG_DEBUG, "Deriving WPA PSK based on " - "passphrase"); - if (hostapd_derive_psk(ssid) < 0) - return -1; - } - ssid->wpa_psk->group = 1; - } - - if (ssid->wpa_psk_file) { - if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file, - &conf->ssid)) - return -1; - } - - return 0; -} - - -int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b) -{ - int i; - - if (a->idx != b->idx || a->default_len != b->default_len) - return 1; - for (i = 0; i < NUM_WEP_KEYS; i++) - if (a->len[i] != b->len[i] || - os_memcmp(a->key[i], b->key[i], a->len[i]) != 0) - return 1; - return 0; -} - - -static void hostapd_config_free_radius(struct hostapd_radius_server *servers, - int num_servers) -{ - int i; - - for (i = 0; i < num_servers; i++) { - os_free(servers[i].shared_secret); - } - os_free(servers); -} - - -struct hostapd_radius_attr * -hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type) -{ - for (; attr; attr = attr->next) { - if (attr->type == type) - return attr; - } - return NULL; -} - - -static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr) -{ - struct hostapd_radius_attr *prev; - - while (attr) { - prev = attr; - attr = attr->next; - wpabuf_free(prev->val); - os_free(prev); - } -} - - -static void hostapd_config_free_eap_user(struct hostapd_eap_user *user) -{ - os_free(user->identity); - os_free(user->password); - os_free(user); -} - - -static void hostapd_config_free_wep(struct hostapd_wep_keys *keys) -{ - int i; - for (i = 0; i < NUM_WEP_KEYS; i++) { - os_free(keys->key[i]); - keys->key[i] = NULL; - } -} - - -void hostapd_config_free_bss(struct hostapd_bss_config *conf) -{ - struct hostapd_wpa_psk *psk, *prev; - struct hostapd_eap_user *user, *prev_user; - - if (conf == NULL) - return; - - psk = conf->ssid.wpa_psk; - while (psk) { - prev = psk; - psk = psk->next; - os_free(prev); - } - - os_free(conf->ssid.wpa_passphrase); - os_free(conf->ssid.wpa_psk_file); - hostapd_config_free_wep(&conf->ssid.wep); -#ifdef CONFIG_FULL_DYNAMIC_VLAN - os_free(conf->ssid.vlan_tagged_interface); -#endif /* CONFIG_FULL_DYNAMIC_VLAN */ - - user = conf->eap_user; - while (user) { - prev_user = user; - user = user->next; - hostapd_config_free_eap_user(prev_user); - } - os_free(conf->eap_user_sqlite); - - os_free(conf->eap_req_id_text); - os_free(conf->accept_mac); - os_free(conf->deny_mac); - os_free(conf->nas_identifier); - if (conf->radius) { - hostapd_config_free_radius(conf->radius->auth_servers, - conf->radius->num_auth_servers); - hostapd_config_free_radius(conf->radius->acct_servers, - conf->radius->num_acct_servers); - } - hostapd_config_free_radius_attr(conf->radius_auth_req_attr); - hostapd_config_free_radius_attr(conf->radius_acct_req_attr); - os_free(conf->rsn_preauth_interfaces); - os_free(conf->ctrl_interface); - os_free(conf->ca_cert); - os_free(conf->server_cert); - os_free(conf->private_key); - os_free(conf->private_key_passwd); - os_free(conf->ocsp_stapling_response); - os_free(conf->dh_file); - os_free(conf->pac_opaque_encr_key); - os_free(conf->eap_fast_a_id); - os_free(conf->eap_fast_a_id_info); - os_free(conf->eap_sim_db); - os_free(conf->radius_server_clients); - os_free(conf->test_socket); - os_free(conf->radius); - os_free(conf->radius_das_shared_secret); - hostapd_config_free_vlan(conf); - os_free(conf->time_zone); - -#ifdef CONFIG_IEEE80211R - { - struct ft_remote_r0kh *r0kh, *r0kh_prev; - struct ft_remote_r1kh *r1kh, *r1kh_prev; - - r0kh = conf->r0kh_list; - conf->r0kh_list = NULL; - while (r0kh) { - r0kh_prev = r0kh; - r0kh = r0kh->next; - os_free(r0kh_prev); - } - - r1kh = conf->r1kh_list; - conf->r1kh_list = NULL; - while (r1kh) { - r1kh_prev = r1kh; - r1kh = r1kh->next; - os_free(r1kh_prev); - } - } -#endif /* CONFIG_IEEE80211R */ - -#ifdef CONFIG_WPS - os_free(conf->wps_pin_requests); - os_free(conf->device_name); - os_free(conf->manufacturer); - os_free(conf->model_name); - os_free(conf->model_number); - os_free(conf->serial_number); - os_free(conf->config_methods); - os_free(conf->ap_pin); - os_free(conf->extra_cred); - os_free(conf->ap_settings); - os_free(conf->upnp_iface); - os_free(conf->friendly_name); - os_free(conf->manufacturer_url); - os_free(conf->model_description); - os_free(conf->model_url); - os_free(conf->upc); - wpabuf_free(conf->wps_nfc_dh_pubkey); - wpabuf_free(conf->wps_nfc_dh_privkey); - wpabuf_free(conf->wps_nfc_dev_pw); -#endif /* CONFIG_WPS */ - - os_free(conf->roaming_consortium); - os_free(conf->venue_name); - os_free(conf->nai_realm_data); - os_free(conf->network_auth_type); - os_free(conf->anqp_3gpp_cell_net); - os_free(conf->domain_name); - -#ifdef CONFIG_RADIUS_TEST - os_free(conf->dump_msk_file); -#endif /* CONFIG_RADIUS_TEST */ - -#ifdef CONFIG_HS20 - os_free(conf->hs20_oper_friendly_name); - os_free(conf->hs20_wan_metrics); - os_free(conf->hs20_connection_capability); - os_free(conf->hs20_operating_class); -#endif /* CONFIG_HS20 */ - - wpabuf_free(conf->vendor_elements); - - os_free(conf->sae_groups); - - os_free(conf->server_id); - - os_free(conf); -} - - -/** - * hostapd_config_free - Free hostapd configuration - * @conf: Configuration data from hostapd_config_read(). - */ -void hostapd_config_free(struct hostapd_config *conf) -{ - size_t i; - - if (conf == NULL) - return; - - for (i = 0; i < conf->num_bss; i++) - hostapd_config_free_bss(conf->bss[i]); - os_free(conf->bss); - os_free(conf->supported_rates); - os_free(conf->basic_rates); - - os_free(conf); -} - - -/** - * hostapd_maclist_found - Find a MAC address from a list - * @list: MAC address list - * @num_entries: Number of addresses in the list - * @addr: Address to search for - * @vlan_id: Buffer for returning VLAN ID or %NULL if not needed - * Returns: 1 if address is in the list or 0 if not. - * - * Perform a binary search for given MAC address from a pre-sorted list. - */ -int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries, - const u8 *addr, int *vlan_id) -{ - int start, end, middle, res; - - start = 0; - end = num_entries - 1; - - while (start <= end) { - middle = (start + end) / 2; - res = os_memcmp(list[middle].addr, addr, ETH_ALEN); - if (res == 0) { - if (vlan_id) - *vlan_id = list[middle].vlan_id; - return 1; - } - if (res < 0) - start = middle + 1; - else - end = middle - 1; - } - - return 0; -} - - -int hostapd_rate_found(int *list, int rate) -{ - int i; - - if (list == NULL) - return 0; - - for (i = 0; list[i] >= 0; i++) - if (list[i] == rate) - return 1; - - return 0; -} - - -int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id) -{ - struct hostapd_vlan *v = vlan; - while (v) { - if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD) - return 1; - v = v->next; - } - return 0; -} - - -const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id) -{ - struct hostapd_vlan *v = vlan; - while (v) { - if (v->vlan_id == vlan_id) - return v->ifname; - v = v->next; - } - return NULL; -} - - -const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, - const u8 *addr, const u8 *p2p_dev_addr, - const u8 *prev_psk) -{ - struct hostapd_wpa_psk *psk; - int next_ok = prev_psk == NULL; - - if (p2p_dev_addr) { - wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR - " p2p_dev_addr=" MACSTR " prev_psk=%p", - MAC2STR(addr), MAC2STR(p2p_dev_addr), prev_psk); - if (!is_zero_ether_addr(p2p_dev_addr)) - addr = NULL; /* Use P2P Device Address for matching */ - } else { - wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR - " prev_psk=%p", - MAC2STR(addr), prev_psk); - } - - for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) { - if (next_ok && - (psk->group || - (addr && os_memcmp(psk->addr, addr, ETH_ALEN) == 0) || - (!addr && p2p_dev_addr && - os_memcmp(psk->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) == - 0))) - return psk->psk; - - if (psk->psk == prev_psk) - next_ok = 1; - } - - return NULL; -} - - -static int hostapd_config_check_bss(struct hostapd_bss_config *bss, - struct hostapd_config *conf, - int full_config) -{ - if (full_config && bss->ieee802_1x && !bss->eap_server && - !bss->radius->auth_servers) { - wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no " - "EAP authenticator configured)."); - return -1; - } - - if (bss->wpa) { - int wep, i; - - wep = bss->default_wep_key_len > 0 || - bss->individual_wep_key_len > 0; - for (i = 0; i < NUM_WEP_KEYS; i++) { - if (bss->ssid.wep.keys_set) { - wep = 1; - break; - } - } - - if (wep) { - wpa_printf(MSG_ERROR, "WEP configuration in a WPA network is not supported"); - return -1; - } - } - - if (full_config && bss->wpa && - bss->wpa_psk_radius != PSK_RADIUS_IGNORED && - bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) { - wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no " - "RADIUS checking (macaddr_acl=2) enabled."); - return -1; - } - - if (full_config && bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) && - bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL && - bss->ssid.wpa_psk_file == NULL && - (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED || - bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) { - wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase " - "is not configured."); - return -1; - } - - if (full_config && hostapd_mac_comp_empty(bss->bssid) != 0) { - size_t i; - - for (i = 0; i < conf->num_bss; i++) { - if (conf->bss[i] != bss && - (hostapd_mac_comp(conf->bss[i]->bssid, - bss->bssid) == 0)) { - wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR - " on interface '%s' and '%s'.", - MAC2STR(bss->bssid), - conf->bss[i]->iface, bss->iface); - return -1; - } - } - } - -#ifdef CONFIG_IEEE80211R - if (full_config && wpa_key_mgmt_ft(bss->wpa_key_mgmt) && - (bss->nas_identifier == NULL || - os_strlen(bss->nas_identifier) < 1 || - os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) { - wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires " - "nas_identifier to be configured as a 1..48 octet " - "string"); - return -1; - } -#endif /* CONFIG_IEEE80211R */ - -#ifdef CONFIG_IEEE80211N - if (full_config && conf->ieee80211n && - conf->hw_mode == HOSTAPD_MODE_IEEE80211B) { - bss->disable_11n = 1; - wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not " - "allowed, disabling HT capabilites"); - } - - if (full_config && conf->ieee80211n && - bss->ssid.security_policy == SECURITY_STATIC_WEP) { - bss->disable_11n = 1; - wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not " - "allowed, disabling HT capabilities"); - } - - if (full_config && conf->ieee80211n && bss->wpa && - !(bss->wpa_pairwise & WPA_CIPHER_CCMP) && - !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | - WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256))) - { - bss->disable_11n = 1; - wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 " - "requires CCMP/GCMP to be enabled, disabling HT " - "capabilities"); - } -#endif /* CONFIG_IEEE80211N */ - -#ifdef CONFIG_WPS2 - if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) { - wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid " - "configuration forced WPS to be disabled"); - bss->wps_state = 0; - } - - if (full_config && bss->wps_state && - bss->ssid.wep.keys_set && bss->wpa == 0) { - wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be " - "disabled"); - bss->wps_state = 0; - } - - if (full_config && bss->wps_state && bss->wpa && - (!(bss->wpa & 2) || - !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) { - wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without " - "WPA2/CCMP forced WPS to be disabled"); - bss->wps_state = 0; - } -#endif /* CONFIG_WPS2 */ - -#ifdef CONFIG_HS20 - if (full_config && bss->hs20 && - (!(bss->wpa & 2) || - !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | - WPA_CIPHER_CCMP_256 | - WPA_CIPHER_GCMP_256)))) { - wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP " - "configuration is required for Hotspot 2.0 " - "functionality"); - return -1; - } -#endif /* CONFIG_HS20 */ - - return 0; -} - - -int hostapd_config_check(struct hostapd_config *conf, int full_config) -{ - size_t i; - - if (full_config && conf->ieee80211d && - (!conf->country[0] || !conf->country[1])) { - wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without " - "setting the country_code"); - return -1; - } - - if (full_config && conf->ieee80211h && !conf->ieee80211d) { - wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11h without " - "IEEE 802.11d enabled"); - return -1; - } - - for (i = 0; i < conf->num_bss; i++) { - if (hostapd_config_check_bss(conf->bss[i], conf, full_config)) - return -1; - } - - return 0; -} - - -void hostapd_set_security_params(struct hostapd_bss_config *bss) -{ - if (bss->individual_wep_key_len == 0) { - /* individual keys are not use; can use key idx0 for - * broadcast keys */ - bss->broadcast_key_idx_min = 0; - } - - if ((bss->wpa & 2) && bss->rsn_pairwise == 0) - bss->rsn_pairwise = bss->wpa_pairwise; - bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise, - bss->rsn_pairwise); - - bss->radius->auth_server = bss->radius->auth_servers; - bss->radius->acct_server = bss->radius->acct_servers; - - if (bss->wpa && bss->ieee802_1x) { - bss->ssid.security_policy = SECURITY_WPA; - } else if (bss->wpa) { - bss->ssid.security_policy = SECURITY_WPA_PSK; - } else if (bss->ieee802_1x) { - int cipher = WPA_CIPHER_NONE; - bss->ssid.security_policy = SECURITY_IEEE_802_1X; - bss->ssid.wep.default_len = bss->default_wep_key_len; - if (bss->default_wep_key_len) - cipher = bss->default_wep_key_len >= 13 ? - WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40; - bss->wpa_group = cipher; - bss->wpa_pairwise = cipher; - bss->rsn_pairwise = cipher; - } else if (bss->ssid.wep.keys_set) { - int cipher = WPA_CIPHER_WEP40; - if (bss->ssid.wep.len[0] >= 13) - cipher = WPA_CIPHER_WEP104; - bss->ssid.security_policy = SECURITY_STATIC_WEP; - bss->wpa_group = cipher; - bss->wpa_pairwise = cipher; - bss->rsn_pairwise = cipher; - } else { - bss->ssid.security_policy = SECURITY_PLAINTEXT; - bss->wpa_group = WPA_CIPHER_NONE; - bss->wpa_pairwise = WPA_CIPHER_NONE; - bss->rsn_pairwise = WPA_CIPHER_NONE; - } -} diff --git a/contrib/hostapd/src/ap/ap_config.h b/contrib/hostapd/src/ap/ap_config.h deleted file mode 100644 index b4860a08b5..0000000000 --- a/contrib/hostapd/src/ap/ap_config.h +++ /dev/null @@ -1,582 +0,0 @@ -/* - * hostapd / Configuration definitions and helpers functions - * Copyright (c) 2003-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef HOSTAPD_CONFIG_H -#define HOSTAPD_CONFIG_H - -#include "common/defs.h" -#include "ip_addr.h" -#include "common/wpa_common.h" -#include "common/ieee802_11_common.h" -#include "wps/wps.h" - -#define MAX_STA_COUNT 2007 -#define MAX_VLAN_ID 4094 - -typedef u8 macaddr[ETH_ALEN]; - -struct mac_acl_entry { - macaddr addr; - int vlan_id; -}; - -struct hostapd_radius_servers; -struct ft_remote_r0kh; -struct ft_remote_r1kh; - -#define HOSTAPD_MAX_SSID_LEN 32 - -#define NUM_WEP_KEYS 4 -struct hostapd_wep_keys { - u8 idx; - u8 *key[NUM_WEP_KEYS]; - size_t len[NUM_WEP_KEYS]; - int keys_set; - size_t default_len; /* key length used for dynamic key generation */ -}; - -typedef enum hostap_security_policy { - SECURITY_PLAINTEXT = 0, - SECURITY_STATIC_WEP = 1, - SECURITY_IEEE_802_1X = 2, - SECURITY_WPA_PSK = 3, - SECURITY_WPA = 4 -} secpolicy; - -struct hostapd_ssid { - u8 ssid[HOSTAPD_MAX_SSID_LEN]; - size_t ssid_len; - unsigned int ssid_set:1; - unsigned int utf8_ssid:1; - unsigned int wpa_passphrase_set:1; - unsigned int wpa_psk_set:1; - - char vlan[IFNAMSIZ + 1]; - secpolicy security_policy; - - struct hostapd_wpa_psk *wpa_psk; - char *wpa_passphrase; - char *wpa_psk_file; - - struct hostapd_wep_keys wep; - -#define DYNAMIC_VLAN_DISABLED 0 -#define DYNAMIC_VLAN_OPTIONAL 1 -#define DYNAMIC_VLAN_REQUIRED 2 - int dynamic_vlan; -#define DYNAMIC_VLAN_NAMING_WITHOUT_DEVICE 0 -#define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1 -#define DYNAMIC_VLAN_NAMING_END 2 - int vlan_naming; -#ifdef CONFIG_FULL_DYNAMIC_VLAN - char *vlan_tagged_interface; -#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -}; - - -#define VLAN_ID_WILDCARD -1 - -struct hostapd_vlan { - struct hostapd_vlan *next; - int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */ - char ifname[IFNAMSIZ + 1]; - int dynamic_vlan; -#ifdef CONFIG_FULL_DYNAMIC_VLAN - -#define DVLAN_CLEAN_BR 0x1 -#define DVLAN_CLEAN_VLAN 0x2 -#define DVLAN_CLEAN_VLAN_PORT 0x4 -#define DVLAN_CLEAN_WLAN_PORT 0x8 - int clean; -#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -}; - -#define PMK_LEN 32 -struct hostapd_sta_wpa_psk_short { - struct hostapd_sta_wpa_psk_short *next; - u8 psk[PMK_LEN]; -}; - -struct hostapd_wpa_psk { - struct hostapd_wpa_psk *next; - int group; - u8 psk[PMK_LEN]; - u8 addr[ETH_ALEN]; - u8 p2p_dev_addr[ETH_ALEN]; -}; - -struct hostapd_eap_user { - struct hostapd_eap_user *next; - u8 *identity; - size_t identity_len; - struct { - int vendor; - u32 method; - } methods[EAP_MAX_METHODS]; - u8 *password; - size_t password_len; - int phase2; - int force_version; - unsigned int wildcard_prefix:1; - unsigned int password_hash:1; /* whether password is hashed with - * nt_password_hash() */ - int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */ -}; - -struct hostapd_radius_attr { - u8 type; - struct wpabuf *val; - struct hostapd_radius_attr *next; -}; - - -#define NUM_TX_QUEUES 4 - -struct hostapd_tx_queue_params { - int aifs; - int cwmin; - int cwmax; - int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */ -}; - - -#define MAX_ROAMING_CONSORTIUM_LEN 15 - -struct hostapd_roaming_consortium { - u8 len; - u8 oi[MAX_ROAMING_CONSORTIUM_LEN]; -}; - -struct hostapd_lang_string { - u8 lang[3]; - u8 name_len; - u8 name[252]; -}; - -#define MAX_NAI_REALMS 10 -#define MAX_NAI_REALMLEN 255 -#define MAX_NAI_EAP_METHODS 5 -#define MAX_NAI_AUTH_TYPES 4 -struct hostapd_nai_realm_data { - u8 encoding; - char realm_buf[MAX_NAI_REALMLEN + 1]; - char *realm[MAX_NAI_REALMS]; - u8 eap_method_count; - struct hostapd_nai_realm_eap { - u8 eap_method; - u8 num_auths; - u8 auth_id[MAX_NAI_AUTH_TYPES]; - u8 auth_val[MAX_NAI_AUTH_TYPES]; - } eap_method[MAX_NAI_EAP_METHODS]; -}; - -/** - * struct hostapd_bss_config - Per-BSS configuration - */ -struct hostapd_bss_config { - char iface[IFNAMSIZ + 1]; - char bridge[IFNAMSIZ + 1]; - char vlan_bridge[IFNAMSIZ + 1]; - char wds_bridge[IFNAMSIZ + 1]; - - enum hostapd_logger_level logger_syslog_level, logger_stdout_level; - - unsigned int logger_syslog; /* module bitfield */ - unsigned int logger_stdout; /* module bitfield */ - - int max_num_sta; /* maximum number of STAs in station table */ - - int dtim_period; - - int ieee802_1x; /* use IEEE 802.1X */ - int eapol_version; - int eap_server; /* Use internal EAP server instead of external - * RADIUS server */ - struct hostapd_eap_user *eap_user; - char *eap_user_sqlite; - char *eap_sim_db; - struct hostapd_ip_addr own_ip_addr; - char *nas_identifier; - struct hostapd_radius_servers *radius; - int acct_interim_interval; - int radius_request_cui; - struct hostapd_radius_attr *radius_auth_req_attr; - struct hostapd_radius_attr *radius_acct_req_attr; - int radius_das_port; - unsigned int radius_das_time_window; - int radius_das_require_event_timestamp; - struct hostapd_ip_addr radius_das_client_addr; - u8 *radius_das_shared_secret; - size_t radius_das_shared_secret_len; - - struct hostapd_ssid ssid; - - char *eap_req_id_text; /* optional displayable message sent with - * EAP Request-Identity */ - size_t eap_req_id_text_len; - int eapol_key_index_workaround; - - size_t default_wep_key_len; - int individual_wep_key_len; - int wep_rekeying_period; - int broadcast_key_idx_min, broadcast_key_idx_max; - int eap_reauth_period; - - int ieee802_11f; /* use IEEE 802.11f (IAPP) */ - char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast - * frames */ - - enum { - ACCEPT_UNLESS_DENIED = 0, - DENY_UNLESS_ACCEPTED = 1, - USE_EXTERNAL_RADIUS_AUTH = 2 - } macaddr_acl; - struct mac_acl_entry *accept_mac; - int num_accept_mac; - struct mac_acl_entry *deny_mac; - int num_deny_mac; - int wds_sta; - int isolate; - int start_disabled; - - int auth_algs; /* bitfield of allowed IEEE 802.11 authentication - * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */ - - int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */ - int wpa_key_mgmt; -#ifdef CONFIG_IEEE80211W - enum mfp_options ieee80211w; - /* dot11AssociationSAQueryMaximumTimeout (in TUs) */ - unsigned int assoc_sa_query_max_timeout; - /* 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; - int wpa_strict_rekey; - int wpa_gmk_rekey; - int wpa_ptk_rekey; - int rsn_pairwise; - int rsn_preauth; - char *rsn_preauth_interfaces; - int peerkey; - -#ifdef CONFIG_IEEE80211R - /* IEEE 802.11r - Fast BSS Transition */ - u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; - u8 r1_key_holder[FT_R1KH_ID_LEN]; - u32 r0_key_lifetime; - u32 reassociation_deadline; - struct ft_remote_r0kh *r0kh_list; - struct ft_remote_r1kh *r1kh_list; - int pmk_r1_push; - int ft_over_ds; -#endif /* CONFIG_IEEE80211R */ - - char *ctrl_interface; /* directory for UNIX domain sockets */ -#ifndef CONFIG_NATIVE_WINDOWS - gid_t ctrl_interface_gid; -#endif /* CONFIG_NATIVE_WINDOWS */ - int ctrl_interface_gid_set; - - char *ca_cert; - char *server_cert; - char *private_key; - char *private_key_passwd; - int check_crl; - char *ocsp_stapling_response; - char *dh_file; - u8 *pac_opaque_encr_key; - u8 *eap_fast_a_id; - size_t eap_fast_a_id_len; - char *eap_fast_a_id_info; - int eap_fast_prov; - int pac_key_lifetime; - int pac_key_refresh_time; - int eap_sim_aka_result_ind; - int tnc; - int fragment_size; - u16 pwd_group; - - char *radius_server_clients; - int radius_server_auth_port; - int radius_server_ipv6; - - char *test_socket; /* UNIX domain socket path for driver_test */ - - int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group - * address instead of individual address - * (for driver_wired.c). - */ - - int ap_max_inactivity; - int ignore_broadcast_ssid; - - int wmm_enabled; - int wmm_uapsd; - - struct hostapd_vlan *vlan; - - macaddr bssid; - - /* - * Maximum listen interval that STAs can use when associating with this - * BSS. If a STA tries to use larger value, the association will be - * denied with status code 51. - */ - u16 max_listen_interval; - - int disable_pmksa_caching; - int okc; /* Opportunistic Key Caching */ - - int wps_state; -#ifdef CONFIG_WPS - int wps_independent; - int ap_setup_locked; - u8 uuid[16]; - char *wps_pin_requests; - char *device_name; - char *manufacturer; - char *model_name; - char *model_number; - char *serial_number; - u8 device_type[WPS_DEV_TYPE_LEN]; - char *config_methods; - u8 os_version[4]; - char *ap_pin; - int skip_cred_build; - u8 *extra_cred; - size_t extra_cred_len; - int wps_cred_processing; - int force_per_enrollee_psk; - u8 *ap_settings; - size_t ap_settings_len; - char *upnp_iface; - char *friendly_name; - char *manufacturer_url; - char *model_description; - char *model_url; - char *upc; - struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; - int wps_nfc_pw_from_config; - int wps_nfc_dev_pw_id; - struct wpabuf *wps_nfc_dh_pubkey; - struct wpabuf *wps_nfc_dh_privkey; - struct wpabuf *wps_nfc_dev_pw; -#endif /* CONFIG_WPS */ - int pbc_in_m1; - char *server_id; - -#define P2P_ENABLED BIT(0) -#define P2P_GROUP_OWNER BIT(1) -#define P2P_GROUP_FORMATION BIT(2) -#define P2P_MANAGE BIT(3) -#define P2P_ALLOW_CROSS_CONNECTION BIT(4) - int p2p; -#ifdef CONFIG_P2P - u8 ip_addr_go[4]; - u8 ip_addr_mask[4]; - u8 ip_addr_start[4]; - u8 ip_addr_end[4]; -#endif /* CONFIG_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; - int disable_11ac; - - /* IEEE 802.11v */ - int time_advertisement; - char *time_zone; - int wnm_sleep_mode; - int bss_transition; - - /* 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; - - /* IEEE 802.11u - Venue Name duples */ - unsigned int venue_name_count; - struct hostapd_lang_string *venue_name; - - /* IEEE 802.11u - Network Authentication Type */ - u8 *network_auth_type; - size_t network_auth_type_len; - - /* IEEE 802.11u - IP Address Type Availability */ - u8 ipaddr_type_availability; - u8 ipaddr_type_configured; - - /* IEEE 802.11u - 3GPP Cellular Network */ - u8 *anqp_3gpp_cell_net; - size_t anqp_3gpp_cell_net_len; - - /* IEEE 802.11u - Domain Name */ - u8 *domain_name; - size_t domain_name_len; - - unsigned int nai_realm_count; - struct hostapd_nai_realm_data *nai_realm_data; - - u16 gas_comeback_delay; - int gas_frag_limit; - - u8 qos_map_set[16 + 2 * 21]; - unsigned int qos_map_set_len; - -#ifdef CONFIG_HS20 - int hs20; - int disable_dgaf; - unsigned int hs20_oper_friendly_name_count; - struct hostapd_lang_string *hs20_oper_friendly_name; - u8 *hs20_wan_metrics; - u8 *hs20_connection_capability; - size_t hs20_connection_capability_len; - u8 *hs20_operating_class; - u8 hs20_operating_class_len; -#endif /* CONFIG_HS20 */ - - u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */ - -#ifdef CONFIG_RADIUS_TEST - char *dump_msk_file; -#endif /* CONFIG_RADIUS_TEST */ - - struct wpabuf *vendor_elements; - - unsigned int sae_anti_clogging_threshold; - int *sae_groups; - -#ifdef CONFIG_TESTING_OPTIONS - u8 bss_load_test[5]; - u8 bss_load_test_set; -#endif /* CONFIG_TESTING_OPTIONS */ -}; - - -/** - * struct hostapd_config - Per-radio interface configuration - */ -struct hostapd_config { - struct hostapd_bss_config **bss, *last_bss; - size_t num_bss; - - u16 beacon_int; - int rts_threshold; - int fragm_threshold; - u8 send_probe_response; - u8 channel; - enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */ - enum { - LONG_PREAMBLE = 0, - SHORT_PREAMBLE = 1 - } preamble; - - int *supported_rates; - int *basic_rates; - - const struct wpa_driver_ops *driver; - - int ap_table_max_size; - int ap_table_expiration_time; - - char country[3]; /* first two octets: country code as described in - * ISO/IEC 3166-1. Third octet: - * ' ' (ascii 32): all environments - * 'O': Outdoor environemnt only - * 'I': Indoor environment only - */ - - int ieee80211d; - - int ieee80211h; /* DFS */ - - struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES]; - - /* - * WMM AC parameters, in same order as 802.1D, i.e. - * 0 = BE (best effort) - * 1 = BK (background) - * 2 = VI (video) - * 3 = VO (voice) - */ - struct hostapd_wmm_ac_params wmm_ac_params[4]; - - int ht_op_mode_fixed; - u16 ht_capab; - int ieee80211n; - int secondary_channel; - int require_ht; - int obss_interval; - u32 vht_capab; - int ieee80211ac; - int require_vht; - u8 vht_oper_chwidth; - u8 vht_oper_centr_freq_seg0_idx; - u8 vht_oper_centr_freq_seg1_idx; - -#ifdef CONFIG_TESTING_OPTIONS - double ignore_probe_probability; - double ignore_auth_probability; - double ignore_assoc_probability; - double ignore_reassoc_probability; - double corrupt_gtk_rekey_mic_probability; -#endif /* CONFIG_TESTING_OPTIONS */ - -#ifdef CONFIG_ACS - unsigned int acs_num_scans; -#endif /* CONFIG_ACS */ -}; - - -int hostapd_mac_comp(const void *a, const void *b); -int hostapd_mac_comp_empty(const void *a); -struct hostapd_config * hostapd_config_defaults(void); -void hostapd_config_defaults_bss(struct hostapd_bss_config *bss); -void hostapd_config_free_bss(struct hostapd_bss_config *conf); -void hostapd_config_free(struct hostapd_config *conf); -int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries, - const u8 *addr, int *vlan_id); -int hostapd_rate_found(int *list, int rate); -int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, - struct hostapd_wep_keys *b); -const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, - const u8 *addr, const u8 *p2p_dev_addr, - const u8 *prev_psk); -int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf); -int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id); -const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, - int vlan_id); -struct hostapd_radius_attr * -hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type); -int hostapd_config_check(struct hostapd_config *conf, int full_config); -void hostapd_set_security_params(struct hostapd_bss_config *bss); - -#endif /* HOSTAPD_CONFIG_H */ diff --git a/contrib/hostapd/src/ap/ap_drv_ops.c b/contrib/hostapd/src/ap/ap_drv_ops.c deleted file mode 100644 index 893e6d9eee..0000000000 --- a/contrib/hostapd/src/ap/ap_drv_ops.c +++ /dev/null @@ -1,775 +0,0 @@ -/* - * hostapd - Driver operations - * Copyright (c) 2009-2010, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "common/ieee802_11_defs.h" -#include "wps/wps.h" -#include "p2p/p2p.h" -#include "hostapd.h" -#include "ieee802_11.h" -#include "sta_info.h" -#include "ap_config.h" -#include "p2p_hostapd.h" -#include "hs20.h" -#include "ap_drv_ops.h" - - -u32 hostapd_sta_flags_to_drv(u32 flags) -{ - int res = 0; - if (flags & WLAN_STA_AUTHORIZED) - res |= WPA_STA_AUTHORIZED; - if (flags & WLAN_STA_WMM) - res |= WPA_STA_WMM; - if (flags & WLAN_STA_SHORT_PREAMBLE) - res |= WPA_STA_SHORT_PREAMBLE; - if (flags & WLAN_STA_MFP) - res |= WPA_STA_MFP; - return res; -} - - -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 = NULL, *proberesp = NULL, *assocresp = NULL; - u8 buf[200], *pos; - - *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); - } - - 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->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->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) { - if (wpabuf_resize(&beacon, 100) == 0) { - u8 *start, *p; - start = wpabuf_put(beacon, 0); - p = hostapd_eid_p2p_manage(hapd, start); - wpabuf_put(beacon, p - start); - } - - if (wpabuf_resize(&proberesp, 100) == 0) { - u8 *start, *p; - start = wpabuf_put(proberesp, 0); - p = hostapd_eid_p2p_manage(hapd, start); - wpabuf_put(proberesp, p - start); - } - } -#endif /* CONFIG_P2P_MANAGER */ - -#ifdef CONFIG_WPS2 - 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) { - if (wpabuf_resize(&assocresp, 100) == 0) { - u8 *start, *p; - start = wpabuf_put(assocresp, 0); - p = hostapd_eid_p2p_manage(hapd, start); - wpabuf_put(assocresp, p - start); - } - } -#endif /* CONFIG_P2P_MANAGER */ - -#ifdef CONFIG_WIFI_DISPLAY - if (hapd->p2p_group) { - struct wpabuf *a; - a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS); - if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0) - wpabuf_put_buf(assocresp, a); - wpabuf_free(a); - } -#endif /* CONFIG_WIFI_DISPLAY */ - -#ifdef CONFIG_HS20 - pos = buf; - pos = hostapd_eid_hs20_indication(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); - } -#endif /* CONFIG_HS20 */ - - if (hapd->conf->vendor_elements) { - size_t add = wpabuf_len(hapd->conf->vendor_elements); - if (wpabuf_resize(&beacon, add) == 0) - wpabuf_put_buf(beacon, hapd->conf->vendor_elements); - if (wpabuf_resize(&proberesp, add) == 0) - wpabuf_put_buf(proberesp, hapd->conf->vendor_elements); - } - - *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); - - hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); - - return ret; -} - - -int hostapd_set_authorized(struct hostapd_data *hapd, - struct sta_info *sta, int authorized) -{ - if (authorized) { - return hostapd_sta_set_flags(hapd, sta->addr, - hostapd_sta_flags_to_drv( - sta->flags), - WPA_STA_AUTHORIZED, ~0); - } - - return hostapd_sta_set_flags(hapd, sta->addr, - hostapd_sta_flags_to_drv(sta->flags), - 0, ~WPA_STA_AUTHORIZED); -} - - -int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta) -{ - int set_flags, total_flags, flags_and, flags_or; - total_flags = hostapd_sta_flags_to_drv(sta->flags); - set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP; - if (((!hapd->conf->ieee802_1x && !hapd->conf->wpa) || - sta->auth_alg == WLAN_AUTH_FT) && - sta->flags & WLAN_STA_AUTHORIZED) - set_flags |= WPA_STA_AUTHORIZED; - flags_or = total_flags & set_flags; - flags_and = total_flags | ~set_flags; - return hostapd_sta_set_flags(hapd, sta->addr, total_flags, - flags_or, flags_and); -} - - -int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname, - int enabled) -{ - struct wpa_bss_params params; - os_memset(¶ms, 0, sizeof(params)); - params.ifname = ifname; - params.enabled = enabled; - if (enabled) { - params.wpa = hapd->conf->wpa; - params.ieee802_1x = hapd->conf->ieee802_1x; - params.wpa_group = hapd->conf->wpa_group; - params.wpa_pairwise = hapd->conf->wpa_pairwise; - params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt; - params.rsn_preauth = hapd->conf->rsn_preauth; -#ifdef CONFIG_IEEE80211W - params.ieee80211w = hapd->conf->ieee80211w; -#endif /* CONFIG_IEEE80211W */ - } - return hostapd_set_ieee8021x(hapd, ¶ms); -} - - -int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname) -{ - char force_ifname[IFNAMSIZ]; - u8 if_addr[ETH_ALEN]; - return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr, - NULL, NULL, force_ifname, if_addr, NULL, 0); -} - - -int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname) -{ - return hostapd_if_remove(hapd, WPA_IF_AP_VLAN, ifname); -} - - -int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds, - const u8 *addr, int aid, int val) -{ - const char *bridge = NULL; - - if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL) - return -1; - if (hapd->conf->wds_bridge[0]) - bridge = hapd->conf->wds_bridge; - else if (hapd->conf->bridge[0]) - bridge = hapd->conf->bridge; - return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val, - bridge, ifname_wds); -} - - -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_vht_capabilities *vht_capab, - u32 flags, u8 qosinfo) -{ - struct hostapd_sta_add_params params; - - if (hapd->driver == NULL) - return 0; - if (hapd->driver->sta_add == NULL) - return 0; - - os_memset(¶ms, 0, sizeof(params)); - params.addr = addr; - params.aid = aid; - params.capability = capability; - params.supp_rates = supp_rates; - params.supp_rates_len = supp_rates_len; - params.listen_interval = listen_interval; - params.ht_capabilities = ht_capab; - params.vht_capabilities = vht_capab; - params.flags = hostapd_sta_flags_to_drv(flags); - params.qosinfo = qosinfo; - return hapd->driver->sta_add(hapd->drv_priv, ¶ms); -} - - -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) - return 0; - return hapd->driver->set_privacy(hapd->drv_priv, enabled); -} - - -int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem, - size_t elem_len) -{ - if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL) - return 0; - return hapd->driver->set_generic_elem(hapd->drv_priv, elem, elem_len); -} - - -int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len) -{ - if (hapd->driver == NULL || hapd->driver->hapd_get_ssid == NULL) - return 0; - return hapd->driver->hapd_get_ssid(hapd->drv_priv, buf, len); -} - - -int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len) -{ - if (hapd->driver == NULL || hapd->driver->hapd_set_ssid == NULL) - return 0; - return hapd->driver->hapd_set_ssid(hapd->drv_priv, buf, len); -} - - -int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type, - const char *ifname, const u8 *addr, void *bss_ctx, - void **drv_priv, char *force_ifname, u8 *if_addr, - const char *bridge, int use_existing) -{ - if (hapd->driver == NULL || hapd->driver->if_add == NULL) - return -1; - return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr, - bss_ctx, drv_priv, force_ifname, if_addr, - bridge, use_existing); -} - - -int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type, - const char *ifname) -{ - if (hapd->driver == NULL || hapd->drv_priv == NULL || - hapd->driver->if_remove == NULL) - return -1; - return hapd->driver->if_remove(hapd->drv_priv, type, ifname); -} - - -int hostapd_set_ieee8021x(struct hostapd_data *hapd, - struct wpa_bss_params *params) -{ - if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL) - return 0; - return hapd->driver->set_ieee8021x(hapd->drv_priv, params); -} - - -int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd, - const u8 *addr, int idx, u8 *seq) -{ - if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL) - return 0; - return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx, - seq); -} - - -int hostapd_flush(struct hostapd_data *hapd) -{ - if (hapd->driver == NULL || hapd->driver->flush == NULL) - return 0; - return hapd->driver->flush(hapd->drv_priv); -} - - -int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode, - int freq, int channel, int ht_enabled, - int vht_enabled, int sec_channel_offset, - int vht_oper_chwidth, int center_segment0, - int center_segment1, u32 vht_caps) -{ - int tmp; - - os_memset(data, 0, sizeof(*data)); - data->mode = mode; - data->freq = freq; - data->channel = channel; - data->ht_enabled = ht_enabled; - data->vht_enabled = vht_enabled; - data->sec_channel_offset = sec_channel_offset; - data->center_freq1 = freq + sec_channel_offset * 10; - data->center_freq2 = 0; - data->bandwidth = sec_channel_offset ? 40 : 20; - - /* - * This validation code is probably misplaced, maybe it should be - * in src/ap/hw_features.c and check the hardware support as well. - */ - if (data->vht_enabled) switch (vht_oper_chwidth) { - case VHT_CHANWIDTH_USE_HT: - if (center_segment1) - return -1; - if (5000 + center_segment0 * 5 != data->center_freq1 && - 2407 + center_segment0 * 5 != data->center_freq1) - return -1; - break; - case VHT_CHANWIDTH_80P80MHZ: - if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) { - wpa_printf(MSG_ERROR, - "80+80 channel width is not supported!"); - return -1; - } - if (center_segment1 == center_segment0 + 4 || - center_segment1 == center_segment0 - 4) - return -1; - data->center_freq2 = 5000 + center_segment1 * 5; - /* fall through */ - case VHT_CHANWIDTH_80MHZ: - data->bandwidth = 80; - if (vht_oper_chwidth == 1 && center_segment1) - return -1; - if (vht_oper_chwidth == 3 && !center_segment1) - return -1; - if (!sec_channel_offset) - return -1; - /* primary 40 part must match the HT configuration */ - tmp = (30 + freq - 5000 - center_segment0 * 5)/20; - tmp /= 2; - if (data->center_freq1 != 5000 + - center_segment0 * 5 - 20 + 40 * tmp) - return -1; - data->center_freq1 = 5000 + center_segment0 * 5; - break; - case VHT_CHANWIDTH_160MHZ: - data->bandwidth = 160; - if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | - VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { - wpa_printf(MSG_ERROR, - "160MHZ channel width is not supported!"); - return -1; - } - if (center_segment1) - return -1; - if (!sec_channel_offset) - return -1; - /* primary 40 part must match the HT configuration */ - tmp = (70 + freq - 5000 - center_segment0 * 5)/20; - tmp /= 2; - if (data->center_freq1 != 5000 + - center_segment0 * 5 - 60 + 40 * tmp) - return -1; - data->center_freq1 = 5000 + center_segment0 * 5; - break; - } - - return 0; -} - - -int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq, - int channel, int ht_enabled, int vht_enabled, - int sec_channel_offset, int vht_oper_chwidth, - int center_segment0, int center_segment1) -{ - struct hostapd_freq_params data; - - if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled, - vht_enabled, sec_channel_offset, - vht_oper_chwidth, - center_segment0, center_segment1, - hapd->iface->current_mode->vht_capab)) - return -1; - - if (hapd->driver == NULL) - return 0; - if (hapd->driver->set_freq == NULL) - return 0; - return hapd->driver->set_freq(hapd->drv_priv, &data); -} - -int hostapd_set_rts(struct hostapd_data *hapd, int rts) -{ - if (hapd->driver == NULL || hapd->driver->set_rts == NULL) - return 0; - return hapd->driver->set_rts(hapd->drv_priv, rts); -} - - -int hostapd_set_frag(struct hostapd_data *hapd, int frag) -{ - if (hapd->driver == NULL || hapd->driver->set_frag == NULL) - return 0; - return hapd->driver->set_frag(hapd->drv_priv, frag); -} - - -int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr, - int total_flags, int flags_or, int flags_and) -{ - if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL) - return 0; - return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags, - flags_or, flags_and); -} - - -int hostapd_set_country(struct hostapd_data *hapd, const char *country) -{ - if (hapd->driver == NULL || - hapd->driver->set_country == NULL) - return 0; - return hapd->driver->set_country(hapd->drv_priv, country); -} - - -int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs, - int cw_min, int cw_max, int burst_time) -{ - if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL) - return 0; - return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs, - cw_min, cw_max, burst_time); -} - - -struct hostapd_hw_modes * -hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes, - u16 *flags) -{ - if (hapd->driver == NULL || - hapd->driver->get_hw_feature_data == NULL) - return NULL; - return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes, - flags); -} - - -int hostapd_driver_commit(struct hostapd_data *hapd) -{ - if (hapd->driver == NULL || hapd->driver->commit == NULL) - return 0; - return hapd->driver->commit(hapd->drv_priv); -} - - -int hostapd_drv_none(struct hostapd_data *hapd) -{ - return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0; -} - - -int hostapd_driver_scan(struct hostapd_data *hapd, - struct wpa_driver_scan_params *params) -{ - if (hapd->driver && hapd->driver->scan2) - return hapd->driver->scan2(hapd->drv_priv, params); - return -1; -} - - -struct wpa_scan_results * hostapd_driver_get_scan_results( - struct hostapd_data *hapd) -{ - if (hapd->driver && hapd->driver->get_scan_results2) - return hapd->driver->get_scan_results2(hapd->drv_priv); - return NULL; -} - - -int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start, - int duration) -{ - if (hapd->driver && hapd->driver->set_noa) - return hapd->driver->set_noa(hapd->drv_priv, count, start, - duration); - return -1; -} - - -int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd, - 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) -{ - if (hapd->driver == NULL || hapd->driver->set_key == NULL) - return 0; - return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr, - key_idx, set_tx, seq, seq_len, key, - key_len); -} - - -int hostapd_drv_send_mlme(struct hostapd_data *hapd, - 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, noack); -} - - -int hostapd_drv_sta_deauth(struct hostapd_data *hapd, - const u8 *addr, int reason) -{ - if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL) - return 0; - return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr, - reason); -} - - -int hostapd_drv_sta_disassoc(struct hostapd_data *hapd, - const u8 *addr, int reason) -{ - if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL) - return 0; - return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr, - reason); -} - - -int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper, - const u8 *peer, u8 *buf, u16 *buf_len) -{ - if (hapd->driver == NULL || hapd->driver->wnm_oper == NULL) - return -1; - return hapd->driver->wnm_oper(hapd->drv_priv, oper, peer, buf, - buf_len); -} - - -int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq, - unsigned int wait, const u8 *dst, const u8 *data, - size_t len) -{ - if (hapd->driver == NULL || hapd->driver->send_action == NULL) - return 0; - return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst, - hapd->own_addr, hapd->own_addr, data, - len, 0); -} - - -int hostapd_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq, - int channel, int ht_enabled, int vht_enabled, - int sec_channel_offset, int vht_oper_chwidth, - int center_segment0, int center_segment1) -{ - struct hostapd_data *hapd = iface->bss[0]; - struct hostapd_freq_params data; - int res; - - if (!hapd->driver || !hapd->driver->start_dfs_cac) - return 0; - - if (!iface->conf->ieee80211h) { - wpa_printf(MSG_ERROR, "Can't start DFS CAC, DFS functionality " - "is not enabled"); - return -1; - } - - if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled, - vht_enabled, sec_channel_offset, - vht_oper_chwidth, center_segment0, - center_segment1, - iface->current_mode->vht_capab)) - return -1; - - res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data); - if (!res) - iface->cac_started = 1; - - return res; -} - - -int hostapd_drv_set_qos_map(struct hostapd_data *hapd, - const u8 *qos_map_set, u8 qos_map_set_len) -{ - if (hapd->driver == NULL || hapd->driver->set_qos_map == NULL) - return 0; - return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set, - qos_map_set_len); -} diff --git a/contrib/hostapd/src/ap/ap_drv_ops.h b/contrib/hostapd/src/ap/ap_drv_ops.h deleted file mode 100644 index 15a4b26782..0000000000 --- a/contrib/hostapd/src/ap/ap_drv_ops.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * hostapd - Driver operations - * Copyright (c) 2009-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef AP_DRV_OPS -#define AP_DRV_OPS - -enum wpa_driver_if_type; -struct wpa_bss_params; -struct wpa_driver_scan_params; -struct ieee80211_ht_capabilities; -struct ieee80211_vht_capabilities; -struct hostapd_freq_params; - -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_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, char *ifname_wds, - const u8 *addr, int aid, int val); -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_vht_capabilities *vht_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); -int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len); -int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len); -int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type, - const char *ifname, const u8 *addr, void *bss_ctx, - void **drv_priv, char *force_ifname, u8 *if_addr, - const char *bridge, int use_existing); -int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type, - const char *ifname); -int hostapd_set_ieee8021x(struct hostapd_data *hapd, - struct wpa_bss_params *params); -int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd, - const u8 *addr, int idx, u8 *seq); -int hostapd_flush(struct hostapd_data *hapd); -int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq, - int channel, int ht_enabled, int vht_enabled, - int sec_channel_offset, int vht_oper_chwidth, - int center_segment0, int center_segment1); -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_country(struct hostapd_data *hapd, const char *country); -int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs, - int cw_min, int cw_max, int burst_time); -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_drv_none(struct hostapd_data *hapd); -int hostapd_driver_scan(struct hostapd_data *hapd, - struct wpa_driver_scan_params *params); -struct wpa_scan_results * hostapd_driver_get_scan_results( - struct hostapd_data *hapd); -int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start, - int duration); -int hostapd_drv_set_key(const char *ifname, - struct hostapd_data *hapd, - 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); -int hostapd_drv_send_mlme(struct hostapd_data *hapd, - 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_drv_send_action(struct hostapd_data *hapd, unsigned int freq, - unsigned int wait, const u8 *dst, const u8 *data, - size_t len); -int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr, - u16 auth_alg); -int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr, - 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); -int hostapd_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq, - int channel, int ht_enabled, int vht_enabled, - int sec_channel_offset, int vht_oper_chwidth, - int center_segment0, int center_segment1); -int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode, - int freq, int channel, int ht_enabled, - int vht_enabled, int sec_channel_offset, - int vht_oper_chwidth, int center_segment0, - int center_segment1, u32 vht_caps); - - -#include "drivers/driver.h" - -int hostapd_drv_wnm_oper(struct hostapd_data *hapd, - enum wnm_oper oper, const u8 *peer, - u8 *buf, u16 *buf_len); - -int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set, - u8 qos_map_set_len); - -static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd, - int enabled) -{ - if (hapd->driver == NULL || - hapd->driver->hapd_set_countermeasures == NULL) - return 0; - return hapd->driver->hapd_set_countermeasures(hapd->drv_priv, enabled); -} - -static inline int hostapd_drv_set_sta_vlan(const char *ifname, - struct hostapd_data *hapd, - const u8 *addr, int vlan_id) -{ - if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL) - return 0; - return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname, - vlan_id); -} - -static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd, - const u8 *addr) -{ - if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL) - return 0; - return hapd->driver->get_inact_sec(hapd->drv_priv, addr); -} - -static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd, - const u8 *addr) -{ - if (hapd->driver == NULL || hapd->driver->sta_remove == NULL) - return 0; - return hapd->driver->sta_remove(hapd->drv_priv, addr); -} - -static inline int hostapd_drv_hapd_send_eapol(struct hostapd_data *hapd, - const u8 *addr, const u8 *data, - size_t data_len, int encrypt, - u32 flags) -{ - if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL) - return 0; - return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data, - data_len, encrypt, - hapd->own_addr, flags); -} - -static inline int hostapd_drv_read_sta_data( - struct hostapd_data *hapd, struct hostap_sta_driver_data *data, - const u8 *addr) -{ - if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL) - return -1; - return hapd->driver->read_sta_data(hapd->drv_priv, data, addr); -} - -static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd, - const u8 *addr) -{ - if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL) - return 0; - return hapd->driver->sta_clear_stats(hapd->drv_priv, addr); -} - -static inline int hostapd_drv_set_acl(struct hostapd_data *hapd, - struct hostapd_acl_params *params) -{ - if (hapd->driver == NULL || hapd->driver->set_acl == NULL) - return 0; - return hapd->driver->set_acl(hapd->drv_priv, params); -} - -static inline int hostapd_drv_set_ap(struct hostapd_data *hapd, - struct wpa_driver_ap_params *params) -{ - if (hapd->driver == NULL || hapd->driver->set_ap == NULL) - return 0; - return hapd->driver->set_ap(hapd->drv_priv, params); -} - -static inline int hostapd_drv_set_radius_acl_auth(struct hostapd_data *hapd, - const u8 *mac, int accepted, - u32 session_timeout) -{ - if (hapd->driver == NULL || hapd->driver->set_radius_acl_auth == NULL) - return 0; - return hapd->driver->set_radius_acl_auth(hapd->drv_priv, mac, accepted, - session_timeout); -} - -static inline int hostapd_drv_set_radius_acl_expire(struct hostapd_data *hapd, - const u8 *mac) -{ - if (hapd->driver == NULL || - hapd->driver->set_radius_acl_expire == NULL) - return 0; - return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac); -} - -static inline int hostapd_drv_set_authmode(struct hostapd_data *hapd, - int auth_algs) -{ - if (hapd->driver == NULL || hapd->driver->set_authmode == NULL) - return 0; - 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); -} - -static inline int hostapd_drv_get_survey(struct hostapd_data *hapd, - unsigned int freq) -{ - if (hapd->driver == NULL) - return -1; - if (!hapd->driver->get_survey) - return -1; - return hapd->driver->get_survey(hapd->drv_priv, freq); -} - -static inline int hostapd_get_country(struct hostapd_data *hapd, char *alpha2) -{ - if (hapd->driver == NULL || hapd->driver->get_country == NULL) - return -1; - return hapd->driver->get_country(hapd->drv_priv, alpha2); -} - -static inline const char * hostapd_drv_get_radio_name(struct hostapd_data *hapd) -{ - if (hapd->driver == NULL || hapd->drv_priv == NULL || - hapd->driver->get_radio_name == NULL) - return NULL; - return hapd->driver->get_radio_name(hapd->drv_priv); -} - -static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd, - struct csa_settings *settings) -{ - if (hapd->driver == NULL || hapd->driver->switch_channel == NULL) - return -ENOTSUP; - - return hapd->driver->switch_channel(hapd->drv_priv, settings); -} - -static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf, - size_t buflen) -{ - if (hapd->driver == NULL || hapd->driver->status == NULL) - return -1; - return hapd->driver->status(hapd->drv_priv, buf, buflen); -} - -#endif /* AP_DRV_OPS */ diff --git a/contrib/hostapd/src/ap/ap_list.c b/contrib/hostapd/src/ap/ap_list.c deleted file mode 100644 index f9b154012a..0000000000 --- a/contrib/hostapd/src/ap/ap_list.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * hostapd / AP table - * Copyright (c) 2002-2009, Jouni Malinen - * Copyright (c) 2003-2004, Instant802 Networks, Inc. - * Copyright (c) 2006, Devicescape Software, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "hostapd.h" -#include "ap_config.h" -#include "ieee802_11.h" -#include "sta_info.h" -#include "beacon.h" -#include "ap_list.h" - - -/* AP list is a double linked list with head->prev pointing to the end of the - * list and tail->next = NULL. Entries are moved to the head of the list - * whenever a beacon has been received from the AP in question. The tail entry - * in this link will thus be the least recently used entry. */ - - -static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap) -{ - int i; - - if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G || - iface->conf->channel != ap->channel) - return 0; - - if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT)) - return 1; - - for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) { - int rate = (ap->supported_rates[i] & 0x7f) * 5; - if (rate == 60 || rate == 90 || rate > 110) - return 0; - } - - return 1; -} - - -static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap) -{ - struct ap_info *s; - - s = iface->ap_hash[STA_HASH(ap)]; - while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0) - s = s->hnext; - return s; -} - - -static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap) -{ - if (iface->ap_list) { - ap->prev = iface->ap_list->prev; - iface->ap_list->prev = ap; - } else - ap->prev = ap; - ap->next = iface->ap_list; - iface->ap_list = ap; -} - - -static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap) -{ - if (iface->ap_list == ap) - iface->ap_list = ap->next; - else - ap->prev->next = ap->next; - - if (ap->next) - ap->next->prev = ap->prev; - else if (iface->ap_list) - iface->ap_list->prev = ap->prev; -} - - -static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap) -{ - ap->hnext = iface->ap_hash[STA_HASH(ap->addr)]; - iface->ap_hash[STA_HASH(ap->addr)] = ap; -} - - -static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap) -{ - struct ap_info *s; - - s = iface->ap_hash[STA_HASH(ap->addr)]; - if (s == NULL) return; - if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) { - iface->ap_hash[STA_HASH(ap->addr)] = s->hnext; - return; - } - - while (s->hnext != NULL && - os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0) - s = s->hnext; - if (s->hnext != NULL) - s->hnext = s->hnext->hnext; - else - printf("AP: could not remove AP " MACSTR " from hash table\n", - MAC2STR(ap->addr)); -} - - -static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap) -{ - ap_ap_hash_del(iface, ap); - ap_ap_list_del(iface, ap); - - iface->num_ap--; - os_free(ap); -} - - -static void hostapd_free_aps(struct hostapd_iface *iface) -{ - struct ap_info *ap, *prev; - - ap = iface->ap_list; - - while (ap) { - prev = ap; - ap = ap->next; - ap_free_ap(iface, prev); - } - - iface->ap_list = NULL; -} - - -static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr) -{ - struct ap_info *ap; - - ap = os_zalloc(sizeof(struct ap_info)); - if (ap == NULL) - return NULL; - - /* initialize AP info data */ - os_memcpy(ap->addr, addr, ETH_ALEN); - ap_ap_list_add(iface, ap); - iface->num_ap++; - ap_ap_hash_add(iface, ap); - - if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) { - wpa_printf(MSG_DEBUG, "Removing the least recently used AP " - MACSTR " from AP table", MAC2STR(ap->prev->addr)); - ap_free_ap(iface, ap->prev); - } - - return ap; -} - - -void ap_list_process_beacon(struct hostapd_iface *iface, - const struct ieee80211_mgmt *mgmt, - struct ieee802_11_elems *elems, - struct hostapd_frame_info *fi) -{ - struct ap_info *ap; - int new_ap = 0; - int set_beacon = 0; - - if (iface->conf->ap_table_max_size < 1) - return; - - ap = ap_get_ap(iface, mgmt->bssid); - if (!ap) { - ap = ap_ap_add(iface, mgmt->bssid); - if (!ap) { - printf("Failed to allocate AP information entry\n"); - return; - } - new_ap = 1; - } - - merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX, - elems->supp_rates, elems->supp_rates_len, - elems->ext_supp_rates, elems->ext_supp_rates_len); - - if (elems->erp_info && elems->erp_info_len == 1) - ap->erp = elems->erp_info[0]; - else - ap->erp = -1; - - if (elems->ds_params && elems->ds_params_len == 1) - ap->channel = elems->ds_params[0]; - else if (elems->ht_operation && elems->ht_operation_len >= 1) - ap->channel = elems->ht_operation[0]; - else if (fi) - ap->channel = fi->channel; - - if (elems->ht_capabilities) - ap->ht_support = 1; - else - ap->ht_support = 0; - - os_get_reltime(&ap->last_beacon); - - if (!new_ap && ap != iface->ap_list) { - /* move AP entry into the beginning of the list so that the - * oldest entry is always in the end of the list */ - ap_ap_list_del(iface, ap); - ap_ap_list_add(iface, ap); - } - - if (!iface->olbc && - ap_list_beacon_olbc(iface, ap)) { - iface->olbc = 1; - wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR - " (channel %d) - enable protection", - MAC2STR(ap->addr), ap->channel); - set_beacon++; - } - -#ifdef CONFIG_IEEE80211N - if (!iface->olbc_ht && !ap->ht_support && - (ap->channel == 0 || - ap->channel == iface->conf->channel || - ap->channel == iface->conf->channel + - iface->conf->secondary_channel * 4)) { - iface->olbc_ht = 1; - hostapd_ht_operation_update(iface); - wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR - " (channel %d) - enable protection", - MAC2STR(ap->addr), ap->channel); - set_beacon++; - } -#endif /* CONFIG_IEEE80211N */ - - if (set_beacon) - ieee802_11_update_beacons(iface); -} - - -static void ap_list_timer(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_iface *iface = eloop_ctx; - struct os_reltime now; - struct ap_info *ap; - int set_beacon = 0; - - eloop_register_timeout(10, 0, ap_list_timer, iface, NULL); - - if (!iface->ap_list) - return; - - os_get_reltime(&now); - - while (iface->ap_list) { - ap = iface->ap_list->prev; - if (!os_reltime_expired(&now, &ap->last_beacon, - iface->conf->ap_table_expiration_time)) - break; - - ap_free_ap(iface, ap); - } - - if (iface->olbc || iface->olbc_ht) { - int olbc = 0; - int olbc_ht = 0; - - ap = iface->ap_list; - while (ap && (olbc == 0 || olbc_ht == 0)) { - if (ap_list_beacon_olbc(iface, ap)) - olbc = 1; - if (!ap->ht_support) - olbc_ht = 1; - ap = ap->next; - } - if (!olbc && iface->olbc) { - wpa_printf(MSG_DEBUG, "OLBC not detected anymore"); - iface->olbc = 0; - set_beacon++; - } -#ifdef CONFIG_IEEE80211N - if (!olbc_ht && iface->olbc_ht) { - wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore"); - iface->olbc_ht = 0; - hostapd_ht_operation_update(iface); - set_beacon++; - } -#endif /* CONFIG_IEEE80211N */ - } - - if (set_beacon) - ieee802_11_update_beacons(iface); -} - - -int ap_list_init(struct hostapd_iface *iface) -{ - eloop_register_timeout(10, 0, ap_list_timer, iface, NULL); - return 0; -} - - -void ap_list_deinit(struct hostapd_iface *iface) -{ - eloop_cancel_timeout(ap_list_timer, iface, NULL); - hostapd_free_aps(iface); -} diff --git a/contrib/hostapd/src/ap/ap_list.h b/contrib/hostapd/src/ap/ap_list.h deleted file mode 100644 index 93dc0eda88..0000000000 --- a/contrib/hostapd/src/ap/ap_list.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * hostapd / AP table - * Copyright (c) 2002-2003, Jouni Malinen - * Copyright (c) 2003-2004, Instant802 Networks, Inc. - * Copyright (c) 2006, Devicescape Software, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef AP_LIST_H -#define AP_LIST_H - -struct ap_info { - /* Note: next/prev pointers are updated whenever a new beacon is - * received because these are used to find the least recently used - * entries. */ - struct ap_info *next; /* next entry in AP list */ - struct ap_info *prev; /* previous entry in AP list */ - struct ap_info *hnext; /* next entry in hash table list */ - u8 addr[6]; - u8 supported_rates[WLAN_SUPP_RATES_MAX]; - int erp; /* ERP Info or -1 if ERP info element not present */ - - int channel; - - int ht_support; - - struct os_reltime last_beacon; -}; - -struct ieee802_11_elems; -struct hostapd_frame_info; - -void ap_list_process_beacon(struct hostapd_iface *iface, - const struct ieee80211_mgmt *mgmt, - struct ieee802_11_elems *elems, - struct hostapd_frame_info *fi); -#ifdef NEED_AP_MLME -int ap_list_init(struct hostapd_iface *iface); -void ap_list_deinit(struct hostapd_iface *iface); -#else /* NEED_AP_MLME */ -static inline int ap_list_init(struct hostapd_iface *iface) -{ - return 0; -} - -static inline void ap_list_deinit(struct hostapd_iface *iface) -{ -} -#endif /* NEED_AP_MLME */ - -#endif /* AP_LIST_H */ diff --git a/contrib/hostapd/src/ap/ap_mlme.c b/contrib/hostapd/src/ap/ap_mlme.c deleted file mode 100644 index a9596947fa..0000000000 --- a/contrib/hostapd/src/ap/ap_mlme.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * hostapd / IEEE 802.11 MLME - * Copyright 2003-2006, Jouni Malinen - * Copyright 2003-2004, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "common/ieee802_11_defs.h" -#include "ieee802_11.h" -#include "wpa_auth.h" -#include "sta_info.h" -#include "ap_mlme.h" - - -#ifndef CONFIG_NO_HOSTAPD_LOGGER -static const char * mlme_auth_alg_str(int alg) -{ - switch (alg) { - case WLAN_AUTH_OPEN: - return "OPEN_SYSTEM"; - case WLAN_AUTH_SHARED_KEY: - return "SHARED_KEY"; - case WLAN_AUTH_FT: - return "FT"; - } - - return "unknown"; -} -#endif /* CONFIG_NO_HOSTAPD_LOGGER */ - - -/** - * mlme_authenticate_indication - Report the establishment of an authentication - * relationship with a specific peer MAC entity - * @hapd: BSS data - * @sta: peer STA data - * - * MLME calls this function as a result of the establishment of an - * authentication relationship with a specific peer MAC entity that - * resulted from an authentication procedure that was initiated by - * that specific peer MAC entity. - * - * PeerSTAAddress = sta->addr - * AuthenticationType = sta->auth_alg (WLAN_AUTH_OPEN / WLAN_AUTH_SHARED_KEY) - */ -void mlme_authenticate_indication(struct hostapd_data *hapd, - struct sta_info *sta) -{ - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME, - HOSTAPD_LEVEL_DEBUG, - "MLME-AUTHENTICATE.indication(" MACSTR ", %s)", - MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg)); - if (sta->auth_alg != WLAN_AUTH_FT && !(sta->flags & WLAN_STA_MFP)) - mlme_deletekeys_request(hapd, sta); -} - - -/** - * mlme_deauthenticate_indication - Report the invalidation of an - * authentication relationship with a specific peer MAC entity - * @hapd: BSS data - * @sta: Peer STA data - * @reason_code: ReasonCode from Deauthentication frame - * - * MLME calls this function as a result of the invalidation of an - * authentication relationship with a specific peer MAC entity. - * - * PeerSTAAddress = sta->addr - */ -void mlme_deauthenticate_indication(struct hostapd_data *hapd, - struct sta_info *sta, u16 reason_code) -{ - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME, - HOSTAPD_LEVEL_DEBUG, - "MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)", - MAC2STR(sta->addr), reason_code); - mlme_deletekeys_request(hapd, sta); -} - - -/** - * mlme_associate_indication - Report the establishment of an association with - * a specific peer MAC entity - * @hapd: BSS data - * @sta: peer STA data - * - * MLME calls this function as a result of the establishment of an - * association with a specific peer MAC entity that resulted from an - * association procedure that was initiated by that specific peer MAC entity. - * - * PeerSTAAddress = sta->addr - */ -void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta) -{ - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME, - HOSTAPD_LEVEL_DEBUG, - "MLME-ASSOCIATE.indication(" MACSTR ")", - MAC2STR(sta->addr)); - if (sta->auth_alg != WLAN_AUTH_FT) - mlme_deletekeys_request(hapd, sta); -} - - -/** - * mlme_reassociate_indication - Report the establishment of an reassociation - * with a specific peer MAC entity - * @hapd: BSS data - * @sta: peer STA data - * - * MLME calls this function as a result of the establishment of an - * reassociation with a specific peer MAC entity that resulted from a - * reassociation procedure that was initiated by that specific peer MAC entity. - * - * PeerSTAAddress = sta->addr - * - * sta->previous_ap contains the "Current AP" information from ReassocReq. - */ -void mlme_reassociate_indication(struct hostapd_data *hapd, - struct sta_info *sta) -{ - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME, - HOSTAPD_LEVEL_DEBUG, - "MLME-REASSOCIATE.indication(" MACSTR ")", - MAC2STR(sta->addr)); - if (sta->auth_alg != WLAN_AUTH_FT) - mlme_deletekeys_request(hapd, sta); -} - - -/** - * mlme_disassociate_indication - Report disassociation with a specific peer - * MAC entity - * @hapd: BSS data - * @sta: Peer STA data - * @reason_code: ReasonCode from Disassociation frame - * - * MLME calls this function as a result of the invalidation of an association - * relationship with a specific peer MAC entity. - * - * PeerSTAAddress = sta->addr - */ -void mlme_disassociate_indication(struct hostapd_data *hapd, - struct sta_info *sta, u16 reason_code) -{ - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME, - HOSTAPD_LEVEL_DEBUG, - "MLME-DISASSOCIATE.indication(" MACSTR ", %d)", - MAC2STR(sta->addr), reason_code); - mlme_deletekeys_request(hapd, sta); -} - - -void mlme_michaelmicfailure_indication(struct hostapd_data *hapd, - const u8 *addr) -{ - hostapd_logger(hapd, addr, HOSTAPD_MODULE_MLME, - HOSTAPD_LEVEL_DEBUG, - "MLME-MichaelMICFailure.indication(" MACSTR ")", - MAC2STR(addr)); -} - - -void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta) -{ - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME, - HOSTAPD_LEVEL_DEBUG, - "MLME-DELETEKEYS.request(" MACSTR ")", - MAC2STR(sta->addr)); - - if (sta->wpa_sm) - wpa_remove_ptk(sta->wpa_sm); -} diff --git a/contrib/hostapd/src/ap/ap_mlme.h b/contrib/hostapd/src/ap/ap_mlme.h deleted file mode 100644 index e7fd69d61c..0000000000 --- a/contrib/hostapd/src/ap/ap_mlme.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * hostapd / IEEE 802.11 MLME - * Copyright 2003, Jouni Malinen - * Copyright 2003-2004, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef MLME_H -#define MLME_H - -void mlme_authenticate_indication(struct hostapd_data *hapd, - struct sta_info *sta); - -void mlme_deauthenticate_indication(struct hostapd_data *hapd, - struct sta_info *sta, u16 reason_code); - -void mlme_associate_indication(struct hostapd_data *hapd, - struct sta_info *sta); - -void mlme_reassociate_indication(struct hostapd_data *hapd, - struct sta_info *sta); - -void mlme_disassociate_indication(struct hostapd_data *hapd, - struct sta_info *sta, u16 reason_code); - -void mlme_michaelmicfailure_indication(struct hostapd_data *hapd, - const u8 *addr); - -void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta); - -#endif /* MLME_H */ diff --git a/contrib/hostapd/src/ap/authsrv.c b/contrib/hostapd/src/ap/authsrv.c deleted file mode 100644 index 8bb58a6f66..0000000000 --- a/contrib/hostapd/src/ap/authsrv.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Authentication server setup - * Copyright (c) 2002-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "crypto/tls.h" -#include "eap_server/eap.h" -#include "eap_server/eap_sim_db.h" -#include "eapol_auth/eapol_auth_sm.h" -#include "radius/radius_server.h" -#include "hostapd.h" -#include "ap_config.h" -#include "sta_info.h" -#include "authsrv.h" - - -#if defined(EAP_SERVER_SIM) || defined(EAP_SERVER_AKA) -#define EAP_SIM_DB -#endif /* EAP_SERVER_SIM || EAP_SERVER_AKA */ - - -#ifdef EAP_SIM_DB -static int hostapd_sim_db_cb_sta(struct hostapd_data *hapd, - struct sta_info *sta, void *ctx) -{ - if (eapol_auth_eap_pending_cb(sta->eapol_sm, ctx) == 0) - return 1; - return 0; -} - - -static void hostapd_sim_db_cb(void *ctx, void *session_ctx) -{ - struct hostapd_data *hapd = ctx; - if (ap_for_each_sta(hapd, hostapd_sim_db_cb_sta, session_ctx) == 0) { -#ifdef RADIUS_SERVER - radius_server_eap_pending_cb(hapd->radius_srv, session_ctx); -#endif /* RADIUS_SERVER */ - } -} -#endif /* EAP_SIM_DB */ - - -#ifdef RADIUS_SERVER - -static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, - size_t identity_len, int phase2, - struct eap_user *user) -{ - const struct hostapd_eap_user *eap_user; - int i; - - eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2); - if (eap_user == NULL) - return -1; - - if (user == NULL) - return 0; - - os_memset(user, 0, sizeof(*user)); - 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; - } - - if (eap_user->password) { - user->password = os_malloc(eap_user->password_len); - if (user->password == NULL) - return -1; - 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; - - return 0; -} - - -static int hostapd_setup_radius_srv(struct hostapd_data *hapd) -{ - struct radius_server_conf srv; - struct hostapd_bss_config *conf = hapd->conf; - os_memset(&srv, 0, sizeof(srv)); - srv.client_file = conf->radius_server_clients; - srv.auth_port = conf->radius_server_auth_port; - srv.conf_ctx = hapd; - srv.eap_sim_db_priv = hapd->eap_sim_db_priv; - srv.ssl_ctx = hapd->ssl_ctx; - srv.msg_ctx = hapd->msg_ctx; - srv.pac_opaque_encr_key = conf->pac_opaque_encr_key; - srv.eap_fast_a_id = conf->eap_fast_a_id; - srv.eap_fast_a_id_len = conf->eap_fast_a_id_len; - srv.eap_fast_a_id_info = conf->eap_fast_a_id_info; - srv.eap_fast_prov = conf->eap_fast_prov; - srv.pac_key_lifetime = conf->pac_key_lifetime; - srv.pac_key_refresh_time = conf->pac_key_refresh_time; - srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; - srv.tnc = conf->tnc; - srv.wps = hapd->wps; - srv.ipv6 = conf->radius_server_ipv6; - srv.get_eap_user = hostapd_radius_get_eap_user; - srv.eap_req_id_text = conf->eap_req_id_text; - srv.eap_req_id_text_len = conf->eap_req_id_text_len; - srv.pwd_group = conf->pwd_group; - srv.server_id = conf->server_id ? conf->server_id : "hostapd"; -#ifdef CONFIG_RADIUS_TEST - srv.dump_msk_file = conf->dump_msk_file; -#endif /* CONFIG_RADIUS_TEST */ - - hapd->radius_srv = radius_server_init(&srv); - if (hapd->radius_srv == NULL) { - wpa_printf(MSG_ERROR, "RADIUS server initialization failed."); - return -1; - } - - return 0; -} - -#endif /* RADIUS_SERVER */ - - -int authsrv_init(struct hostapd_data *hapd) -{ -#ifdef EAP_TLS_FUNCS - if (hapd->conf->eap_server && - (hapd->conf->ca_cert || hapd->conf->server_cert || - hapd->conf->private_key || hapd->conf->dh_file)) { - struct tls_connection_params params; - - hapd->ssl_ctx = tls_init(NULL); - if (hapd->ssl_ctx == NULL) { - wpa_printf(MSG_ERROR, "Failed to initialize TLS"); - authsrv_deinit(hapd); - return -1; - } - - os_memset(¶ms, 0, sizeof(params)); - params.ca_cert = hapd->conf->ca_cert; - params.client_cert = hapd->conf->server_cert; - params.private_key = hapd->conf->private_key; - params.private_key_passwd = hapd->conf->private_key_passwd; - params.dh_file = hapd->conf->dh_file; - params.ocsp_stapling_response = - hapd->conf->ocsp_stapling_response; - - if (tls_global_set_params(hapd->ssl_ctx, ¶ms)) { - wpa_printf(MSG_ERROR, "Failed to set TLS parameters"); - authsrv_deinit(hapd); - return -1; - } - - if (tls_global_set_verify(hapd->ssl_ctx, - hapd->conf->check_crl)) { - wpa_printf(MSG_ERROR, "Failed to enable check_crl"); - authsrv_deinit(hapd); - return -1; - } - } -#endif /* EAP_TLS_FUNCS */ - -#ifdef EAP_SIM_DB - if (hapd->conf->eap_sim_db) { - hapd->eap_sim_db_priv = - eap_sim_db_init(hapd->conf->eap_sim_db, - hostapd_sim_db_cb, hapd); - if (hapd->eap_sim_db_priv == NULL) { - wpa_printf(MSG_ERROR, "Failed to initialize EAP-SIM " - "database interface"); - authsrv_deinit(hapd); - return -1; - } - } -#endif /* EAP_SIM_DB */ - -#ifdef RADIUS_SERVER - if (hapd->conf->radius_server_clients && - hostapd_setup_radius_srv(hapd)) - return -1; -#endif /* RADIUS_SERVER */ - - return 0; -} - - -void authsrv_deinit(struct hostapd_data *hapd) -{ -#ifdef RADIUS_SERVER - radius_server_deinit(hapd->radius_srv); - hapd->radius_srv = NULL; -#endif /* RADIUS_SERVER */ - -#ifdef EAP_TLS_FUNCS - if (hapd->ssl_ctx) { - tls_deinit(hapd->ssl_ctx); - hapd->ssl_ctx = NULL; - } -#endif /* EAP_TLS_FUNCS */ - -#ifdef EAP_SIM_DB - if (hapd->eap_sim_db_priv) { - eap_sim_db_deinit(hapd->eap_sim_db_priv); - hapd->eap_sim_db_priv = NULL; - } -#endif /* EAP_SIM_DB */ -} diff --git a/contrib/hostapd/src/ap/authsrv.h b/contrib/hostapd/src/ap/authsrv.h deleted file mode 100644 index 2f4ed3419c..0000000000 --- a/contrib/hostapd/src/ap/authsrv.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Authentication server setup - * Copyright (c) 2002-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef AUTHSRV_H -#define AUTHSRV_H - -int authsrv_init(struct hostapd_data *hapd); -void authsrv_deinit(struct hostapd_data *hapd); - -#endif /* AUTHSRV_H */ diff --git a/contrib/hostapd/src/ap/beacon.c b/contrib/hostapd/src/ap/beacon.c deleted file mode 100644 index 5318ecb742..0000000000 --- a/contrib/hostapd/src/ap/beacon.c +++ /dev/null @@ -1,941 +0,0 @@ -/* - * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response - * Copyright (c) 2002-2004, Instant802 Networks, Inc. - * Copyright (c) 2005-2006, Devicescape Software, Inc. - * Copyright (c) 2008-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#ifndef CONFIG_NATIVE_WINDOWS - -#include "utils/common.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "wps/wps_defs.h" -#include "p2p/p2p.h" -#include "hostapd.h" -#include "ieee802_11.h" -#include "wpa_auth.h" -#include "wmm.h" -#include "ap_config.h" -#include "sta_info.h" -#include "p2p_hostapd.h" -#include "ap_drv_ops.h" -#include "beacon.h" -#include "hs20.h" - - -#ifdef NEED_AP_MLME - -static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len) -{ -#ifdef CONFIG_TESTING_OPTIONS - if (hapd->conf->bss_load_test_set) { - if (2 + 5 > len) - return eid; - *eid++ = WLAN_EID_BSS_LOAD; - *eid++ = 5; - os_memcpy(eid, hapd->conf->bss_load_test, 5); - eid += 5; - } -#endif /* CONFIG_TESTING_OPTIONS */ - return eid; -} - - -static u8 ieee802_11_erp_info(struct hostapd_data *hapd) -{ - u8 erp = 0; - - if (hapd->iface->current_mode == NULL || - hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) - return 0; - - 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) - erp |= ERP_INFO_BARKER_PREAMBLE_MODE; - - return erp; -} - - -static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid) -{ - *eid++ = WLAN_EID_DS_PARAMS; - *eid++ = 1; - *eid++ = hapd->iconf->channel; - return eid; -} - - -static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid) -{ - if (hapd->iface->current_mode == NULL || - hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) - return eid; - - /* Set NonERP_present and use_protection bits if there - * are any associated NonERP stations. */ - /* TODO: use_protection bit can be set to zero even if - * there are NonERP stations present. This optimization - * might be useful if NonERP stations are "quiet". - * See 802.11g/D6 E-1 for recommended practice. - * In addition, Non ERP present might be set, if AP detects Non ERP - * operation on other APs. */ - - /* Add ERP Information element */ - *eid++ = WLAN_EID_ERP_INFO; - *eid++ = 1; - *eid++ = ieee802_11_erp_info(hapd); - - return eid; -} - - -static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing, - struct hostapd_channel_data *start, - struct hostapd_channel_data *prev) -{ - if (end - pos < 3) - return pos; - - /* first channel number */ - *pos++ = start->chan; - /* number of channels */ - *pos++ = (prev->chan - start->chan) / chan_spacing + 1; - /* maximum transmit power level */ - *pos++ = start->max_tx_power; - - return pos; -} - - -static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, - int max_len) -{ - u8 *pos = eid; - u8 *end = eid + max_len; - int i; - struct hostapd_hw_modes *mode; - struct hostapd_channel_data *start, *prev; - int chan_spacing = 1; - - if (!hapd->iconf->ieee80211d || max_len < 6 || - hapd->iface->current_mode == NULL) - return eid; - - *pos++ = WLAN_EID_COUNTRY; - pos++; /* length will be set later */ - os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */ - pos += 3; - - mode = hapd->iface->current_mode; - if (mode->mode == HOSTAPD_MODE_IEEE80211A) - chan_spacing = 4; - - start = prev = NULL; - for (i = 0; i < mode->num_channels; i++) { - struct hostapd_channel_data *chan = &mode->channels[i]; - if (chan->flag & HOSTAPD_CHAN_DISABLED) - continue; - if (start && prev && - prev->chan + chan_spacing == chan->chan && - start->max_tx_power == chan->max_tx_power) { - prev = chan; - continue; /* can use same entry */ - } - - if (start) { - pos = hostapd_eid_country_add(pos, end, chan_spacing, - start, prev); - start = NULL; - } - - /* Start new group */ - start = prev = chan; - } - - if (start) { - pos = hostapd_eid_country_add(pos, end, chan_spacing, - start, prev); - } - - if ((pos - eid) & 1) { - if (end - pos < 1) - return eid; - *pos++ = 0; /* pad for 16-bit alignment */ - } - - eid[1] = (pos - eid) - 2; - - return pos; -} - - -static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len) -{ - const u8 *ie; - size_t ielen; - - ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen); - if (ie == NULL || ielen > len) - return eid; - - os_memcpy(eid, ie, ielen); - return eid + ielen; -} - - -static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid) -{ - u8 chan; - - if (!hapd->iface->cs_freq_params.freq) - return eid; - - if (ieee80211_freq_to_chan(hapd->iface->cs_freq_params.freq, &chan) == - NUM_HOSTAPD_MODES) - return eid; - - *eid++ = WLAN_EID_CHANNEL_SWITCH; - *eid++ = 3; - *eid++ = hapd->iface->cs_block_tx; - *eid++ = chan; - *eid++ = hapd->iface->cs_count; - - return eid; -} - - -static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid) -{ - u8 sec_ch; - - if (!hapd->iface->cs_freq_params.sec_channel_offset) - return eid; - - if (hapd->iface->cs_freq_params.sec_channel_offset == -1) - sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW; - else if (hapd->iface->cs_freq_params.sec_channel_offset == 1) - sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE; - else - return eid; - - *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; - *eid++ = 1; - *eid++ = sec_ch; - - return eid; -} - - -static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos, - u8 *start, unsigned int *csa_counter_off) -{ - u8 *old_pos = pos; - - if (!csa_counter_off) - return pos; - - *csa_counter_off = 0; - pos = hostapd_eid_csa(hapd, pos); - - if (pos != old_pos) { - /* save an offset to the counter - should be last byte */ - *csa_counter_off = pos - start - 1; - pos = hostapd_eid_secondary_channel(hapd, pos); - } - - return pos; -} - - -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 */ - if (hapd->conf->vendor_elements) - buflen += wpabuf_len(hapd->conf->vendor_elements); - 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); - - pos = hostapd_eid_bss_load(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); - - pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp, - &hapd->iface->cs_c_off_proberesp); -#ifdef CONFIG_IEEE80211AC - pos = hostapd_eid_vht_capabilities(hapd, pos); - pos = hostapd_eid_vht_operation(hapd, pos); -#endif /* CONFIG_IEEE80211AC */ - - /* Wi-Fi Alliance WMM */ - pos = hostapd_eid_wmm(hapd, pos); - -#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 */ - -#ifdef CONFIG_HS20 - pos = hostapd_eid_hs20_indication(hapd, pos); -#endif /* CONFIG_HS20 */ - - if (hapd->conf->vendor_elements) { - os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements), - wpabuf_len(hapd->conf->vendor_elements)); - pos += wpabuf_len(hapd->conf->vendor_elements); - } - - *resp_len = pos - (u8 *) resp; - return (u8 *) resp; -} - - -enum ssid_match_result { - NO_SSID_MATCH, - EXACT_SSID_MATCH, - WILDCARD_SSID_MATCH -}; - -static enum ssid_match_result ssid_match(struct hostapd_data *hapd, - const u8 *ssid, size_t ssid_len, - const u8 *ssid_list, - size_t ssid_list_len) -{ - const u8 *pos, *end; - int wildcard = 0; - - if (ssid_len == 0) - wildcard = 1; - if (ssid_len == hapd->conf->ssid.ssid_len && - os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0) - return EXACT_SSID_MATCH; - - if (ssid_list == NULL) - return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH; - - pos = ssid_list; - end = ssid_list + ssid_list_len; - while (pos + 1 <= end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[1] == 0) - wildcard = 1; - if (pos[1] == hapd->conf->ssid.ssid_len && - os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0) - return EXACT_SSID_MATCH; - pos += 2 + pos[1]; - } - - return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH; -} - - -void handle_probe_req(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len, - int ssi_signal) -{ - u8 *resp; - struct ieee802_11_elems elems; - const u8 *ie; - size_t ie_len; - struct sta_info *sta = NULL; - size_t i, resp_len; - int noack; - enum ssid_match_result res; - - 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)); - - for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) - if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, - mgmt->sa, mgmt->da, mgmt->bssid, - ie, ie_len, ssi_signal) > 0) - return; - - if (!hapd->iconf->send_probe_response) - return; - - if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { - wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR, - MAC2STR(mgmt->sa)); - return; - } - - if ((!elems.ssid || !elems.supp_rates)) { - wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request " - "without SSID or supported rates element", - MAC2STR(mgmt->sa)); - return; - } - -#ifdef CONFIG_P2P - if (hapd->p2p && elems.wps_ie) { - struct wpabuf *wps; - wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); - if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) { - wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request " - "due to mismatch with Requested Device " - "Type"); - wpabuf_free(wps); - return; - } - wpabuf_free(wps); - } - - if (hapd->p2p && elems.p2p) { - struct wpabuf *p2p; - p2p = ieee802_11_vendor_ie_concat(ie, ie_len, P2P_IE_VENDOR_TYPE); - if (p2p && !p2p_group_match_dev_id(hapd->p2p_group, p2p)) { - wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request " - "due to mismatch with Device ID"); - wpabuf_free(p2p); - return; - } - wpabuf_free(p2p); - } -#endif /* CONFIG_P2P */ - - if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 && - elems.ssid_list_len == 0) { - wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for " - "broadcast SSID ignored", MAC2STR(mgmt->sa)); - return; - } - - sta = ap_get_sta(hapd, mgmt->sa); - -#ifdef CONFIG_P2P - if ((hapd->conf->p2p & P2P_GROUP_OWNER) && - elems.ssid_len == P2P_WILDCARD_SSID_LEN && - os_memcmp(elems.ssid, P2P_WILDCARD_SSID, - P2P_WILDCARD_SSID_LEN) == 0) { - /* Process P2P Wildcard SSID like Wildcard SSID */ - elems.ssid_len = 0; - } -#endif /* CONFIG_P2P */ - - res = ssid_match(hapd, elems.ssid, elems.ssid_len, - elems.ssid_list, elems.ssid_list_len); - if (res != NO_SSID_MATCH) { - if (sta) - sta->ssid_probe = &hapd->conf->ssid; - } else { - if (!(mgmt->da[0] & 0x01)) { - char ssid_txt[33]; - ieee802_11_print_ssid(ssid_txt, elems.ssid, - elems.ssid_len); - wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR - " for foreign SSID '%s' (DA " MACSTR ")%s", - MAC2STR(mgmt->sa), ssid_txt, - MAC2STR(mgmt->da), - elems.ssid_list ? " (SSID list)" : ""); - } - 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 */ - -#ifdef CONFIG_P2P - if ((hapd->conf->p2p & P2P_GROUP_OWNER) && - supp_rates_11b_only(&elems)) { - /* Indicates support for 11b rates only */ - wpa_printf(MSG_EXCESSIVE, "P2P: Ignore Probe Request from " - MACSTR " with only 802.11b rates", - MAC2STR(mgmt->sa)); - return; - } -#endif /* CONFIG_P2P */ - - /* TODO: verify that supp_rates contains at least one matching rate - * with AP configuration */ - -#ifdef CONFIG_TESTING_OPTIONS - if (hapd->iconf->ignore_probe_probability > 0.0d && - drand48() < hapd->iconf->ignore_probe_probability) { - wpa_printf(MSG_INFO, - "TESTING: ignoring probe request from " MACSTR, - MAC2STR(mgmt->sa)); - return; - } -#endif /* CONFIG_TESTING_OPTIONS */ - - resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL, - &resp_len); - if (resp == NULL) - return; - - /* - * If this is a broadcast probe request, apply no ack policy to avoid - * excessive retries. - */ - noack = !!(res == WILDCARD_SSID_MATCH && - is_broadcast_ether_addr(mgmt->da)); - - if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0) - wpa_printf(MSG_INFO, "handle_probe_req: send failed"); - - os_free(resp); - - wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s " - "SSID", MAC2STR(mgmt->sa), - elems.ssid_len == 0 ? "broadcast" : "our"); -} - - -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 && - (!(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) && 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 */ - - -int ieee802_11_build_ap_params(struct hostapd_data *hapd, - struct wpa_driver_ap_params *params) -{ - struct ieee80211_mgmt *head = NULL; - u8 *tail = NULL; - size_t head_len = 0, tail_len = 0; - u8 *resp = NULL; - size_t resp_len = 0; -#ifdef NEED_AP_MLME - u16 capab_info; - u8 *pos, *tailpos; - -#define BEACON_HEAD_BUF_SIZE 256 -#define BEACON_TAIL_BUF_SIZE 512 - head = os_zalloc(BEACON_HEAD_BUF_SIZE); - tail_len = BEACON_TAIL_BUF_SIZE; -#ifdef CONFIG_WPS - if (hapd->conf->wps_state && hapd->wps_beacon_ie) - tail_len += wpabuf_len(hapd->wps_beacon_ie); -#endif /* CONFIG_WPS */ -#ifdef CONFIG_P2P - if (hapd->p2p_beacon_ie) - tail_len += wpabuf_len(hapd->p2p_beacon_ie); -#endif /* CONFIG_P2P */ - if (hapd->conf->vendor_elements) - tail_len += wpabuf_len(hapd->conf->vendor_elements); - tailpos = tail = os_malloc(tail_len); - if (head == NULL || tail == NULL) { - wpa_printf(MSG_ERROR, "Failed to set beacon data"); - os_free(head); - os_free(tail); - return -1; - } - - head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_BEACON); - head->duration = host_to_le16(0); - os_memset(head->da, 0xff, ETH_ALEN); - - os_memcpy(head->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN); - head->u.beacon.beacon_int = - host_to_le16(hapd->iconf->beacon_int); - - /* hardware or low-level driver will setup seq_ctrl and timestamp */ - capab_info = hostapd_own_capab_info(hapd, NULL, 0); - head->u.beacon.capab_info = host_to_le16(capab_info); - pos = &head->u.beacon.variable[0]; - - /* SSID */ - *pos++ = WLAN_EID_SSID; - if (hapd->conf->ignore_broadcast_ssid == 2) { - /* clear the data, but keep the correct length of the SSID */ - *pos++ = hapd->conf->ssid.ssid_len; - os_memset(pos, 0, hapd->conf->ssid.ssid_len); - pos += hapd->conf->ssid.ssid_len; - } else if (hapd->conf->ignore_broadcast_ssid) { - *pos++ = 0; /* empty SSID */ - } else { - *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); - - head_len = pos - (u8 *) head; - - tailpos = hostapd_eid_country(hapd, tailpos, - tail + BEACON_TAIL_BUF_SIZE - tailpos); - - /* ERP Information element */ - tailpos = hostapd_eid_erp_info(hapd, tailpos); - - /* Extended supported rates */ - tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos); - - /* RSN, MDIE, WPA */ - tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - - tailpos); - - tailpos = hostapd_eid_bss_load(hapd, tailpos, - tail + BEACON_TAIL_BUF_SIZE - tailpos); - -#ifdef CONFIG_IEEE80211N - tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); - tailpos = hostapd_eid_ht_operation(hapd, tailpos); -#endif /* CONFIG_IEEE80211N */ - - 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); - tailpos = hostapd_add_csa_elems(hapd, tailpos, tail, - &hapd->iface->cs_c_off_beacon); -#ifdef CONFIG_IEEE80211AC - tailpos = hostapd_eid_vht_capabilities(hapd, tailpos); - tailpos = hostapd_eid_vht_operation(hapd, tailpos); -#endif /* CONFIG_IEEE80211AC */ - - /* Wi-Fi Alliance WMM */ - tailpos = hostapd_eid_wmm(hapd, tailpos); - -#ifdef CONFIG_WPS - if (hapd->conf->wps_state && hapd->wps_beacon_ie) { - os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie), - wpabuf_len(hapd->wps_beacon_ie)); - tailpos += wpabuf_len(hapd->wps_beacon_ie); - } -#endif /* CONFIG_WPS */ - -#ifdef CONFIG_P2P - if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_beacon_ie) { - os_memcpy(tailpos, wpabuf_head(hapd->p2p_beacon_ie), - wpabuf_len(hapd->p2p_beacon_ie)); - tailpos += wpabuf_len(hapd->p2p_beacon_ie); - } -#endif /* CONFIG_P2P */ -#ifdef CONFIG_P2P_MANAGER - if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == - P2P_MANAGE) - tailpos = hostapd_eid_p2p_manage(hapd, tailpos); -#endif /* CONFIG_P2P_MANAGER */ - -#ifdef CONFIG_HS20 - tailpos = hostapd_eid_hs20_indication(hapd, tailpos); -#endif /* CONFIG_HS20 */ - - if (hapd->conf->vendor_elements) { - os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements), - wpabuf_len(hapd->conf->vendor_elements)); - tailpos += wpabuf_len(hapd->conf->vendor_elements); - } - - tail_len = tailpos > tail ? tailpos - tail : 0; - - 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->iface->basic_rates; - params->ssid = 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; - } - 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; - params->ap_max_inactivity = hapd->conf->ap_max_inactivity; -#ifdef CONFIG_HS20 - params->disable_dgaf = hapd->conf->disable_dgaf; -#endif /* CONFIG_HS20 */ - return 0; -} - - -void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params) -{ - os_free(params->tail); - params->tail = NULL; - os_free(params->head); - params->head = NULL; - os_free(params->proberesp); - params->proberesp = NULL; -} - - -int ieee802_11_set_beacon(struct hostapd_data *hapd) -{ - struct wpa_driver_ap_params params; - struct wpabuf *beacon, *proberesp, *assocresp; - int res, ret = -1; - - if (hapd->iface->csa_in_progress) { - wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period"); - return -1; - } - - hapd->beacon_set_done = 1; - - if (ieee802_11_build_ap_params(hapd, ¶ms) < 0) - return -1; - - if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) < - 0) - goto fail; - - params.beacon_ies = beacon; - params.proberesp_ies = proberesp; - params.assocresp_ies = assocresp; - - res = hostapd_drv_set_ap(hapd, ¶ms); - hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); - if (res) - wpa_printf(MSG_ERROR, "Failed to set beacon parameters"); - else - ret = 0; -fail: - ieee802_11_free_ap_params(¶ms); - return ret; -} - - -int ieee802_11_set_beacons(struct hostapd_iface *iface) -{ - size_t i; - int ret = 0; - - for (i = 0; i < iface->num_bss; i++) { - if (iface->bss[i]->started && - ieee802_11_set_beacon(iface->bss[i]) < 0) - ret = -1; - } - - return ret; -} - - -/* only update beacons if started */ -int ieee802_11_update_beacons(struct hostapd_iface *iface) -{ - size_t i; - int ret = 0; - - for (i = 0; i < iface->num_bss; i++) { - if (iface->bss[i]->beacon_set_done && iface->bss[i]->started && - ieee802_11_set_beacon(iface->bss[i]) < 0) - ret = -1; - } - - return ret; -} - -#endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/contrib/hostapd/src/ap/beacon.h b/contrib/hostapd/src/ap/beacon.h deleted file mode 100644 index 722159a750..0000000000 --- a/contrib/hostapd/src/ap/beacon.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response - * Copyright (c) 2002-2004, Instant802 Networks, Inc. - * Copyright (c) 2005-2006, Devicescape Software, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef BEACON_H -#define BEACON_H - -struct ieee80211_mgmt; - -void handle_probe_req(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len, - int ssi_signal); -int ieee802_11_set_beacon(struct hostapd_data *hapd); -int ieee802_11_set_beacons(struct hostapd_iface *iface); -int ieee802_11_update_beacons(struct hostapd_iface *iface); -int ieee802_11_build_ap_params(struct hostapd_data *hapd, - struct wpa_driver_ap_params *params); -void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params); - -#endif /* BEACON_H */ diff --git a/contrib/hostapd/src/ap/ctrl_iface_ap.c b/contrib/hostapd/src/ap/ctrl_iface_ap.c deleted file mode 100644 index 8c0cbab665..0000000000 --- a/contrib/hostapd/src/ap/ctrl_iface_ap.c +++ /dev/null @@ -1,510 +0,0 @@ -/* - * Control interface for shared AP commands - * Copyright (c) 2004-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "common/ieee802_11_defs.h" -#include "eapol_auth/eapol_auth_sm.h" -#include "hostapd.h" -#include "ieee802_1x.h" -#include "wpa_auth.h" -#include "ieee802_11.h" -#include "sta_info.h" -#include "wps_hostapd.h" -#include "p2p_hostapd.h" -#include "ctrl_iface_ap.h" -#include "ap_drv_ops.h" - - -static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd, - struct sta_info *sta, - char *buf, size_t buflen) -{ - struct hostap_sta_driver_data data; - int ret; - - if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) - return 0; - - ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n" - "rx_bytes=%lu\ntx_bytes=%lu\n", - data.rx_packets, data.tx_packets, - data.rx_bytes, data.tx_bytes); - if (ret < 0 || (size_t) ret >= buflen) - return 0; - return ret; -} - - -static int hostapd_get_sta_conn_time(struct sta_info *sta, - char *buf, size_t buflen) -{ - struct os_reltime age; - int ret; - - if (!sta->connected_time.sec) - return 0; - - os_reltime_age(&sta->connected_time, &age); - - ret = os_snprintf(buf, buflen, "connected_time=%u\n", - (unsigned int) age.sec); - if (ret < 0 || (size_t) ret >= buflen) - return 0; - return ret; -} - - -static const char * timeout_next_str(int val) -{ - switch (val) { - case STA_NULLFUNC: - return "NULLFUNC POLL"; - case STA_DISASSOC: - return "DISASSOC"; - case STA_DEAUTH: - return "DEAUTH"; - case STA_REMOVE: - return "REMOVE"; - case STA_DISASSOC_FROM_CLI: - return "DISASSOC_FROM_CLI"; - } - - return "?"; -} - - -static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, - struct sta_info *sta, - char *buf, size_t buflen) -{ - int len, res, ret, i; - - if (!sta) - return 0; - - len = 0; - ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=", - MAC2STR(sta->addr)); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len); - if (ret < 0) - return len; - len += ret; - - ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n" - "listen_interval=%d\nsupported_rates=", - sta->aid, sta->capability, sta->listen_interval); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - for (i = 0; i < sta->supported_rates_len; i++) { - ret = os_snprintf(buf + len, buflen - len, "%02x%s", - sta->supported_rates[i], - i + 1 < sta->supported_rates_len ? " " : ""); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - } - - ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n", - timeout_next_str(sta->timeout_next)); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len); - if (res >= 0) - len += res; - res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len); - if (res >= 0) - len += res; - res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len); - if (res >= 0) - len += res; - res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len, - buflen - len); - if (res >= 0) - len += res; - res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len); - if (res >= 0) - len += res; - - len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len); - len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len); - - return len; -} - - -int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd, - char *buf, size_t buflen) -{ - return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen); -} - - -int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr, - char *buf, size_t buflen) -{ - u8 addr[ETH_ALEN]; - int ret; - const char *pos; - struct sta_info *sta; - - if (hwaddr_aton(txtaddr, addr)) { - ret = os_snprintf(buf, buflen, "FAIL\n"); - if (ret < 0 || (size_t) ret >= buflen) - return 0; - return ret; - } - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) - return -1; - - pos = os_strchr(txtaddr, ' '); - if (pos) { - pos++; - -#ifdef HOSTAPD_DUMP_STATE - if (os_strcmp(pos, "eapol") == 0) { - if (sta->eapol_sm == NULL) - return -1; - return eapol_auth_dump_state(sta->eapol_sm, buf, - buflen); - } -#endif /* HOSTAPD_DUMP_STATE */ - - return -1; - } - - return hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen); -} - - -int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr, - char *buf, size_t buflen) -{ - u8 addr[ETH_ALEN]; - struct sta_info *sta; - int ret; - - if (hwaddr_aton(txtaddr, addr) || - (sta = ap_get_sta(hapd, addr)) == NULL) { - ret = os_snprintf(buf, buflen, "FAIL\n"); - if (ret < 0 || (size_t) ret >= buflen) - return 0; - return ret; - } - - if (!sta->next) - return 0; - - return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen); -} - - -#ifdef CONFIG_P2P_MANAGER -static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype, - u8 minor_reason_code, const u8 *addr) -{ - struct ieee80211_mgmt *mgmt; - int ret; - u8 *pos; - - if (hapd->driver->send_frame == NULL) - return -1; - - mgmt = os_zalloc(sizeof(*mgmt) + 100); - if (mgmt == NULL) - return -1; - - wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR - " with minor reason code %u (stype=%u)", - MAC2STR(addr), minor_reason_code, stype); - - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype); - os_memcpy(mgmt->da, addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); - if (stype == WLAN_FC_STYPE_DEAUTH) { - mgmt->u.deauth.reason_code = - host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); - pos = (u8 *) (&mgmt->u.deauth.reason_code + 1); - } else { - mgmt->u.disassoc.reason_code = - host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); - pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1); - } - - *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = 4 + 3 + 1; - WPA_PUT_BE24(pos, OUI_WFA); - pos += 3; - *pos++ = P2P_OUI_TYPE; - - *pos++ = P2P_ATTR_MINOR_REASON_CODE; - WPA_PUT_LE16(pos, 1); - pos += 2; - *pos++ = minor_reason_code; - - ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt, - pos - (u8 *) mgmt, 1); - os_free(mgmt); - - return ret < 0 ? -1 : 0; -} -#endif /* CONFIG_P2P_MANAGER */ - - -int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, - const char *txtaddr) -{ - u8 addr[ETH_ALEN]; - struct sta_info *sta; - const char *pos; - u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID; - - wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", - txtaddr); - - if (hwaddr_aton(txtaddr, addr)) - return -1; - - pos = os_strstr(txtaddr, " test="); - if (pos) { - struct ieee80211_mgmt mgmt; - int encrypt; - if (hapd->driver->send_frame == NULL) - return -1; - pos += 6; - encrypt = atoi(pos); - os_memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DEAUTH); - os_memcpy(mgmt.da, addr, ETH_ALEN); - os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); - mgmt.u.deauth.reason_code = - host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); - if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, - IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth), - encrypt) < 0) - return -1; - return 0; - } - -#ifdef CONFIG_P2P_MANAGER - pos = os_strstr(txtaddr, " p2p="); - if (pos) { - return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH, - atoi(pos + 5), addr); - } -#endif /* CONFIG_P2P_MANAGER */ - - pos = os_strstr(txtaddr, " reason="); - if (pos) - reason = atoi(pos + 8); - - hostapd_drv_sta_deauth(hapd, addr, reason); - sta = ap_get_sta(hapd, addr); - if (sta) - ap_sta_deauthenticate(hapd, sta, reason); - else if (addr[0] == 0xff) - hostapd_free_stas(hapd); - - return 0; -} - - -int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, - const char *txtaddr) -{ - u8 addr[ETH_ALEN]; - struct sta_info *sta; - const char *pos; - u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID; - - wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", - txtaddr); - - if (hwaddr_aton(txtaddr, addr)) - return -1; - - pos = os_strstr(txtaddr, " test="); - if (pos) { - struct ieee80211_mgmt mgmt; - int encrypt; - if (hapd->driver->send_frame == NULL) - return -1; - pos += 6; - encrypt = atoi(pos); - os_memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DISASSOC); - os_memcpy(mgmt.da, addr, ETH_ALEN); - os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); - mgmt.u.disassoc.reason_code = - host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); - if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, - IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth), - encrypt) < 0) - return -1; - return 0; - } - -#ifdef CONFIG_P2P_MANAGER - pos = os_strstr(txtaddr, " p2p="); - if (pos) { - return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC, - atoi(pos + 5), addr); - } -#endif /* CONFIG_P2P_MANAGER */ - - pos = os_strstr(txtaddr, " reason="); - if (pos) - reason = atoi(pos + 8); - - hostapd_drv_sta_disassoc(hapd, addr, reason); - sta = ap_get_sta(hapd, addr); - if (sta) - ap_sta_disassociate(hapd, sta, reason); - else if (addr[0] == 0xff) - hostapd_free_stas(hapd); - - return 0; -} - - -int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, - size_t buflen) -{ - struct hostapd_iface *iface = hapd->iface; - int len = 0, ret; - size_t i; - - ret = os_snprintf(buf + len, buflen - len, - "state=%s\n" - "phy=%s\n" - "freq=%d\n" - "num_sta_non_erp=%d\n" - "num_sta_no_short_slot_time=%d\n" - "num_sta_no_short_preamble=%d\n" - "olbc=%d\n" - "num_sta_ht_no_gf=%d\n" - "num_sta_no_ht=%d\n" - "num_sta_ht_20_mhz=%d\n" - "olbc_ht=%d\n" - "ht_op_mode=0x%x\n", - hostapd_state_text(iface->state), - iface->phy, - iface->freq, - iface->num_sta_non_erp, - iface->num_sta_no_short_slot_time, - iface->num_sta_no_short_preamble, - iface->olbc, - iface->num_sta_ht_no_gf, - iface->num_sta_no_ht, - iface->num_sta_ht_20mhz, - iface->olbc_ht, - iface->ht_op_mode); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - ret = os_snprintf(buf + len, buflen - len, - "channel=%u\n" - "secondary_channel=%d\n" - "ieee80211n=%d\n" - "ieee80211ac=%d\n" - "vht_oper_chwidth=%d\n" - "vht_oper_centr_freq_seg0_idx=%d\n" - "vht_oper_centr_freq_seg1_idx=%d\n", - iface->conf->channel, - iface->conf->secondary_channel, - iface->conf->ieee80211n, - iface->conf->ieee80211ac, - iface->conf->vht_oper_chwidth, - iface->conf->vht_oper_centr_freq_seg0_idx, - iface->conf->vht_oper_centr_freq_seg1_idx); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - for (i = 0; i < iface->num_bss; i++) { - struct hostapd_data *bss = iface->bss[i]; - ret = os_snprintf(buf + len, buflen - len, - "bss[%d]=%s\n" - "bssid[%d]=" MACSTR "\n" - "ssid[%d]=%s\n" - "num_sta[%d]=%d\n", - (int) i, bss->conf->iface, - (int) i, MAC2STR(bss->own_addr), - (int) i, - wpa_ssid_txt(bss->conf->ssid.ssid, - bss->conf->ssid.ssid_len), - (int) i, bss->num_sta); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - } - - return len; -} - - -int hostapd_parse_csa_settings(const char *pos, - struct csa_settings *settings) -{ - char *end; - - if (!settings) - return -1; - - os_memset(settings, 0, sizeof(*settings)); - settings->cs_count = strtol(pos, &end, 10); - if (pos == end) { - wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided"); - return -1; - } - - settings->freq_params.freq = atoi(end); - if (settings->freq_params.freq == 0) { - wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided"); - return -1; - } - -#define SET_CSA_SETTING(str) \ - do { \ - const char *pos2 = os_strstr(pos, " " #str "="); \ - if (pos2) { \ - pos2 += sizeof(" " #str "=") - 1; \ - settings->freq_params.str = atoi(pos2); \ - } \ - } while (0) - - SET_CSA_SETTING(center_freq1); - SET_CSA_SETTING(center_freq2); - SET_CSA_SETTING(bandwidth); - SET_CSA_SETTING(sec_channel_offset); - settings->freq_params.ht_enabled = !!os_strstr(pos, " ht"); - settings->freq_params.vht_enabled = !!os_strstr(pos, " vht"); - settings->block_tx = !!os_strstr(pos, " blocktx"); -#undef SET_CSA_SETTING - - return 0; -} diff --git a/contrib/hostapd/src/ap/ctrl_iface_ap.h b/contrib/hostapd/src/ap/ctrl_iface_ap.h deleted file mode 100644 index ee58b4c969..0000000000 --- a/contrib/hostapd/src/ap/ctrl_iface_ap.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Control interface for shared AP commands - * Copyright (c) 2004-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef CTRL_IFACE_AP_H -#define CTRL_IFACE_AP_H - -int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd, - char *buf, size_t buflen); -int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr, - char *buf, size_t buflen); -int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr, - char *buf, size_t buflen); -int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, - const char *txtaddr); -int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, - const char *txtaddr); -int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, - size_t buflen); -int hostapd_parse_csa_settings(const char *pos, - struct csa_settings *settings); - - -#endif /* CTRL_IFACE_AP_H */ diff --git a/contrib/hostapd/src/ap/dfs.c b/contrib/hostapd/src/ap/dfs.c deleted file mode 100644 index e4c00f8a14..0000000000 --- a/contrib/hostapd/src/ap/dfs.c +++ /dev/null @@ -1,803 +0,0 @@ -/* - * DFS - Dynamic Frequency Selection - * Copyright (c) 2002-2013, Jouni Malinen - * Copyright (c) 2013, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "common/ieee802_11_defs.h" -#include "common/wpa_ctrl.h" -#include "hostapd.h" -#include "ap_drv_ops.h" -#include "drivers/driver.h" -#include "dfs.h" - - -static int dfs_get_used_n_chans(struct hostapd_iface *iface) -{ - int n_chans = 1; - - if (iface->conf->ieee80211n && iface->conf->secondary_channel) - n_chans = 2; - - if (iface->conf->ieee80211ac) { - switch (iface->conf->vht_oper_chwidth) { - case VHT_CHANWIDTH_USE_HT: - break; - case VHT_CHANWIDTH_80MHZ: - n_chans = 4; - break; - case VHT_CHANWIDTH_160MHZ: - n_chans = 8; - break; - default: - break; - } - } - - return n_chans; -} - - -static int dfs_channel_available(struct hostapd_channel_data *chan, - int skip_radar) -{ - /* - * When radar detection happens, CSA is performed. However, there's no - * time for CAC, so radar channels must be skipped when finding a new - * channel for CSA. - */ - if (skip_radar && chan->flag & HOSTAPD_CHAN_RADAR) - return 0; - - if (chan->flag & HOSTAPD_CHAN_DISABLED) - return 0; - if ((chan->flag & HOSTAPD_CHAN_RADAR) && - ((chan->flag & HOSTAPD_CHAN_DFS_MASK) == - HOSTAPD_CHAN_DFS_UNAVAILABLE)) - return 0; - return 1; -} - - -static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans) -{ - /* - * The tables contain first valid channel number based on channel width. - * We will also choose this first channel as the control one. - */ - int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, - 184, 192 }; - /* - * VHT80, valid channels based on center frequency: - * 42, 58, 106, 122, 138, 155 - */ - int allowed_80[] = { 36, 52, 100, 116, 132, 149 }; - int *allowed = allowed_40; - unsigned int i, allowed_no = 0; - - switch (n_chans) { - case 2: - allowed = allowed_40; - allowed_no = ARRAY_SIZE(allowed_40); - break; - case 4: - allowed = allowed_80; - allowed_no = ARRAY_SIZE(allowed_80); - break; - default: - wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans); - break; - } - - for (i = 0; i < allowed_no; i++) { - if (chan->chan == allowed[i]) - return 1; - } - - return 0; -} - - -static int dfs_chan_range_available(struct hostapd_hw_modes *mode, - int first_chan_idx, int num_chans, - int skip_radar) -{ - struct hostapd_channel_data *first_chan, *chan; - int i; - - if (first_chan_idx + num_chans >= mode->num_channels) - return 0; - - first_chan = &mode->channels[first_chan_idx]; - - for (i = 0; i < num_chans; i++) { - chan = &mode->channels[first_chan_idx + i]; - - if (first_chan->freq + i * 20 != chan->freq) - return 0; - - if (!dfs_channel_available(chan, skip_radar)) - return 0; - } - - return 1; -} - - -/* - * The function assumes HT40+ operation. - * Make sure to adjust the following variables after calling this: - * - hapd->secondary_channel - * - hapd->vht_oper_centr_freq_seg0_idx - * - hapd->vht_oper_centr_freq_seg1_idx - */ -static int dfs_find_channel(struct hostapd_iface *iface, - struct hostapd_channel_data **ret_chan, - int idx, int skip_radar) -{ - struct hostapd_hw_modes *mode; - struct hostapd_channel_data *chan; - int i, channel_idx = 0, n_chans; - - mode = iface->current_mode; - n_chans = dfs_get_used_n_chans(iface); - - wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans); - for (i = 0; i < mode->num_channels; i++) { - chan = &mode->channels[i]; - - /* Skip HT40/VHT incompatible channels */ - if (iface->conf->ieee80211n && - iface->conf->secondary_channel && - !dfs_is_chan_allowed(chan, n_chans)) - continue; - - /* Skip incompatible chandefs */ - if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) - continue; - - if (ret_chan && idx == channel_idx) { - wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan); - *ret_chan = chan; - return idx; - } - wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan); - channel_idx++; - } - return channel_idx; -} - - -static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface, - struct hostapd_channel_data *chan, - int secondary_channel, - u8 *vht_oper_centr_freq_seg0_idx, - u8 *vht_oper_centr_freq_seg1_idx) -{ - if (!iface->conf->ieee80211ac) - return; - - if (!chan) - return; - - *vht_oper_centr_freq_seg1_idx = 0; - - switch (iface->conf->vht_oper_chwidth) { - case VHT_CHANWIDTH_USE_HT: - if (secondary_channel == 1) - *vht_oper_centr_freq_seg0_idx = chan->chan + 2; - else if (secondary_channel == -1) - *vht_oper_centr_freq_seg0_idx = chan->chan - 2; - else - *vht_oper_centr_freq_seg0_idx = chan->chan; - break; - case VHT_CHANWIDTH_80MHZ: - *vht_oper_centr_freq_seg0_idx = chan->chan + 6; - break; - case VHT_CHANWIDTH_160MHZ: - *vht_oper_centr_freq_seg0_idx = chan->chan + 14; - break; - default: - wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now"); - break; - } - - wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d", - *vht_oper_centr_freq_seg0_idx, - *vht_oper_centr_freq_seg1_idx); -} - - -/* Return start channel idx we will use for mode->channels[idx] */ -static int dfs_get_start_chan_idx(struct hostapd_iface *iface) -{ - struct hostapd_hw_modes *mode; - struct hostapd_channel_data *chan; - int channel_no = iface->conf->channel; - int res = -1, i; - - /* HT40- */ - if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1) - channel_no -= 4; - - /* VHT */ - if (iface->conf->ieee80211ac) { - switch (iface->conf->vht_oper_chwidth) { - case VHT_CHANWIDTH_USE_HT: - break; - case VHT_CHANWIDTH_80MHZ: - channel_no = - iface->conf->vht_oper_centr_freq_seg0_idx - 6; - break; - case VHT_CHANWIDTH_160MHZ: - channel_no = - iface->conf->vht_oper_centr_freq_seg0_idx - 14; - break; - default: - wpa_printf(MSG_INFO, - "DFS only VHT20/40/80/160 is supported now"); - channel_no = -1; - break; - } - } - - /* Get idx */ - mode = iface->current_mode; - for (i = 0; i < mode->num_channels; i++) { - chan = &mode->channels[i]; - if (chan->chan == channel_no) { - res = i; - break; - } - } - - if (res == -1) - wpa_printf(MSG_DEBUG, "DFS chan_idx seems wrong: -1"); - - return res; -} - - -/* At least one channel have radar flag */ -static int dfs_check_chans_radar(struct hostapd_iface *iface, - int start_chan_idx, int n_chans) -{ - struct hostapd_channel_data *channel; - struct hostapd_hw_modes *mode; - int i, res = 0; - - mode = iface->current_mode; - - for (i = 0; i < n_chans; i++) { - channel = &mode->channels[start_chan_idx + i]; - if (channel->flag & HOSTAPD_CHAN_RADAR) - res++; - } - - return res; -} - - -/* All channels available */ -static int dfs_check_chans_available(struct hostapd_iface *iface, - int start_chan_idx, int n_chans) -{ - struct hostapd_channel_data *channel; - struct hostapd_hw_modes *mode; - int i; - - mode = iface->current_mode; - - for(i = 0; i < n_chans; i++) { - channel = &mode->channels[start_chan_idx + i]; - if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) != - HOSTAPD_CHAN_DFS_AVAILABLE) - break; - } - - return i == n_chans; -} - - -/* At least one channel unavailable */ -static int dfs_check_chans_unavailable(struct hostapd_iface *iface, - int start_chan_idx, - int n_chans) -{ - struct hostapd_channel_data *channel; - struct hostapd_hw_modes *mode; - int i, res = 0; - - mode = iface->current_mode; - - for(i = 0; i < n_chans; i++) { - channel = &mode->channels[start_chan_idx + i]; - if (channel->flag & HOSTAPD_CHAN_DISABLED) - res++; - if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) == - HOSTAPD_CHAN_DFS_UNAVAILABLE) - res++; - } - - return res; -} - - -static struct hostapd_channel_data * -dfs_get_valid_channel(struct hostapd_iface *iface, - int *secondary_channel, - u8 *vht_oper_centr_freq_seg0_idx, - u8 *vht_oper_centr_freq_seg1_idx, - int skip_radar) -{ - struct hostapd_hw_modes *mode; - struct hostapd_channel_data *chan = NULL; - int num_available_chandefs; - int chan_idx; - u32 _rand; - - wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); - - if (iface->current_mode == NULL) - return NULL; - - mode = iface->current_mode; - if (mode->mode != HOSTAPD_MODE_IEEE80211A) - return NULL; - - /* Get the count first */ - num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar); - if (num_available_chandefs == 0) - return NULL; - - os_get_random((u8 *) &_rand, sizeof(_rand)); - chan_idx = _rand % num_available_chandefs; - dfs_find_channel(iface, &chan, chan_idx, skip_radar); - - /* dfs_find_channel() calculations assume HT40+ */ - if (iface->conf->secondary_channel) - *secondary_channel = 1; - else - *secondary_channel = 0; - - dfs_adjust_vht_center_freq(iface, chan, - *secondary_channel, - vht_oper_centr_freq_seg0_idx, - vht_oper_centr_freq_seg1_idx); - - return chan; -} - - -static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state) -{ - struct hostapd_hw_modes *mode; - struct hostapd_channel_data *chan = NULL; - int i; - - mode = iface->current_mode; - if (mode == NULL) - return 0; - - wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq); - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - if (chan->freq == freq) { - if (chan->flag & HOSTAPD_CHAN_RADAR) { - chan->flag &= ~HOSTAPD_CHAN_DFS_MASK; - chan->flag |= state; - return 1; /* Channel found */ - } - } - } - wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq); - return 0; -} - - -static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled, - int chan_offset, int chan_width, int cf1, - int cf2, u32 state) -{ - int n_chans = 1, i; - struct hostapd_hw_modes *mode; - int frequency = freq; - int ret = 0; - - mode = iface->current_mode; - if (mode == NULL) - return 0; - - if (mode->mode != HOSTAPD_MODE_IEEE80211A) { - wpa_printf(MSG_WARNING, "current_mode != IEEE80211A"); - return 0; - } - - /* Seems cf1 and chan_width is enough here */ - switch (chan_width) { - case CHAN_WIDTH_20_NOHT: - case CHAN_WIDTH_20: - n_chans = 1; - if (frequency == 0) - frequency = cf1; - break; - case CHAN_WIDTH_40: - n_chans = 2; - frequency = cf1 - 10; - break; - case CHAN_WIDTH_80: - n_chans = 4; - frequency = cf1 - 30; - break; - case CHAN_WIDTH_160: - n_chans = 8; - frequency = cf1 - 70; - break; - default: - wpa_printf(MSG_INFO, "DFS chan_width %d not supported", - chan_width); - break; - } - - wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency, - n_chans); - for (i = 0; i < n_chans; i++) { - ret += set_dfs_state_freq(iface, frequency, state); - frequency = frequency + 20; - } - - return ret; -} - - -static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq, - int chan_width, int cf1, int cf2) -{ - int start_chan_idx; - struct hostapd_hw_modes *mode; - struct hostapd_channel_data *chan; - int n_chans, i, j, frequency = freq, radar_n_chans = 1; - u8 radar_chan; - int res = 0; - - /* Our configuration */ - mode = iface->current_mode; - start_chan_idx = dfs_get_start_chan_idx(iface); - n_chans = dfs_get_used_n_chans(iface); - - /* Check we are on DFS channel(s) */ - if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans)) - return 0; - - /* Reported via radar event */ - switch (chan_width) { - case CHAN_WIDTH_20_NOHT: - case CHAN_WIDTH_20: - radar_n_chans = 1; - if (frequency == 0) - frequency = cf1; - break; - case CHAN_WIDTH_40: - radar_n_chans = 2; - frequency = cf1 - 10; - break; - case CHAN_WIDTH_80: - radar_n_chans = 4; - frequency = cf1 - 30; - break; - case CHAN_WIDTH_160: - radar_n_chans = 8; - frequency = cf1 - 70; - break; - default: - wpa_printf(MSG_INFO, "DFS chan_width %d not supported", - chan_width); - break; - } - - ieee80211_freq_to_chan(frequency, &radar_chan); - - for (i = 0; i < n_chans; i++) { - chan = &mode->channels[start_chan_idx + i]; - if (!(chan->flag & HOSTAPD_CHAN_RADAR)) - continue; - for (j = 0; j < radar_n_chans; j++) { - wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d", - chan->chan, radar_chan + j * 4); - if (chan->chan == radar_chan + j * 4) - res++; - } - } - - wpa_printf(MSG_DEBUG, "overlapped: %d", res); - - return res; -} - - -/* - * Main DFS handler - * 1 - continue channel/ap setup - * 0 - channel/ap setup will be continued after CAC - * -1 - hit critical error - */ -int hostapd_handle_dfs(struct hostapd_iface *iface) -{ - struct hostapd_channel_data *channel; - int res, n_chans, start_chan_idx; - int skip_radar = 0; - - iface->cac_started = 0; - - do { - /* Get start (first) channel for current configuration */ - start_chan_idx = dfs_get_start_chan_idx(iface); - if (start_chan_idx == -1) - return -1; - - /* Get number of used channels, depend on width */ - n_chans = dfs_get_used_n_chans(iface); - - /* Check if any of configured channels require DFS */ - res = dfs_check_chans_radar(iface, start_chan_idx, n_chans); - wpa_printf(MSG_DEBUG, - "DFS %d channels required radar detection", - res); - if (!res) - return 1; - - /* Check if all channels are DFS available */ - res = dfs_check_chans_available(iface, start_chan_idx, n_chans); - wpa_printf(MSG_DEBUG, - "DFS all channels available, (SKIP CAC): %s", - res ? "yes" : "no"); - if (res) - return 1; - - /* Check if any of configured channels is unavailable */ - res = dfs_check_chans_unavailable(iface, start_chan_idx, - n_chans); - wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", - res, res ? "yes": "no"); - if (res) { - int sec; - u8 cf1, cf2; - - channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, - skip_radar); - if (!channel) { - wpa_printf(MSG_ERROR, "could not get valid channel"); - return -1; - } - - iface->freq = channel->freq; - iface->conf->channel = channel->chan; - iface->conf->secondary_channel = sec; - iface->conf->vht_oper_centr_freq_seg0_idx = cf1; - iface->conf->vht_oper_centr_freq_seg1_idx = cf2; - } - } while (res); - - /* Finally start CAC */ - hostapd_set_state(iface, HAPD_IFACE_DFS); - wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq); - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START - "freq=%d chan=%d sec_chan=%d", - iface->freq, - iface->conf->channel, iface->conf->secondary_channel); - if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode, - iface->freq, - iface->conf->channel, - iface->conf->ieee80211n, - iface->conf->ieee80211ac, - iface->conf->secondary_channel, - iface->conf->vht_oper_chwidth, - iface->conf->vht_oper_centr_freq_seg0_idx, - iface->conf->vht_oper_centr_freq_seg1_idx)) { - wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed"); - return -1; - } - - return 0; -} - - -int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, - int ht_enabled, int chan_offset, int chan_width, - int cf1, int cf2) -{ - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED - "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", - success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2); - - if (success) { - /* Complete iface/ap configuration */ - set_dfs_state(iface, freq, ht_enabled, chan_offset, - chan_width, cf1, cf2, - HOSTAPD_CHAN_DFS_AVAILABLE); - iface->cac_started = 0; - hostapd_setup_interface_complete(iface, 0); - } - - return 0; -} - - -static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) -{ - struct hostapd_channel_data *channel; - int secondary_channel; - u8 vht_oper_centr_freq_seg0_idx; - u8 vht_oper_centr_freq_seg1_idx; - int skip_radar = 0; - int err = 1; - - /* Radar detected during active CAC */ - iface->cac_started = 0; - channel = dfs_get_valid_channel(iface, &secondary_channel, - &vht_oper_centr_freq_seg0_idx, - &vht_oper_centr_freq_seg1_idx, - skip_radar); - - if (!channel) { - wpa_printf(MSG_ERROR, "No valid channel available"); - hostapd_setup_interface_complete(iface, err); - return err; - } - - wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", - channel->chan); - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL - "freq=%d chan=%d sec_chan=%d", channel->freq, - channel->chan, secondary_channel); - - iface->freq = channel->freq; - iface->conf->channel = channel->chan; - iface->conf->secondary_channel = secondary_channel; - iface->conf->vht_oper_centr_freq_seg0_idx = - vht_oper_centr_freq_seg0_idx; - iface->conf->vht_oper_centr_freq_seg1_idx = - vht_oper_centr_freq_seg1_idx; - err = 0; - - hostapd_setup_interface_complete(iface, err); - return err; -} - - -static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) -{ - struct hostapd_channel_data *channel; - int secondary_channel; - u8 vht_oper_centr_freq_seg0_idx; - u8 vht_oper_centr_freq_seg1_idx; - int skip_radar = 1; - struct csa_settings csa_settings; - struct hostapd_data *hapd = iface->bss[0]; - int err = 1; - - wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", - __func__, iface->cac_started ? "yes" : "no", - iface->csa_in_progress ? "yes" : "no"); - - /* Check if CSA in progress */ - if (iface->csa_in_progress) - return 0; - - /* Check if active CAC */ - if (iface->cac_started) - return hostapd_dfs_start_channel_switch_cac(iface); - - /* Perform channel switch/CSA */ - channel = dfs_get_valid_channel(iface, &secondary_channel, - &vht_oper_centr_freq_seg0_idx, - &vht_oper_centr_freq_seg1_idx, - skip_radar); - - if (!channel) { - /* FIXME: Wait for channel(s) to become available */ - hostapd_disable_iface(iface); - return err; - } - - wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", - channel->chan); - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL - "freq=%d chan=%d sec_chan=%d", channel->freq, - channel->chan, secondary_channel); - - /* Setup CSA request */ - os_memset(&csa_settings, 0, sizeof(csa_settings)); - csa_settings.cs_count = 5; - csa_settings.block_tx = 1; - err = hostapd_set_freq_params(&csa_settings.freq_params, - iface->conf->hw_mode, - channel->freq, - channel->chan, - iface->conf->ieee80211n, - iface->conf->ieee80211ac, - secondary_channel, - iface->conf->vht_oper_chwidth, - vht_oper_centr_freq_seg0_idx, - vht_oper_centr_freq_seg1_idx, - iface->current_mode->vht_capab); - - if (err) { - wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); - hostapd_disable_iface(iface); - return err; - } - - err = hostapd_switch_channel(hapd, &csa_settings); - if (err) { - wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", - err); - iface->freq = channel->freq; - iface->conf->channel = channel->chan; - iface->conf->secondary_channel = secondary_channel; - iface->conf->vht_oper_centr_freq_seg0_idx = - vht_oper_centr_freq_seg0_idx; - iface->conf->vht_oper_centr_freq_seg1_idx = - vht_oper_centr_freq_seg1_idx; - - hostapd_disable_iface(iface); - hostapd_enable_iface(iface); - return 0; - } - - /* Channel configuration will be updated once CSA completes and - * ch_switch_notify event is received */ - - wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); - return 0; -} - - -int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, - int ht_enabled, int chan_offset, int chan_width, - int cf1, int cf2) -{ - int res; - - if (!iface->conf->ieee80211h) - return 0; - - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED - "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", - freq, ht_enabled, chan_offset, chan_width, cf1, cf2); - - /* mark radar frequency as invalid */ - res = set_dfs_state(iface, freq, ht_enabled, chan_offset, - chan_width, cf1, cf2, - HOSTAPD_CHAN_DFS_UNAVAILABLE); - - /* Skip if reported radar event not overlapped our channels */ - res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); - if (!res) - return 0; - - /* radar detected while operating, switch the channel. */ - res = hostapd_dfs_start_channel_switch(iface); - - return res; -} - - -int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, - int ht_enabled, int chan_offset, int chan_width, - int cf1, int cf2) -{ - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED - "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", - freq, ht_enabled, chan_offset, chan_width, cf1, cf2); - /* TODO add correct implementation here */ - set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, - cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); - return 0; -} diff --git a/contrib/hostapd/src/ap/dfs.h b/contrib/hostapd/src/ap/dfs.h deleted file mode 100644 index 859ff79159..0000000000 --- a/contrib/hostapd/src/ap/dfs.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * DFS - Dynamic Frequency Selection - * Copyright (c) 2002-2013, Jouni Malinen - * Copyright (c) 2013, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ -#ifndef DFS_H -#define DFS_H - -int hostapd_handle_dfs(struct hostapd_iface *iface); - -int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, - int ht_enabled, int chan_offset, int chan_width, - int cf1, int cf2); -int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, - int ht_enabled, - int chan_offset, int chan_width, - int cf1, int cf2); -int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, - int ht_enabled, - int chan_offset, int chan_width, int cf1, int cf2); - -#endif /* DFS_H */ diff --git a/contrib/hostapd/src/ap/drv_callbacks.c b/contrib/hostapd/src/ap/drv_callbacks.c deleted file mode 100644 index 9af964686a..0000000000 --- a/contrib/hostapd/src/ap/drv_callbacks.c +++ /dev/null @@ -1,1038 +0,0 @@ -/* - * hostapd / Callback functions for driver wrappers - * Copyright (c) 2002-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "radius/radius.h" -#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" -#include "wnm_ap.h" -#include "hostapd.h" -#include "ieee802_11.h" -#include "sta_info.h" -#include "accounting.h" -#include "tkip_countermeasures.h" -#include "ieee802_1x.h" -#include "wpa_auth.h" -#include "wps_hostapd.h" -#include "ap_drv_ops.h" -#include "ap_config.h" -#include "hw_features.h" -#include "dfs.h" - - -int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, - const u8 *req_ies, size_t req_ies_len, int reassoc) -{ - struct sta_info *sta; - int new_assoc, res; - struct ieee802_11_elems elems; - const u8 *ie; - size_t ielen; -#ifdef CONFIG_IEEE80211R - u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; - u8 *p = buf; -#endif /* CONFIG_IEEE80211R */ - u16 reason = WLAN_REASON_UNSPECIFIED; - u16 status = WLAN_STATUS_SUCCESS; - const u8 *p2p_dev_addr = NULL; - - if (addr == NULL) { - /* - * This could potentially happen with unexpected event from the - * driver wrapper. This was seen at least in one case where the - * driver ended up being set to station mode while hostapd was - * running, so better make sure we stop processing such an - * event here. - */ - wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with " - "no address"); - return -1; - } - random_add_randomness(addr, ETH_ALEN); - - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "associated"); - - 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; - wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); - } else if (elems.rsn_ie) { - ie = elems.rsn_ie - 2; - ielen = elems.rsn_ie_len + 2; - wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); - } else if (elems.wpa_ie) { - ie = elems.wpa_ie - 2; - ielen = elems.wpa_ie_len + 2; - wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); - } else { - ie = NULL; - ielen = 0; - wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in " - "(Re)AssocReq"); - } - - sta = ap_get_sta(hapd, addr); - if (sta) { - ap_sta_no_session_timeout(hapd, sta); - accounting_sta_stop(hapd, sta); - - /* - * Make sure that the previously registered inactivity timer - * will not remove the STA immediately. - */ - sta->timeout_next = STA_NULLFUNC; - } else { - sta = ap_sta_add(hapd, addr); - if (sta == NULL) { - hostapd_drv_sta_disassoc(hapd, addr, - WLAN_REASON_DISASSOC_AP_BUSY); - return -1; - } - } - sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); - -#ifdef CONFIG_P2P - if (elems.p2p) { - wpabuf_free(sta->p2p_ie); - sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, - P2P_IE_VENDOR_TYPE); - if (sta->p2p_ie) - p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); - } -#endif /* CONFIG_P2P */ - -#ifdef CONFIG_INTERWORKING - if (elems.ext_capab && elems.ext_capab_len > 4) { - if (elems.ext_capab[4] & 0x01) - sta->qos_map_enabled = 1; - } -#endif /* CONFIG_INTERWORKING */ - -#ifdef CONFIG_HS20 - wpabuf_free(sta->hs20_ie); - if (elems.hs20 && elems.hs20_len > 4) { - sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, - elems.hs20_len - 4); - } else - sta->hs20_ie = NULL; -#endif /* CONFIG_HS20 */ - - 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 " - "Request - possible WPS use"); - 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, - sta->addr, - p2p_dev_addr); - if (sta->wpa_sm == NULL) { - wpa_printf(MSG_ERROR, "Failed to initialize WPA state " - "machine"); - return -1; - } - res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, - ie, ielen, - elems.mdie, elems.mdie_len); - if (res != WPA_IE_OK) { - wpa_printf(MSG_DEBUG, "WPA/RSN information element " - "rejected? (res %u)", res); - wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); - if (res == WPA_INVALID_GROUP) { - reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; - status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; - } else if (res == WPA_INVALID_PAIRWISE) { - reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; - status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; - } else if (res == WPA_INVALID_AKMP) { - reason = WLAN_REASON_AKMP_NOT_VALID; - status = WLAN_STATUS_AKMP_NOT_VALID; - } -#ifdef CONFIG_IEEE80211W - else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) { - reason = WLAN_REASON_INVALID_IE; - status = WLAN_STATUS_INVALID_IE; - } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) { - reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; - status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; - } -#endif /* CONFIG_IEEE80211W */ - else { - reason = WLAN_REASON_INVALID_IE; - status = WLAN_STATUS_INVALID_IE; - } - goto fail; - } -#ifdef CONFIG_IEEE80211W - if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && - sta->sa_query_count > 0) - ap_check_sa_query_timeout(hapd, sta); - if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && - (sta->auth_alg != WLAN_AUTH_FT)) { - /* - * STA has already been associated with MFP and SA - * Query timeout has not been reached. Reject the - * association attempt temporarily and start SA Query, - * if one is not pending. - */ - - if (sta->sa_query_count == 0) - ap_sta_start_sa_query(hapd, sta); - -#ifdef CONFIG_IEEE80211R - status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; - - p = hostapd_eid_assoc_comeback_time(hapd, sta, p); - - hostapd_sta_assoc(hapd, addr, reassoc, status, buf, - p - buf); -#endif /* CONFIG_IEEE80211R */ - return 0; - } - - if (wpa_auth_uses_mfp(sta->wpa_sm)) - sta->flags |= WLAN_STA_MFP; - else - sta->flags &= ~WLAN_STA_MFP; -#endif /* CONFIG_IEEE80211W */ - -#ifdef CONFIG_IEEE80211R - if (sta->auth_alg == WLAN_AUTH_FT) { - status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies, - req_ies_len); - if (status != WLAN_STATUS_SUCCESS) { - if (status == WLAN_STATUS_INVALID_PMKID) - reason = WLAN_REASON_INVALID_IE; - if (status == WLAN_STATUS_INVALID_MDIE) - reason = WLAN_REASON_INVALID_IE; - if (status == WLAN_STATUS_INVALID_FTIE) - reason = WLAN_REASON_INVALID_IE; - goto fail; - } - } -#endif /* CONFIG_IEEE80211R */ - } else if (hapd->conf->wps_state) { -#ifdef CONFIG_WPS - struct wpabuf *wps; - if (req_ies) - wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, - WPS_IE_VENDOR_TYPE); - else - wps = NULL; -#ifdef CONFIG_WPS_STRICT - if (wps && wps_validate_assoc_req(wps) < 0) { - reason = WLAN_REASON_INVALID_IE; - status = WLAN_STATUS_INVALID_IE; - wpabuf_free(wps); - goto fail; - } -#endif /* CONFIG_WPS_STRICT */ - 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 */ - -#ifdef CONFIG_IEEE80211R - p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf), - sta->auth_alg, req_ies, req_ies_len); - - hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); -#else /* CONFIG_IEEE80211R */ - /* Keep compiler silent about unused variables */ - if (status) { - } -#endif /* CONFIG_IEEE80211R */ - - new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; - sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; - - if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) - wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); - else - wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); - - hostapd_new_assoc_sta(hapd, sta, !new_assoc); - - ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); - -#ifdef CONFIG_P2P - if (req_ies) { - p2p_group_notif_assoc(hapd->p2p_group, sta->addr, - req_ies, req_ies_len); - } -#endif /* CONFIG_P2P */ - - return 0; - -fail: -#ifdef CONFIG_IEEE80211R - hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); -#endif /* CONFIG_IEEE80211R */ - hostapd_drv_sta_disassoc(hapd, sta->addr, reason); - ap_free_sta(hapd, sta); - return -1; -} - - -void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) -{ - struct sta_info *sta; - - if (addr == NULL) { - /* - * This could potentially happen with unexpected event from the - * driver wrapper. This was seen at least in one case where the - * driver ended up reporting a station mode event while hostapd - * was running, so better make sure we stop processing such an - * event here. - */ - wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event " - "with no address"); - return; - } - - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "disassociated"); - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Disassociation notification for " - "unknown STA " MACSTR, MAC2STR(addr)); - return; - } - - ap_sta_set_authorized(hapd, sta, 0); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - 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); - ap_free_sta(hapd, sta); -} - - -void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr) -{ - struct sta_info *sta = ap_get_sta(hapd, addr); - - if (!sta || !hapd->conf->disassoc_low_ack) - return; - - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "disconnected due to excessive " - "missing ACKs"); - hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK); - if (sta) - ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK); -} - - -void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, - int offset, int width, int cf1, int cf2) -{ -#ifdef NEED_AP_MLME - int channel, chwidth, seg0_idx = 0, seg1_idx = 0; - - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "driver had channel switch: " - "freq=%d, ht=%d, offset=%d, width=%d, cf1=%d, cf2=%d", - freq, ht, offset, width, cf1, cf2); - - hapd->iface->freq = freq; - - channel = hostapd_hw_get_channel(hapd, freq); - if (!channel) { - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_WARNING, "driver switched to " - "bad channel!"); - return; - } - - switch (width) { - case CHAN_WIDTH_80: - chwidth = VHT_CHANWIDTH_80MHZ; - break; - case CHAN_WIDTH_80P80: - chwidth = VHT_CHANWIDTH_80P80MHZ; - break; - case CHAN_WIDTH_160: - chwidth = VHT_CHANWIDTH_160MHZ; - break; - case CHAN_WIDTH_20_NOHT: - case CHAN_WIDTH_20: - case CHAN_WIDTH_40: - default: - chwidth = VHT_CHANWIDTH_USE_HT; - break; - } - - switch (hapd->iface->current_mode->mode) { - case HOSTAPD_MODE_IEEE80211A: - if (cf1 > 5000) - seg0_idx = (cf1 - 5000) / 5; - if (cf2 > 5000) - seg1_idx = (cf2 - 5000) / 5; - break; - default: - seg0_idx = hostapd_hw_get_channel(hapd, cf1); - seg1_idx = hostapd_hw_get_channel(hapd, cf2); - break; - } - - hapd->iconf->channel = channel; - hapd->iconf->ieee80211n = ht; - hapd->iconf->secondary_channel = offset; - hapd->iconf->vht_oper_chwidth = chwidth; - hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx; - hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx; - - if (hapd->iface->csa_in_progress && - freq == hapd->iface->cs_freq_params.freq) { - hostapd_cleanup_cs_params(hapd); - - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d", - freq); - } -#endif /* NEED_AP_MLME */ -} - - -void hostapd_event_connect_failed_reason(struct hostapd_data *hapd, - const u8 *addr, int reason_code) -{ - switch (reason_code) { - case MAX_CLIENT_REACHED: - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR, - MAC2STR(addr)); - break; - case BLOCKED_CLIENT: - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR, - MAC2STR(addr)); - break; - } -} - - -int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, - const u8 *bssid, const u8 *ie, size_t ie_len, - int ssi_signal) -{ - size_t i; - int ret = 0; - - if (sa == NULL || ie == NULL) - return -1; - - random_add_randomness(sa, ETH_ALEN); - for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) { - if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, - sa, da, bssid, ie, ie_len, - ssi_signal) > 0) { - ret = 1; - break; - } - } - return ret; -} - - -#ifdef HOSTAPD - -#ifdef CONFIG_IEEE80211R -static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst, - const u8 *bssid, - u16 auth_transaction, u16 status, - const u8 *ies, size_t ies_len) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta; - - sta = ap_get_sta(hapd, dst); - if (sta == NULL) - return; - - hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)"); - sta->flags |= WLAN_STA_AUTH; - - hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len); -} -#endif /* CONFIG_IEEE80211R */ - - -static void hostapd_notif_auth(struct hostapd_data *hapd, - struct auth_info *rx_auth) -{ - struct sta_info *sta; - u16 status = WLAN_STATUS_SUCCESS; - u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; - size_t resp_ies_len = 0; - - sta = ap_get_sta(hapd, rx_auth->peer); - if (!sta) { - sta = ap_sta_add(hapd, rx_auth->peer); - if (sta == NULL) { - status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; - goto fail; - } - } - sta->flags &= ~WLAN_STA_PREAUTH; - ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); -#ifdef CONFIG_IEEE80211R - if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) { - sta->auth_alg = WLAN_AUTH_FT; - if (sta->wpa_sm == NULL) - sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, - sta->addr, NULL); - if (sta->wpa_sm == NULL) { - wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA " - "state machine"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid, - rx_auth->auth_transaction, rx_auth->ies, - rx_auth->ies_len, - hostapd_notify_auth_ft_finish, hapd); - return; - } -#endif /* CONFIG_IEEE80211R */ -fail: - hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1, - status, resp_ies, resp_ies_len); -} - - -static void hostapd_action_rx(struct hostapd_data *hapd, - struct rx_mgmt *drv_mgmt) -{ - struct ieee80211_mgmt *mgmt; - struct sta_info *sta; - size_t plen __maybe_unused; - u16 fc; - - if (drv_mgmt->frame_len < 24 + 1) - return; - - plen = drv_mgmt->frame_len - 24 - 1; - - mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame; - fc = le_to_host16(mgmt->frame_control); - if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) - return; /* handled by the driver */ - - wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d", - mgmt->u.action.category, (int) plen); - - sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "%s: station not found", __func__); - return; - } -#ifdef CONFIG_IEEE80211R - if (mgmt->u.action.category == WLAN_ACTION_FT) { - const u8 *payload = drv_mgmt->frame + 24 + 1; - wpa_ft_action_rx(sta->wpa_sm, payload, plen); - } -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) { - 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); - } -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WNM - if (mgmt->u.action.category == WLAN_ACTION_WNM) { - ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len); - } -#endif /* CONFIG_WNM */ -} - - -#ifdef NEED_AP_MLME - -#define HAPD_BROADCAST ((struct hostapd_data *) -1) - -static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, - const u8 *bssid) -{ - size_t i; - - if (bssid == NULL) - return NULL; - if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff && - bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff) - return HAPD_BROADCAST; - - for (i = 0; i < iface->num_bss; i++) { - if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) - return iface->bss[i]; - } - - return NULL; -} - - -static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, - const u8 *bssid, const u8 *addr, - int wds) -{ - hapd = get_hapd_bssid(hapd->iface, bssid); - if (hapd == NULL || hapd == HAPD_BROADCAST) - return; - - ieee802_11_rx_from_unknown(hapd, addr, wds); -} - - -static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) -{ - struct hostapd_iface *iface = hapd->iface; - const struct ieee80211_hdr *hdr; - const u8 *bssid; - struct hostapd_frame_info fi; - int ret; - - hdr = (const struct ieee80211_hdr *) rx_mgmt->frame; - bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len); - if (bssid == NULL) - return 0; - - hapd = get_hapd_bssid(iface, bssid); - if (hapd == NULL) { - u16 fc; - fc = le_to_host16(hdr->frame_control); - - /* - * Drop frames to unknown BSSIDs except for Beacon frames which - * could be used to update neighbor information. - */ - if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) - hapd = iface->bss[0]; - else - return 0; - } - - os_memset(&fi, 0, sizeof(fi)); - fi.datarate = rx_mgmt->datarate; - fi.ssi_signal = rx_mgmt->ssi_signal; - - if (hapd == HAPD_BROADCAST) { - size_t i; - ret = 0; - for (i = 0; i < iface->num_bss; i++) { - if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, - rx_mgmt->frame_len, &fi) > 0) - ret = 1; - } - } else - ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, - &fi); - - random_add_randomness(&fi, sizeof(fi)); - - return ret; -} - - -static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf, - size_t len, u16 stype, int ok) -{ - struct ieee80211_hdr *hdr; - hdr = (struct ieee80211_hdr *) buf; - hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); - if (hapd == NULL || hapd == HAPD_BROADCAST) - return; - ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); -} - -#endif /* NEED_AP_MLME */ - - -static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr) -{ - struct sta_info *sta = ap_get_sta(hapd, addr); - if (sta) - return 0; - - wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR - " - adding a new STA", MAC2STR(addr)); - sta = ap_sta_add(hapd, addr); - if (sta) { - hostapd_new_assoc_sta(hapd, sta, 0); - } else { - wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR, - MAC2STR(addr)); - return -1; - } - - return 0; -} - - -static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, - const u8 *data, size_t data_len) -{ - struct hostapd_iface *iface = hapd->iface; - struct sta_info *sta; - size_t j; - - for (j = 0; j < iface->num_bss; j++) { - if ((sta = ap_get_sta(iface->bss[j], src))) { - if (sta->flags & WLAN_STA_ASSOC) { - hapd = iface->bss[j]; - break; - } - } - } - - ieee802_1x_receive(hapd, src, data, data_len); -} - - -static struct hostapd_channel_data * hostapd_get_mode_channel( - struct hostapd_iface *iface, unsigned int freq) -{ - int i; - struct hostapd_channel_data *chan; - - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - if (!chan) - return NULL; - if ((unsigned int) chan->freq == freq) - return chan; - } - - return NULL; -} - - -static void hostapd_update_nf(struct hostapd_iface *iface, - struct hostapd_channel_data *chan, - struct freq_survey *survey) -{ - if (!iface->chans_surveyed) { - chan->min_nf = survey->nf; - iface->lowest_nf = survey->nf; - } else { - if (dl_list_empty(&chan->survey_list)) - chan->min_nf = survey->nf; - else if (survey->nf < chan->min_nf) - chan->min_nf = survey->nf; - if (survey->nf < iface->lowest_nf) - iface->lowest_nf = survey->nf; - } -} - - -static void hostapd_event_get_survey(struct hostapd_data *hapd, - struct survey_results *survey_results) -{ - struct hostapd_iface *iface = hapd->iface; - struct freq_survey *survey, *tmp; - struct hostapd_channel_data *chan; - - if (dl_list_empty(&survey_results->survey_list)) { - wpa_printf(MSG_DEBUG, "No survey data received"); - return; - } - - dl_list_for_each_safe(survey, tmp, &survey_results->survey_list, - struct freq_survey, list) { - chan = hostapd_get_mode_channel(iface, survey->freq); - if (!chan) - continue; - if (chan->flag & HOSTAPD_CHAN_DISABLED) - continue; - - dl_list_del(&survey->list); - dl_list_add_tail(&chan->survey_list, &survey->list); - - hostapd_update_nf(iface, chan, survey); - - iface->chans_surveyed++; - } -} - - -#ifdef NEED_AP_MLME - -static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd, - struct dfs_event *radar) -{ - wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq); - hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled, - radar->chan_offset, radar->chan_width, - radar->cf1, radar->cf2); -} - - -static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd, - struct dfs_event *radar) -{ - wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq); - hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled, - radar->chan_offset, radar->chan_width, - radar->cf1, radar->cf2); -} - - -static void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd, - struct dfs_event *radar) -{ - wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq); - hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled, - radar->chan_offset, radar->chan_width, - radar->cf1, radar->cf2); -} - - -static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd, - struct dfs_event *radar) -{ - wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq); - hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled, - radar->chan_offset, radar->chan_width, - radar->cf1, radar->cf2); -} - -#endif /* NEED_AP_MLME */ - - -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->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; - if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) - 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: - michael_mic_failure(hapd, data->michael_mic_failure.src, 1); - break; - case EVENT_SCAN_RESULTS: - if (hapd->iface->scan_cb) - hapd->iface->scan_cb(hapd->iface); - break; -#ifdef CONFIG_IEEE80211R - case EVENT_FT_RRB_RX: - wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src, - data->ft_rrb_rx.data, data->ft_rrb_rx.data_len); - break; -#endif /* CONFIG_IEEE80211R */ - case EVENT_WPS_BUTTON_PUSHED: - hostapd_wps_button_pushed(hapd, NULL); - break; -#ifdef NEED_AP_MLME - case EVENT_TX_STATUS: - switch (data->tx_status.type) { - case WLAN_FC_TYPE_MGMT: - hostapd_mgmt_tx_cb(hapd, data->tx_status.data, - data->tx_status.data_len, - data->tx_status.stype, - data->tx_status.ack); - break; - case WLAN_FC_TYPE_DATA: - hostapd_tx_status(hapd, data->tx_status.dst, - data->tx_status.data, - data->tx_status.data_len, - data->tx_status.ack); - 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.bssid, - data->rx_from_unknown.addr, - data->rx_from_unknown.wds); - break; -#endif /* NEED_AP_MLME */ - case EVENT_RX_MGMT: -#ifdef NEED_AP_MLME - if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0) - break; -#endif /* NEED_AP_MLME */ - hostapd_action_rx(hapd, &data->rx_mgmt); - break; - case EVENT_RX_PROBE_REQ: - if (data->rx_probe_req.sa == NULL || - 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, - data->rx_probe_req.ssi_signal); - break; - case EVENT_NEW_STA: - hostapd_event_new_sta(hapd, data->new_sta.addr); - break; - case EVENT_EAPOL_RX: - hostapd_event_eapol_rx(hapd, data->eapol_rx.src, - data->eapol_rx.data, - data->eapol_rx.data_len); - break; - case EVENT_ASSOC: - hostapd_notif_assoc(hapd, data->assoc_info.addr, - data->assoc_info.req_ies, - data->assoc_info.req_ies_len, - data->assoc_info.reassoc); - break; - case EVENT_DISASSOC: - if (data) - hostapd_notif_disassoc(hapd, data->disassoc_info.addr); - break; - case EVENT_DEAUTH: - if (data) - hostapd_notif_disassoc(hapd, data->deauth_info.addr); - break; - case EVENT_STATION_LOW_ACK: - if (!data) - break; - hostapd_event_sta_low_ack(hapd, data->low_ack.addr); - break; - case EVENT_AUTH: - hostapd_notif_auth(hapd, &data->auth); - break; - case EVENT_CH_SWITCH: - if (!data) - break; - hostapd_event_ch_switch(hapd, data->ch_switch.freq, - data->ch_switch.ht_enabled, - data->ch_switch.ch_offset, - data->ch_switch.ch_width, - data->ch_switch.cf1, - data->ch_switch.cf2); - break; - case EVENT_CONNECT_FAILED_REASON: - if (!data) - break; - hostapd_event_connect_failed_reason( - hapd, data->connect_failed_reason.addr, - data->connect_failed_reason.code); - break; - case EVENT_SURVEY: - hostapd_event_get_survey(hapd, &data->survey_results); - break; -#ifdef NEED_AP_MLME - case EVENT_DFS_RADAR_DETECTED: - if (!data) - break; - hostapd_event_dfs_radar_detected(hapd, &data->dfs_event); - break; - case EVENT_DFS_CAC_FINISHED: - if (!data) - break; - hostapd_event_dfs_cac_finished(hapd, &data->dfs_event); - break; - case EVENT_DFS_CAC_ABORTED: - if (!data) - break; - hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event); - break; - case EVENT_DFS_NOP_FINISHED: - if (!data) - break; - hostapd_event_dfs_nop_finished(hapd, &data->dfs_event); - break; - case EVENT_CHANNEL_LIST_CHANGED: - /* channel list changed (regulatory?), update channel list */ - /* TODO: check this. hostapd_get_hw_features() initializes - * too much stuff. */ - /* hostapd_get_hw_features(hapd->iface); */ - hostapd_channel_list_updated( - hapd->iface, data->channel_list_changed.initiator); - break; -#endif /* NEED_AP_MLME */ - default: - wpa_printf(MSG_DEBUG, "Unknown event %d", event); - break; - } -} - -#endif /* HOSTAPD */ diff --git a/contrib/hostapd/src/ap/eap_user_db.c b/contrib/hostapd/src/ap/eap_user_db.c deleted file mode 100644 index 79d50e5169..0000000000 --- a/contrib/hostapd/src/ap/eap_user_db.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * hostapd / EAP user database - * Copyright (c) 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#ifdef CONFIG_SQLITE -#include -#endif /* CONFIG_SQLITE */ - -#include "common.h" -#include "eap_common/eap_wsc_common.h" -#include "eap_server/eap_methods.h" -#include "eap_server/eap.h" -#include "ap_config.h" -#include "hostapd.h" - -#ifdef CONFIG_SQLITE - -static void set_user_methods(struct hostapd_eap_user *user, const char *methods) -{ - char *buf, *start; - int num_methods; - - buf = os_strdup(methods); - if (buf == NULL) - return; - - os_memset(&user->methods, 0, sizeof(user->methods)); - num_methods = 0; - start = buf; - while (*start) { - char *pos3 = os_strchr(start, ','); - if (pos3) - *pos3++ = '\0'; - user->methods[num_methods].method = - eap_server_get_type(start, - &user->methods[num_methods].vendor); - if (user->methods[num_methods].vendor == EAP_VENDOR_IETF && - user->methods[num_methods].method == EAP_TYPE_NONE) { - if (os_strcmp(start, "TTLS-PAP") == 0) { - user->ttls_auth |= EAP_TTLS_AUTH_PAP; - goto skip_eap; - } - if (os_strcmp(start, "TTLS-CHAP") == 0) { - user->ttls_auth |= EAP_TTLS_AUTH_CHAP; - goto skip_eap; - } - if (os_strcmp(start, "TTLS-MSCHAP") == 0) { - user->ttls_auth |= EAP_TTLS_AUTH_MSCHAP; - goto skip_eap; - } - if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) { - user->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2; - goto skip_eap; - } - wpa_printf(MSG_INFO, "DB: Unsupported EAP type '%s'", - start); - os_free(buf); - return; - } - - num_methods++; - if (num_methods >= EAP_MAX_METHODS) - break; - skip_eap: - if (pos3 == NULL) - break; - start = pos3; - } - - os_free(buf); -} - - -static int get_user_cb(void *ctx, int argc, char *argv[], char *col[]) -{ - struct hostapd_eap_user *user = ctx; - int i; - - for (i = 0; i < argc; i++) { - if (os_strcmp(col[i], "password") == 0 && argv[i]) { - os_free(user->password); - user->password_len = os_strlen(argv[i]); - user->password = (u8 *) os_strdup(argv[i]); - user->next = (void *) 1; - } else if (os_strcmp(col[i], "methods") == 0 && argv[i]) { - set_user_methods(user, argv[i]); - } - } - - return 0; -} - - -static int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[]) -{ - struct hostapd_eap_user *user = ctx; - int i, id = -1, methods = -1; - size_t len; - - for (i = 0; i < argc; i++) { - if (os_strcmp(col[i], "identity") == 0 && argv[i]) - id = i; - else if (os_strcmp(col[i], "methods") == 0 && argv[i]) - methods = i; - } - - if (id < 0 || methods < 0) - return 0; - - len = os_strlen(argv[id]); - if (len <= user->identity_len && - os_memcmp(argv[id], user->identity, len) == 0 && - (user->password == NULL || len > user->password_len)) { - os_free(user->password); - user->password_len = os_strlen(argv[id]); - user->password = (u8 *) os_strdup(argv[id]); - user->next = (void *) 1; - set_user_methods(user, argv[methods]); - } - - return 0; -} - - -static const struct hostapd_eap_user * -eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity, - size_t identity_len, int phase2) -{ - sqlite3 *db; - struct hostapd_eap_user *user = NULL; - char id_str[256], cmd[300]; - size_t i; - - if (identity_len >= sizeof(id_str)) - return NULL; - os_memcpy(id_str, identity, identity_len); - id_str[identity_len] = '\0'; - for (i = 0; i < identity_len; i++) { - if (id_str[i] >= 'a' && id_str[i] <= 'z') - continue; - if (id_str[i] >= 'A' && id_str[i] <= 'Z') - continue; - if (id_str[i] >= '0' && id_str[i] <= '9') - continue; - if (id_str[i] == '-' || id_str[i] == '_' || id_str[i] == '.' || - id_str[i] == ',' || id_str[i] == '@' || id_str[i] == '\\' || - id_str[i] == '!' || id_str[i] == '#' || id_str[i] == '%' || - id_str[i] == '=' || id_str[i] == ' ') - continue; - wpa_printf(MSG_INFO, "DB: Unsupported character in identity"); - return NULL; - } - - os_free(hapd->tmp_eap_user.identity); - os_free(hapd->tmp_eap_user.password); - os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user)); - hapd->tmp_eap_user.phase2 = phase2; - hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1); - if (hapd->tmp_eap_user.identity == NULL) - return NULL; - os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len); - - if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) { - wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s", - hapd->conf->eap_user_sqlite, sqlite3_errmsg(db)); - sqlite3_close(db); - return NULL; - } - - os_snprintf(cmd, sizeof(cmd), - "SELECT password,methods FROM users WHERE " - "identity='%s' AND phase2=%d;", id_str, phase2); - wpa_printf(MSG_DEBUG, "DB: %s", cmd); - if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) != - SQLITE_OK) { - wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation"); - } else if (hapd->tmp_eap_user.next) - user = &hapd->tmp_eap_user; - - if (user == NULL && !phase2) { - os_snprintf(cmd, sizeof(cmd), - "SELECT identity,methods FROM wildcards;"); - wpa_printf(MSG_DEBUG, "DB: %s", cmd); - if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user, - NULL) != SQLITE_OK) { - wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL " - "operation"); - } else if (hapd->tmp_eap_user.next) { - user = &hapd->tmp_eap_user; - os_free(user->identity); - user->identity = user->password; - user->identity_len = user->password_len; - user->password = NULL; - user->password_len = 0; - } - } - - sqlite3_close(db); - - return user; -} - -#endif /* CONFIG_SQLITE */ - - -const struct hostapd_eap_user * -hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, - size_t identity_len, int phase2) -{ - const struct hostapd_bss_config *conf = hapd->conf; - struct hostapd_eap_user *user = conf->eap_user; - -#ifdef CONFIG_WPS - if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN && - os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) { - static struct hostapd_eap_user wsc_enrollee; - os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee)); - wsc_enrollee.methods[0].method = eap_server_get_type( - "WSC", &wsc_enrollee.methods[0].vendor); - return &wsc_enrollee; - } - - if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN && - os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) { - static struct hostapd_eap_user wsc_registrar; - os_memset(&wsc_registrar, 0, sizeof(wsc_registrar)); - wsc_registrar.methods[0].method = eap_server_get_type( - "WSC", &wsc_registrar.methods[0].vendor); - wsc_registrar.password = (u8 *) conf->ap_pin; - wsc_registrar.password_len = conf->ap_pin ? - os_strlen(conf->ap_pin) : 0; - return &wsc_registrar; - } -#endif /* CONFIG_WPS */ - - while (user) { - if (!phase2 && user->identity == NULL) { - /* Wildcard match */ - break; - } - - if (user->phase2 == !!phase2 && user->wildcard_prefix && - identity_len >= user->identity_len && - os_memcmp(user->identity, identity, user->identity_len) == - 0) { - /* Wildcard prefix match */ - break; - } - - if (user->phase2 == !!phase2 && - user->identity_len == identity_len && - os_memcmp(user->identity, identity, identity_len) == 0) - break; - user = user->next; - } - -#ifdef CONFIG_SQLITE - if (user == NULL && conf->eap_user_sqlite) { - return eap_user_sqlite_get(hapd, identity, identity_len, - phase2); - } -#endif /* CONFIG_SQLITE */ - - return user; -} diff --git a/contrib/hostapd/src/ap/gas_serv.c b/contrib/hostapd/src/ap/gas_serv.c deleted file mode 100644 index b5fb7dfbc2..0000000000 --- a/contrib/hostapd/src/ap/gas_serv.c +++ /dev/null @@ -1,1199 +0,0 @@ -/* - * Generic advertisement service (GAS) server - * Copyright (c) 2011-2014, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "common/ieee802_11_defs.h" -#include "common/gas.h" -#include "utils/eloop.h" -#include "hostapd.h" -#include "ap_config.h" -#include "ap_drv_ops.h" -#include "sta_info.h" -#include "gas_serv.h" - - -static void convert_to_protected_dual(struct wpabuf *msg) -{ - u8 *categ = wpabuf_mhead_u8(msg); - *categ = WLAN_ACTION_PROTECTED_DUAL; -} - - -static struct gas_dialog_info * -gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token) -{ - struct sta_info *sta; - struct gas_dialog_info *dia = NULL; - int i, j; - - sta = ap_get_sta(hapd, addr); - if (!sta) { - /* - * We need a STA entry to be able to maintain state for - * the GAS query. - */ - wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for " - "GAS query"); - sta = ap_sta_add(hapd, addr); - if (!sta) { - wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR - " for GAS query", MAC2STR(addr)); - return NULL; - } - sta->flags |= WLAN_STA_GAS; - /* - * The default inactivity is 300 seconds. We don't need - * it to be that long. - */ - ap_sta_session_timeout(hapd, sta, 5); - } else { - ap_sta_replenish_timeout(hapd, sta, 5); - } - - if (sta->gas_dialog == NULL) { - sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX * - sizeof(struct gas_dialog_info)); - if (sta->gas_dialog == NULL) - return NULL; - } - - for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) { - if (i == GAS_DIALOG_MAX) - i = 0; - if (sta->gas_dialog[i].valid) - continue; - dia = &sta->gas_dialog[i]; - dia->valid = 1; - dia->index = i; - dia->dialog_token = dialog_token; - sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i; - return dia; - } - - wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for " - MACSTR " dialog_token %u. Consider increasing " - "GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token); - - return NULL; -} - - -struct gas_dialog_info * -gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr, - u8 dialog_token) -{ - struct sta_info *sta; - int i; - - sta = ap_get_sta(hapd, addr); - if (!sta) { - wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR, - MAC2STR(addr)); - return NULL; - } - for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) { - if (sta->gas_dialog[i].dialog_token != dialog_token || - !sta->gas_dialog[i].valid) - continue; - return &sta->gas_dialog[i]; - } - wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for " - MACSTR " dialog_token %u", MAC2STR(addr), dialog_token); - return NULL; -} - - -void gas_serv_dialog_clear(struct gas_dialog_info *dia) -{ - wpabuf_free(dia->sd_resp); - os_memset(dia, 0, sizeof(*dia)); -} - - -static void gas_serv_free_dialogs(struct hostapd_data *hapd, - const u8 *sta_addr) -{ - struct sta_info *sta; - int i; - - sta = ap_get_sta(hapd, sta_addr); - if (sta == NULL || sta->gas_dialog == NULL) - return; - - for (i = 0; i < GAS_DIALOG_MAX; i++) { - if (sta->gas_dialog[i].valid) - return; - } - - os_free(sta->gas_dialog); - sta->gas_dialog = NULL; -} - - -#ifdef CONFIG_HS20 -static void anqp_add_hs_capab_list(struct hostapd_data *hapd, - struct wpabuf *buf) -{ - u8 *len; - - len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); - wpabuf_put_be24(buf, OUI_WFA); - wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); - wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST); - wpabuf_put_u8(buf, 0); /* Reserved */ - wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST); - if (hapd->conf->hs20_oper_friendly_name) - wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME); - if (hapd->conf->hs20_wan_metrics) - wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS); - if (hapd->conf->hs20_connection_capability) - wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY); - if (hapd->conf->nai_realm_data) - wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY); - if (hapd->conf->hs20_operating_class) - wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS); - gas_anqp_set_element_len(buf, len); -} -#endif /* CONFIG_HS20 */ - - -static void anqp_add_capab_list(struct hostapd_data *hapd, - struct wpabuf *buf) -{ - u8 *len; - - len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST); - wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST); - if (hapd->conf->venue_name) - wpabuf_put_le16(buf, ANQP_VENUE_NAME); - if (hapd->conf->network_auth_type) - wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE); - if (hapd->conf->roaming_consortium) - wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM); - if (hapd->conf->ipaddr_type_configured) - wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY); - if (hapd->conf->nai_realm_data) - wpabuf_put_le16(buf, ANQP_NAI_REALM); - if (hapd->conf->anqp_3gpp_cell_net) - wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK); - if (hapd->conf->domain_name) - wpabuf_put_le16(buf, ANQP_DOMAIN_NAME); -#ifdef CONFIG_HS20 - anqp_add_hs_capab_list(hapd, buf); -#endif /* CONFIG_HS20 */ - gas_anqp_set_element_len(buf, len); -} - - -static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf) -{ - if (hapd->conf->venue_name) { - u8 *len; - unsigned int i; - len = gas_anqp_add_element(buf, ANQP_VENUE_NAME); - wpabuf_put_u8(buf, hapd->conf->venue_group); - wpabuf_put_u8(buf, hapd->conf->venue_type); - for (i = 0; i < hapd->conf->venue_name_count; i++) { - struct hostapd_lang_string *vn; - vn = &hapd->conf->venue_name[i]; - wpabuf_put_u8(buf, 3 + vn->name_len); - wpabuf_put_data(buf, vn->lang, 3); - wpabuf_put_data(buf, vn->name, vn->name_len); - } - gas_anqp_set_element_len(buf, len); - } -} - - -static void anqp_add_network_auth_type(struct hostapd_data *hapd, - struct wpabuf *buf) -{ - if (hapd->conf->network_auth_type) { - wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE); - wpabuf_put_le16(buf, hapd->conf->network_auth_type_len); - wpabuf_put_data(buf, hapd->conf->network_auth_type, - hapd->conf->network_auth_type_len); - } -} - - -static void anqp_add_roaming_consortium(struct hostapd_data *hapd, - struct wpabuf *buf) -{ - unsigned int i; - u8 *len; - - len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM); - for (i = 0; i < hapd->conf->roaming_consortium_count; i++) { - struct hostapd_roaming_consortium *rc; - rc = &hapd->conf->roaming_consortium[i]; - wpabuf_put_u8(buf, rc->len); - wpabuf_put_data(buf, rc->oi, rc->len); - } - gas_anqp_set_element_len(buf, len); -} - - -static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd, - struct wpabuf *buf) -{ - if (hapd->conf->ipaddr_type_configured) { - wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY); - wpabuf_put_le16(buf, 1); - wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability); - } -} - - -static void anqp_add_nai_realm_eap(struct wpabuf *buf, - struct hostapd_nai_realm_data *realm) -{ - unsigned int i, j; - - wpabuf_put_u8(buf, realm->eap_method_count); - - for (i = 0; i < realm->eap_method_count; i++) { - struct hostapd_nai_realm_eap *eap = &realm->eap_method[i]; - wpabuf_put_u8(buf, 2 + (3 * eap->num_auths)); - wpabuf_put_u8(buf, eap->eap_method); - wpabuf_put_u8(buf, eap->num_auths); - for (j = 0; j < eap->num_auths; j++) { - wpabuf_put_u8(buf, eap->auth_id[j]); - wpabuf_put_u8(buf, 1); - wpabuf_put_u8(buf, eap->auth_val[j]); - } - } -} - - -static void anqp_add_nai_realm_data(struct wpabuf *buf, - struct hostapd_nai_realm_data *realm, - unsigned int realm_idx) -{ - u8 *realm_data_len; - - wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx], - (int) os_strlen(realm->realm[realm_idx])); - realm_data_len = wpabuf_put(buf, 2); - wpabuf_put_u8(buf, realm->encoding); - wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx])); - wpabuf_put_str(buf, realm->realm[realm_idx]); - anqp_add_nai_realm_eap(buf, realm); - gas_anqp_set_element_len(buf, realm_data_len); -} - - -static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd, - struct wpabuf *buf, - const u8 *home_realm, - size_t home_realm_len) -{ - unsigned int i, j, k; - u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len; - struct hostapd_nai_realm_data *realm; - const u8 *pos, *realm_name, *end; - struct { - unsigned int realm_data_idx; - unsigned int realm_idx; - } matches[10]; - - pos = home_realm; - end = pos + home_realm_len; - if (pos + 1 > end) { - wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query", - home_realm, home_realm_len); - return -1; - } - num_realms = *pos++; - - for (i = 0; i < num_realms && num_matching < 10; i++) { - if (pos + 2 > end) { - wpa_hexdump(MSG_DEBUG, - "Truncated NAI Home Realm Query", - home_realm, home_realm_len); - return -1; - } - encoding = *pos++; - realm_len = *pos++; - if (pos + realm_len > end) { - wpa_hexdump(MSG_DEBUG, - "Truncated NAI Home Realm Query", - home_realm, home_realm_len); - return -1; - } - realm_name = pos; - for (j = 0; j < hapd->conf->nai_realm_count && - num_matching < 10; j++) { - const u8 *rpos, *rend; - realm = &hapd->conf->nai_realm_data[j]; - if (encoding != realm->encoding) - continue; - - rpos = realm_name; - while (rpos < realm_name + realm_len && - num_matching < 10) { - for (rend = rpos; - rend < realm_name + realm_len; rend++) { - if (*rend == ';') - break; - } - for (k = 0; k < MAX_NAI_REALMS && - realm->realm[k] && - num_matching < 10; k++) { - if ((int) os_strlen(realm->realm[k]) != - rend - rpos || - os_strncmp((char *) rpos, - realm->realm[k], - rend - rpos) != 0) - continue; - matches[num_matching].realm_data_idx = - j; - matches[num_matching].realm_idx = k; - num_matching++; - } - rpos = rend + 1; - } - } - pos += realm_len; - } - - realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM); - wpabuf_put_le16(buf, num_matching); - - /* - * There are two ways to format. 1. each realm in a NAI Realm Data unit - * 2. all realms that share the same EAP methods in a NAI Realm Data - * unit. The first format is likely to be bigger in size than the - * second, but may be easier to parse and process by the receiver. - */ - for (i = 0; i < num_matching; i++) { - wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d", - matches[i].realm_data_idx, matches[i].realm_idx); - realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx]; - anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx); - } - gas_anqp_set_element_len(buf, realm_list_len); - return 0; -} - - -static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf, - const u8 *home_realm, size_t home_realm_len, - int nai_realm, int nai_home_realm) -{ - if (nai_realm && hapd->conf->nai_realm_data) { - u8 *len; - unsigned int i, j; - len = gas_anqp_add_element(buf, ANQP_NAI_REALM); - wpabuf_put_le16(buf, hapd->conf->nai_realm_count); - for (i = 0; i < hapd->conf->nai_realm_count; i++) { - u8 *realm_data_len, *realm_len; - struct hostapd_nai_realm_data *realm; - - realm = &hapd->conf->nai_realm_data[i]; - realm_data_len = wpabuf_put(buf, 2); - wpabuf_put_u8(buf, realm->encoding); - realm_len = wpabuf_put(buf, 1); - for (j = 0; realm->realm[j]; j++) { - if (j > 0) - wpabuf_put_u8(buf, ';'); - wpabuf_put_str(buf, realm->realm[j]); - } - *realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1; - anqp_add_nai_realm_eap(buf, realm); - gas_anqp_set_element_len(buf, realm_data_len); - } - gas_anqp_set_element_len(buf, len); - } else if (nai_home_realm && hapd->conf->nai_realm_data) { - hs20_add_nai_home_realm_matches(hapd, buf, home_realm, - home_realm_len); - } -} - - -static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd, - struct wpabuf *buf) -{ - if (hapd->conf->anqp_3gpp_cell_net) { - wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK); - wpabuf_put_le16(buf, - hapd->conf->anqp_3gpp_cell_net_len); - wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net, - hapd->conf->anqp_3gpp_cell_net_len); - } -} - - -static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf) -{ - if (hapd->conf->domain_name) { - wpabuf_put_le16(buf, ANQP_DOMAIN_NAME); - wpabuf_put_le16(buf, hapd->conf->domain_name_len); - wpabuf_put_data(buf, hapd->conf->domain_name, - hapd->conf->domain_name_len); - } -} - - -#ifdef CONFIG_HS20 - -static void anqp_add_operator_friendly_name(struct hostapd_data *hapd, - struct wpabuf *buf) -{ - if (hapd->conf->hs20_oper_friendly_name) { - u8 *len; - unsigned int i; - len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); - wpabuf_put_be24(buf, OUI_WFA); - wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); - wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME); - wpabuf_put_u8(buf, 0); /* Reserved */ - for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++) - { - struct hostapd_lang_string *vn; - vn = &hapd->conf->hs20_oper_friendly_name[i]; - wpabuf_put_u8(buf, 3 + vn->name_len); - wpabuf_put_data(buf, vn->lang, 3); - wpabuf_put_data(buf, vn->name, vn->name_len); - } - gas_anqp_set_element_len(buf, len); - } -} - - -static void anqp_add_wan_metrics(struct hostapd_data *hapd, - struct wpabuf *buf) -{ - if (hapd->conf->hs20_wan_metrics) { - u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); - wpabuf_put_be24(buf, OUI_WFA); - wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); - wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS); - wpabuf_put_u8(buf, 0); /* Reserved */ - wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13); - gas_anqp_set_element_len(buf, len); - } -} - - -static void anqp_add_connection_capability(struct hostapd_data *hapd, - struct wpabuf *buf) -{ - if (hapd->conf->hs20_connection_capability) { - u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); - wpabuf_put_be24(buf, OUI_WFA); - wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); - wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY); - wpabuf_put_u8(buf, 0); /* Reserved */ - wpabuf_put_data(buf, hapd->conf->hs20_connection_capability, - hapd->conf->hs20_connection_capability_len); - gas_anqp_set_element_len(buf, len); - } -} - - -static void anqp_add_operating_class(struct hostapd_data *hapd, - struct wpabuf *buf) -{ - if (hapd->conf->hs20_operating_class) { - u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); - wpabuf_put_be24(buf, OUI_WFA); - wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); - wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS); - wpabuf_put_u8(buf, 0); /* Reserved */ - wpabuf_put_data(buf, hapd->conf->hs20_operating_class, - hapd->conf->hs20_operating_class_len); - gas_anqp_set_element_len(buf, len); - } -} - -#endif /* CONFIG_HS20 */ - - -static struct wpabuf * -gas_serv_build_gas_resp_payload(struct hostapd_data *hapd, - unsigned int request, - struct gas_dialog_info *di, - const u8 *home_realm, size_t home_realm_len) -{ - struct wpabuf *buf; - - buf = wpabuf_alloc(1400); - if (buf == NULL) - return NULL; - - if (request & ANQP_REQ_CAPABILITY_LIST) - anqp_add_capab_list(hapd, buf); - if (request & ANQP_REQ_VENUE_NAME) - anqp_add_venue_name(hapd, buf); - if (request & ANQP_REQ_NETWORK_AUTH_TYPE) - anqp_add_network_auth_type(hapd, buf); - if (request & ANQP_REQ_ROAMING_CONSORTIUM) - anqp_add_roaming_consortium(hapd, buf); - if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY) - anqp_add_ip_addr_type_availability(hapd, buf); - if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM)) - anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len, - request & ANQP_REQ_NAI_REALM, - request & ANQP_REQ_NAI_HOME_REALM); - if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK) - anqp_add_3gpp_cellular_network(hapd, buf); - if (request & ANQP_REQ_DOMAIN_NAME) - anqp_add_domain_name(hapd, buf); - -#ifdef CONFIG_HS20 - if (request & ANQP_REQ_HS_CAPABILITY_LIST) - anqp_add_hs_capab_list(hapd, buf); - if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME) - anqp_add_operator_friendly_name(hapd, buf); - if (request & ANQP_REQ_WAN_METRICS) - anqp_add_wan_metrics(hapd, buf); - if (request & ANQP_REQ_CONNECTION_CAPABILITY) - anqp_add_connection_capability(hapd, buf); - if (request & ANQP_REQ_OPERATING_CLASS) - anqp_add_operating_class(hapd, buf); -#endif /* CONFIG_HS20 */ - - return buf; -} - - -static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx) -{ - struct gas_dialog_info *dia = eloop_data; - - wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for " - "dialog token %d", dia->dialog_token); - - gas_serv_dialog_clear(dia); -} - - -struct anqp_query_info { - unsigned int request; - unsigned int remote_request; - const u8 *home_realm_query; - size_t home_realm_query_len; - u16 remote_delay; -}; - - -static void set_anqp_req(unsigned int bit, const char *name, int local, - unsigned int remote, u16 remote_delay, - struct anqp_query_info *qi) -{ - qi->request |= bit; - if (local) { - wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name); - } else if (bit & remote) { - wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name); - qi->remote_request |= bit; - if (remote_delay > qi->remote_delay) - qi->remote_delay = remote_delay; - } else { - wpa_printf(MSG_DEBUG, "ANQP: %s not available", name); - } -} - - -static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id, - struct anqp_query_info *qi) -{ - switch (info_id) { - case ANQP_CAPABILITY_LIST: - set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0, - 0, qi); - break; - case ANQP_VENUE_NAME: - set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name", - hapd->conf->venue_name != NULL, 0, 0, qi); - break; - case ANQP_NETWORK_AUTH_TYPE: - set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type", - hapd->conf->network_auth_type != NULL, - 0, 0, qi); - break; - case ANQP_ROAMING_CONSORTIUM: - set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium", - hapd->conf->roaming_consortium != NULL, 0, 0, qi); - break; - case ANQP_IP_ADDR_TYPE_AVAILABILITY: - set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY, - "IP Addr Type Availability", - hapd->conf->ipaddr_type_configured, - 0, 0, qi); - break; - case ANQP_NAI_REALM: - set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm", - hapd->conf->nai_realm_data != NULL, - 0, 0, qi); - break; - case ANQP_3GPP_CELLULAR_NETWORK: - set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK, - "3GPP Cellular Network", - hapd->conf->anqp_3gpp_cell_net != NULL, - 0, 0, qi); - break; - case ANQP_DOMAIN_NAME: - set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name", - hapd->conf->domain_name != NULL, - 0, 0, qi); - break; - default: - wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u", - info_id); - break; - } -} - - -static void rx_anqp_query_list(struct hostapd_data *hapd, - const u8 *pos, const u8 *end, - struct anqp_query_info *qi) -{ - wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list", - (unsigned int) (end - pos) / 2); - - while (pos + 2 <= end) { - rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi); - pos += 2; - } -} - - -#ifdef CONFIG_HS20 - -static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype, - struct anqp_query_info *qi) -{ - switch (subtype) { - case HS20_STYPE_CAPABILITY_LIST: - set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List", - 1, 0, 0, qi); - break; - case HS20_STYPE_OPERATOR_FRIENDLY_NAME: - set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME, - "Operator Friendly Name", - hapd->conf->hs20_oper_friendly_name != NULL, - 0, 0, qi); - break; - case HS20_STYPE_WAN_METRICS: - set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics", - hapd->conf->hs20_wan_metrics != NULL, - 0, 0, qi); - break; - case HS20_STYPE_CONNECTION_CAPABILITY: - set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY, - "Connection Capability", - hapd->conf->hs20_connection_capability != NULL, - 0, 0, qi); - break; - case HS20_STYPE_OPERATING_CLASS: - set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class", - hapd->conf->hs20_operating_class != NULL, - 0, 0, qi); - break; - default: - wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u", - subtype); - break; - } -} - - -static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd, - const u8 *pos, const u8 *end, - struct anqp_query_info *qi) -{ - qi->request |= ANQP_REQ_NAI_HOME_REALM; - qi->home_realm_query = pos; - qi->home_realm_query_len = end - pos; - if (hapd->conf->nai_realm_data != NULL) { - wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query " - "(local)"); - } else { - wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not " - "available"); - } -} - - -static void rx_anqp_vendor_specific(struct hostapd_data *hapd, - const u8 *pos, const u8 *end, - struct anqp_query_info *qi) -{ - u32 oui; - u8 subtype; - - if (pos + 4 > end) { - wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP " - "Query element"); - return; - } - - oui = WPA_GET_BE24(pos); - pos += 3; - if (oui != OUI_WFA) { - wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x", - oui); - return; - } - - if (*pos != HS20_ANQP_OUI_TYPE) { - wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u", - *pos); - return; - } - pos++; - - if (pos + 1 >= end) - return; - - subtype = *pos++; - pos++; /* Reserved */ - switch (subtype) { - case HS20_STYPE_QUERY_LIST: - wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List"); - while (pos < end) { - rx_anqp_hs_query_list(hapd, *pos, qi); - pos++; - } - break; - case HS20_STYPE_NAI_HOME_REALM_QUERY: - rx_anqp_hs_nai_home_realm(hapd, pos, end, qi); - break; - default: - wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype " - "%u", subtype); - break; - } -} - -#endif /* CONFIG_HS20 */ - - -static void gas_serv_req_local_processing(struct hostapd_data *hapd, - const u8 *sa, u8 dialog_token, - struct anqp_query_info *qi, int prot) -{ - struct wpabuf *buf, *tx_buf; - - buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL, - qi->home_realm_query, - qi->home_realm_query_len); - wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses", - buf); - if (!buf) - return; - - if (wpabuf_len(buf) > hapd->gas_frag_limit || - hapd->conf->gas_comeback_delay) { - struct gas_dialog_info *di; - u16 comeback_delay = 1; - - if (hapd->conf->gas_comeback_delay) { - /* Testing - allow overriding of the delay value */ - comeback_delay = hapd->conf->gas_comeback_delay; - } - - wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in " - "initial response - use GAS comeback"); - di = gas_dialog_create(hapd, sa, dialog_token); - if (!di) { - wpa_printf(MSG_INFO, "ANQP: Could not create dialog " - "for " MACSTR " (dialog token %u)", - MAC2STR(sa), dialog_token); - wpabuf_free(buf); - return; - } - di->prot = prot; - di->sd_resp = buf; - di->sd_resp_pos = 0; - tx_buf = gas_anqp_build_initial_resp_buf( - dialog_token, WLAN_STATUS_SUCCESS, comeback_delay, - NULL); - } else { - wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)"); - tx_buf = gas_anqp_build_initial_resp_buf( - dialog_token, WLAN_STATUS_SUCCESS, 0, buf); - wpabuf_free(buf); - } - if (!tx_buf) - return; - if (prot) - convert_to_protected_dual(tx_buf); - hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, - wpabuf_head(tx_buf), wpabuf_len(tx_buf)); - wpabuf_free(tx_buf); -} - - -static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd, - const u8 *sa, - const u8 *data, size_t len, int prot) -{ - const u8 *pos = data; - const u8 *end = data + len; - const u8 *next; - u8 dialog_token; - u16 slen; - struct anqp_query_info qi; - const u8 *adv_proto; - - if (len < 1 + 2) - return; - - os_memset(&qi, 0, sizeof(qi)); - - dialog_token = *pos++; - wpa_msg(hapd->msg_ctx, MSG_DEBUG, - "GAS: GAS Initial Request from " MACSTR " (dialog token %u) ", - MAC2STR(sa), dialog_token); - - if (*pos != WLAN_EID_ADV_PROTO) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, - "GAS: Unexpected IE in GAS Initial Request: %u", *pos); - return; - } - adv_proto = pos++; - - slen = *pos++; - next = pos + slen; - if (next > end || slen < 2) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, - "GAS: Invalid IE in GAS Initial Request"); - return; - } - pos++; /* skip QueryRespLenLimit and PAME-BI */ - - if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { - struct wpabuf *buf; - wpa_msg(hapd->msg_ctx, MSG_DEBUG, - "GAS: Unsupported GAS advertisement protocol id %u", - *pos); - if (sa[0] & 0x01) - return; /* Invalid source address - drop silently */ - buf = gas_build_initial_resp( - dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED, - 0, 2 + slen + 2); - if (buf == NULL) - return; - wpabuf_put_data(buf, adv_proto, 2 + slen); - wpabuf_put_le16(buf, 0); /* Query Response Length */ - if (prot) - convert_to_protected_dual(buf); - hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, - wpabuf_head(buf), wpabuf_len(buf)); - wpabuf_free(buf); - return; - } - - pos = next; - /* Query Request */ - if (pos + 2 > end) - return; - slen = WPA_GET_LE16(pos); - pos += 2; - if (pos + slen > end) - return; - end = pos + slen; - - /* ANQP Query Request */ - while (pos < end) { - u16 info_id, elen; - - if (pos + 4 > end) - return; - - info_id = WPA_GET_LE16(pos); - pos += 2; - elen = WPA_GET_LE16(pos); - pos += 2; - - if (pos + elen > end) { - wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request"); - return; - } - - switch (info_id) { - case ANQP_QUERY_LIST: - rx_anqp_query_list(hapd, pos, pos + elen, &qi); - break; -#ifdef CONFIG_HS20 - case ANQP_VENDOR_SPECIFIC: - rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi); - break; -#endif /* CONFIG_HS20 */ - default: - wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query " - "Request element %u", info_id); - break; - } - - pos += elen; - } - - gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot); -} - - -void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst, - struct gas_dialog_info *dialog) -{ - struct wpabuf *buf, *tx_buf; - u8 dialog_token = dialog->dialog_token; - size_t frag_len; - - if (dialog->sd_resp == NULL) { - buf = gas_serv_build_gas_resp_payload(hapd, - dialog->all_requested, - dialog, NULL, 0); - wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses", - buf); - if (!buf) - goto tx_gas_response_done; - dialog->sd_resp = buf; - dialog->sd_resp_pos = 0; - } - frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos; - if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay || - hapd->conf->gas_comeback_delay) { - u16 comeback_delay_tus = dialog->comeback_delay + - GAS_SERV_COMEBACK_DELAY_FUDGE; - u32 comeback_delay_secs, comeback_delay_usecs; - - if (hapd->conf->gas_comeback_delay) { - /* Testing - allow overriding of the delay value */ - comeback_delay_tus = hapd->conf->gas_comeback_delay; - } - - wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit " - "%u) and comeback delay %u, " - "requesting comebacks", (unsigned int) frag_len, - (unsigned int) hapd->gas_frag_limit, - dialog->comeback_delay); - tx_buf = gas_anqp_build_initial_resp_buf(dialog_token, - WLAN_STATUS_SUCCESS, - comeback_delay_tus, - NULL); - if (tx_buf) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, - "GAS: Tx GAS Initial Resp (comeback = 10TU)"); - if (dialog->prot) - convert_to_protected_dual(tx_buf); - hostapd_drv_send_action(hapd, hapd->iface->freq, 0, - dst, - wpabuf_head(tx_buf), - wpabuf_len(tx_buf)); - } - wpabuf_free(tx_buf); - - /* start a timer of 1.5 * comeback-delay */ - comeback_delay_tus = comeback_delay_tus + - (comeback_delay_tus / 2); - comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000; - comeback_delay_usecs = (comeback_delay_tus * 1024) - - (comeback_delay_secs * 1000000); - eloop_register_timeout(comeback_delay_secs, - comeback_delay_usecs, - gas_serv_clear_cached_ies, dialog, - NULL); - goto tx_gas_response_done; - } - - buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) + - dialog->sd_resp_pos, frag_len); - if (buf == NULL) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation " - "failed"); - goto tx_gas_response_done; - } - tx_buf = gas_anqp_build_initial_resp_buf(dialog_token, - WLAN_STATUS_SUCCESS, 0, buf); - wpabuf_free(buf); - if (tx_buf == NULL) - goto tx_gas_response_done; - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial " - "Response (frag_id %d frag_len %d)", - dialog->sd_frag_id, (int) frag_len); - dialog->sd_frag_id++; - - if (dialog->prot) - convert_to_protected_dual(tx_buf); - hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst, - wpabuf_head(tx_buf), wpabuf_len(tx_buf)); - wpabuf_free(tx_buf); -tx_gas_response_done: - gas_serv_clear_cached_ies(dialog, NULL); -} - - -static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd, - const u8 *sa, - const u8 *data, size_t len, int prot) -{ - struct gas_dialog_info *dialog; - struct wpabuf *buf, *tx_buf; - u8 dialog_token; - size_t frag_len; - int more = 0; - - wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len); - if (len < 1) - return; - dialog_token = *data; - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u", - dialog_token); - - dialog = gas_serv_dialog_find(hapd, sa, dialog_token); - if (!dialog) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD " - "response fragment for " MACSTR " dialog token %u", - MAC2STR(sa), dialog_token); - - if (sa[0] & 0x01) - return; /* Invalid source address - drop silently */ - tx_buf = gas_anqp_build_comeback_resp_buf( - dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0, - 0, NULL); - if (tx_buf == NULL) - return; - goto send_resp; - } - - if (dialog->sd_resp == NULL) { - wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x", - dialog->requested, dialog->received); - if ((dialog->requested & dialog->received) != - dialog->requested) { - wpa_printf(MSG_DEBUG, "GAS: Did not receive response " - "from remote processing"); - gas_serv_dialog_clear(dialog); - tx_buf = gas_anqp_build_comeback_resp_buf( - dialog_token, - WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0, - NULL); - if (tx_buf == NULL) - return; - goto send_resp; - } - - buf = gas_serv_build_gas_resp_payload(hapd, - dialog->all_requested, - dialog, NULL, 0); - wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses", - buf); - if (!buf) - goto rx_gas_comeback_req_done; - dialog->sd_resp = buf; - dialog->sd_resp_pos = 0; - } - frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos; - if (frag_len > hapd->gas_frag_limit) { - frag_len = hapd->gas_frag_limit; - more = 1; - } - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u", - (unsigned int) frag_len); - buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) + - dialog->sd_resp_pos, frag_len); - if (buf == NULL) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate " - "buffer"); - goto rx_gas_comeback_req_done; - } - tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token, - WLAN_STATUS_SUCCESS, - dialog->sd_frag_id, - more, 0, buf); - wpabuf_free(buf); - if (tx_buf == NULL) - goto rx_gas_comeback_req_done; - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response " - "(frag_id %d more=%d frag_len=%d)", - dialog->sd_frag_id, more, (int) frag_len); - dialog->sd_frag_id++; - dialog->sd_resp_pos += frag_len; - - if (more) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain " - "to be sent", - (int) (wpabuf_len(dialog->sd_resp) - - dialog->sd_resp_pos)); - } else { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of " - "SD response sent"); - gas_serv_dialog_clear(dialog); - gas_serv_free_dialogs(hapd, sa); - } - -send_resp: - if (prot) - convert_to_protected_dual(tx_buf); - hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, - wpabuf_head(tx_buf), wpabuf_len(tx_buf)); - wpabuf_free(tx_buf); - return; - -rx_gas_comeback_req_done: - gas_serv_clear_cached_ies(dialog, NULL); -} - - -static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len, - int freq) -{ - struct hostapd_data *hapd = ctx; - const struct ieee80211_mgmt *mgmt; - size_t hdr_len; - const u8 *sa, *data; - int prot; - - mgmt = (const struct ieee80211_mgmt *) buf; - hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf; - if (hdr_len > len) - return; - if (mgmt->u.action.category != WLAN_ACTION_PUBLIC && - mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL) - return; - /* - * Note: Public Action and Protected Dual of Public Action frames share - * the same payload structure, so it is fine to use definitions of - * Public Action frames to process both. - */ - prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL; - sa = mgmt->sa; - len -= hdr_len; - data = &mgmt->u.action.u.public_action.action; - switch (data[0]) { - case WLAN_PA_GAS_INITIAL_REQ: - gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot); - break; - case WLAN_PA_GAS_COMEBACK_REQ: - gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot); - break; - } -} - - -int gas_serv_init(struct hostapd_data *hapd) -{ - hapd->public_action_cb2 = gas_serv_rx_public_action; - hapd->public_action_cb2_ctx = hapd; - hapd->gas_frag_limit = 1400; - if (hapd->conf->gas_frag_limit > 0) - hapd->gas_frag_limit = hapd->conf->gas_frag_limit; - return 0; -} - - -void gas_serv_deinit(struct hostapd_data *hapd) -{ -} diff --git a/contrib/hostapd/src/ap/gas_serv.h b/contrib/hostapd/src/ap/gas_serv.h deleted file mode 100644 index 74739fef15..0000000000 --- a/contrib/hostapd/src/ap/gas_serv.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Generic advertisement service (GAS) server - * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef GAS_SERV_H -#define GAS_SERV_H - -#define ANQP_REQ_CAPABILITY_LIST \ - (1 << (ANQP_CAPABILITY_LIST - ANQP_QUERY_LIST)) -#define ANQP_REQ_VENUE_NAME \ - (1 << (ANQP_VENUE_NAME - ANQP_QUERY_LIST)) -#define ANQP_REQ_NETWORK_AUTH_TYPE \ - (1 << (ANQP_NETWORK_AUTH_TYPE - ANQP_QUERY_LIST)) -#define ANQP_REQ_ROAMING_CONSORTIUM \ - (1 << (ANQP_ROAMING_CONSORTIUM - ANQP_QUERY_LIST)) -#define ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY \ - (1 << (ANQP_IP_ADDR_TYPE_AVAILABILITY - ANQP_QUERY_LIST)) -#define ANQP_REQ_NAI_REALM \ - (1 << (ANQP_NAI_REALM - ANQP_QUERY_LIST)) -#define ANQP_REQ_3GPP_CELLULAR_NETWORK \ - (1 << (ANQP_3GPP_CELLULAR_NETWORK - ANQP_QUERY_LIST)) -#define ANQP_REQ_DOMAIN_NAME \ - (1 << (ANQP_DOMAIN_NAME - ANQP_QUERY_LIST)) -#define ANQP_REQ_HS_CAPABILITY_LIST \ - (0x10000 << HS20_STYPE_CAPABILITY_LIST) -#define ANQP_REQ_OPERATOR_FRIENDLY_NAME \ - (0x10000 << HS20_STYPE_OPERATOR_FRIENDLY_NAME) -#define ANQP_REQ_WAN_METRICS \ - (0x10000 << HS20_STYPE_WAN_METRICS) -#define ANQP_REQ_CONNECTION_CAPABILITY \ - (0x10000 << HS20_STYPE_CONNECTION_CAPABILITY) -#define ANQP_REQ_NAI_HOME_REALM \ - (0x10000 << HS20_STYPE_NAI_HOME_REALM_QUERY) -#define ANQP_REQ_OPERATING_CLASS \ - (0x10000 << HS20_STYPE_OPERATING_CLASS) - -/* To account for latencies between hostapd and external ANQP processor */ -#define GAS_SERV_COMEBACK_DELAY_FUDGE 10 -#define GAS_SERV_MIN_COMEBACK_DELAY 100 /* in TU */ - -struct gas_dialog_info { - u8 valid; - u8 index; - struct wpabuf *sd_resp; /* Fragmented response */ - u8 dialog_token; - size_t sd_resp_pos; /* Offset in sd_resp */ - u8 sd_frag_id; - u16 comeback_delay; - int prot; /* whether Protected Dual of Public Action frame is used */ - - unsigned int requested; - unsigned int received; - unsigned int all_requested; -}; - -struct hostapd_data; - -void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst, - struct gas_dialog_info *dialog); -struct gas_dialog_info * -gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr, - u8 dialog_token); -void gas_serv_dialog_clear(struct gas_dialog_info *dialog); - -int gas_serv_init(struct hostapd_data *hapd); -void gas_serv_deinit(struct hostapd_data *hapd); - -#endif /* GAS_SERV_H */ diff --git a/contrib/hostapd/src/ap/hostapd.c b/contrib/hostapd/src/ap/hostapd.c deleted file mode 100644 index f9edf3b3f8..0000000000 --- a/contrib/hostapd/src/ap/hostapd.c +++ /dev/null @@ -1,2255 +0,0 @@ -/* - * hostapd / Initialization and configuration - * Copyright (c) 2002-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "common/ieee802_11_defs.h" -#include "common/wpa_ctrl.h" -#include "radius/radius_client.h" -#include "radius/radius_das.h" -#include "hostapd.h" -#include "authsrv.h" -#include "sta_info.h" -#include "accounting.h" -#include "ap_list.h" -#include "beacon.h" -#include "iapp.h" -#include "ieee802_1x.h" -#include "ieee802_11_auth.h" -#include "vlan_init.h" -#include "wpa_auth.h" -#include "wps_hostapd.h" -#include "hw_features.h" -#include "wpa_auth_glue.h" -#include "ap_drv_ops.h" -#include "ap_config.h" -#include "p2p_hostapd.h" -#include "gas_serv.h" -#include "dfs.h" - - -static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason); -static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd); -static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd); -static int setup_interface2(struct hostapd_iface *iface); -static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx); - - -int hostapd_for_each_interface(struct hapd_interfaces *interfaces, - int (*cb)(struct hostapd_iface *iface, - void *ctx), void *ctx) -{ - size_t i; - int ret; - - for (i = 0; i < interfaces->count; i++) { - ret = cb(interfaces->iface[i], ctx); - if (ret) - return ret; - } - - return 0; -} - - -static void hostapd_reload_bss(struct hostapd_data *hapd) -{ - struct hostapd_ssid *ssid; - -#ifndef CONFIG_NO_RADIUS - radius_client_reconfig(hapd->radius, hapd->conf->radius); -#endif /* CONFIG_NO_RADIUS */ - - ssid = &hapd->conf->ssid; - if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next && - ssid->wpa_passphrase_set && ssid->wpa_passphrase) { - /* - * Force PSK to be derived again since SSID or passphrase may - * have changed. - */ - os_free(ssid->wpa_psk); - ssid->wpa_psk = NULL; - } - if (hostapd_setup_wpa_psk(hapd->conf)) { - wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK " - "after reloading configuration"); - } - - if (hapd->conf->ieee802_1x || hapd->conf->wpa) - hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1); - else - hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); - - if (hapd->conf->wpa && hapd->wpa_auth == NULL) { - hostapd_setup_wpa(hapd); - 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); - wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len); - if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) - wpa_printf(MSG_ERROR, "Failed to configure WPA IE for " - "the kernel driver."); - } else if (hapd->wpa_auth) { - wpa_deinit(hapd->wpa_auth); - hapd->wpa_auth = NULL; - hostapd_set_privacy(hapd, 0); - hostapd_setup_encryption(hapd->conf->iface, hapd); - hostapd_set_generic_elem(hapd, (u8 *) "", 0); - } - - ieee802_11_set_beacon(hapd); - hostapd_update_wps(hapd); - - if (hapd->conf->ssid.ssid_set && - hostapd_set_ssid(hapd, hapd->conf->ssid.ssid, - hapd->conf->ssid.ssid_len)) { - wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); - /* try to continue */ - } - wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface); -} - - -static void hostapd_clear_old(struct hostapd_iface *iface) -{ - size_t j; - - /* - * Deauthenticate all stations since the new configuration may not - * allow them to use the BSS anymore. - */ - for (j = 0; j < iface->num_bss; j++) { - hostapd_flush_old_stations(iface->bss[j], - WLAN_REASON_PREV_AUTH_NOT_VALID); - hostapd_broadcast_wep_clear(iface->bss[j]); - -#ifndef CONFIG_NO_RADIUS - /* TODO: update dynamic data based on changed configuration - * items (e.g., open/close sockets, etc.) */ - radius_client_flush(iface->bss[j]->radius, 0); -#endif /* CONFIG_NO_RADIUS */ - } -} - - -int hostapd_reload_config(struct hostapd_iface *iface) -{ - struct hostapd_data *hapd = iface->bss[0]; - struct hostapd_config *newconf, *oldconf; - size_t j; - - if (iface->config_fname == NULL) { - /* Only in-memory config in use - assume it has been updated */ - hostapd_clear_old(iface); - for (j = 0; j < iface->num_bss; j++) - hostapd_reload_bss(iface->bss[j]); - return 0; - } - - if (iface->interfaces == NULL || - iface->interfaces->config_read_cb == NULL) - return -1; - newconf = iface->interfaces->config_read_cb(iface->config_fname); - if (newconf == NULL) - return -1; - - hostapd_clear_old(iface); - - oldconf = hapd->iconf; - iface->conf = newconf; - - for (j = 0; j < iface->num_bss; j++) { - hapd = iface->bss[j]; - hapd->iconf = newconf; - hapd->conf = newconf->bss[j]; - hostapd_reload_bss(hapd); - } - - hostapd_config_free(oldconf); - - - return 0; -} - - -static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, - char *ifname) -{ - int i; - - for (i = 0; i < NUM_WEP_KEYS; i++) { - if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, - 0, NULL, 0, NULL, 0)) { - wpa_printf(MSG_DEBUG, "Failed to clear default " - "encryption keys (ifname=%s keyidx=%d)", - ifname, i); - } - } -#ifdef CONFIG_IEEE80211W - if (hapd->conf->ieee80211w) { - for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) { - if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, - NULL, i, 0, NULL, - 0, NULL, 0)) { - wpa_printf(MSG_DEBUG, "Failed to clear " - "default mgmt encryption keys " - "(ifname=%s keyidx=%d)", ifname, i); - } - } - } -#endif /* CONFIG_IEEE80211W */ -} - - -static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd) -{ - hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface); - return 0; -} - - -static int hostapd_broadcast_wep_set(struct hostapd_data *hapd) -{ - int errors = 0, idx; - struct hostapd_ssid *ssid = &hapd->conf->ssid; - - idx = ssid->wep.idx; - if (ssid->wep.default_len && - hostapd_drv_set_key(hapd->conf->iface, - hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, - 1, NULL, 0, ssid->wep.key[idx], - ssid->wep.len[idx])) { - wpa_printf(MSG_WARNING, "Could not set WEP encryption."); - errors++; - } - - return errors; -} - - -static void hostapd_free_hapd_data(struct hostapd_data *hapd) -{ - if (!hapd->started) { - wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started", - __func__, hapd->conf->iface); - return; - } - hapd->started = 0; - - wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface); - iapp_deinit(hapd->iapp); - hapd->iapp = NULL; - accounting_deinit(hapd); - hostapd_deinit_wpa(hapd); - vlan_deinit(hapd); - hostapd_acl_deinit(hapd); -#ifndef CONFIG_NO_RADIUS - radius_client_deinit(hapd->radius); - hapd->radius = NULL; - radius_das_deinit(hapd->radius_das); - hapd->radius_das = NULL; -#endif /* CONFIG_NO_RADIUS */ - - hostapd_deinit_wps(hapd); - - authsrv_deinit(hapd); - - if (hapd->interface_added && - hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) { - wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s", - hapd->conf->iface); - } - - os_free(hapd->probereq_cb); - hapd->probereq_cb = NULL; - -#ifdef CONFIG_P2P - wpabuf_free(hapd->p2p_beacon_ie); - hapd->p2p_beacon_ie = NULL; - wpabuf_free(hapd->p2p_probe_resp_ie); - hapd->p2p_probe_resp_ie = NULL; -#endif /* CONFIG_P2P */ - - wpabuf_free(hapd->time_adv); - -#ifdef CONFIG_INTERWORKING - gas_serv_deinit(hapd); -#endif /* CONFIG_INTERWORKING */ - -#ifdef CONFIG_SQLITE - os_free(hapd->tmp_eap_user.identity); - os_free(hapd->tmp_eap_user.password); -#endif /* CONFIG_SQLITE */ -} - - -/** - * hostapd_cleanup - Per-BSS cleanup (deinitialization) - * @hapd: Pointer to BSS data - * - * This function is used to free all per-BSS data structures and resources. - * Most of the modules that are initialized in hostapd_setup_bss() are - * deinitialized here. - */ -static void hostapd_cleanup(struct hostapd_data *hapd) -{ - wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd, - hapd->conf->iface); - if (hapd->iface->interfaces && - hapd->iface->interfaces->ctrl_iface_deinit) - hapd->iface->interfaces->ctrl_iface_deinit(hapd); - hostapd_free_hapd_data(hapd); -} - - -static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) -{ - wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); - hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); - iface->hw_features = NULL; - os_free(iface->current_rates); - iface->current_rates = NULL; - os_free(iface->basic_rates); - iface->basic_rates = NULL; - ap_list_deinit(iface); -} - - -/** - * hostapd_cleanup_iface - Complete per-interface cleanup - * @iface: Pointer to interface data - * - * This function is called after per-BSS data structures are deinitialized - * with hostapd_cleanup(). - */ -static void hostapd_cleanup_iface(struct hostapd_iface *iface) -{ - wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); - eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); - - hostapd_cleanup_iface_partial(iface); - hostapd_config_free(iface->conf); - iface->conf = NULL; - - os_free(iface->config_fname); - os_free(iface->bss); - wpa_printf(MSG_DEBUG, "%s: free iface=%p", __func__, iface); - os_free(iface); -} - - -static void hostapd_clear_wep(struct hostapd_data *hapd) -{ - if (hapd->drv_priv) { - hostapd_set_privacy(hapd, 0); - hostapd_broadcast_wep_clear(hapd); - } -} - - -static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd) -{ - int i; - - hostapd_broadcast_wep_set(hapd); - - if (hapd->conf->ssid.wep.default_len) { - hostapd_set_privacy(hapd, 1); - return 0; - } - - /* - * When IEEE 802.1X is not enabled, the driver may need to know how to - * set authentication algorithms for static WEP. - */ - hostapd_drv_set_authmode(hapd, hapd->conf->auth_algs); - - for (i = 0; i < 4; i++) { - if (hapd->conf->ssid.wep.key[i] && - hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, - i == hapd->conf->ssid.wep.idx, NULL, 0, - hapd->conf->ssid.wep.key[i], - hapd->conf->ssid.wep.len[i])) { - wpa_printf(MSG_WARNING, "Could not set WEP " - "encryption."); - return -1; - } - if (hapd->conf->ssid.wep.key[i] && - i == hapd->conf->ssid.wep.idx) - hostapd_set_privacy(hapd, 1); - } - - return 0; -} - - -static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason) -{ - int ret = 0; - u8 addr[ETH_ALEN]; - - if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL) - return 0; - - wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries"); - if (hostapd_flush(hapd)) { - wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to " - "kernel driver"); - ret = -1; - } - wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations"); - os_memset(addr, 0xff, ETH_ALEN); - hostapd_drv_sta_deauth(hapd, addr, reason); - hostapd_free_stas(hapd); - - return ret; -} - - -/** - * hostapd_validate_bssid_configuration - Validate BSSID configuration - * @iface: Pointer to interface data - * Returns: 0 on success, -1 on failure - * - * This function is used to validate that the configured BSSIDs are valid. - */ -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 auto_addr = 0; - - if (hostapd_drv_none(hapd)) - return 0; - - /* Generate BSSID mask that is large enough to cover the BSSIDs. */ - - /* Determine the bits necessary to cover the number of BSSIDs. */ - for (i--; i; i >>= 1) - bits++; - - /* Determine the bits necessary to any configured BSSIDs, - if they are higher than the number of BSSIDs. */ - for (j = 0; j < iface->conf->num_bss; j++) { - if (hostapd_mac_comp_empty(iface->conf->bss[j]->bssid) == 0) { - if (j) - auto_addr++; - continue; - } - - for (i = 0; i < ETH_ALEN; i++) { - mask[i] |= - iface->conf->bss[j]->bssid[i] ^ - hapd->own_addr[i]; - } - } - - if (!auto_addr) - goto skip_mask_ext; - - for (i = 0; i < ETH_ALEN && mask[i] == 0; i++) - ; - j = 0; - if (i < ETH_ALEN) { - j = (5 - i) * 8; - - while (mask[i] != 0) { - mask[i] >>= 1; - j++; - } - } - - if (bits < j) - bits = j; - - if (bits > 40) { - wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)", - bits); - return -1; - } - - os_memset(mask, 0xff, ETH_ALEN); - j = bits / 8; - for (i = 5; i > 5 - j; i--) - mask[i] = 0; - j = bits % 8; - while (j--) - mask[i] <<= 1; - -skip_mask_ext: - wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)", - (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits); - - if (!auto_addr) - return 0; - - for (i = 0; i < ETH_ALEN; i++) { - if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) { - wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR - " for start address " MACSTR ".", - MAC2STR(mask), MAC2STR(hapd->own_addr)); - wpa_printf(MSG_ERROR, "Start address must be the " - "first address in the block (i.e., addr " - "AND mask == addr)."); - return -1; - } - } - - return 0; -} - - -static int mac_in_conf(struct hostapd_config *conf, const void *a) -{ - size_t i; - - for (i = 0; i < conf->num_bss; i++) { - if (hostapd_mac_comp(conf->bss[i]->bssid, a) == 0) { - return 1; - } - } - - return 0; -} - - -#ifndef CONFIG_NO_RADIUS - -static int hostapd_das_nas_mismatch(struct hostapd_data *hapd, - struct radius_das_attrs *attr) -{ - /* TODO */ - return 0; -} - - -static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd, - struct radius_das_attrs *attr) -{ - struct sta_info *sta = NULL; - char buf[128]; - - if (attr->sta_addr) - sta = ap_get_sta(hapd, attr->sta_addr); - - if (sta == NULL && attr->acct_session_id && - attr->acct_session_id_len == 17) { - for (sta = hapd->sta_list; sta; sta = sta->next) { - os_snprintf(buf, sizeof(buf), "%08X-%08X", - sta->acct_session_id_hi, - sta->acct_session_id_lo); - if (os_memcmp(attr->acct_session_id, buf, 17) == 0) - break; - } - } - - if (sta == NULL && attr->cui) { - for (sta = hapd->sta_list; sta; sta = sta->next) { - struct wpabuf *cui; - cui = ieee802_1x_get_radius_cui(sta->eapol_sm); - if (cui && wpabuf_len(cui) == attr->cui_len && - os_memcmp(wpabuf_head(cui), attr->cui, - attr->cui_len) == 0) - break; - } - } - - if (sta == NULL && attr->user_name) { - for (sta = hapd->sta_list; sta; sta = sta->next) { - u8 *identity; - size_t identity_len; - identity = ieee802_1x_get_identity(sta->eapol_sm, - &identity_len); - if (identity && - identity_len == attr->user_name_len && - os_memcmp(identity, attr->user_name, identity_len) - == 0) - break; - } - } - - return sta; -} - - -static enum radius_das_res -hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta; - - if (hostapd_das_nas_mismatch(hapd, attr)) - return RADIUS_DAS_NAS_MISMATCH; - - sta = hostapd_das_find_sta(hapd, attr); - if (sta == NULL) - return RADIUS_DAS_SESSION_NOT_FOUND; - - hostapd_drv_sta_deauth(hapd, sta->addr, - WLAN_REASON_PREV_AUTH_NOT_VALID); - ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID); - - return RADIUS_DAS_SUCCESS; -} - -#endif /* CONFIG_NO_RADIUS */ - - -/** - * hostapd_setup_bss - Per-BSS setup (initialization) - * @hapd: Pointer to BSS data - * @first: Whether this BSS is the first BSS of an interface; -1 = not first, - * but interface may exist - * - * This function is used to initialize all per-BSS data structures and - * resources. This gets called in a loop for each BSS when an interface is - * initialized. Most of the modules that are initialized here will be - * deinitialized in hostapd_cleanup(). - */ -static int hostapd_setup_bss(struct hostapd_data *hapd, int first) -{ - struct hostapd_bss_config *conf = hapd->conf; - u8 ssid[HOSTAPD_MAX_SSID_LEN + 1]; - int ssid_len, set_ssid; - char force_ifname[IFNAMSIZ]; - u8 if_addr[ETH_ALEN]; - - wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)", - __func__, hapd, hapd->conf->iface, first); - - if (hapd->started) { - wpa_printf(MSG_ERROR, "%s: Interface %s was already started", - __func__, hapd->conf->iface); - return -1; - } - hapd->started = 1; - - if (!first || first == -1) { - if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) { - /* Allocate the next available BSSID. */ - do { - inc_byte_array(hapd->own_addr, ETH_ALEN); - } while (mac_in_conf(hapd->iconf, hapd->own_addr)); - } else { - /* Allocate the configured BSSID. */ - os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN); - - if (hostapd_mac_comp(hapd->own_addr, - hapd->iface->bss[0]->own_addr) == - 0) { - wpa_printf(MSG_ERROR, "BSS '%s' may not have " - "BSSID set to the MAC address of " - "the radio", hapd->conf->iface); - return -1; - } - } - - hapd->interface_added = 1; - if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS, - hapd->conf->iface, hapd->own_addr, hapd, - &hapd->drv_priv, force_ifname, if_addr, - hapd->conf->bridge[0] ? hapd->conf->bridge : - NULL, first == -1)) { - wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID=" - MACSTR ")", MAC2STR(hapd->own_addr)); - hapd->interface_added = 0; - return -1; - } - } - - if (conf->wmm_enabled < 0) - conf->wmm_enabled = hapd->iconf->ieee80211n; - - hostapd_flush_old_stations(hapd, WLAN_REASON_PREV_AUTH_NOT_VALID); - hostapd_set_privacy(hapd, 0); - - hostapd_broadcast_wep_clear(hapd); - if (hostapd_setup_encryption(hapd->conf->iface, hapd)) - return -1; - - /* - * Fetch the SSID from the system and use it or, - * if one was specified in the config file, verify they - * match. - */ - ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid)); - if (ssid_len < 0) { - wpa_printf(MSG_ERROR, "Could not read SSID from system"); - return -1; - } - if (conf->ssid.ssid_set) { - /* - * If SSID is specified in the config file and it differs - * from what is being used then force installation of the - * new SSID. - */ - set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len || - os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0); - } else { - /* - * No SSID in the config file; just use the one we got - * from the system. - */ - set_ssid = 0; - conf->ssid.ssid_len = ssid_len; - os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len); - } - - if (!hostapd_drv_none(hapd)) { - wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR - " and ssid \"%s\"", - hapd->conf->iface, MAC2STR(hapd->own_addr), - wpa_ssid_txt(hapd->conf->ssid.ssid, - hapd->conf->ssid.ssid_len)); - } - - if (hostapd_setup_wpa_psk(conf)) { - wpa_printf(MSG_ERROR, "WPA-PSK setup failed."); - return -1; - } - - /* Set SSID for the kernel driver (to be used in beacon and probe - * response frames) */ - if (set_ssid && hostapd_set_ssid(hapd, conf->ssid.ssid, - conf->ssid.ssid_len)) { - wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); - return -1; - } - - if (wpa_debug_level == MSG_MSGDUMP) - conf->radius->msg_dumps = 1; -#ifndef CONFIG_NO_RADIUS - hapd->radius = radius_client_init(hapd, conf->radius); - if (hapd->radius == NULL) { - wpa_printf(MSG_ERROR, "RADIUS client initialization failed."); - return -1; - } - - if (hapd->conf->radius_das_port) { - struct radius_das_conf das_conf; - os_memset(&das_conf, 0, sizeof(das_conf)); - das_conf.port = hapd->conf->radius_das_port; - das_conf.shared_secret = hapd->conf->radius_das_shared_secret; - das_conf.shared_secret_len = - hapd->conf->radius_das_shared_secret_len; - das_conf.client_addr = &hapd->conf->radius_das_client_addr; - das_conf.time_window = hapd->conf->radius_das_time_window; - das_conf.require_event_timestamp = - hapd->conf->radius_das_require_event_timestamp; - das_conf.ctx = hapd; - das_conf.disconnect = hostapd_das_disconnect; - hapd->radius_das = radius_das_init(&das_conf); - if (hapd->radius_das == NULL) { - wpa_printf(MSG_ERROR, "RADIUS DAS initialization " - "failed."); - return -1; - } - } -#endif /* CONFIG_NO_RADIUS */ - - if (hostapd_acl_init(hapd)) { - wpa_printf(MSG_ERROR, "ACL initialization failed."); - return -1; - } - if (hostapd_init_wps(hapd, conf)) - return -1; - - if (authsrv_init(hapd) < 0) - return -1; - - if (ieee802_1x_init(hapd)) { - wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed."); - return -1; - } - - if (hapd->conf->wpa && hostapd_setup_wpa(hapd)) - return -1; - - if (accounting_init(hapd)) { - wpa_printf(MSG_ERROR, "Accounting initialization failed."); - return -1; - } - - if (hapd->conf->ieee802_11f && - (hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) { - wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization " - "failed."); - return -1; - } - -#ifdef CONFIG_INTERWORKING - if (gas_serv_init(hapd)) { - wpa_printf(MSG_ERROR, "GAS server initialization failed"); - return -1; - } - - if (conf->qos_map_set_len && - hostapd_drv_set_qos_map(hapd, conf->qos_map_set, - conf->qos_map_set_len)) { - wpa_printf(MSG_ERROR, "Failed to initialize QoS Map"); - return -1; - } -#endif /* CONFIG_INTERWORKING */ - - if (!hostapd_drv_none(hapd) && vlan_init(hapd)) { - wpa_printf(MSG_ERROR, "VLAN initialization failed."); - return -1; - } - - if (!hapd->conf->start_disabled && ieee802_11_set_beacon(hapd) < 0) - return -1; - - 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); - - return 0; -} - - -static void hostapd_tx_queue_params(struct hostapd_iface *iface) -{ - struct hostapd_data *hapd = iface->bss[0]; - int i; - struct hostapd_tx_queue_params *p; - - for (i = 0; i < NUM_TX_QUEUES; i++) { - p = &iface->conf->tx_queue[i]; - - if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin, - p->cwmax, p->burst)) { - wpa_printf(MSG_DEBUG, "Failed to set TX queue " - "parameters for queue %d.", i); - /* Continue anyway */ - } - } -} - - -static int hostapd_set_acl_list(struct hostapd_data *hapd, - struct mac_acl_entry *mac_acl, - int n_entries, u8 accept_acl) -{ - struct hostapd_acl_params *acl_params; - int i, err; - - acl_params = os_zalloc(sizeof(*acl_params) + - (n_entries * sizeof(acl_params->mac_acl[0]))); - if (!acl_params) - return -ENOMEM; - - for (i = 0; i < n_entries; i++) - os_memcpy(acl_params->mac_acl[i].addr, mac_acl[i].addr, - ETH_ALEN); - - acl_params->acl_policy = accept_acl; - acl_params->num_mac_acl = n_entries; - - err = hostapd_drv_set_acl(hapd, acl_params); - - os_free(acl_params); - - return err; -} - - -static void hostapd_set_acl(struct hostapd_data *hapd) -{ - struct hostapd_config *conf = hapd->iconf; - int err; - u8 accept_acl; - - if (hapd->iface->drv_max_acl_mac_addrs == 0) - return; - if (!(conf->bss[0]->num_accept_mac || conf->bss[0]->num_deny_mac)) - return; - - if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) { - if (conf->bss[0]->num_accept_mac) { - accept_acl = 1; - err = hostapd_set_acl_list(hapd, - conf->bss[0]->accept_mac, - conf->bss[0]->num_accept_mac, - accept_acl); - if (err) { - wpa_printf(MSG_DEBUG, "Failed to set accept acl"); - return; - } - } else { - wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file"); - } - } else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) { - if (conf->bss[0]->num_deny_mac) { - accept_acl = 0; - err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac, - conf->bss[0]->num_deny_mac, - accept_acl); - if (err) { - wpa_printf(MSG_DEBUG, "Failed to set deny acl"); - return; - } - } else { - wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file"); - } - } -} - - -static int start_ctrl_iface_bss(struct hostapd_data *hapd) -{ - if (!hapd->iface->interfaces || - !hapd->iface->interfaces->ctrl_iface_init) - return 0; - - if (hapd->iface->interfaces->ctrl_iface_init(hapd)) { - wpa_printf(MSG_ERROR, - "Failed to setup control interface for %s", - hapd->conf->iface); - return -1; - } - - return 0; -} - - -static int start_ctrl_iface(struct hostapd_iface *iface) -{ - size_t i; - - if (!iface->interfaces || !iface->interfaces->ctrl_iface_init) - return 0; - - for (i = 0; i < iface->num_bss; i++) { - struct hostapd_data *hapd = iface->bss[i]; - if (iface->interfaces->ctrl_iface_init(hapd)) { - wpa_printf(MSG_ERROR, - "Failed to setup control interface for %s", - hapd->conf->iface); - return -1; - } - } - - return 0; -} - - -static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_iface *iface = eloop_ctx; - - if (!iface->wait_channel_update) { - wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it"); - return; - } - - /* - * It is possible that the existing channel list is acceptable, so try - * to proceed. - */ - wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway"); - setup_interface2(iface); -} - - -void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator) -{ - if (!iface->wait_channel_update || initiator != REGDOM_SET_BY_USER) - return; - - wpa_printf(MSG_DEBUG, "Channel list updated - continue setup"); - eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); - setup_interface2(iface); -} - - -static int setup_interface(struct hostapd_iface *iface) -{ - struct hostapd_data *hapd = iface->bss[0]; - size_t i; - - if (!iface->phy[0]) { - const char *phy = hostapd_drv_get_radio_name(hapd); - if (phy) { - wpa_printf(MSG_DEBUG, "phy: %s", phy); - os_strlcpy(iface->phy, phy, sizeof(iface->phy)); - } - } - - /* - * Make sure that all BSSes get configured with a pointer to the same - * driver interface. - */ - for (i = 1; i < iface->num_bss; i++) { - iface->bss[i]->driver = hapd->driver; - iface->bss[i]->drv_priv = hapd->drv_priv; - } - - if (hostapd_validate_bssid_configuration(iface)) - return -1; - - /* - * Initialize control interfaces early to allow external monitoring of - * channel setup operations that may take considerable amount of time - * especially for DFS cases. - */ - if (start_ctrl_iface(iface)) - return -1; - - if (hapd->iconf->country[0] && hapd->iconf->country[1]) { - char country[4], previous_country[4]; - - hostapd_set_state(iface, HAPD_IFACE_COUNTRY_UPDATE); - if (hostapd_get_country(hapd, previous_country) < 0) - previous_country[0] = '\0'; - - os_memcpy(country, hapd->iconf->country, 3); - country[3] = '\0'; - if (hostapd_set_country(hapd, country) < 0) { - wpa_printf(MSG_ERROR, "Failed to set country code"); - return -1; - } - - wpa_printf(MSG_DEBUG, "Previous country code %s, new country code %s", - previous_country, country); - - if (os_strncmp(previous_country, country, 2) != 0) { - wpa_printf(MSG_DEBUG, "Continue interface setup after channel list update"); - iface->wait_channel_update = 1; - eloop_register_timeout(5, 0, - channel_list_update_timeout, - iface, NULL); - return 0; - } - } - - return setup_interface2(iface); -} - - -static int setup_interface2(struct hostapd_iface *iface) -{ - iface->wait_channel_update = 0; - - if (hostapd_get_hw_features(iface)) { - /* Not all drivers support this yet, so continue without hw - * feature data. */ - } else { - int ret = hostapd_select_hw_mode(iface); - if (ret < 0) { - wpa_printf(MSG_ERROR, "Could not select hw_mode and " - "channel. (%d)", ret); - return -1; - } - if (ret == 1) { - wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)"); - return 0; - } - ret = hostapd_check_ht_capab(iface); - if (ret < 0) - return -1; - if (ret == 1) { - wpa_printf(MSG_DEBUG, "Interface initialization will " - "be completed in a callback"); - return 0; - } - - if (iface->conf->ieee80211h) - wpa_printf(MSG_DEBUG, "DFS support is enabled"); - } - return hostapd_setup_interface_complete(iface, 0); -} - - -/** - * hostapd_setup_interface_complete - Complete interface setup - * - * This function is called when previous steps in the interface setup has been - * completed. This can also start operations, e.g., DFS, that will require - * additional processing before interface is ready to be enabled. Such - * operations will call this function from eloop callbacks when finished. - */ -int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) -{ - struct hostapd_data *hapd = iface->bss[0]; - size_t j; - u8 *prev_addr; - - if (err) { - wpa_printf(MSG_ERROR, "Interface initialization failed"); - hostapd_set_state(iface, HAPD_IFACE_DISABLED); - if (iface->interfaces && iface->interfaces->terminate_on_error) - eloop_terminate(); - return -1; - } - - wpa_printf(MSG_DEBUG, "Completing interface initialization"); - if (iface->conf->channel) { -#ifdef NEED_AP_MLME - int res; -#endif /* NEED_AP_MLME */ - - iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel); - wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d " - "Frequency: %d MHz", - hostapd_hw_mode_txt(iface->conf->hw_mode), - iface->conf->channel, iface->freq); - -#ifdef NEED_AP_MLME - /* Check DFS */ - res = hostapd_handle_dfs(iface); - if (res <= 0) - return res; -#endif /* NEED_AP_MLME */ - - if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq, - hapd->iconf->channel, - hapd->iconf->ieee80211n, - hapd->iconf->ieee80211ac, - hapd->iconf->secondary_channel, - hapd->iconf->vht_oper_chwidth, - hapd->iconf->vht_oper_centr_freq_seg0_idx, - hapd->iconf->vht_oper_centr_freq_seg1_idx)) { - wpa_printf(MSG_ERROR, "Could not set channel for " - "kernel driver"); - return -1; - } - } - - if (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, - HOSTAPD_LEVEL_WARNING, - "Failed to prepare rates table."); - return -1; - } - } - - if (hapd->iconf->rts_threshold > -1 && - hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) { - wpa_printf(MSG_ERROR, "Could not set RTS threshold for " - "kernel driver"); - return -1; - } - - if (hapd->iconf->fragm_threshold > -1 && - hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) { - wpa_printf(MSG_ERROR, "Could not set fragmentation threshold " - "for kernel driver"); - return -1; - } - - prev_addr = hapd->own_addr; - - for (j = 0; j < iface->num_bss; j++) { - hapd = iface->bss[j]; - if (j) - os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN); - if (hostapd_setup_bss(hapd, j == 0)) - return -1; - if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) - prev_addr = hapd->own_addr; - } - hapd = iface->bss[0]; - - hostapd_tx_queue_params(iface); - - ap_list_init(iface); - - hostapd_set_acl(hapd); - - if (hostapd_driver_commit(hapd) < 0) { - wpa_printf(MSG_ERROR, "%s: Failed to commit driver " - "configuration", __func__); - return -1; - } - - /* - * WPS UPnP module can be initialized only when the "upnp_iface" is up. - * If "interface" and "upnp_iface" are the same (e.g., non-bridge - * mode), the interface is up only after driver_commit, so initialize - * WPS after driver_commit. - */ - for (j = 0; j < iface->num_bss; j++) { - if (hostapd_init_wps_complete(iface->bss[j])) - return -1; - } - - hostapd_set_state(iface, HAPD_IFACE_ENABLED); - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED); - if (hapd->setup_complete_cb) - hapd->setup_complete_cb(hapd->setup_complete_cb_ctx); - - wpa_printf(MSG_DEBUG, "%s: Setup of interface done.", - iface->bss[0]->conf->iface); - if (iface->interfaces && iface->interfaces->terminate_on_error > 0) - iface->interfaces->terminate_on_error--; - - return 0; -} - - -/** - * hostapd_setup_interface - Setup of an interface - * @iface: Pointer to interface data. - * Returns: 0 on success, -1 on failure - * - * Initializes the driver interface, validates the configuration, - * and sets driver parameters based on the configuration. - * Flushes old stations, sets the channel, encryption, - * beacons, and WDS links based on the configuration. - * - * If interface setup requires more time, e.g., to perform HT co-ex scans, ACS, - * or DFS operations, this function returns 0 before such operations have been - * completed. The pending operations are registered into eloop and will be - * completed from eloop callbacks. Those callbacks end up calling - * hostapd_setup_interface_complete() once setup has been completed. - */ -int hostapd_setup_interface(struct hostapd_iface *iface) -{ - int ret; - - ret = setup_interface(iface); - if (ret) { - wpa_printf(MSG_ERROR, "%s: Unable to setup interface.", - iface->bss[0]->conf->iface); - return -1; - } - - return 0; -} - - -/** - * hostapd_alloc_bss_data - Allocate and initialize per-BSS data - * @hapd_iface: Pointer to interface data - * @conf: Pointer to per-interface configuration - * @bss: Pointer to per-BSS configuration for this BSS - * Returns: Pointer to allocated BSS data - * - * This function is used to allocate per-BSS data structure. This data will be - * freed after hostapd_cleanup() is called for it during interface - * deinitialization. - */ -struct hostapd_data * -hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, - struct hostapd_config *conf, - struct hostapd_bss_config *bss) -{ - struct hostapd_data *hapd; - - hapd = os_zalloc(sizeof(*hapd)); - if (hapd == NULL) - return NULL; - - hapd->new_assoc_sta_cb = hostapd_new_assoc_sta; - hapd->iconf = conf; - hapd->conf = bss; - hapd->iface = hapd_iface; - hapd->driver = hapd->iconf->driver; - hapd->ctrl_sock = -1; - - return hapd; -} - - -static void hostapd_bss_deinit(struct hostapd_data *hapd) -{ - wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__, - hapd->conf->iface); - hostapd_free_stas(hapd); - hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING); - hostapd_clear_wep(hapd); - hostapd_cleanup(hapd); -} - - -void hostapd_interface_deinit(struct hostapd_iface *iface) -{ - int j; - - wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); - if (iface == NULL) - return; - - eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); - iface->wait_channel_update = 0; - - for (j = iface->num_bss - 1; j >= 0; j--) - hostapd_bss_deinit(iface->bss[j]); -} - - -void hostapd_interface_free(struct hostapd_iface *iface) -{ - size_t j; - wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); - for (j = 0; j < iface->num_bss; j++) { - wpa_printf(MSG_DEBUG, "%s: free hapd %p", - __func__, iface->bss[j]); - os_free(iface->bss[j]); - } - hostapd_cleanup_iface(iface); -} - - -/** - * hostapd_init - Allocate and initialize per-interface data - * @config_file: Path to the configuration file - * Returns: Pointer to the allocated interface data or %NULL on failure - * - * This function is used to allocate main data structures for per-interface - * data. The allocated data buffer will be freed by calling - * hostapd_cleanup_iface(). - */ -struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces, - const char *config_file) -{ - struct hostapd_iface *hapd_iface = NULL; - struct hostapd_config *conf = NULL; - struct hostapd_data *hapd; - size_t i; - - hapd_iface = os_zalloc(sizeof(*hapd_iface)); - if (hapd_iface == NULL) - goto fail; - - hapd_iface->config_fname = os_strdup(config_file); - if (hapd_iface->config_fname == NULL) - goto fail; - - conf = interfaces->config_read_cb(hapd_iface->config_fname); - if (conf == NULL) - goto fail; - hapd_iface->conf = conf; - - hapd_iface->num_bss = conf->num_bss; - hapd_iface->bss = os_calloc(conf->num_bss, - sizeof(struct hostapd_data *)); - if (hapd_iface->bss == NULL) - goto fail; - - for (i = 0; i < conf->num_bss; i++) { - hapd = hapd_iface->bss[i] = - hostapd_alloc_bss_data(hapd_iface, conf, - conf->bss[i]); - if (hapd == NULL) - goto fail; - hapd->msg_ctx = hapd; - } - - return hapd_iface; - -fail: - wpa_printf(MSG_ERROR, "Failed to set up interface with %s", - config_file); - if (conf) - hostapd_config_free(conf); - if (hapd_iface) { - os_free(hapd_iface->config_fname); - os_free(hapd_iface->bss); - wpa_printf(MSG_DEBUG, "%s: free iface %p", - __func__, hapd_iface); - os_free(hapd_iface); - } - return NULL; -} - - -static int ifname_in_use(struct hapd_interfaces *interfaces, const char *ifname) -{ - size_t i, j; - - for (i = 0; i < interfaces->count; i++) { - struct hostapd_iface *iface = interfaces->iface[i]; - for (j = 0; j < iface->num_bss; j++) { - struct hostapd_data *hapd = iface->bss[j]; - if (os_strcmp(ifname, hapd->conf->iface) == 0) - return 1; - } - } - - return 0; -} - - -/** - * hostapd_interface_init_bss - Read configuration file and init BSS data - * - * This function is used to parse configuration file for a BSS. This BSS is - * added to an existing interface sharing the same radio (if any) or a new - * interface is created if this is the first interface on a radio. This - * allocate memory for the BSS. No actual driver operations are started. - * - * This is similar to hostapd_interface_init(), but for a case where the - * configuration is used to add a single BSS instead of all BSSes for a radio. - */ -struct hostapd_iface * -hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy, - const char *config_fname, int debug) -{ - struct hostapd_iface *new_iface = NULL, *iface = NULL; - struct hostapd_data *hapd; - int k; - size_t i, bss_idx; - - if (!phy || !*phy) - return NULL; - - for (i = 0; i < interfaces->count; i++) { - if (os_strcmp(interfaces->iface[i]->phy, phy) == 0) { - iface = interfaces->iface[i]; - break; - } - } - - wpa_printf(MSG_INFO, "Configuration file: %s (phy %s)%s", - config_fname, phy, iface ? "" : " --> new PHY"); - if (iface) { - struct hostapd_config *conf; - struct hostapd_bss_config **tmp_conf; - struct hostapd_data **tmp_bss; - struct hostapd_bss_config *bss; - const char *ifname; - - /* Add new BSS to existing iface */ - conf = interfaces->config_read_cb(config_fname); - if (conf == NULL) - return NULL; - if (conf->num_bss > 1) { - wpa_printf(MSG_ERROR, "Multiple BSSes specified in BSS-config"); - hostapd_config_free(conf); - return NULL; - } - - ifname = conf->bss[0]->iface; - if (ifname[0] != '\0' && ifname_in_use(interfaces, ifname)) { - wpa_printf(MSG_ERROR, - "Interface name %s already in use", ifname); - hostapd_config_free(conf); - return NULL; - } - - tmp_conf = os_realloc_array( - iface->conf->bss, iface->conf->num_bss + 1, - sizeof(struct hostapd_bss_config *)); - tmp_bss = os_realloc_array(iface->bss, iface->num_bss + 1, - sizeof(struct hostapd_data *)); - if (tmp_bss) - iface->bss = tmp_bss; - if (tmp_conf) { - iface->conf->bss = tmp_conf; - iface->conf->last_bss = tmp_conf[0]; - } - if (tmp_bss == NULL || tmp_conf == NULL) { - hostapd_config_free(conf); - return NULL; - } - bss = iface->conf->bss[iface->conf->num_bss] = conf->bss[0]; - iface->conf->num_bss++; - - hapd = hostapd_alloc_bss_data(iface, iface->conf, bss); - if (hapd == NULL) { - iface->conf->num_bss--; - hostapd_config_free(conf); - return NULL; - } - iface->conf->last_bss = bss; - iface->bss[iface->num_bss] = hapd; - hapd->msg_ctx = hapd; - - bss_idx = iface->num_bss++; - conf->num_bss--; - conf->bss[0] = NULL; - hostapd_config_free(conf); - } else { - /* Add a new iface with the first BSS */ - new_iface = iface = hostapd_init(interfaces, config_fname); - if (!iface) - return NULL; - os_strlcpy(iface->phy, phy, sizeof(iface->phy)); - iface->interfaces = interfaces; - bss_idx = 0; - } - - for (k = 0; k < debug; k++) { - if (iface->bss[bss_idx]->conf->logger_stdout_level > 0) - iface->bss[bss_idx]->conf->logger_stdout_level--; - } - - if (iface->conf->bss[bss_idx]->iface[0] == '\0' && - !hostapd_drv_none(iface->bss[bss_idx])) { - wpa_printf(MSG_ERROR, "Interface name not specified in %s", - config_fname); - if (new_iface) - hostapd_interface_deinit_free(new_iface); - return NULL; - } - - return iface; -} - - -void hostapd_interface_deinit_free(struct hostapd_iface *iface) -{ - const struct wpa_driver_ops *driver; - void *drv_priv; - - wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); - if (iface == NULL) - return; - wpa_printf(MSG_DEBUG, "%s: num_bss=%u conf->num_bss=%u", - __func__, (unsigned int) iface->num_bss, - (unsigned int) iface->conf->num_bss); - driver = iface->bss[0]->driver; - drv_priv = iface->bss[0]->drv_priv; - hostapd_interface_deinit(iface); - wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", - __func__, driver, drv_priv); - if (driver && driver->hapd_deinit && drv_priv) - driver->hapd_deinit(drv_priv); - hostapd_interface_free(iface); -} - - -int hostapd_enable_iface(struct hostapd_iface *hapd_iface) -{ - if (hapd_iface->bss[0]->drv_priv != NULL) { - wpa_printf(MSG_ERROR, "Interface %s already enabled", - hapd_iface->conf->bss[0]->iface); - return -1; - } - - wpa_printf(MSG_DEBUG, "Enable interface %s", - hapd_iface->conf->bss[0]->iface); - - if (hostapd_config_check(hapd_iface->conf, 1) < 0) { - wpa_printf(MSG_INFO, "Invalid configuration - cannot enable"); - return -1; - } - - if (hapd_iface->interfaces == NULL || - hapd_iface->interfaces->driver_init == NULL || - hapd_iface->interfaces->driver_init(hapd_iface)) - return -1; - - if (hostapd_setup_interface(hapd_iface)) { - const struct wpa_driver_ops *driver; - void *drv_priv; - - driver = hapd_iface->bss[0]->driver; - drv_priv = hapd_iface->bss[0]->drv_priv; - wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", - __func__, driver, drv_priv); - if (driver && driver->hapd_deinit && drv_priv) { - driver->hapd_deinit(drv_priv); - hapd_iface->bss[0]->drv_priv = NULL; - } - return -1; - } - - return 0; -} - - -int hostapd_reload_iface(struct hostapd_iface *hapd_iface) -{ - size_t j; - - wpa_printf(MSG_DEBUG, "Reload interface %s", - hapd_iface->conf->bss[0]->iface); - for (j = 0; j < hapd_iface->num_bss; j++) - hostapd_set_security_params(hapd_iface->conf->bss[j]); - if (hostapd_config_check(hapd_iface->conf, 1) < 0) { - wpa_printf(MSG_ERROR, "Updated configuration is invalid"); - return -1; - } - hostapd_clear_old(hapd_iface); - for (j = 0; j < hapd_iface->num_bss; j++) - hostapd_reload_bss(hapd_iface->bss[j]); - - return 0; -} - - -int hostapd_disable_iface(struct hostapd_iface *hapd_iface) -{ - size_t j; - const struct wpa_driver_ops *driver; - void *drv_priv; - - if (hapd_iface == NULL) - return -1; - wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); - driver = hapd_iface->bss[0]->driver; - drv_priv = hapd_iface->bss[0]->drv_priv; - - /* whatever hostapd_interface_deinit does */ - for (j = 0; j < hapd_iface->num_bss; j++) { - struct hostapd_data *hapd = hapd_iface->bss[j]; - hostapd_free_stas(hapd); - hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING); - hostapd_clear_wep(hapd); - hostapd_free_hapd_data(hapd); - } - - wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", - __func__, driver, drv_priv); - if (driver && driver->hapd_deinit && drv_priv) { - driver->hapd_deinit(drv_priv); - hapd_iface->bss[0]->drv_priv = NULL; - } - - /* From hostapd_cleanup_iface: These were initialized in - * hostapd_setup_interface and hostapd_setup_interface_complete - */ - hostapd_cleanup_iface_partial(hapd_iface); - - wpa_printf(MSG_DEBUG, "Interface %s disabled", - hapd_iface->bss[0]->conf->iface); - hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED); - return 0; -} - - -static struct hostapd_iface * -hostapd_iface_alloc(struct hapd_interfaces *interfaces) -{ - struct hostapd_iface **iface, *hapd_iface; - - iface = os_realloc_array(interfaces->iface, interfaces->count + 1, - sizeof(struct hostapd_iface *)); - if (iface == NULL) - return NULL; - interfaces->iface = iface; - hapd_iface = interfaces->iface[interfaces->count] = - os_zalloc(sizeof(*hapd_iface)); - if (hapd_iface == NULL) { - wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for " - "the interface", __func__); - return NULL; - } - interfaces->count++; - hapd_iface->interfaces = interfaces; - - return hapd_iface; -} - - -static struct hostapd_config * -hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname, - const char *ctrl_iface) -{ - struct hostapd_bss_config *bss; - struct hostapd_config *conf; - - /* Allocates memory for bss and conf */ - conf = hostapd_config_defaults(); - if (conf == NULL) { - wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for " - "configuration", __func__); - return NULL; - } - - conf->driver = wpa_drivers[0]; - if (conf->driver == NULL) { - wpa_printf(MSG_ERROR, "No driver wrappers registered!"); - hostapd_config_free(conf); - return NULL; - } - - bss = conf->last_bss = conf->bss[0]; - - os_strlcpy(bss->iface, ifname, sizeof(bss->iface)); - bss->ctrl_interface = os_strdup(ctrl_iface); - if (bss->ctrl_interface == NULL) { - hostapd_config_free(conf); - return NULL; - } - - /* Reading configuration file skipped, will be done in SET! - * From reading the configuration till the end has to be done in - * SET - */ - return conf; -} - - -static struct hostapd_iface * hostapd_data_alloc( - struct hapd_interfaces *interfaces, struct hostapd_config *conf) -{ - size_t i; - struct hostapd_iface *hapd_iface = - interfaces->iface[interfaces->count - 1]; - struct hostapd_data *hapd; - - hapd_iface->conf = conf; - hapd_iface->num_bss = conf->num_bss; - - hapd_iface->bss = os_zalloc(conf->num_bss * - sizeof(struct hostapd_data *)); - if (hapd_iface->bss == NULL) - return NULL; - - for (i = 0; i < conf->num_bss; i++) { - hapd = hapd_iface->bss[i] = - hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]); - if (hapd == NULL) - return NULL; - hapd->msg_ctx = hapd; - } - - hapd_iface->interfaces = interfaces; - - return hapd_iface; -} - - -int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf) -{ - struct hostapd_config *conf = NULL; - struct hostapd_iface *hapd_iface = NULL, *new_iface = NULL; - struct hostapd_data *hapd; - char *ptr; - size_t i, j; - const char *conf_file = NULL, *phy_name = NULL; - - if (os_strncmp(buf, "bss_config=", 11) == 0) { - char *pos; - phy_name = buf + 11; - pos = os_strchr(phy_name, ':'); - if (!pos) - return -1; - *pos++ = '\0'; - conf_file = pos; - if (!os_strlen(conf_file)) - return -1; - - hapd_iface = hostapd_interface_init_bss(interfaces, phy_name, - conf_file, 0); - if (!hapd_iface) - return -1; - for (j = 0; j < interfaces->count; j++) { - if (interfaces->iface[j] == hapd_iface) - break; - } - if (j == interfaces->count) { - struct hostapd_iface **tmp; - tmp = os_realloc_array(interfaces->iface, - interfaces->count + 1, - sizeof(struct hostapd_iface *)); - if (!tmp) { - hostapd_interface_deinit_free(hapd_iface); - return -1; - } - interfaces->iface = tmp; - interfaces->iface[interfaces->count++] = hapd_iface; - new_iface = hapd_iface; - } - - if (new_iface) { - if (interfaces->driver_init(hapd_iface) || - hostapd_setup_interface(hapd_iface)) { - interfaces->count--; - goto fail; - } - } else { - /* Assign new BSS with bss[0]'s driver info */ - hapd = hapd_iface->bss[hapd_iface->num_bss - 1]; - hapd->driver = hapd_iface->bss[0]->driver; - hapd->drv_priv = hapd_iface->bss[0]->drv_priv; - os_memcpy(hapd->own_addr, hapd_iface->bss[0]->own_addr, - ETH_ALEN); - - if (start_ctrl_iface_bss(hapd) < 0 || - (hapd_iface->state == HAPD_IFACE_ENABLED && - hostapd_setup_bss(hapd, -1))) { - hapd_iface->conf->num_bss--; - hapd_iface->num_bss--; - wpa_printf(MSG_DEBUG, "%s: free hapd %p %s", - __func__, hapd, hapd->conf->iface); - os_free(hapd); - return -1; - } - } - return 0; - } - - ptr = os_strchr(buf, ' '); - if (ptr == NULL) - return -1; - *ptr++ = '\0'; - - if (os_strncmp(ptr, "config=", 7) == 0) - conf_file = ptr + 7; - - for (i = 0; i < interfaces->count; i++) { - if (!os_strcmp(interfaces->iface[i]->conf->bss[0]->iface, - buf)) { - wpa_printf(MSG_INFO, "Cannot add interface - it " - "already exists"); - return -1; - } - } - - hapd_iface = hostapd_iface_alloc(interfaces); - if (hapd_iface == NULL) { - wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " - "for interface", __func__); - goto fail; - } - - if (conf_file && interfaces->config_read_cb) { - conf = interfaces->config_read_cb(conf_file); - if (conf && conf->bss) - os_strlcpy(conf->bss[0]->iface, buf, - sizeof(conf->bss[0]->iface)); - } else - conf = hostapd_config_alloc(interfaces, buf, ptr); - if (conf == NULL || conf->bss == NULL) { - wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " - "for configuration", __func__); - goto fail; - } - - hapd_iface = hostapd_data_alloc(interfaces, conf); - if (hapd_iface == NULL) { - wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " - "for hostapd", __func__); - goto fail; - } - - if (start_ctrl_iface(hapd_iface) < 0) - goto fail; - - wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0]->iface); - - return 0; - -fail: - if (conf) - hostapd_config_free(conf); - if (hapd_iface) { - if (hapd_iface->bss) { - for (i = 0; i < hapd_iface->num_bss; i++) { - hapd = hapd_iface->bss[i]; - if (hapd && hapd_iface->interfaces && - hapd_iface->interfaces->ctrl_iface_deinit) - hapd_iface->interfaces-> - ctrl_iface_deinit(hapd); - wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)", - __func__, hapd_iface->bss[i], - hapd_iface->bss[i]->conf->iface); - os_free(hapd_iface->bss[i]); - } - os_free(hapd_iface->bss); - } - wpa_printf(MSG_DEBUG, "%s: free iface %p", - __func__, hapd_iface); - os_free(hapd_iface); - } - return -1; -} - - -static int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx) -{ - size_t i; - - wpa_printf(MSG_INFO, "Remove BSS '%s'", iface->conf->bss[idx]->iface); - - /* Remove hostapd_data only if it has already been initialized */ - if (idx < iface->num_bss) { - struct hostapd_data *hapd = iface->bss[idx]; - - hostapd_bss_deinit(hapd); - wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)", - __func__, hapd, hapd->conf->iface); - hostapd_config_free_bss(hapd->conf); - os_free(hapd); - - iface->num_bss--; - - for (i = idx; i < iface->num_bss; i++) - iface->bss[i] = iface->bss[i + 1]; - } else { - hostapd_config_free_bss(iface->conf->bss[idx]); - iface->conf->bss[idx] = NULL; - } - - iface->conf->num_bss--; - for (i = idx; i < iface->conf->num_bss; i++) - iface->conf->bss[i] = iface->conf->bss[i + 1]; - - return 0; -} - - -int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf) -{ - struct hostapd_iface *hapd_iface; - size_t i, j, k = 0; - - for (i = 0; i < interfaces->count; i++) { - hapd_iface = interfaces->iface[i]; - if (hapd_iface == NULL) - return -1; - if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) { - wpa_printf(MSG_INFO, "Remove interface '%s'", buf); - hostapd_interface_deinit_free(hapd_iface); - k = i; - while (k < (interfaces->count - 1)) { - interfaces->iface[k] = - interfaces->iface[k + 1]; - k++; - } - interfaces->count--; - return 0; - } - - for (j = 0; j < hapd_iface->conf->num_bss; j++) { - if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf)) - return hostapd_remove_bss(hapd_iface, j); - } - } - return -1; -} - - -/** - * hostapd_new_assoc_sta - Notify that a new station associated with the AP - * @hapd: Pointer to BSS data - * @sta: Pointer to the associated STA data - * @reassoc: 1 to indicate this was a re-association; 0 = first association - * - * This function will be called whenever a station associates with the AP. It - * can be called from ieee802_11.c for drivers that export MLME to hostapd and - * from drv_callbacks.c based on driver events for drivers that take care of - * management frames (IEEE 802.11 authentication and association) internally. - */ -void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, - int reassoc) -{ - if (hapd->tkip_countermeasures) { - hostapd_drv_sta_deauth(hapd, sta->addr, - WLAN_REASON_MICHAEL_MIC_FAILURE); - return; - } - - hostapd_prune_associations(hapd, sta->addr); - - /* IEEE 802.11F (IAPP) */ - if (hapd->conf->ieee802_11f) - iapp_new_station(hapd->iapp, sta); - -#ifdef CONFIG_P2P - if (sta->p2p_ie == NULL && !sta->no_p2p_set) { - sta->no_p2p_set = 1; - hapd->num_sta_no_p2p++; - if (hapd->num_sta_no_p2p == 1) - hostapd_p2p_non_p2p_sta_connected(hapd); - } -#endif /* CONFIG_P2P */ - - /* Start accounting here, if IEEE 802.1X and WPA are not used. - * IEEE 802.1X/WPA code will start accounting after the station has - * been authorized. */ - if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) { - os_get_reltime(&sta->connected_time); - accounting_sta_start(hapd, sta); - } - - /* Start IEEE 802.1X authentication process for new stations */ - ieee802_1x_new_station(hapd, sta); - if (reassoc) { - if (sta->auth_alg != WLAN_AUTH_FT && - !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) - wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH); - } else - wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm); - - if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) { - wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " - "for " MACSTR " (%d seconds - ap_max_inactivity)", - __func__, MAC2STR(sta->addr), - hapd->conf->ap_max_inactivity); - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, - ap_handle_timer, hapd, sta); - } -} - - -const char * hostapd_state_text(enum hostapd_iface_state s) -{ - switch (s) { - case HAPD_IFACE_UNINITIALIZED: - return "UNINITIALIZED"; - case HAPD_IFACE_DISABLED: - return "DISABLED"; - case HAPD_IFACE_COUNTRY_UPDATE: - return "COUNTRY_UPDATE"; - case HAPD_IFACE_ACS: - return "ACS"; - case HAPD_IFACE_HT_SCAN: - return "HT_SCAN"; - case HAPD_IFACE_DFS: - return "DFS"; - case HAPD_IFACE_ENABLED: - return "ENABLED"; - } - - return "UNKNOWN"; -} - - -void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s) -{ - wpa_printf(MSG_INFO, "%s: interface state %s->%s", - iface->conf->bss[0]->iface, hostapd_state_text(iface->state), - hostapd_state_text(s)); - iface->state = s; -} - - -#ifdef NEED_AP_MLME - -static void free_beacon_data(struct beacon_data *beacon) -{ - os_free(beacon->head); - beacon->head = NULL; - os_free(beacon->tail); - beacon->tail = NULL; - os_free(beacon->probe_resp); - beacon->probe_resp = NULL; - os_free(beacon->beacon_ies); - beacon->beacon_ies = NULL; - os_free(beacon->proberesp_ies); - beacon->proberesp_ies = NULL; - os_free(beacon->assocresp_ies); - beacon->assocresp_ies = NULL; -} - - -static int hostapd_build_beacon_data(struct hostapd_iface *iface, - struct beacon_data *beacon) -{ - struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra; - struct wpa_driver_ap_params params; - int ret; - struct hostapd_data *hapd = iface->bss[0]; - - os_memset(beacon, 0, sizeof(*beacon)); - ret = ieee802_11_build_ap_params(hapd, ¶ms); - if (ret < 0) - return ret; - - ret = hostapd_build_ap_extra_ies(hapd, &beacon_extra, - &proberesp_extra, - &assocresp_extra); - if (ret) - goto free_ap_params; - - ret = -1; - beacon->head = os_malloc(params.head_len); - if (!beacon->head) - goto free_ap_extra_ies; - - os_memcpy(beacon->head, params.head, params.head_len); - beacon->head_len = params.head_len; - - beacon->tail = os_malloc(params.tail_len); - if (!beacon->tail) - goto free_beacon; - - os_memcpy(beacon->tail, params.tail, params.tail_len); - beacon->tail_len = params.tail_len; - - if (params.proberesp != NULL) { - beacon->probe_resp = os_malloc(params.proberesp_len); - if (!beacon->probe_resp) - goto free_beacon; - - os_memcpy(beacon->probe_resp, params.proberesp, - params.proberesp_len); - beacon->probe_resp_len = params.proberesp_len; - } - - /* copy the extra ies */ - if (beacon_extra) { - beacon->beacon_ies = os_malloc(wpabuf_len(beacon_extra)); - if (!beacon->beacon_ies) - goto free_beacon; - - os_memcpy(beacon->beacon_ies, - beacon_extra->buf, wpabuf_len(beacon_extra)); - beacon->beacon_ies_len = wpabuf_len(beacon_extra); - } - - if (proberesp_extra) { - beacon->proberesp_ies = - os_malloc(wpabuf_len(proberesp_extra)); - if (!beacon->proberesp_ies) - goto free_beacon; - - os_memcpy(beacon->proberesp_ies, proberesp_extra->buf, - wpabuf_len(proberesp_extra)); - beacon->proberesp_ies_len = wpabuf_len(proberesp_extra); - } - - if (assocresp_extra) { - beacon->assocresp_ies = - os_malloc(wpabuf_len(assocresp_extra)); - if (!beacon->assocresp_ies) - goto free_beacon; - - os_memcpy(beacon->assocresp_ies, assocresp_extra->buf, - wpabuf_len(assocresp_extra)); - beacon->assocresp_ies_len = wpabuf_len(assocresp_extra); - } - - ret = 0; -free_beacon: - /* if the function fails, the caller should not free beacon data */ - if (ret) - free_beacon_data(beacon); - -free_ap_extra_ies: - hostapd_free_ap_extra_ies(hapd, beacon_extra, proberesp_extra, - assocresp_extra); -free_ap_params: - ieee802_11_free_ap_params(¶ms); - return ret; -} - - -/* - * TODO: This flow currently supports only changing frequency within the - * same hw_mode. Any other changes to MAC parameters or provided settings (even - * width) are not supported. - */ -static int hostapd_change_config_freq(struct hostapd_data *hapd, - struct hostapd_config *conf, - struct hostapd_freq_params *params, - struct hostapd_freq_params *old_params) -{ - int channel; - - if (!params->channel) { - /* check if the new channel is supported by hw */ - channel = hostapd_hw_get_channel(hapd, params->freq); - if (!channel) - return -1; - } else { - channel = params->channel; - } - - /* if a pointer to old_params is provided we save previous state */ - if (old_params) { - old_params->channel = conf->channel; - old_params->ht_enabled = conf->ieee80211n; - old_params->sec_channel_offset = conf->secondary_channel; - } - - conf->channel = channel; - conf->ieee80211n = params->ht_enabled; - conf->secondary_channel = params->sec_channel_offset; - - /* TODO: maybe call here hostapd_config_check here? */ - - return 0; -} - - -static int hostapd_fill_csa_settings(struct hostapd_iface *iface, - struct csa_settings *settings) -{ - struct hostapd_freq_params old_freq; - int ret; - - os_memset(&old_freq, 0, sizeof(old_freq)); - if (!iface || !iface->freq || iface->csa_in_progress) - return -1; - - ret = hostapd_change_config_freq(iface->bss[0], iface->conf, - &settings->freq_params, - &old_freq); - if (ret) - return ret; - - ret = hostapd_build_beacon_data(iface, &settings->beacon_after); - - /* change back the configuration */ - hostapd_change_config_freq(iface->bss[0], iface->conf, - &old_freq, NULL); - - if (ret) - return ret; - - /* set channel switch parameters for csa ie */ - iface->cs_freq_params = settings->freq_params; - iface->cs_count = settings->cs_count; - iface->cs_block_tx = settings->block_tx; - - ret = hostapd_build_beacon_data(iface, &settings->beacon_csa); - if (ret) { - free_beacon_data(&settings->beacon_after); - return ret; - } - - settings->counter_offset_beacon = iface->cs_c_off_beacon; - settings->counter_offset_presp = iface->cs_c_off_proberesp; - - return 0; -} - - -void hostapd_cleanup_cs_params(struct hostapd_data *hapd) -{ - os_memset(&hapd->iface->cs_freq_params, 0, - sizeof(hapd->iface->cs_freq_params)); - hapd->iface->cs_count = 0; - hapd->iface->cs_block_tx = 0; - hapd->iface->cs_c_off_beacon = 0; - hapd->iface->cs_c_off_proberesp = 0; - hapd->iface->csa_in_progress = 0; -} - - -int hostapd_switch_channel(struct hostapd_data *hapd, - struct csa_settings *settings) -{ - int ret; - ret = hostapd_fill_csa_settings(hapd->iface, settings); - if (ret) - return ret; - - ret = hostapd_drv_switch_channel(hapd, settings); - free_beacon_data(&settings->beacon_csa); - free_beacon_data(&settings->beacon_after); - - if (ret) { - /* if we failed, clean cs parameters */ - hostapd_cleanup_cs_params(hapd); - return ret; - } - - hapd->iface->csa_in_progress = 1; - return 0; -} - -#endif /* NEED_AP_MLME */ diff --git a/contrib/hostapd/src/ap/hostapd.h b/contrib/hostapd/src/ap/hostapd.h deleted file mode 100644 index 489ab16527..0000000000 --- a/contrib/hostapd/src/ap/hostapd.h +++ /dev/null @@ -1,424 +0,0 @@ -/* - * hostapd / Initialization and configuration - * Copyright (c) 2002-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef HOSTAPD_H -#define HOSTAPD_H - -#include "common/defs.h" -#include "ap_config.h" -#include "drivers/driver.h" - -struct wpa_ctrl_dst; -struct radius_server_data; -struct upnp_wps_device_sm; -struct hostapd_data; -struct sta_info; -struct ieee80211_ht_capabilities; -struct full_dynamic_vlan; -enum wps_event; -union wps_event_data; - -struct hostapd_iface; -struct hostapd_dynamic_iface; - -struct hapd_interfaces { - int (*reload_config)(struct hostapd_iface *iface); - struct hostapd_config * (*config_read_cb)(const char *config_fname); - int (*ctrl_iface_init)(struct hostapd_data *hapd); - void (*ctrl_iface_deinit)(struct hostapd_data *hapd); - int (*for_each_interface)(struct hapd_interfaces *interfaces, - int (*cb)(struct hostapd_iface *iface, - void *ctx), void *ctx); - int (*driver_init)(struct hostapd_iface *iface); - - size_t count; - size_t count_dynamic; - int global_ctrl_sock; - char *global_iface_path; - char *global_iface_name; -#ifndef CONFIG_NATIVE_WINDOWS - gid_t ctrl_iface_group; -#endif /* CONFIG_NATIVE_WINDOWS */ - struct hostapd_iface **iface; - struct hostapd_dynamic_iface **dynamic_iface; - - size_t terminate_on_error; -}; - -enum hostapd_chan_status { - HOSTAPD_CHAN_VALID = 0, /* channel is ready */ - HOSTAPD_CHAN_INVALID = 1, /* no usable channel found */ - HOSTAPD_CHAN_ACS = 2, /* ACS work being performed */ -}; - -struct hostapd_probereq_cb { - int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid, - const u8 *ie, size_t ie_len, int ssi_signal); - void *ctx; -}; - -#define HOSTAPD_RATE_BASIC 0x00000001 - -struct hostapd_rate_data { - int rate; /* rate in 100 kbps */ - int flags; /* HOSTAPD_RATE_ flags */ -}; - -struct hostapd_frame_info { - u32 channel; - u32 datarate; - int ssi_signal; /* dBm */ -}; - -enum wps_status { - WPS_STATUS_SUCCESS = 1, - WPS_STATUS_FAILURE -}; - -enum pbc_status { - WPS_PBC_STATUS_DISABLE, - WPS_PBC_STATUS_ACTIVE, - WPS_PBC_STATUS_TIMEOUT, - WPS_PBC_STATUS_OVERLAP -}; - -struct wps_stat { - enum wps_status status; - enum wps_error_indication failure_reason; - enum pbc_status pbc_status; - u8 peer_addr[ETH_ALEN]; -}; - - -/** - * struct hostapd_data - hostapd per-BSS data structure - */ -struct hostapd_data { - struct hostapd_iface *iface; - struct hostapd_config *iconf; - struct hostapd_bss_config *conf; - int interface_added; /* virtual interface added for this BSS */ - unsigned int started:1; - - u8 own_addr[ETH_ALEN]; - - int num_sta; /* number of entries in sta_list */ - struct sta_info *sta_list; /* STA info list head */ -#define STA_HASH_SIZE 256 -#define STA_HASH(sta) (sta[5]) - struct sta_info *sta_hash[STA_HASH_SIZE]; - - /* - * Bitfield for indicating which AIDs are allocated. Only AID values - * 1-2007 are used and as such, the bit at index 0 corresponds to AID - * 1. - */ -#define AID_WORDS ((2008 + 31) / 32) - u32 sta_aid[AID_WORDS]; - - const struct wpa_driver_ops *driver; - void *drv_priv; - - void (*new_assoc_sta_cb)(struct hostapd_data *hapd, - struct sta_info *sta, int reassoc); - - void *msg_ctx; /* ctx for wpa_msg() calls */ - 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; - struct radius_das_data *radius_das; - - struct iapp_data *iapp; - - struct hostapd_cached_radius_acl *acl_cache; - struct hostapd_acl_query_data *acl_queries; - - struct wpa_authenticator *wpa_auth; - struct eapol_authenticator *eapol_auth; - - struct rsn_preauth_interface *preauth_iface; - struct os_reltime michael_mic_failure; - int michael_mic_failures; - int tkip_countermeasures; - - int ctrl_sock; - struct wpa_ctrl_dst *ctrl_dst; - - void *ssl_ctx; - void *eap_sim_db_priv; - struct radius_server_data *radius_srv; - - 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 */ - - 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 - unsigned int ap_pin_failures; - unsigned int ap_pin_failures_consecutive; - struct upnp_wps_device_sm *wps_upnp; - unsigned int ap_pin_lockout_time; - - struct wps_stat wps_stats; -#endif /* CONFIG_WPS */ - - struct hostapd_probereq_cb *probereq_cb; - size_t num_probereq_cb; - - void (*public_action_cb)(void *ctx, const u8 *buf, size_t len, - int freq); - void *public_action_cb_ctx; - void (*public_action_cb2)(void *ctx, const u8 *buf, size_t len, - int freq); - void *public_action_cb2_ctx; - - int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len, - int freq); - void *vendor_action_cb_ctx; - - void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr, - const u8 *uuid_e); - void *wps_reg_success_cb_ctx; - - void (*wps_event_cb)(void *ctx, enum wps_event event, - union wps_event_data *data); - void *wps_event_cb_ctx; - - void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr, - int authorized, const u8 *p2p_dev_addr); - void *sta_authorized_cb_ctx; - - void (*setup_complete_cb)(void *ctx); - void *setup_complete_cb_ctx; - - void (*new_psk_cb)(void *ctx, const u8 *mac_addr, - const u8 *p2p_dev_addr, const u8 *psk, - size_t psk_len); - void *new_psk_cb_ctx; - -#ifdef CONFIG_P2P - struct p2p_data *p2p; - struct p2p_group *p2p_group; - struct wpabuf *p2p_beacon_ie; - struct wpabuf *p2p_probe_resp_ie; - - /* Number of non-P2P association stations */ - int num_sta_no_p2p; - - /* Periodic NoA (used only when no non-P2P clients in the group) */ - int noa_enabled; - int noa_start; - int noa_duration; -#endif /* CONFIG_P2P */ -#ifdef CONFIG_INTERWORKING - size_t gas_frag_limit; -#endif /* CONFIG_INTERWORKING */ - -#ifdef CONFIG_SQLITE - struct hostapd_eap_user tmp_eap_user; -#endif /* CONFIG_SQLITE */ - -#ifdef CONFIG_SAE - /** Key used for generating SAE anti-clogging tokens */ - u8 sae_token_key[8]; - struct os_reltime last_sae_token_key_update; -#endif /* CONFIG_SAE */ - -#ifdef CONFIG_TESTING_OPTIONS - int ext_mgmt_frame_handling; -#endif /* CONFIG_TESTING_OPTIONS */ -}; - - -/** - * struct hostapd_iface - hostapd per-interface data structure - */ -struct hostapd_iface { - struct hapd_interfaces *interfaces; - void *owner; - char *config_fname; - struct hostapd_config *conf; - char phy[16]; /* Name of the PHY (radio) */ - - enum hostapd_iface_state { - HAPD_IFACE_UNINITIALIZED, - HAPD_IFACE_DISABLED, - HAPD_IFACE_COUNTRY_UPDATE, - HAPD_IFACE_ACS, - HAPD_IFACE_HT_SCAN, - HAPD_IFACE_DFS, - HAPD_IFACE_ENABLED - } state; - - size_t num_bss; - struct hostapd_data **bss; - - unsigned int wait_channel_update:1; - unsigned int cac_started:1; - - int num_ap; /* number of entries in ap_list */ - struct ap_info *ap_list; /* AP info list head */ - struct ap_info *ap_hash[STA_HASH_SIZE]; - - 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; - - /* extended capabilities supported by the driver */ - const u8 *extended_capa, *extended_capa_mask; - unsigned int extended_capa_len; - - unsigned int drv_max_acl_mac_addrs; - - struct hostapd_hw_modes *hw_features; - int num_hw_features; - struct hostapd_hw_modes *current_mode; - /* Rates that are currently used (i.e., filtered copy of - * current_mode->channels */ - int num_rates; - struct hostapd_rate_data *current_rates; - int *basic_rates; - int freq; - - u16 hw_flags; - - /* Number of associated Non-ERP stations (i.e., stations using 802.11b - * in 802.11g BSS) */ - int num_sta_non_erp; - - /* Number of associated stations that do not support Short Slot Time */ - int num_sta_no_short_slot_time; - - /* Number of associated stations that do not support Short Preamble */ - int num_sta_no_short_preamble; - - int olbc; /* Overlapping Legacy BSS Condition */ - - /* Number of HT associated stations that do not support greenfield */ - int num_sta_ht_no_gf; - - /* Number of associated non-HT stations */ - int num_sta_no_ht; - - /* Number of HT associated stations 20 MHz */ - int num_sta_ht_20mhz; - - /* Overlapping BSS information */ - int olbc_ht; - - u16 ht_op_mode; - - /* surveying helpers */ - - /* number of channels surveyed */ - unsigned int chans_surveyed; - - /* lowest observed noise floor in dBm */ - s8 lowest_nf; - - /* channel switch parameters */ - struct hostapd_freq_params cs_freq_params; - u8 cs_count; - int cs_block_tx; - unsigned int cs_c_off_beacon; - unsigned int cs_c_off_proberesp; - int csa_in_progress; - -#ifdef CONFIG_ACS - unsigned int acs_num_completed_scans; -#endif /* CONFIG_ACS */ - - void (*scan_cb)(struct hostapd_iface *iface); -}; - -/** - * struct hostapd_dynamic_iface - hostapd per dynamically allocated - * or added interface data structure - */ -struct hostapd_dynamic_iface { - char parent[IFNAMSIZ + 1]; - char iface[IFNAMSIZ + 1]; - unsigned int usage; -}; - -/* hostapd.c */ -int hostapd_for_each_interface(struct hapd_interfaces *interfaces, - int (*cb)(struct hostapd_iface *iface, - void *ctx), void *ctx); -int hostapd_reload_config(struct hostapd_iface *iface); -struct hostapd_data * -hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, - struct hostapd_config *conf, - struct hostapd_bss_config *bss); -int hostapd_setup_interface(struct hostapd_iface *iface); -int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err); -void hostapd_interface_deinit(struct hostapd_iface *iface); -void hostapd_interface_free(struct hostapd_iface *iface); -struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces, - const char *config_file); -struct hostapd_iface * -hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy, - const char *config_fname, int debug); -void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, - int reassoc); -void hostapd_interface_deinit_free(struct hostapd_iface *iface); -int hostapd_enable_iface(struct hostapd_iface *hapd_iface); -int hostapd_reload_iface(struct hostapd_iface *hapd_iface); -int hostapd_disable_iface(struct hostapd_iface *hapd_iface); -int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf); -int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf); -void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator); -void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s); -const char * hostapd_state_text(enum hostapd_iface_state s); -int hostapd_switch_channel(struct hostapd_data *hapd, - struct csa_settings *settings); -void hostapd_cleanup_cs_params(struct hostapd_data *hapd); - -/* 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, - int ssi_signal), - void *ctx); -void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr); - -/* drv_callbacks.c (TODO: move to somewhere else?) */ -int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, - const u8 *ie, size_t ielen, int reassoc); -void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr); -void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr); -void hostapd_event_connect_failed_reason(struct hostapd_data *hapd, - const u8 *addr, int reason_code); -int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, - const u8 *bssid, const u8 *ie, size_t ie_len, - int ssi_signal); -void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, - int offset, int width, int cf1, int cf2); - -const struct hostapd_eap_user * -hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, - size_t identity_len, int phase2); - -#endif /* HOSTAPD_H */ diff --git a/contrib/hostapd/src/ap/hs20.c b/contrib/hostapd/src/ap/hs20.c deleted file mode 100644 index 45d518bc1e..0000000000 --- a/contrib/hostapd/src/ap/hs20.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Hotspot 2.0 AP ANQP processing - * Copyright (c) 2009, Atheros Communications, Inc. - * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "common/ieee802_11_defs.h" -#include "hostapd.h" -#include "ap_config.h" -#include "hs20.h" - - -u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid) -{ - if (!hapd->conf->hs20) - return eid; - *eid++ = WLAN_EID_VENDOR_SPECIFIC; - *eid++ = 5; - WPA_PUT_BE24(eid, OUI_WFA); - eid += 3; - *eid++ = HS20_INDICATION_OUI_TYPE; - /* Hotspot Configuration: DGAF Enabled */ - *eid++ = hapd->conf->disable_dgaf ? 0x01 : 0x00; - return eid; -} diff --git a/contrib/hostapd/src/ap/hs20.h b/contrib/hostapd/src/ap/hs20.h deleted file mode 100644 index 98698ce2fd..0000000000 --- a/contrib/hostapd/src/ap/hs20.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Hotspot 2.0 AP ANQP processing - * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef HS20_H -#define HS20_H - -struct hostapd_data; - -u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid); - -#endif /* HS20_H */ diff --git a/contrib/hostapd/src/ap/hw_features.c b/contrib/hostapd/src/ap/hw_features.c deleted file mode 100644 index 4e66379572..0000000000 --- a/contrib/hostapd/src/ap/hw_features.c +++ /dev/null @@ -1,1031 +0,0 @@ -/* - * hostapd / Hardware feature query and different modes - * Copyright 2002-2003, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * Copyright (c) 2008-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "common/wpa_ctrl.h" -#include "hostapd.h" -#include "ap_config.h" -#include "ap_drv_ops.h" -#include "acs.h" -#include "hw_features.h" - - -void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, - size_t num_hw_features) -{ - size_t i; - - if (hw_features == NULL) - return; - - for (i = 0; i < num_hw_features; i++) { - os_free(hw_features[i].channels); - os_free(hw_features[i].rates); - } - - os_free(hw_features); -} - - -#ifndef CONFIG_NO_STDOUT_DEBUG -static char * dfs_info(struct hostapd_channel_data *chan) -{ - static char info[256]; - char *state; - - switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) { - case HOSTAPD_CHAN_DFS_UNKNOWN: - state = "unknown"; - break; - case HOSTAPD_CHAN_DFS_USABLE: - state = "usable"; - break; - case HOSTAPD_CHAN_DFS_UNAVAILABLE: - state = "unavailable"; - break; - case HOSTAPD_CHAN_DFS_AVAILABLE: - state = "available"; - break; - default: - return ""; - } - os_snprintf(info, sizeof(info), " (DFS state = %s)", state); - info[sizeof(info) - 1] = '\0'; - - return info; -} -#endif /* CONFIG_NO_STDOUT_DEBUG */ - - -int hostapd_get_hw_features(struct hostapd_iface *iface) -{ - struct hostapd_data *hapd = iface->bss[0]; - int ret = 0, i, j; - u16 num_modes, flags; - struct hostapd_hw_modes *modes; - - if (hostapd_drv_none(hapd)) - return -1; - modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags); - if (modes == NULL) { - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "Fetching hardware channel/rate support not " - "supported."); - return -1; - } - - iface->hw_flags = flags; - - hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); - iface->hw_features = modes; - iface->num_hw_features = num_modes; - - for (i = 0; i < num_modes; i++) { - struct hostapd_hw_modes *feature = &modes[i]; - int dfs_enabled = hapd->iconf->ieee80211h && - (iface->drv_flags & WPA_DRIVER_FLAGS_RADAR); - - /* set flag for channels we can use in current regulatory - * domain */ - for (j = 0; j < feature->num_channels; j++) { - int dfs = 0; - - /* - * Disable all channels that are marked not to allow - * IBSS operation or active scanning. - * Use radar channels only if the driver supports DFS. - */ - if ((feature->channels[j].flag & - HOSTAPD_CHAN_RADAR) && dfs_enabled) { - dfs = 1; - } else if (feature->channels[j].flag & - (HOSTAPD_CHAN_NO_IBSS | - HOSTAPD_CHAN_PASSIVE_SCAN | - HOSTAPD_CHAN_RADAR)) { - feature->channels[j].flag |= - HOSTAPD_CHAN_DISABLED; - } - - if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED) - continue; - - wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d " - "chan=%d freq=%d MHz max_tx_power=%d dBm%s", - feature->mode, - feature->channels[j].chan, - feature->channels[j].freq, - feature->channels[j].max_tx_power, - dfs ? dfs_info(&feature->channels[j]) : ""); - } - } - - return ret; -} - - -int hostapd_prepare_rates(struct hostapd_iface *iface, - struct hostapd_hw_modes *mode) -{ - int i, num_basic_rates = 0; - int basic_rates_a[] = { 60, 120, 240, -1 }; - int basic_rates_b[] = { 10, 20, -1 }; - int basic_rates_g[] = { 10, 20, 55, 110, -1 }; - int *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; - break; - case HOSTAPD_MODE_IEEE80211B: - basic_rates = basic_rates_b; - break; - case HOSTAPD_MODE_IEEE80211G: - basic_rates = basic_rates_g; - break; - case HOSTAPD_MODE_IEEE80211AD: - return 0; /* No basic rates for 11ad */ - default: - return -1; - } - - i = 0; - while (basic_rates[i] >= 0) - i++; - if (i) - i++; /* -1 termination */ - 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(iface->current_rates); - iface->num_rates = 0; - - iface->current_rates = - os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data)); - if (!iface->current_rates) { - wpa_printf(MSG_ERROR, "Failed to allocate memory for rate " - "table."); - return -1; - } - - for (i = 0; i < mode->num_rates; i++) { - struct hostapd_rate_data *rate; - - if (iface->conf->supported_rates && - !hostapd_rate_found(iface->conf->supported_rates, - mode->rates[i])) - continue; - - 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", - iface->num_rates, rate->rate, rate->flags); - iface->num_rates++; - } - - 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).", - iface->num_rates, num_basic_rates); - return -1; - } - - return 0; -} - - -#ifdef CONFIG_IEEE80211N -static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface) -{ - int sec_chan, ok, j, first; - int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, - 184, 192 }; - size_t k; - - if (!iface->conf->secondary_channel) - return 1; /* HT40 not used */ - - sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4; - wpa_printf(MSG_DEBUG, "HT40: control channel: %d " - "secondary channel: %d", - iface->conf->channel, sec_chan); - - /* Verify that HT40 secondary channel is an allowed 20 MHz - * channel */ - ok = 0; - for (j = 0; j < iface->current_mode->num_channels; j++) { - struct hostapd_channel_data *chan = - &iface->current_mode->channels[j]; - if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && - chan->chan == sec_chan) { - ok = 1; - break; - } - } - if (!ok) { - wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed", - sec_chan); - return 0; - } - - /* - * Verify that HT40 primary,secondary channel pair is allowed per - * IEEE 802.11n Annex J. This is only needed for 5 GHz band since - * 2.4 GHz rules allow all cases where the secondary channel fits into - * the list of allowed channels (already checked above). - */ - if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) - return 1; - - if (iface->conf->secondary_channel > 0) - first = iface->conf->channel; - else - first = sec_chan; - - ok = 0; - for (k = 0; k < ARRAY_SIZE(allowed); k++) { - if (first == allowed[k]) { - ok = 1; - break; - } - } - if (!ok) { - wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed", - iface->conf->channel, - iface->conf->secondary_channel); - return 0; - } - - return 1; -} - - -static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface) -{ - if (iface->conf->secondary_channel > 0) { - iface->conf->channel += 4; - iface->conf->secondary_channel = -1; - } else { - iface->conf->channel -= 4; - iface->conf->secondary_channel = 1; - } -} - - -static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss, - int *pri_chan, int *sec_chan) -{ - struct ieee80211_ht_operation *oper; - struct ieee802_11_elems elems; - - *pri_chan = *sec_chan = 0; - - ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); - if (elems.ht_operation && - elems.ht_operation_len >= sizeof(*oper)) { - oper = (struct ieee80211_ht_operation *) elems.ht_operation; - *pri_chan = oper->control_chan; - if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) { - int sec = oper->ht_param & - HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; - if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) - *sec_chan = *pri_chan + 4; - else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) - *sec_chan = *pri_chan - 4; - } - } -} - - -static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, - struct wpa_scan_results *scan_res) -{ - int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss; - int bss_pri_chan, bss_sec_chan; - size_t i; - int match; - - pri_chan = iface->conf->channel; - sec_chan = iface->conf->secondary_channel * 4; - pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan); - if (iface->conf->secondary_channel > 0) - sec_freq = pri_freq + 20; - else - sec_freq = pri_freq - 20; - - /* - * Switch PRI/SEC channels if Beacons were detected on selected SEC - * channel, but not on selected PRI channel. - */ - pri_bss = sec_bss = 0; - for (i = 0; i < scan_res->num; i++) { - struct wpa_scan_res *bss = scan_res->res[i]; - if (bss->freq == pri_freq) - pri_bss++; - else if (bss->freq == sec_freq) - sec_bss++; - } - if (sec_bss && !pri_bss) { - wpa_printf(MSG_INFO, "Switch own primary and secondary " - "channel to get secondary channel with no Beacons " - "from other BSSes"); - ieee80211n_switch_pri_sec(iface); - } - - /* - * Match PRI/SEC channel with any existing HT40 BSS on the same - * channels that we are about to use (if already mixed order in - * existing BSSes, use own preference). - */ - match = 0; - for (i = 0; i < scan_res->num; i++) { - struct wpa_scan_res *bss = scan_res->res[i]; - ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); - if (pri_chan == bss_pri_chan && - sec_chan == bss_sec_chan) { - match = 1; - break; - } - } - if (!match) { - for (i = 0; i < scan_res->num; i++) { - struct wpa_scan_res *bss = scan_res->res[i]; - ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, - &bss_sec_chan); - if (pri_chan == bss_sec_chan && - sec_chan == bss_pri_chan) { - wpa_printf(MSG_INFO, "Switch own primary and " - "secondary channel due to BSS " - "overlap with " MACSTR, - MAC2STR(bss->bssid)); - ieee80211n_switch_pri_sec(iface); - break; - } - } - } - - return 1; -} - - -static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, - struct wpa_scan_results *scan_res) -{ - int pri_freq, sec_freq; - int affected_start, affected_end; - size_t i; - - pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); - if (iface->conf->secondary_channel > 0) - sec_freq = pri_freq + 20; - else - sec_freq = pri_freq - 20; - affected_start = (pri_freq + sec_freq) / 2 - 25; - affected_end = (pri_freq + sec_freq) / 2 + 25; - wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", - affected_start, affected_end); - for (i = 0; i < scan_res->num; i++) { - struct wpa_scan_res *bss = scan_res->res[i]; - int pri = bss->freq; - int sec = pri; - int sec_chan, pri_chan; - - ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan); - - if (sec_chan) { - if (sec_chan < pri_chan) - sec = pri - 20; - else - sec = pri + 20; - } - - if ((pri < affected_start || pri > affected_end) && - (sec < affected_start || sec > affected_end)) - continue; /* not within affected channel range */ - - wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR - " freq=%d pri=%d sec=%d", - MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); - - if (sec_chan) { - if (pri_freq != pri || sec_freq != sec) { - wpa_printf(MSG_DEBUG, "40 MHz pri/sec " - "mismatch with BSS " MACSTR - " <%d,%d> (chan=%d%c) vs. <%d,%d>", - MAC2STR(bss->bssid), - pri, sec, pri_chan, - sec > pri ? '+' : '-', - pri_freq, sec_freq); - return 0; - } - } - - /* TODO: 40 MHz intolerant */ - } - - return 1; -} - - -static void ieee80211n_check_scan(struct hostapd_iface *iface) -{ - struct wpa_scan_results *scan_res; - int oper40; - int res; - - /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is - * allowed per IEEE Std 802.11-2012, 10.15.3.2 */ - - iface->scan_cb = NULL; - - scan_res = hostapd_driver_get_scan_results(iface->bss[0]); - if (scan_res == NULL) { - hostapd_setup_interface_complete(iface, 1); - return; - } - - if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A) - oper40 = ieee80211n_check_40mhz_5g(iface, scan_res); - else - oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res); - wpa_scan_results_free(scan_res); - - if (!oper40) { - wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on " - "channel pri=%d sec=%d based on overlapping BSSes", - iface->conf->channel, - iface->conf->channel + - iface->conf->secondary_channel * 4); - iface->conf->secondary_channel = 0; - } - - res = ieee80211n_allowed_ht40_channel_pair(iface); - hostapd_setup_interface_complete(iface, !res); -} - - -static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface, - struct wpa_driver_scan_params *params) -{ - /* Scan only the affected frequency range */ - int pri_freq, sec_freq; - int affected_start, affected_end; - int i, pos; - struct hostapd_hw_modes *mode; - - if (iface->current_mode == NULL) - return; - - pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); - if (iface->conf->secondary_channel > 0) - sec_freq = pri_freq + 20; - else - sec_freq = pri_freq - 20; - affected_start = (pri_freq + sec_freq) / 2 - 25; - affected_end = (pri_freq + sec_freq) / 2 + 25; - wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", - affected_start, affected_end); - - mode = iface->current_mode; - params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); - if (params->freqs == NULL) - return; - pos = 0; - - for (i = 0; i < mode->num_channels; i++) { - struct hostapd_channel_data *chan = &mode->channels[i]; - if (chan->flag & HOSTAPD_CHAN_DISABLED) - continue; - if (chan->freq < affected_start || - chan->freq > affected_end) - continue; - params->freqs[pos++] = chan->freq; - } -} - - -static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface, - struct wpa_driver_scan_params *params) -{ - /* Scan only the affected frequency range */ - int pri_freq; - int affected_start, affected_end; - int i, pos; - struct hostapd_hw_modes *mode; - - if (iface->current_mode == NULL) - return; - - pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); - if (iface->conf->secondary_channel > 0) { - affected_start = pri_freq - 10; - affected_end = pri_freq + 30; - } else { - affected_start = pri_freq - 30; - affected_end = pri_freq + 10; - } - wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", - affected_start, affected_end); - - mode = iface->current_mode; - params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); - if (params->freqs == NULL) - return; - pos = 0; - - for (i = 0; i < mode->num_channels; i++) { - struct hostapd_channel_data *chan = &mode->channels[i]; - if (chan->flag & HOSTAPD_CHAN_DISABLED) - continue; - if (chan->freq < affected_start || - chan->freq > affected_end) - continue; - params->freqs[pos++] = chan->freq; - } -} - - -static int ieee80211n_check_40mhz(struct hostapd_iface *iface) -{ - struct wpa_driver_scan_params params; - - if (!iface->conf->secondary_channel) - return 0; /* HT40 not used */ - - hostapd_set_state(iface, HAPD_IFACE_HT_SCAN); - wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " - "40 MHz channel"); - os_memset(¶ms, 0, sizeof(params)); - if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) - ieee80211n_scan_channels_2g4(iface, ¶ms); - else - ieee80211n_scan_channels_5g(iface, ¶ms); - if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) { - wpa_printf(MSG_ERROR, "Failed to request a scan of " - "neighboring BSSes"); - os_free(params.freqs); - return -1; - } - os_free(params.freqs); - - iface->scan_cb = ieee80211n_check_scan; - return 1; -} - - -static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) -{ - u16 hw = iface->current_mode->ht_capab; - u16 conf = iface->conf->ht_capab; - - if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) && - !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) { - wpa_printf(MSG_ERROR, "Driver does not support configured " - "HT capability [LDPC]"); - return 0; - } - - if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && - !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { - wpa_printf(MSG_ERROR, "Driver does not support configured " - "HT capability [HT40*]"); - return 0; - } - - if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) && - (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) { - wpa_printf(MSG_ERROR, "Driver does not support configured " - "HT capability [SMPS-*]"); - return 0; - } - - if ((conf & HT_CAP_INFO_GREEN_FIELD) && - !(hw & HT_CAP_INFO_GREEN_FIELD)) { - wpa_printf(MSG_ERROR, "Driver does not support configured " - "HT capability [GF]"); - return 0; - } - - if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) && - !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) { - wpa_printf(MSG_ERROR, "Driver does not support configured " - "HT capability [SHORT-GI-20]"); - return 0; - } - - if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) && - !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) { - wpa_printf(MSG_ERROR, "Driver does not support configured " - "HT capability [SHORT-GI-40]"); - return 0; - } - - if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) { - wpa_printf(MSG_ERROR, "Driver does not support configured " - "HT capability [TX-STBC]"); - return 0; - } - - if ((conf & HT_CAP_INFO_RX_STBC_MASK) > - (hw & HT_CAP_INFO_RX_STBC_MASK)) { - wpa_printf(MSG_ERROR, "Driver does not support configured " - "HT capability [RX-STBC*]"); - return 0; - } - - if ((conf & HT_CAP_INFO_DELAYED_BA) && - !(hw & HT_CAP_INFO_DELAYED_BA)) { - wpa_printf(MSG_ERROR, "Driver does not support configured " - "HT capability [DELAYED-BA]"); - return 0; - } - - if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) && - !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) { - wpa_printf(MSG_ERROR, "Driver does not support configured " - "HT capability [MAX-AMSDU-7935]"); - return 0; - } - - if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) && - !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) { - wpa_printf(MSG_ERROR, "Driver does not support configured " - "HT capability [DSSS_CCK-40]"); - return 0; - } - - if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) { - wpa_printf(MSG_ERROR, "Driver does not support configured " - "HT capability [PSMP]"); - return 0; - } - - if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) && - !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) { - wpa_printf(MSG_ERROR, "Driver does not support configured " - "HT capability [LSIG-TXOP-PROT]"); - return 0; - } - - return 1; -} - - -#ifdef CONFIG_IEEE80211AC - -static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name) -{ - u32 req_cap = conf & cap; - - /* - * Make sure we support all requested capabilities. - * NOTE: We assume that 'cap' represents a capability mask, - * not a discrete value. - */ - if ((hw & req_cap) != req_cap) { - wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]", - name); - return 0; - } - return 1; -} - - -static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 cap, - const char *name) -{ - u32 hw_max = hw & cap; - u32 conf_val = conf & cap; - - if (conf_val > hw_max) { - int offset = find_first_bit(cap); - wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)", - name, conf_val >> offset, hw_max >> offset); - return 0; - } - return 1; -} - - -static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface) -{ - u32 hw = iface->current_mode->vht_capab; - u32 conf = iface->conf->vht_capab; - - wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x", - hw, conf); - -#define VHT_CAP_CHECK(cap) \ - do { \ - if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \ - return 0; \ - } while (0) - -#define VHT_CAP_CHECK_MAX(cap) \ - do { \ - if (!ieee80211ac_cap_check_max(hw, conf, cap, #cap)) \ - return 0; \ - } while (0) - - VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK); - VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ); - VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ); - VHT_CAP_CHECK(VHT_CAP_RXLDPC); - VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80); - VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160); - VHT_CAP_CHECK(VHT_CAP_TXSTBC); - VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK); - VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE); - VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE); - VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX); - VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX); - VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE); - VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE); - VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS); - VHT_CAP_CHECK(VHT_CAP_HTC_VHT); - VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT); - VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB); - VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB); - VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN); - VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN); - -#undef VHT_CAP_CHECK -#undef VHT_CAP_CHECK_MAX - - return 1; -} -#endif /* CONFIG_IEEE80211AC */ - -#endif /* CONFIG_IEEE80211N */ - - -int hostapd_check_ht_capab(struct hostapd_iface *iface) -{ -#ifdef CONFIG_IEEE80211N - int ret; - if (!iface->conf->ieee80211n) - return 0; - if (!ieee80211n_supported_ht_capab(iface)) - return -1; -#ifdef CONFIG_IEEE80211AC - if (!ieee80211ac_supported_vht_capab(iface)) - return -1; -#endif /* CONFIG_IEEE80211AC */ - ret = ieee80211n_check_40mhz(iface); - if (ret) - return ret; - if (!ieee80211n_allowed_ht40_channel_pair(iface)) - return -1; -#endif /* CONFIG_IEEE80211N */ - - return 0; -} - - -static int hostapd_is_usable_chan(struct hostapd_iface *iface, - int channel, int primary) -{ - int i; - struct hostapd_channel_data *chan; - - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - if (chan->chan != channel) - continue; - - if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) - return 1; - - wpa_printf(MSG_DEBUG, - "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s%s", - primary ? "" : "Configured HT40 secondary ", - i, 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" : ""); - } - - return 0; -} - - -static int hostapd_is_usable_chans(struct hostapd_iface *iface) -{ - if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1)) - return 0; - - if (!iface->conf->secondary_channel) - return 1; - - return hostapd_is_usable_chan(iface, iface->conf->channel + - iface->conf->secondary_channel * 4, 0); -} - - -static enum hostapd_chan_status -hostapd_check_chans(struct hostapd_iface *iface) -{ - if (iface->conf->channel) { - if (hostapd_is_usable_chans(iface)) - return HOSTAPD_CHAN_VALID; - else - return HOSTAPD_CHAN_INVALID; - } - - /* - * The user set channel=0 or channel=acs_survey - * which is used to trigger ACS. - */ - - switch (acs_init(iface)) { - case HOSTAPD_CHAN_ACS: - return HOSTAPD_CHAN_ACS; - case HOSTAPD_CHAN_VALID: - case HOSTAPD_CHAN_INVALID: - default: - return HOSTAPD_CHAN_INVALID; - } -} - - -static void hostapd_notify_bad_chans(struct hostapd_iface *iface) -{ - hostapd_logger(iface->bss[0], NULL, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_WARNING, - "Configured channel (%d) not found from the " - "channel list of current mode (%d) %s", - iface->conf->channel, - iface->current_mode->mode, - hostapd_hw_mode_txt(iface->current_mode->mode)); - hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_WARNING, - "Hardware does not support configured channel"); -} - - -int hostapd_acs_completed(struct hostapd_iface *iface, int err) -{ - int ret = -1; - - if (err) - goto out; - - switch (hostapd_check_chans(iface)) { - case HOSTAPD_CHAN_VALID: - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, - ACS_EVENT_COMPLETED "freq=%d channel=%d", - hostapd_hw_get_freq(iface->bss[0], - iface->conf->channel), - iface->conf->channel); - break; - case HOSTAPD_CHAN_ACS: - wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available"); - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED); - hostapd_notify_bad_chans(iface); - goto out; - case HOSTAPD_CHAN_INVALID: - default: - wpa_printf(MSG_ERROR, "ACS picked unusable channels"); - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED); - hostapd_notify_bad_chans(iface); - goto out; - } - - ret = hostapd_check_ht_capab(iface); - if (ret < 0) - goto out; - if (ret == 1) { - wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback"); - return 0; - } - - ret = 0; -out: - return hostapd_setup_interface_complete(iface, ret); -} - - -/** - * hostapd_select_hw_mode - Select the hardware mode - * @iface: Pointer to interface data. - * Returns: 0 on success, < 0 on failure - * - * Sets up the hardware mode, channel, rates, and passive scanning - * based on the configuration. - */ -int hostapd_select_hw_mode(struct hostapd_iface *iface) -{ - int i; - - if (iface->num_hw_features < 1) - return -1; - - iface->current_mode = NULL; - for (i = 0; i < iface->num_hw_features; i++) { - struct hostapd_hw_modes *mode = &iface->hw_features[i]; - if (mode->mode == iface->conf->hw_mode) { - iface->current_mode = mode; - break; - } - } - - if (iface->current_mode == NULL) { - wpa_printf(MSG_ERROR, "Hardware does not support configured " - "mode"); - hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_WARNING, - "Hardware does not support configured mode " - "(%d) (hw_mode in hostapd.conf)", - (int) iface->conf->hw_mode); - return -2; - } - - switch (hostapd_check_chans(iface)) { - case HOSTAPD_CHAN_VALID: - return 0; - case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */ - return 1; - case HOSTAPD_CHAN_INVALID: - default: - hostapd_notify_bad_chans(iface); - return -3; - } - - return 0; -} - - -const char * hostapd_hw_mode_txt(int mode) -{ - switch (mode) { - case HOSTAPD_MODE_IEEE80211A: - return "IEEE 802.11a"; - case HOSTAPD_MODE_IEEE80211B: - return "IEEE 802.11b"; - case HOSTAPD_MODE_IEEE80211G: - return "IEEE 802.11g"; - case HOSTAPD_MODE_IEEE80211AD: - return "IEEE 802.11ad"; - default: - return "UNKNOWN"; - } -} - - -int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) -{ - int i; - - if (!hapd->iface->current_mode) - return 0; - - for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { - struct hostapd_channel_data *ch = - &hapd->iface->current_mode->channels[i]; - if (ch->chan == chan) - return ch->freq; - } - - return 0; -} - - -int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) -{ - int i; - - if (!hapd->iface->current_mode) - return 0; - - for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { - struct hostapd_channel_data *ch = - &hapd->iface->current_mode->channels[i]; - if (ch->freq == freq) - return ch->chan; - } - - return 0; -} diff --git a/contrib/hostapd/src/ap/hw_features.h b/contrib/hostapd/src/ap/hw_features.h deleted file mode 100644 index 783ae5e126..0000000000 --- a/contrib/hostapd/src/ap/hw_features.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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 - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef HW_FEATURES_H -#define HW_FEATURES_H - -#ifdef NEED_AP_MLME -void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, - size_t num_hw_features); -int hostapd_get_hw_features(struct hostapd_iface *iface); -int hostapd_acs_completed(struct hostapd_iface *iface, int err); -int hostapd_select_hw_mode(struct hostapd_iface *iface); -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_iface *iface, - struct hostapd_hw_modes *mode); -#else /* NEED_AP_MLME */ -static inline void -hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, - size_t num_hw_features) -{ -} - -static inline int hostapd_get_hw_features(struct hostapd_iface *iface) -{ - return -1; -} - -static inline int hostapd_select_hw_mode(struct hostapd_iface *iface) -{ - return -100; -} - -static inline const char * hostapd_hw_mode_txt(int mode) -{ - return NULL; -} - -static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) -{ - return -1; -} - -static inline int hostapd_check_ht_capab(struct hostapd_iface *iface) -{ - return 0; -} - -static inline int hostapd_prepare_rates(struct hostapd_iface *iface, - struct hostapd_hw_modes *mode) -{ - return 0; -} - -#endif /* NEED_AP_MLME */ - -#endif /* HW_FEATURES_H */ diff --git a/contrib/hostapd/src/ap/iapp.c b/contrib/hostapd/src/ap/iapp.c deleted file mode 100644 index bad080f028..0000000000 --- a/contrib/hostapd/src/ap/iapp.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP) - * Copyright (c) 2002-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * Note: IEEE 802.11F-2003 was a experimental use specification. It has expired - * and IEEE has withdrawn it. In other words, it is likely better to look at - * using some other mechanism for AP-to-AP communication than extending the - * implementation here. - */ - -/* TODO: - * Level 1: no administrative or security support - * (e.g., static BSSID to IP address mapping in each AP) - * Level 2: support for dynamic mapping of BSSID to IP address - * Level 3: support for encryption and authentication of IAPP messages - * - add support for MOVE-notify and MOVE-response (this requires support for - * finding out IP address for previous AP using RADIUS) - * - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during - * reassociation to another AP - * - implement counters etc. for IAPP MIB - * - verify endianness of fields in IAPP messages; are they big-endian as - * used here? - * - RADIUS connection for AP registration and BSSID to IP address mapping - * - TCP connection for IAPP MOVE, CACHE - * - broadcast ESP for IAPP ADD-notify - * - ESP for IAPP MOVE messages - * - security block sending/processing - * - IEEE 802.11 context transfer - */ - -#include "utils/includes.h" -#include -#include -#ifdef USE_KERNEL_HEADERS -#include -#else /* USE_KERNEL_HEADERS */ -#include -#endif /* USE_KERNEL_HEADERS */ - -#include "utils/common.h" -#include "utils/eloop.h" -#include "common/ieee802_11_defs.h" -#include "hostapd.h" -#include "ap_config.h" -#include "ieee802_11.h" -#include "sta_info.h" -#include "iapp.h" - - -#define IAPP_MULTICAST "224.0.1.178" -#define IAPP_UDP_PORT 3517 -#define IAPP_TCP_PORT 3517 - -struct iapp_hdr { - u8 version; - u8 command; - be16 identifier; - be16 length; - /* followed by length-6 octets of data */ -} __attribute__ ((packed)); - -#define IAPP_VERSION 0 - -enum IAPP_COMMAND { - IAPP_CMD_ADD_notify = 0, - IAPP_CMD_MOVE_notify = 1, - IAPP_CMD_MOVE_response = 2, - IAPP_CMD_Send_Security_Block = 3, - IAPP_CMD_ACK_Security_Block = 4, - IAPP_CMD_CACHE_notify = 5, - IAPP_CMD_CACHE_response = 6, -}; - - -/* ADD-notify - multicast UDP on the local LAN */ -struct iapp_add_notify { - u8 addr_len; /* ETH_ALEN */ - u8 reserved; - u8 mac_addr[ETH_ALEN]; - be16 seq_num; -} __attribute__ ((packed)); - - -/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ -struct iapp_layer2_update { - u8 da[ETH_ALEN]; /* broadcast */ - u8 sa[ETH_ALEN]; /* STA addr */ - be16 len; /* 6 */ - u8 dsap; /* null DSAP address */ - u8 ssap; /* null SSAP address, CR=Response */ - u8 control; - u8 xid_info[3]; -} __attribute__ ((packed)); - - -/* MOVE-notify - unicast TCP */ -struct iapp_move_notify { - u8 addr_len; /* ETH_ALEN */ - u8 reserved; - u8 mac_addr[ETH_ALEN]; - u16 seq_num; - u16 ctx_block_len; - /* followed by ctx_block_len bytes */ -} __attribute__ ((packed)); - - -/* MOVE-response - unicast TCP */ -struct iapp_move_response { - u8 addr_len; /* ETH_ALEN */ - u8 status; - u8 mac_addr[ETH_ALEN]; - u16 seq_num; - u16 ctx_block_len; - /* followed by ctx_block_len bytes */ -} __attribute__ ((packed)); - -enum { - IAPP_MOVE_SUCCESSFUL = 0, - IAPP_MOVE_DENIED = 1, - IAPP_MOVE_STALE_MOVE = 2, -}; - - -/* CACHE-notify */ -struct iapp_cache_notify { - u8 addr_len; /* ETH_ALEN */ - u8 reserved; - u8 mac_addr[ETH_ALEN]; - u16 seq_num; - u8 current_ap[ETH_ALEN]; - u16 ctx_block_len; - /* ctx_block_len bytes of context block followed by 16-bit context - * timeout */ -} __attribute__ ((packed)); - - -/* CACHE-response - unicast TCP */ -struct iapp_cache_response { - u8 addr_len; /* ETH_ALEN */ - u8 status; - u8 mac_addr[ETH_ALEN]; - u16 seq_num; -} __attribute__ ((packed)); - -enum { - IAPP_CACHE_SUCCESSFUL = 0, - IAPP_CACHE_STALE_CACHE = 1, -}; - - -/* Send-Security-Block - unicast TCP */ -struct iapp_send_security_block { - u8 iv[8]; - u16 sec_block_len; - /* followed by sec_block_len bytes of security block */ -} __attribute__ ((packed)); - - -/* ACK-Security-Block - unicast TCP */ -struct iapp_ack_security_block { - u8 iv[8]; - u8 new_ap_ack_authenticator[48]; -} __attribute__ ((packed)); - - -struct iapp_data { - struct hostapd_data *hapd; - u16 identifier; /* next IAPP identifier */ - struct in_addr own, multicast; - int udp_sock; - int packet_sock; -}; - - -static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num) -{ - char buf[128]; - struct iapp_hdr *hdr; - struct iapp_add_notify *add; - struct sockaddr_in addr; - - /* Send IAPP ADD-notify to remove possible association from other APs - */ - - hdr = (struct iapp_hdr *) buf; - hdr->version = IAPP_VERSION; - hdr->command = IAPP_CMD_ADD_notify; - hdr->identifier = host_to_be16(iapp->identifier++); - hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add)); - - add = (struct iapp_add_notify *) (hdr + 1); - add->addr_len = ETH_ALEN; - add->reserved = 0; - os_memcpy(add->mac_addr, mac_addr, ETH_ALEN); - - add->seq_num = host_to_be16(seq_num); - - os_memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = iapp->multicast.s_addr; - addr.sin_port = htons(IAPP_UDP_PORT); - if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0, - (struct sockaddr *) &addr, sizeof(addr)) < 0) - wpa_printf(MSG_INFO, "sendto[IAPP-ADD]: %s", strerror(errno)); -} - - -static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr) -{ - struct iapp_layer2_update msg; - - /* Send Level 2 Update Frame to update forwarding tables in layer 2 - * bridge devices */ - - /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) - * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ - - os_memset(msg.da, 0xff, ETH_ALEN); - os_memcpy(msg.sa, addr, ETH_ALEN); - msg.len = host_to_be16(6); - msg.dsap = 0; /* NULL DSAP address */ - msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */ - msg.control = 0xaf; /* XID response lsb.1111F101. - * F=0 (no poll command; unsolicited frame) */ - msg.xid_info[0] = 0x81; /* XID format identifier */ - msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ - msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW) - * FIX: what is correct RW with 802.11? */ - - if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0) - wpa_printf(MSG_INFO, "send[L2 Update]: %s", strerror(errno)); -} - - -/** - * iapp_new_station - IAPP processing for a new STA - * @iapp: IAPP data - * @sta: The associated station - */ -void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta) -{ - struct ieee80211_mgmt *assoc; - u16 seq; - - if (iapp == NULL) - return; - - assoc = sta->last_assoc_req; - seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0; - - /* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */ - hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP, - HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq); - iapp_send_layer2_update(iapp, sta->addr); - iapp_send_add(iapp, sta->addr, seq); - - if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) == - WLAN_FC_STYPE_REASSOC_REQ) { - /* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP, - * Context Block, Timeout) - */ - /* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to - * IP address */ - } -} - - -static void iapp_process_add_notify(struct iapp_data *iapp, - struct sockaddr_in *from, - struct iapp_hdr *hdr, int len) -{ - struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1); - struct sta_info *sta; - - if (len != sizeof(*add)) { - wpa_printf(MSG_INFO, "Invalid IAPP-ADD packet length %d (expected %lu)", - len, (unsigned long) sizeof(*add)); - return; - } - - sta = ap_get_sta(iapp->hapd, add->mac_addr); - - /* IAPP-ADD.indication(MAC Address, Sequence Number) */ - hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP, - HOSTAPD_LEVEL_INFO, - "Received IAPP ADD-notify (seq# %d) from %s:%d%s", - be_to_host16(add->seq_num), - inet_ntoa(from->sin_addr), ntohs(from->sin_port), - sta ? "" : " (STA not found)"); - - if (!sta) - return; - - /* TODO: could use seq_num to try to determine whether last association - * to this AP is newer than the one advertised in IAPP-ADD. Although, - * this is not really a reliable verification. */ - - hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP, - HOSTAPD_LEVEL_DEBUG, - "Removing STA due to IAPP ADD-notify"); - ap_sta_disconnect(iapp->hapd, sta, NULL, 0); -} - - -/** - * iapp_receive_udp - Process IAPP UDP frames - * @sock: File descriptor for the socket - * @eloop_ctx: IAPP data (struct iapp_data *) - * @sock_ctx: Not used - */ -static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct iapp_data *iapp = eloop_ctx; - int len, hlen; - unsigned char buf[128]; - struct sockaddr_in from; - socklen_t fromlen; - struct iapp_hdr *hdr; - - /* Handle incoming IAPP frames (over UDP/IP) */ - - fromlen = sizeof(from); - len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0, - (struct sockaddr *) &from, &fromlen); - if (len < 0) { - wpa_printf(MSG_INFO, "iapp_receive_udp - recvfrom: %s", - strerror(errno)); - return; - } - - if (from.sin_addr.s_addr == iapp->own.s_addr) - return; /* ignore own IAPP messages */ - - hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP, - HOSTAPD_LEVEL_DEBUG, - "Received %d byte IAPP frame from %s%s\n", - len, inet_ntoa(from.sin_addr), - len < (int) sizeof(*hdr) ? " (too short)" : ""); - - if (len < (int) sizeof(*hdr)) - return; - - hdr = (struct iapp_hdr *) buf; - hlen = be_to_host16(hdr->length); - hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP, - HOSTAPD_LEVEL_DEBUG, - "RX: version=%d command=%d id=%d len=%d\n", - hdr->version, hdr->command, - be_to_host16(hdr->identifier), hlen); - if (hdr->version != IAPP_VERSION) { - wpa_printf(MSG_INFO, "Dropping IAPP frame with unknown version %d", - hdr->version); - return; - } - if (hlen > len) { - wpa_printf(MSG_INFO, "Underflow IAPP frame (hlen=%d len=%d)", - hlen, len); - return; - } - if (hlen < len) { - wpa_printf(MSG_INFO, "Ignoring %d extra bytes from IAPP frame", - len - hlen); - len = hlen; - } - - switch (hdr->command) { - case IAPP_CMD_ADD_notify: - iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr)); - break; - case IAPP_CMD_MOVE_notify: - /* TODO: MOVE is using TCP; so move this to TCP handler once it - * is implemented.. */ - /* IAPP-MOVE.indication(MAC Address, New BSSID, - * Sequence Number, AP Address, Context Block) */ - /* TODO: process */ - break; - default: - wpa_printf(MSG_INFO, "Unknown IAPP command %d", hdr->command); - break; - } -} - - -struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface) -{ - struct ifreq ifr; - struct sockaddr_ll addr; - int ifindex; - struct sockaddr_in *paddr, uaddr; - struct iapp_data *iapp; - struct ip_mreqn mreq; - - iapp = os_zalloc(sizeof(*iapp)); - if (iapp == NULL) - return NULL; - iapp->hapd = hapd; - iapp->udp_sock = iapp->packet_sock = -1; - - /* TODO: - * open socket for sending and receiving IAPP frames over TCP - */ - - iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (iapp->udp_sock < 0) { - wpa_printf(MSG_INFO, "iapp_init - socket[PF_INET,SOCK_DGRAM]: %s", - strerror(errno)); - iapp_deinit(iapp); - return NULL; - } - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); - if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) { - wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFINDEX): %s", - strerror(errno)); - iapp_deinit(iapp); - return NULL; - } - ifindex = ifr.ifr_ifindex; - - if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) { - wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFADDR): %s", - strerror(errno)); - iapp_deinit(iapp); - return NULL; - } - paddr = (struct sockaddr_in *) &ifr.ifr_addr; - if (paddr->sin_family != AF_INET) { - wpa_printf(MSG_INFO, "IAPP: Invalid address family %i (SIOCGIFADDR)", - paddr->sin_family); - iapp_deinit(iapp); - return NULL; - } - iapp->own.s_addr = paddr->sin_addr.s_addr; - - if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) { - wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFBRDADDR): %s", - strerror(errno)); - iapp_deinit(iapp); - return NULL; - } - paddr = (struct sockaddr_in *) &ifr.ifr_addr; - if (paddr->sin_family != AF_INET) { - wpa_printf(MSG_INFO, "Invalid address family %i (SIOCGIFBRDADDR)", - paddr->sin_family); - iapp_deinit(iapp); - return NULL; - } - inet_aton(IAPP_MULTICAST, &iapp->multicast); - - os_memset(&uaddr, 0, sizeof(uaddr)); - uaddr.sin_family = AF_INET; - uaddr.sin_port = htons(IAPP_UDP_PORT); - if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr, - sizeof(uaddr)) < 0) { - wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s", - strerror(errno)); - iapp_deinit(iapp); - return NULL; - } - - os_memset(&mreq, 0, sizeof(mreq)); - mreq.imr_multiaddr = iapp->multicast; - mreq.imr_address.s_addr = INADDR_ANY; - mreq.imr_ifindex = 0; - if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, - sizeof(mreq)) < 0) { - wpa_printf(MSG_INFO, "iapp_init - setsockopt[UDP,IP_ADD_MEMBERSHIP]: %s", - strerror(errno)); - iapp_deinit(iapp); - return NULL; - } - - iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (iapp->packet_sock < 0) { - wpa_printf(MSG_INFO, "iapp_init - socket[PF_PACKET,SOCK_RAW]: %s", - strerror(errno)); - iapp_deinit(iapp); - return NULL; - } - - os_memset(&addr, 0, sizeof(addr)); - addr.sll_family = AF_PACKET; - addr.sll_ifindex = ifindex; - if (bind(iapp->packet_sock, (struct sockaddr *) &addr, - sizeof(addr)) < 0) { - wpa_printf(MSG_INFO, "iapp_init - bind[PACKET]: %s", - strerror(errno)); - iapp_deinit(iapp); - return NULL; - } - - if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp, - iapp, NULL)) { - wpa_printf(MSG_INFO, "Could not register read socket for IAPP"); - iapp_deinit(iapp); - return NULL; - } - - wpa_printf(MSG_INFO, "IEEE 802.11F (IAPP) using interface %s", iface); - - /* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive - * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually - * be openned only after receiving Initiate-Accept. If Initiate-Reject - * is received, IAPP is not started. */ - - return iapp; -} - - -void iapp_deinit(struct iapp_data *iapp) -{ - struct ip_mreqn mreq; - - if (iapp == NULL) - return; - - if (iapp->udp_sock >= 0) { - os_memset(&mreq, 0, sizeof(mreq)); - mreq.imr_multiaddr = iapp->multicast; - mreq.imr_address.s_addr = INADDR_ANY; - mreq.imr_ifindex = 0; - if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP, - &mreq, sizeof(mreq)) < 0) { - wpa_printf(MSG_INFO, "iapp_deinit - setsockopt[UDP,IP_DEL_MEMBERSHIP]: %s", - strerror(errno)); - } - - eloop_unregister_read_sock(iapp->udp_sock); - close(iapp->udp_sock); - } - if (iapp->packet_sock >= 0) { - eloop_unregister_read_sock(iapp->packet_sock); - close(iapp->packet_sock); - } - os_free(iapp); -} diff --git a/contrib/hostapd/src/ap/iapp.h b/contrib/hostapd/src/ap/iapp.h deleted file mode 100644 index c22118342a..0000000000 --- a/contrib/hostapd/src/ap/iapp.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP) - * Copyright (c) 2002-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef IAPP_H -#define IAPP_H - -struct iapp_data; - -#ifdef CONFIG_IAPP - -void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta); -struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface); -void iapp_deinit(struct iapp_data *iapp); - -#else /* CONFIG_IAPP */ - -static inline void iapp_new_station(struct iapp_data *iapp, - struct sta_info *sta) -{ -} - -static inline struct iapp_data * iapp_init(struct hostapd_data *hapd, - const char *iface) -{ - return NULL; -} - -static inline void iapp_deinit(struct iapp_data *iapp) -{ -} - -#endif /* CONFIG_IAPP */ - -#endif /* IAPP_H */ diff --git a/contrib/hostapd/src/ap/ieee802_11.c b/contrib/hostapd/src/ap/ieee802_11.c deleted file mode 100644 index dee3c7a38e..0000000000 --- a/contrib/hostapd/src/ap/ieee802_11.c +++ /dev/null @@ -1,2266 +0,0 @@ -/* - * hostapd / IEEE 802.11 Management - * Copyright (c) 2002-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#ifndef CONFIG_NATIVE_WINDOWS - -#include "utils/common.h" -#include "utils/eloop.h" -#include "crypto/crypto.h" -#include "crypto/sha256.h" -#include "crypto/random.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "common/wpa_ctrl.h" -#include "common/sae.h" -#include "radius/radius.h" -#include "radius/radius_client.h" -#include "p2p/p2p.h" -#include "wps/wps.h" -#include "hostapd.h" -#include "beacon.h" -#include "ieee802_11_auth.h" -#include "sta_info.h" -#include "ieee802_1x.h" -#include "wpa_auth.h" -#include "wmm.h" -#include "ap_list.h" -#include "accounting.h" -#include "ap_config.h" -#include "ap_mlme.h" -#include "p2p_hostapd.h" -#include "ap_drv_ops.h" -#include "wnm_ap.h" -#include "ieee802_11.h" - - -u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) -{ - u8 *pos = eid; - int i, num, count; - - if (hapd->iface->current_rates == NULL) - return eid; - - *pos++ = WLAN_EID_SUPP_RATES; - num = hapd->iface->num_rates; - if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) - num++; - if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) - num++; - if (num > 8) { - /* rest of the rates are encoded in Extended supported - * rates element */ - num = 8; - } - - *pos++ = num; - count = 0; - for (i = 0, count = 0; i < hapd->iface->num_rates && count < num; - i++) { - count++; - *pos = hapd->iface->current_rates[i].rate / 5; - if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC) - *pos |= 0x80; - pos++; - } - - if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) { - count++; - *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY; - } - - if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) { - count++; - *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY; - } - - return pos; -} - - -u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) -{ - u8 *pos = eid; - int i, num, count; - - if (hapd->iface->current_rates == NULL) - return eid; - - num = hapd->iface->num_rates; - if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) - num++; - if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) - num++; - if (num <= 8) - return eid; - num -= 8; - - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = num; - count = 0; - for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8; - i++) { - count++; - if (count <= 8) - continue; /* already in SuppRates IE */ - *pos = hapd->iface->current_rates[i].rate / 5; - if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC) - *pos |= 0x80; - pos++; - } - - if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) { - count++; - if (count > 8) - *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY; - } - - if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) { - count++; - if (count > 8) - *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY; - } - - return pos; -} - - -u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, - int probe) -{ - int capab = WLAN_CAPABILITY_ESS; - int privacy; - - if (hapd->iface->num_sta_no_short_preamble == 0 && - hapd->iconf->preamble == SHORT_PREAMBLE) - capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; - - privacy = hapd->conf->ssid.wep.keys_set; - - if (hapd->conf->ieee802_1x && - (hapd->conf->default_wep_key_len || - hapd->conf->individual_wep_key_len)) - privacy = 1; - - if (hapd->conf->wpa) - privacy = 1; - - if (sta) { - int policy, def_klen; - if (probe && sta->ssid_probe) { - policy = sta->ssid_probe->security_policy; - def_klen = sta->ssid_probe->wep.default_len; - } else { - policy = sta->ssid->security_policy; - def_klen = sta->ssid->wep.default_len; - } - privacy = policy != SECURITY_PLAINTEXT; - if (policy == SECURITY_IEEE_802_1X && def_klen == 0) - privacy = 0; - } - - if (privacy) - capab |= WLAN_CAPABILITY_PRIVACY; - - if (hapd->iface->current_mode && - hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G && - hapd->iface->num_sta_no_short_slot_time == 0) - capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; - - return capab; -} - - -void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len) -{ - int i; - if (len > HOSTAPD_MAX_SSID_LEN) - len = HOSTAPD_MAX_SSID_LEN; - for (i = 0; i < len; i++) { - if (ssid[i] >= 32 && ssid[i] < 127) - buf[i] = ssid[i]; - else - buf[i] = '.'; - } - buf[len] = '\0'; -} - - -static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, - u16 auth_transaction, const u8 *challenge, - int iswep) -{ - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "authentication (shared key, transaction %d)", - auth_transaction); - - if (auth_transaction == 1) { - if (!sta->challenge) { - /* Generate a pseudo-random challenge */ - u8 key[8]; - struct os_time now; - int r; - sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN); - if (sta->challenge == NULL) - return WLAN_STATUS_UNSPECIFIED_FAILURE; - - os_get_time(&now); - r = os_random(); - os_memcpy(key, &now.sec, 4); - os_memcpy(key + 4, &r, 4); - rc4_skip(key, sizeof(key), 0, - sta->challenge, WLAN_AUTH_CHALLENGE_LEN); - } - return 0; - } - - if (auth_transaction != 3) - return WLAN_STATUS_UNSPECIFIED_FAILURE; - - /* Transaction 3 */ - if (!iswep || !sta->challenge || !challenge || - os_memcmp(sta->challenge, challenge, WLAN_AUTH_CHALLENGE_LEN)) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, - "shared key authentication - invalid " - "challenge-response"); - return WLAN_STATUS_CHALLENGE_FAIL; - } - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "authentication OK (shared key)"); - sta->flags |= WLAN_STA_AUTH; - wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); - os_free(sta->challenge); - sta->challenge = NULL; - - return 0; -} - - -static void send_auth_reply(struct hostapd_data *hapd, - const u8 *dst, const u8 *bssid, - u16 auth_alg, u16 auth_transaction, u16 resp, - const u8 *ies, size_t ies_len) -{ - struct ieee80211_mgmt *reply; - u8 *buf; - size_t rlen; - - rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len; - buf = os_zalloc(rlen); - if (buf == NULL) - return; - - reply = (struct ieee80211_mgmt *) buf; - reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_AUTH); - os_memcpy(reply->da, dst, ETH_ALEN); - os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(reply->bssid, bssid, ETH_ALEN); - - reply->u.auth.auth_alg = host_to_le16(auth_alg); - reply->u.auth.auth_transaction = host_to_le16(auth_transaction); - reply->u.auth.status_code = host_to_le16(resp); - - if (ies && ies_len) - os_memcpy(reply->u.auth.variable, ies, ies_len); - - wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR - " 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) < 0) - wpa_printf(MSG_INFO, "send_auth_reply: send"); - - os_free(buf); -} - - -#ifdef CONFIG_IEEE80211R -static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, - u16 auth_transaction, u16 status, - const u8 *ies, size_t ies_len) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta; - - send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, auth_transaction, - status, ies, ies_len); - - if (status != WLAN_STATUS_SUCCESS) - return; - - sta = ap_get_sta(hapd, dst); - if (sta == NULL) - return; - - hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)"); - sta->flags |= WLAN_STA_AUTH; - mlme_authenticate_indication(hapd, sta); -} -#endif /* CONFIG_IEEE80211R */ - - -#ifdef CONFIG_SAE - -static struct wpabuf * auth_process_sae_commit(struct hostapd_data *hapd, - struct sta_info *sta) -{ - struct wpabuf *buf; - - if (hapd->conf->ssid.wpa_passphrase == NULL) { - wpa_printf(MSG_DEBUG, "SAE: No password available"); - return NULL; - } - - if (sae_prepare_commit(hapd->own_addr, sta->addr, - (u8 *) hapd->conf->ssid.wpa_passphrase, - os_strlen(hapd->conf->ssid.wpa_passphrase), - sta->sae) < 0) { - wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE"); - return NULL; - } - - if (sae_process_commit(sta->sae) < 0) { - wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit"); - return NULL; - } - - buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN); - if (buf == NULL) - return NULL; - sae_write_commit(sta->sae, buf, NULL); - - return buf; -} - - -static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd, - struct sta_info *sta) -{ - struct wpabuf *buf; - - buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN); - if (buf == NULL) - return NULL; - - sae_write_confirm(sta->sae, buf); - - return buf; -} - - -static int use_sae_anti_clogging(struct hostapd_data *hapd) -{ - struct sta_info *sta; - unsigned int open = 0; - - if (hapd->conf->sae_anti_clogging_threshold == 0) - return 1; - - for (sta = hapd->sta_list; sta; sta = sta->next) { - if (!sta->sae) - continue; - if (sta->sae->state != SAE_COMMITTED && - sta->sae->state != SAE_CONFIRMED) - continue; - open++; - if (open >= hapd->conf->sae_anti_clogging_threshold) - return 1; - } - - return 0; -} - - -static int check_sae_token(struct hostapd_data *hapd, const u8 *addr, - const u8 *token, size_t token_len) -{ - u8 mac[SHA256_MAC_LEN]; - - if (token_len != SHA256_MAC_LEN) - return -1; - if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key), - addr, ETH_ALEN, mac) < 0 || - os_memcmp(token, mac, SHA256_MAC_LEN) != 0) - return -1; - - return 0; -} - - -static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd, - const u8 *addr) -{ - struct wpabuf *buf; - u8 *token; - struct os_reltime now; - - os_get_reltime(&now); - if (!os_reltime_initialized(&hapd->last_sae_token_key_update) || - os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60)) { - if (random_get_bytes(hapd->sae_token_key, - sizeof(hapd->sae_token_key)) < 0) - return NULL; - wpa_hexdump(MSG_DEBUG, "SAE: Updated token key", - hapd->sae_token_key, sizeof(hapd->sae_token_key)); - hapd->last_sae_token_key_update = now; - } - - buf = wpabuf_alloc(SHA256_MAC_LEN); - if (buf == NULL) - return NULL; - - token = wpabuf_put(buf, SHA256_MAC_LEN); - hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key), - addr, ETH_ALEN, token); - - return buf; -} - - -static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, - const struct ieee80211_mgmt *mgmt, size_t len, - u8 auth_transaction) -{ - u16 resp = WLAN_STATUS_SUCCESS; - struct wpabuf *data = NULL; - - if (!sta->sae) { - if (auth_transaction != 1) - return; - sta->sae = os_zalloc(sizeof(*sta->sae)); - if (sta->sae == NULL) - return; - sta->sae->state = SAE_NOTHING; - } - - if (auth_transaction == 1) { - const u8 *token = NULL; - size_t token_len = 0; - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "start SAE authentication (RX commit)"); - resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable, - ((const u8 *) mgmt) + len - - mgmt->u.auth.variable, &token, - &token_len, hapd->conf->sae_groups); - if (token && check_sae_token(hapd, sta->addr, token, token_len) - < 0) { - wpa_printf(MSG_DEBUG, "SAE: Drop commit message with " - "incorrect token from " MACSTR, - MAC2STR(sta->addr)); - return; - } - - if (resp == WLAN_STATUS_SUCCESS) { - if (!token && use_sae_anti_clogging(hapd)) { - wpa_printf(MSG_DEBUG, "SAE: Request anti-" - "clogging token from " MACSTR, - MAC2STR(sta->addr)); - data = auth_build_token_req(hapd, sta->addr); - resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ; - } else { - data = auth_process_sae_commit(hapd, sta); - if (data == NULL) - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - else - sta->sae->state = SAE_COMMITTED; - } - } - } else if (auth_transaction == 2) { - if (sta->sae->state != SAE_COMMITTED) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "SAE confirm before commit"); - resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; - } - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "SAE authentication (RX confirm)"); - if (sae_check_confirm(sta->sae, mgmt->u.auth.variable, - ((u8 *) mgmt) + len - - mgmt->u.auth.variable) < 0) { - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - } else { - resp = WLAN_STATUS_SUCCESS; - sta->flags |= WLAN_STA_AUTH; - wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); - sta->auth_alg = WLAN_AUTH_SAE; - mlme_authenticate_indication(hapd, sta); - - data = auth_build_sae_confirm(hapd, sta); - if (data == NULL) - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - else { - sta->sae->state = SAE_ACCEPTED; - sae_clear_temp_data(sta->sae); - } - } - } else { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "unexpected SAE authentication transaction %u", - auth_transaction); - resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; - } - - sta->auth_alg = WLAN_AUTH_SAE; - - send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, - auth_transaction, resp, - data ? wpabuf_head(data) : (u8 *) "", - data ? wpabuf_len(data) : 0); - wpabuf_free(data); -} -#endif /* CONFIG_SAE */ - - -static void handle_auth(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len) -{ - u16 auth_alg, auth_transaction, status_code; - u16 resp = WLAN_STATUS_SUCCESS; - struct sta_info *sta = NULL; - int res; - u16 fc; - const u8 *challenge = NULL; - u32 session_timeout, acct_interim_interval; - int vlan_id = 0; - struct hostapd_sta_wpa_psk_short *psk = NULL; - u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; - size_t resp_ies_len = 0; - char *identity = NULL; - char *radius_cui = NULL; - - if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { - wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)", - (unsigned long) len); - return; - } - -#ifdef CONFIG_TESTING_OPTIONS - if (hapd->iconf->ignore_auth_probability > 0.0d && - drand48() < hapd->iconf->ignore_auth_probability) { - wpa_printf(MSG_INFO, - "TESTING: ignoring auth frame from " MACSTR, - MAC2STR(mgmt->sa)); - return; - } -#endif /* CONFIG_TESTING_OPTIONS */ - - auth_alg = le_to_host16(mgmt->u.auth.auth_alg); - auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); - status_code = le_to_host16(mgmt->u.auth.status_code); - fc = le_to_host16(mgmt->frame_control); - - if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) + - 2 + WLAN_AUTH_CHALLENGE_LEN && - mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE && - mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN) - challenge = &mgmt->u.auth.variable[2]; - - wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d " - "auth_transaction=%d status_code=%d wep=%d%s", - MAC2STR(mgmt->sa), auth_alg, auth_transaction, - status_code, !!(fc & WLAN_FC_ISWEP), - challenge ? " challenge" : ""); - - if (hapd->tkip_countermeasures) { - resp = WLAN_REASON_MICHAEL_MIC_FAILURE; - goto fail; - } - - if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) && - auth_alg == WLAN_AUTH_OPEN) || -#ifdef CONFIG_IEEE80211R - (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) && - auth_alg == WLAN_AUTH_FT) || -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_SAE - (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) && - auth_alg == WLAN_AUTH_SAE) || -#endif /* CONFIG_SAE */ - ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) && - auth_alg == WLAN_AUTH_SHARED_KEY))) { - wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)", - auth_alg); - resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; - goto fail; - } - - if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE || - (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) { - wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)", - auth_transaction); - resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; - goto fail; - } - - if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) { - wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate", - MAC2STR(mgmt->sa)); - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - - res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len, - &session_timeout, - &acct_interim_interval, &vlan_id, - &psk, &identity, &radius_cui); - - if (res == HOSTAPD_ACL_REJECT) { - wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate", - MAC2STR(mgmt->sa)); - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - if (res == HOSTAPD_ACL_PENDING) { - wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR - " waiting for an external authentication", - MAC2STR(mgmt->sa)); - /* Authentication code will re-send the authentication frame - * after it has received (and cached) information from the - * external source. */ - return; - } - - sta = ap_sta_add(hapd, mgmt->sa); - if (!sta) { - resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; - goto fail; - } - - if (vlan_id > 0) { - if (!hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_INFO, "Invalid VLAN ID " - "%d received from RADIUS server", - vlan_id); - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - sta->vlan_id = vlan_id; - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); - } - - hostapd_free_psk_list(sta->psk); - if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) { - sta->psk = psk; - psk = NULL; - } else { - sta->psk = NULL; - } - - sta->identity = identity; - identity = NULL; - sta->radius_cui = radius_cui; - radius_cui = NULL; - - sta->flags &= ~WLAN_STA_PREAUTH; - ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); - - if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval) - sta->acct_interim_interval = acct_interim_interval; - if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) - ap_sta_session_timeout(hapd, sta, session_timeout); - else - ap_sta_no_session_timeout(hapd, sta); - - switch (auth_alg) { - case WLAN_AUTH_OPEN: - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "authentication OK (open system)"); - sta->flags |= WLAN_STA_AUTH; - wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); - sta->auth_alg = WLAN_AUTH_OPEN; - mlme_authenticate_indication(hapd, sta); - break; - case WLAN_AUTH_SHARED_KEY: - resp = auth_shared_key(hapd, sta, auth_transaction, challenge, - fc & WLAN_FC_ISWEP); - sta->auth_alg = WLAN_AUTH_SHARED_KEY; - mlme_authenticate_indication(hapd, sta); - if (sta->challenge && auth_transaction == 1) { - resp_ies[0] = WLAN_EID_CHALLENGE; - resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN; - os_memcpy(resp_ies + 2, sta->challenge, - WLAN_AUTH_CHALLENGE_LEN); - resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN; - } - break; -#ifdef CONFIG_IEEE80211R - case WLAN_AUTH_FT: - sta->auth_alg = WLAN_AUTH_FT; - if (sta->wpa_sm == NULL) - sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, - sta->addr, NULL); - if (sta->wpa_sm == NULL) { - wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA " - "state machine"); - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid, - auth_transaction, mgmt->u.auth.variable, - len - IEEE80211_HDRLEN - - sizeof(mgmt->u.auth), - handle_auth_ft_finish, hapd); - /* handle_auth_ft_finish() callback will complete auth. */ - return; -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_SAE - case WLAN_AUTH_SAE: - handle_auth_sae(hapd, sta, mgmt, len, auth_transaction); - return; -#endif /* CONFIG_SAE */ - } - - fail: - os_free(identity); - os_free(radius_cui); - hostapd_free_psk_list(psk); - - send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg, - auth_transaction + 1, resp, resp_ies, resp_ies_len); -} - - -static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta) -{ - int i, j = 32, aid; - - /* get a unique AID */ - if (sta->aid > 0) { - wpa_printf(MSG_DEBUG, " old AID %d", sta->aid); - return 0; - } - - for (i = 0; i < AID_WORDS; i++) { - if (hapd->sta_aid[i] == (u32) -1) - continue; - for (j = 0; j < 32; j++) { - if (!(hapd->sta_aid[i] & BIT(j))) - break; - } - if (j < 32) - break; - } - if (j == 32) - return -1; - aid = i * 32 + j + 1; - if (aid > 2007) - return -1; - - sta->aid = aid; - hapd->sta_aid[i] |= BIT(j); - wpa_printf(MSG_DEBUG, " new AID %d", sta->aid); - return 0; -} - - -static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *ssid_ie, size_t ssid_ie_len) -{ - if (ssid_ie == NULL) - return WLAN_STATUS_UNSPECIFIED_FAILURE; - - if (ssid_ie_len != hapd->conf->ssid.ssid_len || - os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) { - char ssid_txt[33]; - ieee802_11_print_ssid(ssid_txt, ssid_ie, ssid_ie_len); - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, - "Station tried to associate with unknown SSID " - "'%s'", ssid_txt); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - return WLAN_STATUS_SUCCESS; -} - - -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) { - 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"); - 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; -} - - -static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta, - struct ieee802_11_elems *elems) -{ - if (!elems->supp_rates) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "No supported rates element in AssocReq"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - if (elems->supp_rates_len + elems->ext_supp_rates_len > - sizeof(sta->supported_rates)) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "Invalid supported rates element length %d+%d", - elems->supp_rates_len, - elems->ext_supp_rates_len); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - sta->supported_rates_len = merge_byte_arrays( - sta->supported_rates, sizeof(sta->supported_rates), - elems->supp_rates, elems->supp_rates_len, - elems->ext_supp_rates, elems->ext_supp_rates_len); - - return WLAN_STATUS_SUCCESS; -} - - -static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *ext_capab_ie, size_t ext_capab_ie_len) -{ -#ifdef CONFIG_INTERWORKING - /* check for QoS Map support */ - if (ext_capab_ie_len >= 5) { - if (ext_capab_ie[4] & 0x01) - sta->qos_map_enabled = 1; - } -#endif /* CONFIG_INTERWORKING */ - - return WLAN_STATUS_SUCCESS; -} - - -static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *ies, size_t ies_len, int reassoc) -{ - struct ieee802_11_elems elems; - u16 resp; - const u8 *wpa_ie; - size_t wpa_ie_len; - const u8 *p2p_dev_addr = NULL; - - if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "Station sent an invalid " - "association request"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len); - if (resp != WLAN_STATUS_SUCCESS) - return resp; - resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len); - if (resp != WLAN_STATUS_SUCCESS) - return resp; - resp = check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len); - if (resp != WLAN_STATUS_SUCCESS) - return resp; - resp = copy_supp_rates(hapd, sta, &elems); - if (resp != WLAN_STATUS_SUCCESS) - return resp; -#ifdef CONFIG_IEEE80211N - resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities, - elems.ht_capabilities_len); - if (resp != WLAN_STATUS_SUCCESS) - return resp; - if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && - !(sta->flags & WLAN_STA_HT)) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "Station does not support " - "mandatory HT PHY - reject association"); - return WLAN_STATUS_ASSOC_DENIED_NO_HT; - } -#endif /* CONFIG_IEEE80211N */ - -#ifdef CONFIG_IEEE80211AC - resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities, - elems.vht_capabilities_len); - if (resp != WLAN_STATUS_SUCCESS) - return resp; - if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && - !(sta->flags & WLAN_STA_VHT)) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "Station does not support " - "mandatory VHT PHY - reject association"); - return WLAN_STATUS_ASSOC_DENIED_NO_VHT; - } -#endif /* CONFIG_IEEE80211AC */ - -#ifdef CONFIG_P2P - if (elems.p2p) { - wpabuf_free(sta->p2p_ie); - sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len, - P2P_IE_VENDOR_TYPE); - if (sta->p2p_ie) - p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); - } else { - wpabuf_free(sta->p2p_ie); - sta->p2p_ie = NULL; - } -#endif /* CONFIG_P2P */ - - if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) { - wpa_ie = elems.rsn_ie; - wpa_ie_len = elems.rsn_ie_len; - } else if ((hapd->conf->wpa & WPA_PROTO_WPA) && - elems.wpa_ie) { - wpa_ie = elems.wpa_ie; - wpa_ie_len = elems.wpa_ie_len; - } else { - wpa_ie = NULL; - wpa_ie_len = 0; - } - -#ifdef CONFIG_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"); - sta->flags |= WLAN_STA_WPS; - 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) { - wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in " - "(Re)Association Request - reject"); - return WLAN_STATUS_INVALID_IE; - } - } else if (hapd->conf->wps_state && wpa_ie == NULL) { - wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in " - "(Re)Association Request - possible WPS use"); - sta->flags |= WLAN_STA_MAYBE_WPS; - } else -#endif /* CONFIG_WPS */ - if (hapd->conf->wpa && wpa_ie == NULL) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, - "No WPA/RSN IE in association request"); - return WLAN_STATUS_INVALID_IE; - } - - if (hapd->conf->wpa && wpa_ie) { - int res; - wpa_ie -= 2; - wpa_ie_len += 2; - if (sta->wpa_sm == NULL) - sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, - sta->addr, - p2p_dev_addr); - if (sta->wpa_sm == NULL) { - wpa_printf(MSG_WARNING, "Failed to initialize WPA " - "state machine"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, - wpa_ie, wpa_ie_len, - elems.mdie, elems.mdie_len); - if (res == WPA_INVALID_GROUP) - resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; - else if (res == WPA_INVALID_PAIRWISE) - resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; - else if (res == WPA_INVALID_AKMP) - resp = WLAN_STATUS_AKMP_NOT_VALID; - else if (res == WPA_ALLOC_FAIL) - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; -#ifdef CONFIG_IEEE80211W - else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) - resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; - else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) - resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; -#endif /* CONFIG_IEEE80211W */ - else if (res == WPA_INVALID_MDIE) - resp = WLAN_STATUS_INVALID_MDIE; - else if (res != WPA_IE_OK) - resp = WLAN_STATUS_INVALID_IE; - if (resp != WLAN_STATUS_SUCCESS) - return resp; -#ifdef CONFIG_IEEE80211W - if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && - sta->sa_query_count > 0) - ap_check_sa_query_timeout(hapd, sta); - if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && - (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) { - /* - * STA has already been associated with MFP and SA - * Query timeout has not been reached. Reject the - * association attempt temporarily and start SA Query, - * if one is not pending. - */ - - if (sta->sa_query_count == 0) - ap_sta_start_sa_query(hapd, sta); - - return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; - } - - if (wpa_auth_uses_mfp(sta->wpa_sm)) - sta->flags |= WLAN_STA_MFP; - else - sta->flags &= ~WLAN_STA_MFP; -#endif /* CONFIG_IEEE80211W */ - -#ifdef CONFIG_IEEE80211R - if (sta->auth_alg == WLAN_AUTH_FT) { - if (!reassoc) { - wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried " - "to use association (not " - "re-association) with FT auth_alg", - MAC2STR(sta->addr)); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies, - ies_len); - if (resp != WLAN_STATUS_SUCCESS) - return resp; - } -#endif /* CONFIG_IEEE80211R */ - -#ifdef CONFIG_SAE - if (wpa_auth_uses_sae(sta->wpa_sm) && - sta->auth_alg != WLAN_AUTH_SAE && - !(sta->auth_alg == WLAN_AUTH_FT && - wpa_auth_uses_ft_sae(sta->wpa_sm))) { - wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use " - "SAE AKM after non-SAE auth_alg %u", - MAC2STR(sta->addr), sta->auth_alg); - return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; - } -#endif /* CONFIG_SAE */ - -#ifdef CONFIG_IEEE80211N - if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) && - wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, - "Station tried to use TKIP with HT " - "association"); - return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; - } -#endif /* CONFIG_IEEE80211N */ - } else - wpa_auth_sta_no_wpa(sta->wpa_sm); - -#ifdef CONFIG_P2P - p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len); -#endif /* CONFIG_P2P */ - -#ifdef CONFIG_HS20 - wpabuf_free(sta->hs20_ie); - if (elems.hs20 && elems.hs20_len > 4) { - sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, - elems.hs20_len - 4); - } else - sta->hs20_ie = NULL; -#endif /* CONFIG_HS20 */ - - return WLAN_STATUS_SUCCESS; -} - - -static void send_deauth(struct hostapd_data *hapd, const u8 *addr, - u16 reason_code) -{ - int send_len; - struct ieee80211_mgmt reply; - - os_memset(&reply, 0, sizeof(reply)); - reply.frame_control = - IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH); - os_memcpy(reply.da, addr, ETH_ALEN); - os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN); - os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN); - - 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) < 0) - wpa_printf(MSG_INFO, "Failed to send deauth: %s", - strerror(errno)); -} - - -static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, - u16 status_code, int reassoc, const u8 *ies, - size_t ies_len) -{ - int send_len; - u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; - struct ieee80211_mgmt *reply; - u8 *p; - - os_memset(buf, 0, sizeof(buf)); - reply = (struct ieee80211_mgmt *) buf; - reply->frame_control = - IEEE80211_FC(WLAN_FC_TYPE_MGMT, - (reassoc ? WLAN_FC_STYPE_REASSOC_RESP : - WLAN_FC_STYPE_ASSOC_RESP)); - os_memcpy(reply->da, sta->addr, ETH_ALEN); - os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN); - - send_len = IEEE80211_HDRLEN; - send_len += sizeof(reply->u.assoc_resp); - reply->u.assoc_resp.capab_info = - host_to_le16(hostapd_own_capab_info(hapd, sta, 0)); - reply->u.assoc_resp.status_code = host_to_le16(status_code); - reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) - | BIT(14) | BIT(15)); - /* Supported rates */ - p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable); - /* Extended supported rates */ - p = hostapd_eid_ext_supp_rates(hapd, p); - -#ifdef CONFIG_IEEE80211R - if (status_code == WLAN_STATUS_SUCCESS) { - /* IEEE 802.11r: Mobility Domain Information, Fast BSS - * Transition Information, RSN, [RIC Response] */ - p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p, - buf + sizeof(buf) - p, - sta->auth_alg, ies, ies_len); - } -#endif /* CONFIG_IEEE80211R */ - -#ifdef CONFIG_IEEE80211W - if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) - p = hostapd_eid_assoc_comeback_time(hapd, sta, p); -#endif /* CONFIG_IEEE80211W */ - -#ifdef CONFIG_IEEE80211N - p = hostapd_eid_ht_capabilities(hapd, p); - p = hostapd_eid_ht_operation(hapd, p); -#endif /* CONFIG_IEEE80211N */ - -#ifdef CONFIG_IEEE80211AC - p = hostapd_eid_vht_capabilities(hapd, p); - p = hostapd_eid_vht_operation(hapd, p); -#endif /* CONFIG_IEEE80211AC */ - - p = hostapd_eid_ext_capab(hapd, p); - p = hostapd_eid_bss_max_idle_period(hapd, p); - if (sta->qos_map_enabled) - p = hostapd_eid_qos_map_set(hapd, p); - - if (sta->flags & WLAN_STA_WMM) - p = hostapd_eid_wmm(hapd, p); - -#ifdef CONFIG_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)); - p += wpabuf_len(wps); - wpabuf_free(wps); - } - } -#endif /* CONFIG_WPS */ - -#ifdef CONFIG_P2P - if (sta->p2p_ie) { - struct wpabuf *p2p_resp_ie; - enum p2p_status_code status; - switch (status_code) { - case WLAN_STATUS_SUCCESS: - status = P2P_SC_SUCCESS; - break; - case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA: - status = P2P_SC_FAIL_LIMIT_REACHED; - break; - default: - status = P2P_SC_FAIL_INVALID_PARAMS; - break; - } - p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status); - if (p2p_resp_ie) { - os_memcpy(p, wpabuf_head(p2p_resp_ie), - wpabuf_len(p2p_resp_ie)); - p += wpabuf_len(p2p_resp_ie); - wpabuf_free(p2p_resp_ie); - } - } -#endif /* CONFIG_P2P */ - -#ifdef CONFIG_P2P_MANAGER - if (hapd->conf->p2p & P2P_MANAGE) - p = hostapd_eid_p2p_manage(hapd, p); -#endif /* CONFIG_P2P_MANAGER */ - - send_len += p - reply->u.assoc_resp.variable; - - if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) - wpa_printf(MSG_INFO, "Failed to send assoc resp: %s", - strerror(errno)); -} - - -static void handle_assoc(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len, - int reassoc) -{ - u16 capab_info, listen_interval; - u16 resp = WLAN_STATUS_SUCCESS; - const u8 *pos; - int left, i; - struct sta_info *sta; - - if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : - sizeof(mgmt->u.assoc_req))) { - wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)", - reassoc, (unsigned long) len); - return; - } - -#ifdef CONFIG_TESTING_OPTIONS - if (reassoc) { - if (hapd->iconf->ignore_reassoc_probability > 0.0d && - drand48() < hapd->iconf->ignore_reassoc_probability) { - wpa_printf(MSG_INFO, - "TESTING: ignoring reassoc request from " - MACSTR, MAC2STR(mgmt->sa)); - return; - } - } else { - if (hapd->iconf->ignore_assoc_probability > 0.0d && - drand48() < hapd->iconf->ignore_assoc_probability) { - wpa_printf(MSG_INFO, - "TESTING: ignoring assoc request from " - MACSTR, MAC2STR(mgmt->sa)); - return; - } - } -#endif /* CONFIG_TESTING_OPTIONS */ - - if (reassoc) { - capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info); - listen_interval = le_to_host16( - mgmt->u.reassoc_req.listen_interval); - wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR - " capab_info=0x%02x listen_interval=%d current_ap=" - MACSTR, - MAC2STR(mgmt->sa), capab_info, listen_interval, - MAC2STR(mgmt->u.reassoc_req.current_ap)); - left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)); - pos = mgmt->u.reassoc_req.variable; - } else { - capab_info = le_to_host16(mgmt->u.assoc_req.capab_info); - listen_interval = le_to_host16( - mgmt->u.assoc_req.listen_interval); - wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR - " capab_info=0x%02x listen_interval=%d", - MAC2STR(mgmt->sa), capab_info, listen_interval); - left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)); - pos = mgmt->u.assoc_req.variable; - } - - sta = ap_get_sta(hapd, mgmt->sa); -#ifdef CONFIG_IEEE80211R - if (sta && sta->auth_alg == WLAN_AUTH_FT && - (sta->flags & WLAN_STA_AUTH) == 0) { - wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate " - "prior to authentication since it is using " - "over-the-DS FT", MAC2STR(mgmt->sa)); - } else -#endif /* CONFIG_IEEE80211R */ - if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { - hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "Station tried to " - "associate before authentication " - "(aid=%d flags=0x%x)", - sta ? sta->aid : -1, - sta ? sta->flags : 0); - send_deauth(hapd, mgmt->sa, - WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); - return; - } - - if (hapd->tkip_countermeasures) { - resp = WLAN_REASON_MICHAEL_MIC_FAILURE; - goto fail; - } - - if (listen_interval > hapd->conf->max_listen_interval) { - hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "Too large Listen Interval (%d)", - listen_interval); - resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE; - goto fail; - } - - /* followed by SSID and Supported rates; and HT capabilities if 802.11n - * is used */ - resp = check_assoc_ies(hapd, sta, pos, left, reassoc); - if (resp != WLAN_STATUS_SUCCESS) - goto fail; - - if (hostapd_get_aid(hapd, sta) < 0) { - hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "No room for more AIDs"); - resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; - goto fail; - } - - sta->capability = capab_info; - sta->listen_interval = listen_interval; - - if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) - sta->flags |= WLAN_STA_NONERP; - for (i = 0; i < sta->supported_rates_len; i++) { - if ((sta->supported_rates[i] & 0x7f) > 22) { - sta->flags &= ~WLAN_STA_NONERP; - break; - } - } - if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) { - sta->nonerp_set = 1; - hapd->iface->num_sta_non_erp++; - if (hapd->iface->num_sta_non_erp == 1) - ieee802_11_set_beacons(hapd->iface); - } - - if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) && - !sta->no_short_slot_time_set) { - sta->no_short_slot_time_set = 1; - hapd->iface->num_sta_no_short_slot_time++; - if (hapd->iface->current_mode->mode == - HOSTAPD_MODE_IEEE80211G && - hapd->iface->num_sta_no_short_slot_time == 1) - ieee802_11_set_beacons(hapd->iface); - } - - if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) - sta->flags |= WLAN_STA_SHORT_PREAMBLE; - else - sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; - - if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && - !sta->no_short_preamble_set) { - sta->no_short_preamble_set = 1; - hapd->iface->num_sta_no_short_preamble++; - if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G - && hapd->iface->num_sta_no_short_preamble == 1) - ieee802_11_set_beacons(hapd->iface); - } - -#ifdef CONFIG_IEEE80211N - update_ht_state(hapd, sta); -#endif /* CONFIG_IEEE80211N */ - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "association OK (aid %d)", sta->aid); - /* Station will be marked associated, after it acknowledges AssocResp - */ - sta->flags |= WLAN_STA_ASSOC_REQ_OK; - -#ifdef CONFIG_IEEE80211W - if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) { - wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out " - "SA Query procedure", reassoc ? "re" : ""); - /* TODO: Send a protected Disassociate frame to the STA using - * the old key and Reason Code "Previous Authentication no - * longer valid". Make sure this is only sent protected since - * unprotected frame would be received by the STA that is now - * trying to associate. - */ - } -#endif /* CONFIG_IEEE80211W */ - - if (reassoc) { - os_memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap, - ETH_ALEN); - } - - if (sta->last_assoc_req) - os_free(sta->last_assoc_req); - sta->last_assoc_req = os_malloc(len); - if (sta->last_assoc_req) - os_memcpy(sta->last_assoc_req, mgmt, len); - - /* Make sure that the previously registered inactivity timer will not - * remove the STA immediately. */ - sta->timeout_next = STA_NULLFUNC; - - fail: - send_assoc_resp(hapd, sta, resp, reassoc, pos, left); -} - - -static void handle_disassoc(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len) -{ - struct sta_info *sta; - - if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) { - wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)", - (unsigned long) len); - return; - } - - wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d", - MAC2STR(mgmt->sa), - le_to_host16(mgmt->u.disassoc.reason_code)); - - sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL) { - wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated", - MAC2STR(mgmt->sa)); - return; - } - - ap_sta_set_authorized(hapd, sta, 0); - sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); - wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "disassociated"); - sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - /* Stop Accounting and IEEE 802.1X sessions, but leave the STA - * authenticated. */ - accounting_sta_stop(hapd, sta); - ieee802_1x_free_station(sta); - hostapd_drv_sta_remove(hapd, sta->addr); - - if (sta->timeout_next == STA_NULLFUNC || - sta->timeout_next == STA_DISASSOC) { - sta->timeout_next = STA_DEAUTH; - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, - hapd, sta); - } - - mlme_disassociate_indication( - hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code)); -} - - -static void handle_deauth(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len) -{ - struct sta_info *sta; - - if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short " - "payload (len=%lu)", (unsigned long) len); - return; - } - - 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_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_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "deauthenticated"); - mlme_deauthenticate_indication( - hapd, sta, le_to_host16(mgmt->u.deauth.reason_code)); - sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - ap_free_sta(hapd, sta); -} - - -static void handle_beacon(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len, - struct hostapd_frame_info *fi) -{ - struct ieee802_11_elems elems; - - if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) { - wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)", - (unsigned long) len); - return; - } - - (void) ieee802_11_parse_elems(mgmt->u.beacon.variable, - len - (IEEE80211_HDRLEN + - sizeof(mgmt->u.beacon)), &elems, - 0); - - ap_list_process_beacon(hapd->iface, mgmt, &elems, fi); -} - - -#ifdef CONFIG_IEEE80211W - -static int hostapd_sa_query_action(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, - size_t len) -{ - const u8 *end; - - end = mgmt->u.action.u.sa_query_resp.trans_id + - WLAN_SA_QUERY_TR_ID_LEN; - if (((u8 *) mgmt) + len < end) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action " - "frame (len=%lu)", (unsigned long) len); - return 0; - } - - 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); - return 1; -} - - -static int robust_action_frame(u8 category) -{ - return category != WLAN_ACTION_PUBLIC && - category != WLAN_ACTION_HT; -} -#endif /* CONFIG_IEEE80211W */ - - -static int handle_action(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len) -{ - struct sta_info *sta; - sta = ap_get_sta(hapd, mgmt->sa); - - if (len < IEEE80211_HDRLEN + 1) { - hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "handle_action - too short payload (len=%lu)", - (unsigned long) len); - return 0; - } - - if (mgmt->u.action.category != WLAN_ACTION_PUBLIC && - (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action " - "frame (category=%u) from unassociated STA " MACSTR, - MAC2STR(mgmt->sa), mgmt->u.action.category); - return 0; - } - -#ifdef CONFIG_IEEE80211W - if (sta && (sta->flags & WLAN_STA_MFP) && - !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) && - robust_action_frame(mgmt->u.action.category)) { - hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "Dropped unprotected Robust Action frame from " - "an MFP STA"); - return 0; - } -#endif /* CONFIG_IEEE80211W */ - - switch (mgmt->u.action.category) { -#ifdef CONFIG_IEEE80211R - case WLAN_ACTION_FT: - if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, - len - IEEE80211_HDRLEN)) - break; - return 1; -#endif /* CONFIG_IEEE80211R */ - case WLAN_ACTION_WMM: - hostapd_wmm_action(hapd, mgmt, len); - return 1; -#ifdef CONFIG_IEEE80211W - case WLAN_ACTION_SA_QUERY: - return hostapd_sa_query_action(hapd, mgmt, len); -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WNM - case WLAN_ACTION_WNM: - ieee802_11_rx_wnm_action_ap(hapd, mgmt, len); - return 1; -#endif /* CONFIG_WNM */ - case WLAN_ACTION_PUBLIC: - case WLAN_ACTION_PROTECTED_DUAL: - if (hapd->public_action_cb) { - hapd->public_action_cb(hapd->public_action_cb_ctx, - (u8 *) mgmt, len, - hapd->iface->freq); - } - if (hapd->public_action_cb2) { - hapd->public_action_cb2(hapd->public_action_cb2_ctx, - (u8 *) mgmt, len, - hapd->iface->freq); - } - if (hapd->public_action_cb || hapd->public_action_cb2) - return 1; - break; - case WLAN_ACTION_VENDOR_SPECIFIC: - if (hapd->vendor_action_cb) { - if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx, - (u8 *) mgmt, len, - hapd->iface->freq) == 0) - return 1; - } - break; - } - - hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "handle_action - unknown action category %d or invalid " - "frame", - mgmt->u.action.category); - if (!(mgmt->da[0] & 0x01) && !(mgmt->u.action.category & 0x80) && - !(mgmt->sa[0] & 0x01)) { - struct ieee80211_mgmt *resp; - - /* - * IEEE 802.11-REVma/D9.0 - 7.3.1.11 - * Return the Action frame to the source without change - * except that MSB of the Category set to 1. - */ - wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action " - "frame back to sender"); - resp = os_malloc(len); - if (resp == NULL) - return 0; - os_memcpy(resp, mgmt, len); - os_memcpy(resp->da, resp->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 |= 0x80; - - if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) { - wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send " - "Action frame"); - } - os_free(resp); - } - - return 1; -} - - -/** - * ieee802_11_mgmt - process incoming IEEE 802.11 management frames - * @hapd: hostapd BSS data structure (the BSS to which the management frame was - * sent to) - * @buf: management frame data (starting from IEEE 802.11 header) - * @len: length of frame data in octets - * @fi: meta data about received frame (signal level, etc.) - * - * Process all incoming IEEE 802.11 management frames. This will be called for - * each frame received from the kernel driver through wlan#ap interface. In - * addition, it can be called to re-inserted pending frames (e.g., when using - * external RADIUS server as an MAC ACL). - */ -int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, - struct hostapd_frame_info *fi) -{ - struct ieee80211_mgmt *mgmt; - int broadcast; - u16 fc, stype; - int ret = 0; - -#ifdef CONFIG_TESTING_OPTIONS - if (hapd->ext_mgmt_frame_handling) { - size_t hex_len = 2 * len + 1; - char *hex = os_malloc(hex_len); - if (hex) { - wpa_snprintf_hex(hex, hex_len, buf, len); - wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex); - os_free(hex); - } - return 1; - } -#endif /* CONFIG_TESTING_OPTIONS */ - - if (len < 24) - return 0; - - mgmt = (struct ieee80211_mgmt *) buf; - fc = le_to_host16(mgmt->frame_control); - stype = WLAN_FC_GET_STYPE(fc); - - if (stype == WLAN_FC_STYPE_BEACON) { - handle_beacon(hapd, mgmt, len, fi); - return 1; - } - - broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff && - mgmt->bssid[2] == 0xff && mgmt->bssid[3] == 0xff && - 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) { - wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address", - MAC2STR(mgmt->bssid)); - return 0; - } - - - if (stype == WLAN_FC_STYPE_PROBE_REQ) { - handle_probe_req(hapd, mgmt, len, fi->ssi_signal); - return 1; - } - - if (os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) { - hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "MGMT: DA=" MACSTR " not our address", - MAC2STR(mgmt->da)); - return 0; - } - - switch (stype) { - case WLAN_FC_STYPE_AUTH: - wpa_printf(MSG_DEBUG, "mgmt::auth"); - handle_auth(hapd, mgmt, len); - ret = 1; - break; - case WLAN_FC_STYPE_ASSOC_REQ: - wpa_printf(MSG_DEBUG, "mgmt::assoc_req"); - handle_assoc(hapd, mgmt, len, 0); - ret = 1; - break; - case WLAN_FC_STYPE_REASSOC_REQ: - wpa_printf(MSG_DEBUG, "mgmt::reassoc_req"); - handle_assoc(hapd, mgmt, len, 1); - ret = 1; - break; - case WLAN_FC_STYPE_DISASSOC: - wpa_printf(MSG_DEBUG, "mgmt::disassoc"); - handle_disassoc(hapd, mgmt, len); - ret = 1; - break; - case WLAN_FC_STYPE_DEAUTH: - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth"); - handle_deauth(hapd, mgmt, len); - ret = 1; - break; - case WLAN_FC_STYPE_ACTION: - wpa_printf(MSG_DEBUG, "mgmt::action"); - ret = handle_action(hapd, mgmt, len); - break; - default: - hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "unknown mgmt frame subtype %d", stype); - break; - } - - return ret; -} - - -static void handle_auth_cb(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, - size_t len, int ok) -{ - u16 auth_alg, auth_transaction, status_code; - struct sta_info *sta; - - if (!ok) { - hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_NOTICE, - "did not acknowledge authentication response"); - return; - } - - if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { - wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)", - (unsigned long) len); - return; - } - - auth_alg = le_to_host16(mgmt->u.auth.auth_alg); - auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); - status_code = le_to_host16(mgmt->u.auth.status_code); - - sta = ap_get_sta(hapd, mgmt->da); - if (!sta) { - wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found", - MAC2STR(mgmt->da)); - return; - } - - if (status_code == WLAN_STATUS_SUCCESS && - ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || - (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "authenticated"); - sta->flags |= WLAN_STA_AUTH; - } -} - - -static void hostapd_set_wds_encryption(struct hostapd_data *hapd, - struct sta_info *sta, - char *ifname_wds) -{ - int i; - struct hostapd_ssid *ssid = sta->ssid; - - if (hapd->conf->ieee802_1x || hapd->conf->wpa) - return; - - for (i = 0; i < 4; i++) { - if (ssid->wep.key[i] && - hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i, - i == ssid->wep.idx, NULL, 0, - ssid->wep.key[i], ssid->wep.len[i])) { - wpa_printf(MSG_WARNING, - "Could not set WEP keys for WDS interface; %s", - ifname_wds); - break; - } - } -} - - -static void handle_assoc_cb(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, - size_t len, int reassoc, int ok) -{ - u16 status; - struct sta_info *sta; - int new_assoc = 1; - struct ieee80211_ht_capabilities ht_cap; - struct ieee80211_vht_capabilities vht_cap; - - if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) : - sizeof(mgmt->u.assoc_resp))) { - wpa_printf(MSG_INFO, "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)", - reassoc, (unsigned long) len); - return; - } - - sta = ap_get_sta(hapd, mgmt->da); - if (!sta) { - wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found", - MAC2STR(mgmt->da)); - return; - } - - if (!ok) { - hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "did not acknowledge association response"); - sta->flags &= ~WLAN_STA_ASSOC_REQ_OK; - return; - } - - if (reassoc) - status = le_to_host16(mgmt->u.reassoc_resp.status_code); - else - status = le_to_host16(mgmt->u.assoc_resp.status_code); - - if (status != WLAN_STATUS_SUCCESS) - goto fail; - - /* Stop previous accounting session, if one is started, and allocate - * new session id for the new session. */ - accounting_sta_stop(hapd, sta); - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, - "associated (aid %d)", - sta->aid); - - if (sta->flags & WLAN_STA_ASSOC) - new_assoc = 0; - sta->flags |= WLAN_STA_ASSOC; - sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; - if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) || - sta->auth_alg == WLAN_AUTH_FT) { - /* - * Open, static WEP, or FT protocol; no separate authorization - * step. - */ - ap_sta_set_authorized(hapd, sta, 1); - } - - if (reassoc) - mlme_reassociate_indication(hapd, sta); - else - mlme_associate_indication(hapd, sta); - -#ifdef CONFIG_IEEE80211W - sta->sa_query_timed_out = 0; -#endif /* CONFIG_IEEE80211W */ - - /* - * Remove the STA entry in order to make sure the STA PS state gets - * cleared and configuration gets updated in case of reassociation back - * to the same AP. - */ - hostapd_drv_sta_remove(hapd, sta->addr); - -#ifdef CONFIG_IEEE80211N - if (sta->flags & WLAN_STA_HT) - hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap); -#endif /* CONFIG_IEEE80211N */ -#ifdef CONFIG_IEEE80211AC - if (sta->flags & WLAN_STA_VHT) - hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap); -#endif /* CONFIG_IEEE80211AC */ - - 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_VHT ? &vht_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) { - int ret; - char ifname_wds[IFNAMSIZ + 1]; - - ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr, - sta->aid, 1); - if (!ret) - hostapd_set_wds_encryption(hapd, sta, ifname_wds); - } - - if (sta->eapol_sm == NULL) { - /* - * This STA does not use RADIUS server for EAP authentication, - * so bind it to the selected VLAN interface now, since the - * interface selection is not going to change anymore. - */ - if (ap_sta_bind_vlan(hapd, sta, 0) < 0) - goto fail; - } else if (sta->vlan_id) { - /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */ - if (ap_sta_bind_vlan(hapd, sta, 0) < 0) - goto fail; - } - - hostapd_set_sta_flags(hapd, sta); - - if (sta->auth_alg == WLAN_AUTH_FT) - wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); - else - wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); - hapd->new_assoc_sta_cb(hapd, sta, !new_assoc); - - ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); - - fail: - /* Copy of the association request is not needed anymore */ - if (sta->last_assoc_req) { - os_free(sta->last_assoc_req); - sta->last_assoc_req = NULL; - } -} - - -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 - * was sent from) - * @buf: management frame data (starting from IEEE 802.11 header) - * @len: length of frame data in octets - * @stype: management frame subtype from frame control field - * @ok: Whether the frame was ACK'ed - */ -void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, - u16 stype, int ok) -{ - const struct ieee80211_mgmt *mgmt; - mgmt = (const struct ieee80211_mgmt *) buf; - -#ifdef CONFIG_TESTING_OPTIONS - if (hapd->ext_mgmt_frame_handling) { - wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-TX-STATUS stype=%u ok=%d", - stype, ok); - return; - } -#endif /* CONFIG_TESTING_OPTIONS */ - - switch (stype) { - case WLAN_FC_STYPE_AUTH: - wpa_printf(MSG_DEBUG, "mgmt::auth cb"); - handle_auth_cb(hapd, mgmt, len, ok); - break; - case WLAN_FC_STYPE_ASSOC_RESP: - wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb"); - handle_assoc_cb(hapd, mgmt, len, 0, ok); - break; - case WLAN_FC_STYPE_REASSOC_RESP: - wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb"); - handle_assoc_cb(hapd, mgmt, len, 1, ok); - break; - case WLAN_FC_STYPE_PROBE_RESP: - wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb"); - break; - case WLAN_FC_STYPE_DEAUTH: - 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"); - break; - default: - wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype); - break; - } -} - - -int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) -{ - /* TODO */ - return 0; -} - - -int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, - char *buf, size_t buflen) -{ - /* TODO */ - return 0; -} - - -void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, - const u8 *buf, size_t len, int ack) -{ - 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 || !(sta->flags & WLAN_STA_ASSOC)) - return; - if (sta->flags & WLAN_STA_PENDING_POLL) { - wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending " - "activity poll", MAC2STR(sta->addr), - ack ? "ACKed" : "did not ACK"); - if (ack) - sta->flags &= ~WLAN_STA_PENDING_POLL; - } - - ieee802_1x_tx_status(hapd, sta, buf, len, ack); -} - - -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 || !(sta->flags & WLAN_STA_ASSOC)) { - wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA " - MACSTR " that is not currently associated", - MAC2STR(dst)); - 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) -{ - struct sta_info *sta; - - sta = ap_get_sta(hapd, src); - if (sta && (sta->flags & WLAN_STA_ASSOC)) { - if (!hapd->conf->wds_sta) - return; - - if (wds && !(sta->flags & WLAN_STA_WDS)) { - int ret; - char ifname_wds[IFNAMSIZ + 1]; - - wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for " - "STA " MACSTR " (aid %u)", - MAC2STR(sta->addr), sta->aid); - sta->flags |= WLAN_STA_WDS; - ret = hostapd_set_wds_sta(hapd, ifname_wds, - sta->addr, sta->aid, 1); - if (!ret) - hostapd_set_wds_encryption(hapd, sta, - ifname_wds); - } - return; - } - - wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA " - MACSTR, MAC2STR(src)); - if (src[0] & 0x01) { - /* Broadcast bit set in SA?! Ignore the frame silently. */ - return; - } - - if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) { - wpa_printf(MSG_DEBUG, "Association Response to the STA has " - "already been sent, but no TX status yet known - " - "ignore Class 3 frame issue with " MACSTR, - MAC2STR(src)); - return; - } - - if (sta && (sta->flags & WLAN_STA_AUTH)) - hostapd_drv_sta_disassoc( - hapd, src, - WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); - else - hostapd_drv_sta_deauth( - hapd, src, - WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); -} - - -#endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/contrib/hostapd/src/ap/ieee802_11.h b/contrib/hostapd/src/ap/ieee802_11.h deleted file mode 100644 index 5edeb71cb9..0000000000 --- a/contrib/hostapd/src/ap/ieee802_11.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * hostapd / IEEE 802.11 Management - * Copyright (c) 2002-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef IEEE802_11_H -#define IEEE802_11_H - -struct hostapd_iface; -struct hostapd_data; -struct sta_info; -struct hostapd_frame_info; -struct ieee80211_ht_capabilities; - -int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, - struct hostapd_frame_info *fi); -void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, - u16 stype, int ok); -void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len); -#ifdef NEED_AP_MLME -int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen); -int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, - char *buf, size_t buflen); -#else /* NEED_AP_MLME */ -static inline int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, - size_t buflen) -{ - return 0; -} - -static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd, - struct sta_info *sta, - char *buf, size_t buflen) -{ - return 0; -} -#endif /* NEED_AP_MLME */ -u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, - int probe); -u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid); -u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid); -u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid); -u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid); -u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid); -u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid); -u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid); -u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid); -int hostapd_ht_operation_update(struct hostapd_iface *iface); -void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, - const u8 *addr, const u8 *trans_id); -void hostapd_get_ht_capab(struct hostapd_data *hapd, - struct ieee80211_ht_capabilities *ht_cap, - struct ieee80211_ht_capabilities *neg_ht_cap); -void hostapd_get_vht_capab(struct hostapd_data *hapd, - struct ieee80211_vht_capabilities *vht_cap, - struct ieee80211_vht_capabilities *neg_vht_cap); -u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *ht_capab, size_t ht_capab_len); -void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta); -u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *vht_capab, size_t vht_capab_len); -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); -u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid); - -#endif /* IEEE802_11_H */ diff --git a/contrib/hostapd/src/ap/ieee802_11_auth.c b/contrib/hostapd/src/ap/ieee802_11_auth.c deleted file mode 100644 index 56c3ce0313..0000000000 --- a/contrib/hostapd/src/ap/ieee802_11_auth.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * hostapd / IEEE 802.11 authentication (ACL) - * Copyright (c) 2003-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * Access control list for IEEE 802.11 authentication can uses statically - * configured ACL from configuration files or an external RADIUS server. - * Results from external RADIUS queries are cached to allow faster - * authentication frame processing. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "crypto/sha1.h" -#include "radius/radius.h" -#include "radius/radius_client.h" -#include "hostapd.h" -#include "ap_config.h" -#include "ap_drv_ops.h" -#include "ieee802_11.h" -#include "ieee802_1x.h" -#include "ieee802_11_auth.h" - -#define RADIUS_ACL_TIMEOUT 30 - - -struct hostapd_cached_radius_acl { - struct os_reltime timestamp; - macaddr addr; - int accepted; /* HOSTAPD_ACL_* */ - struct hostapd_cached_radius_acl *next; - u32 session_timeout; - u32 acct_interim_interval; - int vlan_id; - struct hostapd_sta_wpa_psk_short *psk; - char *identity; - char *radius_cui; -}; - - -struct hostapd_acl_query_data { - struct os_reltime timestamp; - u8 radius_id; - macaddr addr; - u8 *auth_msg; /* IEEE 802.11 authentication frame from station */ - size_t auth_msg_len; - struct hostapd_acl_query_data *next; -}; - - -#ifndef CONFIG_NO_RADIUS -static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e) -{ - os_free(e->identity); - os_free(e->radius_cui); - hostapd_free_psk_list(e->psk); - os_free(e); -} - - -static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache) -{ - struct hostapd_cached_radius_acl *prev; - - while (acl_cache) { - prev = acl_cache; - acl_cache = acl_cache->next; - hostapd_acl_cache_free_entry(prev); - } -} - - -static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk, - struct hostapd_sta_wpa_psk_short *src) -{ - struct hostapd_sta_wpa_psk_short **copy_to; - struct hostapd_sta_wpa_psk_short *copy_from; - - /* Copy PSK linked list */ - copy_to = psk; - copy_from = src; - while (copy_from && copy_to) { - *copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short)); - if (*copy_to == NULL) - break; - os_memcpy(*copy_to, copy_from, - sizeof(struct hostapd_sta_wpa_psk_short)); - copy_from = copy_from->next; - copy_to = &((*copy_to)->next); - } - if (copy_to) - *copy_to = NULL; -} - - -static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, - u32 *session_timeout, - u32 *acct_interim_interval, int *vlan_id, - struct hostapd_sta_wpa_psk_short **psk, - char **identity, char **radius_cui) -{ - struct hostapd_cached_radius_acl *entry; - struct os_reltime now; - - os_get_reltime(&now); - - for (entry = hapd->acl_cache; entry; entry = entry->next) { - if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0) - continue; - - if (os_reltime_expired(&now, &entry->timestamp, - RADIUS_ACL_TIMEOUT)) - return -1; /* entry has expired */ - if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT) - if (session_timeout) - *session_timeout = entry->session_timeout; - if (acct_interim_interval) - *acct_interim_interval = - entry->acct_interim_interval; - if (vlan_id) - *vlan_id = entry->vlan_id; - copy_psk_list(psk, entry->psk); - if (identity) { - if (entry->identity) - *identity = os_strdup(entry->identity); - else - *identity = NULL; - } - if (radius_cui) { - if (entry->radius_cui) - *radius_cui = os_strdup(entry->radius_cui); - else - *radius_cui = NULL; - } - return entry->accepted; - } - - return -1; -} -#endif /* CONFIG_NO_RADIUS */ - - -static void hostapd_acl_query_free(struct hostapd_acl_query_data *query) -{ - if (query == NULL) - return; - os_free(query->auth_msg); - os_free(query); -} - - -#ifndef CONFIG_NO_RADIUS -static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, - struct hostapd_acl_query_data *query) -{ - struct radius_msg *msg; - char buf[128]; - - query->radius_id = radius_client_get_id(hapd->radius); - msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id); - if (msg == NULL) - return -1; - - radius_msg_make_authenticator(msg, addr, ETH_ALEN); - - os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr)); - if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf, - os_strlen(buf))) { - wpa_printf(MSG_DEBUG, "Could not add User-Name"); - goto fail; - } - - if (!radius_msg_add_attr_user_password( - msg, (u8 *) buf, os_strlen(buf), - hapd->conf->radius->auth_server->shared_secret, - hapd->conf->radius->auth_server->shared_secret_len)) { - wpa_printf(MSG_DEBUG, "Could not add User-Password"); - goto fail; - } - - if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, - NULL, msg) < 0) - goto fail; - - os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, - MAC2STR(addr)); - if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, - (u8 *) buf, os_strlen(buf))) { - wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id"); - goto fail; - } - - os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b"); - if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, - (u8 *) buf, os_strlen(buf))) { - wpa_printf(MSG_DEBUG, "Could not add Connect-Info"); - goto fail; - } - - if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0) - goto fail; - return 0; - - fail: - radius_msg_free(msg); - return -1; -} -#endif /* CONFIG_NO_RADIUS */ - - -/** - * hostapd_allowed_address - Check whether a specified STA can be authenticated - * @hapd: hostapd BSS data - * @addr: MAC address of the STA - * @msg: Authentication message - * @len: Length of msg in octets - * @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: Linked list buffer for returning WPA PSK - * @identity: Buffer for returning identity (from RADIUS) - * @radius_cui: Buffer for returning CUI (from RADIUS) - * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING - * - * The caller is responsible for freeing the returned *identity and *radius_cui - * values with os_free(). - */ -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, - struct hostapd_sta_wpa_psk_short **psk, - char **identity, char **radius_cui) -{ - if (session_timeout) - *session_timeout = 0; - if (acct_interim_interval) - *acct_interim_interval = 0; - if (vlan_id) - *vlan_id = 0; - if (psk) - *psk = NULL; - if (identity) - *identity = NULL; - if (radius_cui) - *radius_cui = NULL; - - if (hostapd_maclist_found(hapd->conf->accept_mac, - hapd->conf->num_accept_mac, addr, vlan_id)) - return HOSTAPD_ACL_ACCEPT; - - if (hostapd_maclist_found(hapd->conf->deny_mac, - hapd->conf->num_deny_mac, addr, vlan_id)) - return HOSTAPD_ACL_REJECT; - - if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED) - return HOSTAPD_ACL_ACCEPT; - if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED) - return HOSTAPD_ACL_REJECT; - - if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) { -#ifdef CONFIG_NO_RADIUS - return HOSTAPD_ACL_REJECT; -#else /* CONFIG_NO_RADIUS */ - struct hostapd_acl_query_data *query; - - /* 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, psk, - identity, radius_cui); - if (res == HOSTAPD_ACL_ACCEPT || - res == HOSTAPD_ACL_ACCEPT_TIMEOUT) - return res; - if (res == HOSTAPD_ACL_REJECT) - return HOSTAPD_ACL_REJECT; - - query = hapd->acl_queries; - while (query) { - if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) { - /* pending query in RADIUS retransmit queue; - * do not generate a new one */ - if (identity) { - os_free(*identity); - *identity = NULL; - } - if (radius_cui) { - os_free(*radius_cui); - *radius_cui = NULL; - } - return HOSTAPD_ACL_PENDING; - } - query = query->next; - } - - if (!hapd->conf->radius->auth_server) - return HOSTAPD_ACL_REJECT; - - /* No entry in the cache - query external RADIUS server */ - query = os_zalloc(sizeof(*query)); - if (query == NULL) { - wpa_printf(MSG_ERROR, "malloc for query data failed"); - return HOSTAPD_ACL_REJECT; - } - os_get_reltime(&query->timestamp); - os_memcpy(query->addr, addr, ETH_ALEN); - if (hostapd_radius_acl_query(hapd, addr, query)) { - wpa_printf(MSG_DEBUG, "Failed to send Access-Request " - "for ACL query."); - hostapd_acl_query_free(query); - return HOSTAPD_ACL_REJECT; - } - - query->auth_msg = os_malloc(len); - if (query->auth_msg == NULL) { - wpa_printf(MSG_ERROR, "Failed to allocate memory for " - "auth frame."); - hostapd_acl_query_free(query); - return HOSTAPD_ACL_REJECT; - } - os_memcpy(query->auth_msg, msg, len); - query->auth_msg_len = len; - query->next = hapd->acl_queries; - hapd->acl_queries = query; - - /* Queued data will be processed in hostapd_acl_recv_radius() - * when RADIUS server replies to the sent Access-Request. */ - return HOSTAPD_ACL_PENDING; -#endif /* CONFIG_NO_RADIUS */ - } - - return HOSTAPD_ACL_REJECT; -} - - -#ifndef CONFIG_NO_RADIUS -static void hostapd_acl_expire_cache(struct hostapd_data *hapd, - struct os_reltime *now) -{ - struct hostapd_cached_radius_acl *prev, *entry, *tmp; - - prev = NULL; - entry = hapd->acl_cache; - - while (entry) { - if (os_reltime_expired(now, &entry->timestamp, - RADIUS_ACL_TIMEOUT)) { - wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR - " has expired.", MAC2STR(entry->addr)); - if (prev) - prev->next = entry->next; - else - hapd->acl_cache = entry->next; - hostapd_drv_set_radius_acl_expire(hapd, entry->addr); - tmp = entry; - entry = entry->next; - hostapd_acl_cache_free_entry(tmp); - continue; - } - - prev = entry; - entry = entry->next; - } -} - - -static void hostapd_acl_expire_queries(struct hostapd_data *hapd, - struct os_reltime *now) -{ - struct hostapd_acl_query_data *prev, *entry, *tmp; - - prev = NULL; - entry = hapd->acl_queries; - - while (entry) { - if (os_reltime_expired(now, &entry->timestamp, - RADIUS_ACL_TIMEOUT)) { - wpa_printf(MSG_DEBUG, "ACL query for " MACSTR - " has expired.", MAC2STR(entry->addr)); - if (prev) - prev->next = entry->next; - else - hapd->acl_queries = entry->next; - - tmp = entry; - entry = entry->next; - hostapd_acl_query_free(tmp); - continue; - } - - prev = entry; - entry = entry->next; - } -} - - -/** - * hostapd_acl_expire - ACL cache expiration callback - * @eloop_ctx: struct hostapd_data * - * @timeout_ctx: Not used - */ -static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - struct os_reltime now; - - os_get_reltime(&now); - hostapd_acl_expire_cache(hapd, &now); - hostapd_acl_expire_queries(hapd, &now); - - eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL); -} - - -static void decode_tunnel_passwords(struct hostapd_data *hapd, - const u8 *shared_secret, - size_t shared_secret_len, - struct radius_msg *msg, - struct radius_msg *req, - struct hostapd_cached_radius_acl *cache) -{ - int passphraselen; - char *passphrase, *strpassphrase; - size_t i; - struct hostapd_sta_wpa_psk_short *psk; - - /* - * Decode all tunnel passwords as PSK and save them into a linked list. - */ - for (i = 0; ; i++) { - passphrase = radius_msg_get_tunnel_password( - msg, &passphraselen, shared_secret, shared_secret_len, - req, i); - /* - * Passphrase is NULL iff there is no i-th Tunnel-Password - * attribute in msg. - */ - if (passphrase == NULL) - break; - /* - * passphrase does not contain the NULL termination. - * Add it here as pbkdf2_sha1() requires it. - */ - strpassphrase = os_zalloc(passphraselen + 1); - psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short)); - if (strpassphrase && psk) { - os_memcpy(strpassphrase, passphrase, passphraselen); - pbkdf2_sha1(strpassphrase, - hapd->conf->ssid.ssid, - hapd->conf->ssid.ssid_len, 4096, - psk->psk, PMK_LEN); - psk->next = cache->psk; - cache->psk = psk; - psk = NULL; - } - os_free(strpassphrase); - os_free(psk); - os_free(passphrase); - } -} - - -/** - * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages - * @msg: RADIUS response message - * @req: RADIUS request message - * @shared_secret: RADIUS shared secret - * @shared_secret_len: Length of shared_secret in octets - * @data: Context data (struct hostapd_data *) - * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and - * was processed here) or RADIUS_RX_UNKNOWN if not. - */ -static RadiusRxResult -hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, - const u8 *shared_secret, size_t shared_secret_len, - void *data) -{ - struct hostapd_data *hapd = data; - struct hostapd_acl_query_data *query, *prev; - struct hostapd_cached_radius_acl *cache; - struct radius_hdr *hdr = radius_msg_get_hdr(msg); - - query = hapd->acl_queries; - prev = NULL; - while (query) { - if (query->radius_id == hdr->identifier) - break; - prev = query; - query = query->next; - } - if (query == NULL) - return RADIUS_RX_UNKNOWN; - - wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS " - "message (id=%d)", query->radius_id); - - if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) { - wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have " - "correct authenticator - dropped\n"); - return RADIUS_RX_INVALID_AUTHENTICATOR; - } - - if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && - hdr->code != RADIUS_CODE_ACCESS_REJECT) { - wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL " - "query", hdr->code); - return RADIUS_RX_UNKNOWN; - } - - /* Insert Accept/Reject info into ACL cache */ - cache = os_zalloc(sizeof(*cache)); - if (cache == NULL) { - wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry"); - goto done; - } - os_get_reltime(&cache->timestamp); - os_memcpy(cache->addr, query->addr, sizeof(cache->addr)); - if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) { - u8 *buf; - size_t len; - - if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, - &cache->session_timeout) == 0) - cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT; - else - cache->accepted = HOSTAPD_ACL_ACCEPT; - - if (radius_msg_get_attr_int32( - msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, - &cache->acct_interim_interval) == 0 && - cache->acct_interim_interval < 60) { - wpa_printf(MSG_DEBUG, "Ignored too small " - "Acct-Interim-Interval %d for STA " MACSTR, - cache->acct_interim_interval, - MAC2STR(query->addr)); - cache->acct_interim_interval = 0; - } - - cache->vlan_id = radius_msg_get_vlanid(msg); - - decode_tunnel_passwords(hapd, shared_secret, shared_secret_len, - msg, req, cache); - - if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, - &buf, &len, NULL) == 0) { - cache->identity = os_zalloc(len + 1); - if (cache->identity) - os_memcpy(cache->identity, buf, len); - } - if (radius_msg_get_attr_ptr( - msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, - &buf, &len, NULL) == 0) { - cache->radius_cui = os_zalloc(len + 1); - if (cache->radius_cui) - os_memcpy(cache->radius_cui, buf, len); - } - - if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED && - !cache->psk) - cache->accepted = HOSTAPD_ACL_REJECT; - } else - cache->accepted = HOSTAPD_ACL_REJECT; - cache->next = hapd->acl_cache; - hapd->acl_cache = cache; - -#ifdef CONFIG_DRIVER_RADIUS_ACL - hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted, - cache->session_timeout); -#else /* CONFIG_DRIVER_RADIUS_ACL */ -#ifdef NEED_AP_MLME - /* Re-send original authentication frame for 802.11 processing */ - wpa_printf(MSG_DEBUG, "Re-sending authentication frame after " - "successful RADIUS ACL query"); - ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL); -#endif /* NEED_AP_MLME */ -#endif /* CONFIG_DRIVER_RADIUS_ACL */ - - done: - if (prev == NULL) - hapd->acl_queries = query->next; - else - prev->next = query->next; - - hostapd_acl_query_free(query); - - return RADIUS_RX_PROCESSED; -} -#endif /* CONFIG_NO_RADIUS */ - - -/** - * hostapd_acl_init: Initialize IEEE 802.11 ACL - * @hapd: hostapd BSS data - * Returns: 0 on success, -1 on failure - */ -int hostapd_acl_init(struct hostapd_data *hapd) -{ -#ifndef CONFIG_NO_RADIUS - if (radius_client_register(hapd->radius, RADIUS_AUTH, - hostapd_acl_recv_radius, hapd)) - return -1; - - eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL); -#endif /* CONFIG_NO_RADIUS */ - - return 0; -} - - -/** - * hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL - * @hapd: hostapd BSS data - */ -void hostapd_acl_deinit(struct hostapd_data *hapd) -{ - struct hostapd_acl_query_data *query, *prev; - -#ifndef CONFIG_NO_RADIUS - eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL); - - hostapd_acl_cache_free(hapd->acl_cache); -#endif /* CONFIG_NO_RADIUS */ - - query = hapd->acl_queries; - while (query) { - prev = query; - query = query->next; - hostapd_acl_query_free(prev); - } -} - - -void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk) -{ - while (psk) { - struct hostapd_sta_wpa_psk_short *prev = psk; - psk = psk->next; - os_free(prev); - } -} diff --git a/contrib/hostapd/src/ap/ieee802_11_auth.h b/contrib/hostapd/src/ap/ieee802_11_auth.h deleted file mode 100644 index 2bc1065a22..0000000000 --- a/contrib/hostapd/src/ap/ieee802_11_auth.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * hostapd / IEEE 802.11 authentication (ACL) - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef IEEE802_11_AUTH_H -#define IEEE802_11_AUTH_H - -enum { - HOSTAPD_ACL_REJECT = 0, - HOSTAPD_ACL_ACCEPT = 1, - HOSTAPD_ACL_PENDING = 2, - HOSTAPD_ACL_ACCEPT_TIMEOUT = 3 -}; - -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, - struct hostapd_sta_wpa_psk_short **psk, - char **identity, char **radius_cui); -int hostapd_acl_init(struct hostapd_data *hapd); -void hostapd_acl_deinit(struct hostapd_data *hapd); -void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk); - -#endif /* IEEE802_11_AUTH_H */ diff --git a/contrib/hostapd/src/ap/ieee802_11_ht.c b/contrib/hostapd/src/ap/ieee802_11_ht.c deleted file mode 100644 index 31dc47edd1..0000000000 --- a/contrib/hostapd/src/ap/ieee802_11_ht.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * hostapd / IEEE 802.11n HT - * Copyright (c) 2002-2009, Jouni Malinen - * Copyright (c) 2007-2008, Intel Corporation - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "common/ieee802_11_defs.h" -#include "hostapd.h" -#include "ap_config.h" -#include "sta_info.h" -#include "beacon.h" -#include "ieee802_11.h" - - -u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid) -{ - struct ieee80211_ht_capabilities *cap; - u8 *pos = eid; - - if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode || - hapd->conf->disable_11n) - return eid; - - *pos++ = WLAN_EID_HT_CAP; - *pos++ = sizeof(*cap); - - cap = (struct ieee80211_ht_capabilities *) pos; - os_memset(cap, 0, sizeof(*cap)); - cap->ht_capabilities_info = host_to_le16(hapd->iconf->ht_capab); - cap->a_mpdu_params = hapd->iface->current_mode->a_mpdu_params; - os_memcpy(cap->supported_mcs_set, hapd->iface->current_mode->mcs_set, - 16); - - /* TODO: ht_extended_capabilities (now fully disabled) */ - /* TODO: tx_bf_capability_info (now fully disabled) */ - /* TODO: asel_capabilities (now fully disabled) */ - - pos += sizeof(*cap); - - if (hapd->iconf->obss_interval) { - struct ieee80211_obss_scan_parameters *scan_params; - - *pos++ = WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS; - *pos++ = sizeof(*scan_params); - - scan_params = (struct ieee80211_obss_scan_parameters *) pos; - os_memset(scan_params, 0, sizeof(*scan_params)); - scan_params->width_trigger_scan_interval = - host_to_le16(hapd->iconf->obss_interval); - - /* TODO: Fill in more parameters (supplicant ignores them) */ - - pos += sizeof(*scan_params); - } - - return pos; -} - - -u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid) -{ - struct ieee80211_ht_operation *oper; - u8 *pos = eid; - - if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n) - return eid; - - *pos++ = WLAN_EID_HT_OPERATION; - *pos++ = sizeof(*oper); - - oper = (struct ieee80211_ht_operation *) pos; - os_memset(oper, 0, sizeof(*oper)); - - oper->control_chan = hapd->iconf->channel; - oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode); - if (hapd->iconf->secondary_channel == 1) - oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE | - HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH; - if (hapd->iconf->secondary_channel == -1) - oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW | - HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH; - - pos += sizeof(*oper); - - return pos; -} - - -/* -op_mode -Set to 0 (HT pure) under the followign conditions - - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or - - all STAs in the BSS are 20 MHz HT in 20 MHz BSS -Set to 1 (HT non-member protection) if there may be non-HT STAs - in both the primary and the secondary channel -Set to 2 if only HT STAs are associated in BSS, - however and at least one 20 MHz HT STA is associated -Set to 3 (HT mixed mode) when one or more non-HT STAs are associated -*/ -int hostapd_ht_operation_update(struct hostapd_iface *iface) -{ - u16 cur_op_mode, new_op_mode; - int op_mode_changes = 0; - - if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed) - return 0; - - wpa_printf(MSG_DEBUG, "%s current operation mode=0x%X", - __func__, iface->ht_op_mode); - - if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) - && iface->num_sta_ht_no_gf) { - iface->ht_op_mode |= - HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; - op_mode_changes++; - } else if ((iface->ht_op_mode & - HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) && - iface->num_sta_ht_no_gf == 0) { - iface->ht_op_mode &= - ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; - op_mode_changes++; - } - - if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && - (iface->num_sta_no_ht || iface->olbc_ht)) { - iface->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; - op_mode_changes++; - } else if ((iface->ht_op_mode & - HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && - (iface->num_sta_no_ht == 0 && !iface->olbc_ht)) { - iface->ht_op_mode &= - ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; - op_mode_changes++; - } - - new_op_mode = 0; - if (iface->num_sta_no_ht) - new_op_mode = OP_MODE_MIXED; - else if (iface->conf->secondary_channel && iface->num_sta_ht_20mhz) - new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED; - else if (iface->olbc_ht) - new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS; - else - new_op_mode = OP_MODE_PURE; - - cur_op_mode = iface->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK; - if (cur_op_mode != new_op_mode) { - iface->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK; - iface->ht_op_mode |= new_op_mode; - op_mode_changes++; - } - - wpa_printf(MSG_DEBUG, "%s new operation mode=0x%X changes=%d", - __func__, iface->ht_op_mode, op_mode_changes); - - return op_mode_changes; -} - - -u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *ht_capab, size_t ht_capab_len) -{ - /* Disable HT caps for STAs associated to no-HT BSSes. */ - if (!ht_capab || - ht_capab_len < sizeof(struct ieee80211_ht_capabilities) || - hapd->conf->disable_11n) { - sta->flags &= ~WLAN_STA_HT; - os_free(sta->ht_capabilities); - sta->ht_capabilities = NULL; - return WLAN_STATUS_SUCCESS; - } - - if (sta->ht_capabilities == NULL) { - sta->ht_capabilities = - os_zalloc(sizeof(struct ieee80211_ht_capabilities)); - if (sta->ht_capabilities == NULL) - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - sta->flags |= WLAN_STA_HT; - os_memcpy(sta->ht_capabilities, ht_capab, - sizeof(struct ieee80211_ht_capabilities)); - - return WLAN_STATUS_SUCCESS; -} - - -static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta) -{ - u16 ht_capab; - - ht_capab = le_to_host16(sta->ht_capabilities->ht_capabilities_info); - wpa_printf(MSG_DEBUG, "HT: STA " MACSTR " HT Capabilities Info: " - "0x%04x", MAC2STR(sta->addr), ht_capab); - if ((ht_capab & HT_CAP_INFO_GREEN_FIELD) == 0) { - if (!sta->no_ht_gf_set) { - sta->no_ht_gf_set = 1; - hapd->iface->num_sta_ht_no_gf++; - } - wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no greenfield, num " - "of non-gf stations %d", - __func__, MAC2STR(sta->addr), - hapd->iface->num_sta_ht_no_gf); - } - if ((ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) == 0) { - if (!sta->ht_20mhz_set) { - sta->ht_20mhz_set = 1; - hapd->iface->num_sta_ht_20mhz++; - } - wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - 20 MHz HT, num of " - "20MHz HT STAs %d", - __func__, MAC2STR(sta->addr), - hapd->iface->num_sta_ht_20mhz); - } -} - - -static void update_sta_no_ht(struct hostapd_data *hapd, struct sta_info *sta) -{ - if (!sta->no_ht_set) { - sta->no_ht_set = 1; - hapd->iface->num_sta_no_ht++; - } - if (hapd->iconf->ieee80211n) { - wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no HT, num of " - "non-HT stations %d", - __func__, MAC2STR(sta->addr), - hapd->iface->num_sta_no_ht); - } -} - - -void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta) -{ - if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) - update_sta_ht(hapd, sta); - else - update_sta_no_ht(hapd, sta); - - if (hostapd_ht_operation_update(hapd->iface) > 0) - ieee802_11_set_beacons(hapd->iface); -} - - -void hostapd_get_ht_capab(struct hostapd_data *hapd, - struct ieee80211_ht_capabilities *ht_cap, - struct ieee80211_ht_capabilities *neg_ht_cap) -{ - u16 cap; - - if (ht_cap == NULL) - return; - os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap)); - cap = le_to_host16(neg_ht_cap->ht_capabilities_info); - - /* - * Mask out HT features we don't support, but don't overwrite - * non-symmetric features like STBC and SMPS. Just because - * we're not in dynamic SMPS mode the STA might still be. - */ - cap &= (hapd->iconf->ht_capab | HT_CAP_INFO_RX_STBC_MASK | - HT_CAP_INFO_TX_STBC | HT_CAP_INFO_SMPS_MASK); - - /* - * STBC needs to be handled specially - * if we don't support RX STBC, mask out TX STBC in the STA's HT caps - * if we don't support TX STBC, mask out RX STBC in the STA's HT caps - */ - if (!(hapd->iconf->ht_capab & HT_CAP_INFO_RX_STBC_MASK)) - cap &= ~HT_CAP_INFO_TX_STBC; - if (!(hapd->iconf->ht_capab & HT_CAP_INFO_TX_STBC)) - cap &= ~HT_CAP_INFO_RX_STBC_MASK; - - neg_ht_cap->ht_capabilities_info = host_to_le16(cap); -} diff --git a/contrib/hostapd/src/ap/ieee802_11_shared.c b/contrib/hostapd/src/ap/ieee802_11_shared.c deleted file mode 100644 index eadaa4d187..0000000000 --- a/contrib/hostapd/src/ap/ieee802_11_shared.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * hostapd / IEEE 802.11 Management - * Copyright (c) 2002-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README 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_reltime now, passed; - - *pos++ = WLAN_EID_TIMEOUT_INTERVAL; - *pos++ = 5; - *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK; - os_get_reltime(&now); - os_reltime_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) - wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed"); -} - - -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) - wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed"); -} - - -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 */ - - -static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) -{ - *pos = 0x00; - - switch (idx) { - case 0: /* Bits 0-7 */ - break; - case 1: /* Bits 8-15 */ - break; - case 2: /* Bits 16-23 */ - if (hapd->conf->wnm_sleep_mode) - *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */ - if (hapd->conf->bss_transition) - *pos |= 0x08; /* Bit 19 - BSS Transition */ - break; - case 3: /* Bits 24-31 */ -#ifdef CONFIG_WNM - *pos |= 0x02; /* Bit 25 - SSID List */ -#endif /* CONFIG_WNM */ - if (hapd->conf->time_advertisement == 2) - *pos |= 0x08; /* Bit 27 - UTC TSF Offset */ - if (hapd->conf->interworking) - *pos |= 0x80; /* Bit 31 - Interworking */ - break; - case 4: /* Bits 32-39 */ - if (hapd->conf->qos_map_set_len) - *pos |= 0x01; /* Bit 32 - QoS Map */ - if (hapd->conf->tdls & TDLS_PROHIBIT) - *pos |= 0x40; /* Bit 38 - TDLS Prohibited */ - if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) { - /* Bit 39 - TDLS Channel Switching Prohibited */ - *pos |= 0x80; - } - break; - case 5: /* Bits 40-47 */ - break; - case 6: /* Bits 48-55 */ - if (hapd->conf->ssid.utf8_ssid) - *pos |= 0x01; /* Bit 48 - UTF-8 SSID */ - break; - } -} - - -u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) -{ - u8 *pos = eid; - u8 len = 0, i; - - if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)) - len = 5; - if (len < 4 && hapd->conf->interworking) - len = 4; - if (len < 3 && hapd->conf->wnm_sleep_mode) - len = 3; - if (len < 7 && hapd->conf->ssid.utf8_ssid) - len = 7; -#ifdef CONFIG_WNM - if (len < 4) - len = 4; -#endif /* CONFIG_WNM */ - if (len < hapd->iface->extended_capa_len) - len = hapd->iface->extended_capa_len; - if (len == 0) - return eid; - - *pos++ = WLAN_EID_EXT_CAPAB; - *pos++ = len; - for (i = 0; i < len; i++, pos++) { - hostapd_ext_capab_byte(hapd, pos, i); - - if (i < hapd->iface->extended_capa_len) { - *pos &= ~hapd->iface->extended_capa_mask[i]; - *pos |= hapd->iface->extended_capa[i]; - } - } - - while (len > 0 && eid[1 + len] == 0) { - len--; - eid[1] = len; - } - if (len == 0) - return eid; - - return eid + 2 + len; -} - - -u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid) -{ - u8 *pos = eid; - u8 len = hapd->conf->qos_map_set_len; - - if (!len) - return eid; - - *pos++ = WLAN_EID_QOS_MAP_SET; - *pos++ = len; - os_memcpy(pos, hapd->conf->qos_map_set, len); - pos += len; - - 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; -} - - -u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid) -{ - u8 *pos = eid; - -#ifdef CONFIG_WNM - if (hapd->conf->ap_max_inactivity > 0) { - unsigned int val; - *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD; - *pos++ = 3; - val = hapd->conf->ap_max_inactivity; - if (val > 68000) - val = 68000; - val *= 1000; - val /= 1024; - if (val == 0) - val = 1; - if (val > 65535) - val = 65535; - WPA_PUT_LE16(pos, val); - pos += 2; - *pos++ = 0x00; /* TODO: Protected Keep-Alive Required */ - } -#endif /* CONFIG_WNM */ - - return pos; -} diff --git a/contrib/hostapd/src/ap/ieee802_11_vht.c b/contrib/hostapd/src/ap/ieee802_11_vht.c deleted file mode 100644 index f2ab182db3..0000000000 --- a/contrib/hostapd/src/ap/ieee802_11_vht.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * hostapd / IEEE 802.11ac VHT - * Copyright (c) 2002-2009, Jouni Malinen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of BSD license - * - * See README and COPYING for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "common/ieee802_11_defs.h" -#include "hostapd.h" -#include "ap_config.h" -#include "sta_info.h" -#include "beacon.h" -#include "ieee802_11.h" - - -u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid) -{ - struct ieee80211_vht_capabilities *cap; - u8 *pos = eid; - - if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode || - hapd->conf->disable_11ac) - return eid; - - *pos++ = WLAN_EID_VHT_CAP; - *pos++ = sizeof(*cap); - - cap = (struct ieee80211_vht_capabilities *) pos; - os_memset(cap, 0, sizeof(*cap)); - cap->vht_capabilities_info = host_to_le32( - hapd->iface->conf->vht_capab); - - /* Supported MCS set comes from hw */ - os_memcpy(&cap->vht_supported_mcs_set, - hapd->iface->current_mode->vht_mcs_set, 8); - - pos += sizeof(*cap); - - return pos; -} - - -u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid) -{ - struct ieee80211_vht_operation *oper; - u8 *pos = eid; - - if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac) - return eid; - - *pos++ = WLAN_EID_VHT_OPERATION; - *pos++ = sizeof(*oper); - - oper = (struct ieee80211_vht_operation *) pos; - os_memset(oper, 0, sizeof(*oper)); - - /* - * center freq = 5 GHz + (5 * index) - * So index 42 gives center freq 5.210 GHz - * which is channel 42 in 5G band - */ - oper->vht_op_info_chan_center_freq_seg0_idx = - hapd->iconf->vht_oper_centr_freq_seg0_idx; - oper->vht_op_info_chan_center_freq_seg1_idx = - hapd->iconf->vht_oper_centr_freq_seg1_idx; - - oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth; - - /* VHT Basic MCS set comes from hw */ - /* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */ - oper->vht_basic_mcs_set = host_to_le16(0xfffc); - pos += sizeof(*oper); - - return pos; -} - - -u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *vht_capab, size_t vht_capab_len) -{ - /* Disable VHT caps for STAs associated to no-VHT BSSes. */ - if (!vht_capab || - vht_capab_len < sizeof(struct ieee80211_vht_capabilities) || - hapd->conf->disable_11ac) { - sta->flags &= ~WLAN_STA_VHT; - os_free(sta->vht_capabilities); - sta->vht_capabilities = NULL; - return WLAN_STATUS_SUCCESS; - } - - if (sta->vht_capabilities == NULL) { - sta->vht_capabilities = - os_zalloc(sizeof(struct ieee80211_vht_capabilities)); - if (sta->vht_capabilities == NULL) - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - sta->flags |= WLAN_STA_VHT; - os_memcpy(sta->vht_capabilities, vht_capab, - sizeof(struct ieee80211_vht_capabilities)); - - return WLAN_STATUS_SUCCESS; -} - -void hostapd_get_vht_capab(struct hostapd_data *hapd, - struct ieee80211_vht_capabilities *vht_cap, - struct ieee80211_vht_capabilities *neg_vht_cap) -{ - u32 cap, own_cap, sym_caps; - - if (vht_cap == NULL) - return; - os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap)); - - cap = le_to_host32(neg_vht_cap->vht_capabilities_info); - own_cap = hapd->iconf->vht_capab; - - /* mask out symmetric VHT capabilities we don't support */ - sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160; - cap &= ~sym_caps | (own_cap & sym_caps); - - /* mask out beamformer/beamformee caps if not supported */ - if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE)) - cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE | - VHT_CAP_BEAMFORMEE_STS_MAX); - - if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE)) - cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE | - VHT_CAP_SOUNDING_DIMENSION_MAX); - - if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE)) - cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE; - - if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE)) - cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE; - - /* mask channel widths we don't support */ - switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) { - case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: - break; - case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: - if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) { - cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; - cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; - } - break; - default: - cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK; - break; - } - - if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK)) - cap &= ~VHT_CAP_SHORT_GI_160; - - /* - * if we don't support RX STBC, mask out TX STBC in the STA's HT caps - * if we don't support TX STBC, mask out RX STBC in the STA's HT caps - */ - if (!(own_cap & VHT_CAP_RXSTBC_MASK)) - cap &= ~VHT_CAP_TXSTBC; - if (!(own_cap & VHT_CAP_TXSTBC)) - cap &= ~VHT_CAP_RXSTBC_MASK; - - neg_vht_cap->vht_capabilities_info = host_to_le32(cap); -} diff --git a/contrib/hostapd/src/ap/ieee802_1x.c b/contrib/hostapd/src/ap/ieee802_1x.c deleted file mode 100644 index 49b30e41c5..0000000000 --- a/contrib/hostapd/src/ap/ieee802_1x.c +++ /dev/null @@ -1,2145 +0,0 @@ -/* - * hostapd / IEEE 802.1X-2004 Authenticator - * Copyright (c) 2002-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "crypto/md5.h" -#include "crypto/crypto.h" -#include "crypto/random.h" -#include "common/ieee802_11_defs.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" -#include "wpa_auth.h" -#include "preauth_auth.h" -#include "pmksa_cache_auth.h" -#include "ap_config.h" -#include "ap_drv_ops.h" -#include "wps_hostapd.h" -#include "ieee802_1x.h" - - -static void ieee802_1x_finished(struct hostapd_data *hapd, - struct sta_info *sta, int success); - - -static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, - u8 type, const u8 *data, size_t datalen) -{ - u8 *buf; - struct ieee802_1x_hdr *xhdr; - size_t len; - int encrypt = 0; - - len = sizeof(*xhdr) + datalen; - buf = os_zalloc(len); - if (buf == NULL) { - wpa_printf(MSG_ERROR, "malloc() failed for " - "ieee802_1x_send(len=%lu)", - (unsigned long) len); - return; - } - - xhdr = (struct ieee802_1x_hdr *) buf; - xhdr->version = hapd->conf->eapol_version; - xhdr->type = type; - xhdr->length = host_to_be16(datalen); - - if (datalen > 0 && data != NULL) - os_memcpy(xhdr + 1, data, datalen); - - if (wpa_auth_pairwise_set(sta->wpa_sm)) - encrypt = 1; - if (sta->flags & WLAN_STA_PREAUTH) { - rsn_preauth_send(hapd, sta, buf, len); - } else { - hostapd_drv_hapd_send_eapol( - hapd, sta->addr, buf, len, - encrypt, hostapd_sta_flags_to_drv(sta->flags)); - } - - os_free(buf); -} - - -void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, - struct sta_info *sta, int authorized) -{ - int res; - - if (sta->flags & WLAN_STA_PREAUTH) - return; - - if (authorized) { - 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 { - ap_sta_set_authorized(hapd, sta, 0); - res = hostapd_set_authorized(hapd, sta, 0); - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); - } - - if (res && errno != ENOENT) { - wpa_printf(MSG_DEBUG, "Could not set station " MACSTR - " flags for kernel driver (errno=%d).", - MAC2STR(sta->addr), errno); - } - - if (authorized) { - os_get_reltime(&sta->connected_time); - accounting_sta_start(hapd, sta); - } -} - - -static void ieee802_1x_tx_key_one(struct hostapd_data *hapd, - struct sta_info *sta, - int idx, int broadcast, - u8 *key_data, size_t key_len) -{ - u8 *buf, *ekey; - struct ieee802_1x_hdr *hdr; - struct ieee802_1x_eapol_key *key; - size_t len, ekey_len; - struct eapol_state_machine *sm = sta->eapol_sm; - - if (sm == NULL) - return; - - len = sizeof(*key) + key_len; - buf = os_zalloc(sizeof(*hdr) + len); - if (buf == NULL) - return; - - hdr = (struct ieee802_1x_hdr *) buf; - key = (struct ieee802_1x_eapol_key *) (hdr + 1); - key->type = EAPOL_KEY_TYPE_RC4; - WPA_PUT_BE16(key->key_length, key_len); - wpa_get_ntp_timestamp(key->replay_counter); - - if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) { - wpa_printf(MSG_ERROR, "Could not get random numbers"); - os_free(buf); - return; - } - - key->key_index = idx | (broadcast ? 0 : BIT(7)); - if (hapd->conf->eapol_key_index_workaround) { - /* According to some information, WinXP Supplicant seems to - * interpret bit7 as an indication whether the key is to be - * activated, so make it possible to enable workaround that - * sets this bit for all keys. */ - key->key_index |= BIT(7); - } - - /* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and - * MSK[32..63] is used to sign the message. */ - if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) { - wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting " - "and signing EAPOL-Key"); - os_free(buf); - return; - } - os_memcpy((u8 *) (key + 1), key_data, key_len); - ekey_len = sizeof(key->key_iv) + 32; - ekey = os_malloc(ekey_len); - if (ekey == NULL) { - wpa_printf(MSG_ERROR, "Could not encrypt key"); - os_free(buf); - return; - } - os_memcpy(ekey, key->key_iv, sizeof(key->key_iv)); - os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32); - rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len); - os_free(ekey); - - /* This header is needed here for HMAC-MD5, but it will be regenerated - * in ieee802_1x_send() */ - hdr->version = hapd->conf->eapol_version; - hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; - hdr->length = host_to_be16(len); - hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len, - key->key_signature); - - wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR - " (%s index=%d)", MAC2STR(sm->addr), - broadcast ? "broadcast" : "unicast", idx); - ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len); - if (sta->eapol_sm) - sta->eapol_sm->dot1xAuthEapolFramesTx++; - os_free(buf); -} - - -void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) -{ - struct eapol_authenticator *eapol = hapd->eapol_auth; - struct eapol_state_machine *sm = sta->eapol_sm; - - if (sm == NULL || !sm->eap_if->eapKeyData) - return; - - wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR, - MAC2STR(sta->addr)); - -#ifndef CONFIG_NO_VLAN - if (sta->vlan_id > 0 && sta->vlan_id <= MAX_VLAN_ID) { - wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported."); - return; - } -#endif /* CONFIG_NO_VLAN */ - - if (eapol->default_wep_key) { - ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1, - eapol->default_wep_key, - hapd->conf->default_wep_key_len); - } - - if (hapd->conf->individual_wep_key_len > 0) { - u8 *ikey; - ikey = os_malloc(hapd->conf->individual_wep_key_len); - if (ikey == NULL || - random_get_bytes(ikey, hapd->conf->individual_wep_key_len)) - { - wpa_printf(MSG_ERROR, "Could not generate random " - "individual WEP key."); - os_free(ikey); - return; - } - - wpa_hexdump_key(MSG_DEBUG, "Individual WEP key", - ikey, hapd->conf->individual_wep_key_len); - - ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey, - hapd->conf->individual_wep_key_len); - - /* TODO: set encryption in TX callback, i.e., only after STA - * has ACKed EAPOL-Key frame */ - if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, - sta->addr, 0, 1, NULL, 0, ikey, - hapd->conf->individual_wep_key_len)) { - wpa_printf(MSG_ERROR, "Could not set individual WEP " - "encryption."); - } - - os_free(ikey); - } -} - - -const char *radius_mode_txt(struct hostapd_data *hapd) -{ - switch (hapd->iface->conf->hw_mode) { - case HOSTAPD_MODE_IEEE80211AD: - return "802.11ad"; - case HOSTAPD_MODE_IEEE80211A: - return "802.11a"; - case HOSTAPD_MODE_IEEE80211G: - return "802.11g"; - case HOSTAPD_MODE_IEEE80211B: - default: - return "802.11b"; - } -} - - -int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta) -{ - int i; - u8 rate = 0; - - for (i = 0; i < sta->supported_rates_len; i++) - if ((sta->supported_rates[i] & 0x7f) > rate) - rate = sta->supported_rates[i] & 0x7f; - - return rate; -} - - -#ifndef CONFIG_NO_RADIUS -static void ieee802_1x_learn_identity(struct hostapd_data *hapd, - struct eapol_state_machine *sm, - const u8 *eap, size_t len) -{ - const u8 *identity; - size_t identity_len; - - if (len <= sizeof(struct eap_hdr) || - eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) - return; - - identity = eap_get_identity(sm->eap, &identity_len); - if (identity == NULL) - return; - - /* Save station identity for future RADIUS packets */ - os_free(sm->identity); - sm->identity = (u8 *) dup_binstr(identity, identity_len); - if (sm->identity == NULL) { - sm->identity_len = 0; - return; - } - - sm->identity_len = identity_len; - hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity); - sm->dot1xAuthEapolRespIdFramesRx++; -} - - -static int add_common_radius_sta_attr(struct hostapd_data *hapd, - struct hostapd_radius_attr *req_attr, - struct sta_info *sta, - struct radius_msg *msg) -{ - char buf[128]; - - if (!hostapd_config_get_radius_attr(req_attr, - RADIUS_ATTR_NAS_PORT) && - !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { - wpa_printf(MSG_ERROR, "Could not add NAS-Port"); - return -1; - } - - os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, - MAC2STR(sta->addr)); - buf[sizeof(buf) - 1] = '\0'; - if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, - (u8 *) buf, os_strlen(buf))) { - wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id"); - return -1; - } - - if (sta->flags & WLAN_STA_PREAUTH) { - os_strlcpy(buf, "IEEE 802.11i Pre-Authentication", - sizeof(buf)); - } else { - os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", - radius_sta_rate(hapd, sta) / 2, - (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", - radius_mode_txt(hapd)); - buf[sizeof(buf) - 1] = '\0'; - } - if (!hostapd_config_get_radius_attr(req_attr, - RADIUS_ATTR_CONNECT_INFO) && - !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, - (u8 *) buf, os_strlen(buf))) { - wpa_printf(MSG_ERROR, "Could not add Connect-Info"); - return -1; - } - - if (sta->acct_session_id_hi || sta->acct_session_id_lo) { - os_snprintf(buf, sizeof(buf), "%08X-%08X", - sta->acct_session_id_hi, sta->acct_session_id_lo); - if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, - (u8 *) buf, os_strlen(buf))) { - wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id"); - return -1; - } - } - - return 0; -} - - -int add_common_radius_attr(struct hostapd_data *hapd, - struct hostapd_radius_attr *req_attr, - struct sta_info *sta, - struct radius_msg *msg) -{ - char buf[128]; - struct hostapd_radius_attr *attr; - - if (!hostapd_config_get_radius_attr(req_attr, - RADIUS_ATTR_NAS_IP_ADDRESS) && - hapd->conf->own_ip_addr.af == AF_INET && - !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, - (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { - wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address"); - return -1; - } - -#ifdef CONFIG_IPV6 - if (!hostapd_config_get_radius_attr(req_attr, - RADIUS_ATTR_NAS_IPV6_ADDRESS) && - hapd->conf->own_ip_addr.af == AF_INET6 && - !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, - (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { - wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address"); - return -1; - } -#endif /* CONFIG_IPV6 */ - - if (!hostapd_config_get_radius_attr(req_attr, - RADIUS_ATTR_NAS_IDENTIFIER) && - hapd->conf->nas_identifier && - !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, - (u8 *) hapd->conf->nas_identifier, - os_strlen(hapd->conf->nas_identifier))) { - wpa_printf(MSG_ERROR, "Could not add NAS-Identifier"); - return -1; - } - - os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", - MAC2STR(hapd->own_addr), - wpa_ssid_txt(hapd->conf->ssid.ssid, - hapd->conf->ssid.ssid_len)); - buf[sizeof(buf) - 1] = '\0'; - if (!hostapd_config_get_radius_attr(req_attr, - RADIUS_ATTR_CALLED_STATION_ID) && - !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, - (u8 *) buf, os_strlen(buf))) { - wpa_printf(MSG_ERROR, "Could not add Called-Station-Id"); - return -1; - } - - if (!hostapd_config_get_radius_attr(req_attr, - RADIUS_ATTR_NAS_PORT_TYPE) && - !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, - RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { - wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type"); - return -1; - } - - if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0) - return -1; - - for (attr = req_attr; attr; attr = attr->next) { - if (!radius_msg_add_attr(msg, attr->type, - wpabuf_head(attr->val), - wpabuf_len(attr->val))) { - wpa_printf(MSG_ERROR, "Could not add RADIUS " - "attribute"); - return -1; - } - } - - return 0; -} - - -static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, - struct sta_info *sta, - const u8 *eap, size_t len) -{ - struct radius_msg *msg; - struct eapol_state_machine *sm = sta->eapol_sm; - - if (sm == NULL) - return; - - ieee802_1x_learn_identity(hapd, sm, eap, len); - - wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " - "packet"); - - sm->radius_identifier = radius_client_get_id(hapd->radius); - msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, - sm->radius_identifier); - if (msg == NULL) { - wpa_printf(MSG_INFO, "Could not create new RADIUS packet"); - return; - } - - radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta)); - - if (sm->identity && - !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, - sm->identity, sm->identity_len)) { - wpa_printf(MSG_INFO, "Could not add User-Name"); - goto fail; - } - - if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta, - msg) < 0) - goto fail; - - /* TODO: should probably check MTU from driver config; 2304 is max for - * IEEE 802.11, but use 1400 to avoid problems with too large packets - */ - if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr, - RADIUS_ATTR_FRAMED_MTU) && - !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { - wpa_printf(MSG_INFO, "Could not add Framed-MTU"); - goto fail; - } - - if (eap && !radius_msg_add_eap(msg, eap, len)) { - wpa_printf(MSG_INFO, "Could not add EAP-Message"); - goto fail; - } - - /* State attribute must be copied if and only if this packet is - * Access-Request reply to the previous Access-Challenge */ - if (sm->last_recv_radius && - radius_msg_get_hdr(sm->last_recv_radius)->code == - RADIUS_CODE_ACCESS_CHALLENGE) { - int res = radius_msg_copy_attr(msg, sm->last_recv_radius, - RADIUS_ATTR_STATE); - if (res < 0) { - wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge"); - goto fail; - } - if (res > 0) { - wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute"); - } - } - - if (hapd->conf->radius_request_cui) { - const u8 *cui; - size_t cui_len; - /* Add previously learned CUI or nul CUI to request CUI */ - if (sm->radius_cui) { - cui = wpabuf_head(sm->radius_cui); - cui_len = wpabuf_len(sm->radius_cui); - } else { - cui = (const u8 *) "\0"; - cui_len = 1; - } - if (!radius_msg_add_attr(msg, - RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, - cui, cui_len)) { - wpa_printf(MSG_ERROR, "Could not add CUI"); - goto fail; - } - } - - if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0) - goto fail; - - return; - - fail: - radius_msg_free(msg); -} -#endif /* CONFIG_NO_RADIUS */ - - -static void handle_eap_response(struct hostapd_data *hapd, - struct sta_info *sta, struct eap_hdr *eap, - size_t len) -{ - u8 type, *data; - struct eapol_state_machine *sm = sta->eapol_sm; - if (sm == NULL) - return; - - data = (u8 *) (eap + 1); - - if (len < sizeof(*eap) + 1) { - wpa_printf(MSG_INFO, "handle_eap_response: too short response data"); - return; - } - - sm->eap_type_supp = type = data[0]; - - hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " - "id=%d len=%d) from STA: EAP Response-%s (%d)", - eap->code, eap->identifier, be_to_host16(eap->length), - eap_server_get_name(0, type), type); - - sm->dot1xAuthEapolRespFramesRx++; - - wpabuf_free(sm->eap_if->eapRespData); - sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); - sm->eapolEap = TRUE; -} - - -/* Process incoming EAP packet from Supplicant */ -static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta, - u8 *buf, size_t len) -{ - struct eap_hdr *eap; - u16 eap_len; - - if (len < sizeof(*eap)) { - wpa_printf(MSG_INFO, " too short EAP packet"); - return; - } - - eap = (struct eap_hdr *) buf; - - eap_len = be_to_host16(eap->length); - wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d", - eap->code, eap->identifier, eap_len); - if (eap_len < sizeof(*eap)) { - wpa_printf(MSG_DEBUG, " Invalid EAP length"); - return; - } else if (eap_len > len) { - wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP " - "packet"); - return; - } else if (eap_len < len) { - wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP " - "packet", (unsigned long) len - eap_len); - } - - switch (eap->code) { - case EAP_CODE_REQUEST: - wpa_printf(MSG_DEBUG, " (request)"); - return; - case EAP_CODE_RESPONSE: - wpa_printf(MSG_DEBUG, " (response)"); - handle_eap_response(hapd, sta, eap, eap_len); - break; - case EAP_CODE_SUCCESS: - wpa_printf(MSG_DEBUG, " (success)"); - return; - case EAP_CODE_FAILURE: - wpa_printf(MSG_DEBUG, " (failure)"); - return; - default: - wpa_printf(MSG_DEBUG, " (unknown code)"); - return; - } -} - - -static struct eapol_state_machine * -ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) -{ - int flags = 0; - if (sta->flags & WLAN_STA_PREAUTH) - flags |= EAPOL_SM_PREAUTH; - if (sta->wpa_sm) { - flags |= EAPOL_SM_USES_WPA; - if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) - flags |= EAPOL_SM_FROM_PMKSA_CACHE; - } - return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags, - sta->wps_ie, sta->p2p_ie, sta, - sta->identity, sta->radius_cui); -} - - -/** - * ieee802_1x_receive - Process the EAPOL frames from the Supplicant - * @hapd: hostapd BSS data - * @sa: Source address (sender of the EAPOL frame) - * @buf: EAPOL frame - * @len: Length of buf in octets - * - * This function is called for each incoming EAPOL frame from the interface - */ -void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, - size_t len) -{ - struct sta_info *sta; - struct ieee802_1x_hdr *hdr; - struct ieee802_1x_eapol_key *key; - u16 datalen; - struct rsn_pmksa_cache_entry *pmksa; - int key_mgmt; - - if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && - !hapd->conf->wps_state) - return; - - 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)) && - !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) { - wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " - "associated/Pre-authenticating STA"); - return; - } - - if (len < sizeof(*hdr)) { - wpa_printf(MSG_INFO, " too short IEEE 802.1X packet"); - return; - } - - hdr = (struct ieee802_1x_hdr *) buf; - datalen = be_to_host16(hdr->length); - wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", - hdr->version, hdr->type, datalen); - - if (len - sizeof(*hdr) < datalen) { - wpa_printf(MSG_INFO, " frame too short for this IEEE 802.1X packet"); - if (sta->eapol_sm) - sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++; - return; - } - if (len - sizeof(*hdr) > datalen) { - wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after " - "IEEE 802.1X packet", - (unsigned long) len - sizeof(*hdr) - datalen); - } - - if (sta->eapol_sm) { - sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version; - sta->eapol_sm->dot1xAuthEapolFramesRx++; - } - - key = (struct ieee802_1x_eapol_key *) (hdr + 1); - if (datalen >= sizeof(struct ieee802_1x_eapol_key) && - hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && - (key->type == EAPOL_KEY_TYPE_WPA || - key->type == EAPOL_KEY_TYPE_RSN)) { - wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr, - sizeof(*hdr) + datalen); - return; - } - - if (!hapd->conf->ieee802_1x && - !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { - wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " - "802.1X not enabled and WPS not used"); - return; - } - - key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); - if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) { - wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " - "STA is using PSK"); - return; - } - - if (!sta->eapol_sm) { - sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); - if (!sta->eapol_sm) - return; - -#ifdef CONFIG_WPS - 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 */ - - sta->eapol_sm->eap_if->portEnabled = TRUE; - } - - /* since we support version 1, we can ignore version field and proceed - * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */ - /* TODO: actually, we are not version 1 anymore.. However, Version 2 - * does not change frame contents, so should be ok to process frames - * more or less identically. Some changes might be needed for - * verification of fields. */ - - switch (hdr->type) { - case IEEE802_1X_TYPE_EAP_PACKET: - handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen); - break; - - case IEEE802_1X_TYPE_EAPOL_START: - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start " - "from STA"); - sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; - pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); - if (pmksa) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, - HOSTAPD_LEVEL_DEBUG, "cached PMKSA " - "available - ignore it since " - "STA sent EAPOL-Start"); - wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa); - } - sta->eapol_sm->eapolStart = TRUE; - sta->eapol_sm->dot1xAuthEapolStartFramesRx++; - eap_server_clear_identity(sta->eapol_sm->eap); - wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); - break; - - case IEEE802_1X_TYPE_EAPOL_LOGOFF: - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff " - "from STA"); - sta->acct_terminate_cause = - RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; - accounting_sta_stop(hapd, sta); - sta->eapol_sm->eapolLogoff = TRUE; - sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; - eap_server_clear_identity(sta->eapol_sm->eap); - break; - - case IEEE802_1X_TYPE_EAPOL_KEY: - wpa_printf(MSG_DEBUG, " EAPOL-Key"); - if (!ap_sta_is_authorized(sta)) { - wpa_printf(MSG_DEBUG, " Dropped key data from " - "unauthorized Supplicant"); - break; - } - break; - - case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: - wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert"); - /* TODO: implement support for this; show data */ - break; - - default: - wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type"); - sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++; - break; - } - - eapol_auth_step(sta->eapol_sm); -} - - -/** - * ieee802_1x_new_station - Start IEEE 802.1X authentication - * @hapd: hostapd BSS data - * @sta: The station - * - * This function is called to start IEEE 802.1X authentication when a new - * station completes IEEE 802.11 association. - */ -void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) -{ - struct rsn_pmksa_cache_entry *pmksa; - int reassoc = 1; - int force_1x = 0; - int key_mgmt; - -#ifdef CONFIG_WPS - if (hapd->conf->wps_state && hapd->conf->wpa && - (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { - /* - * Need to enable IEEE 802.1X/EAPOL state machines for possible - * WPS handshake even if IEEE 802.1X/EAPOL is not used for - * authentication in this BSS. - */ - force_1x = 1; - } -#endif /* CONFIG_WPS */ - - if (!force_1x && !hapd->conf->ieee802_1x) { - wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - " - "802.1X not enabled or forced for WPS"); - /* - * Clear any possible EAPOL authenticator state to support - * reassociation change from WPS to PSK. - */ - ieee802_1x_free_station(sta); - return; - } - - key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); - if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) { - wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK"); - /* - * Clear any possible EAPOL authenticator state to support - * reassociation change from WPA-EAP to PSK. - */ - ieee802_1x_free_station(sta); - return; - } - - if (sta->eapol_sm == NULL) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, "start authentication"); - sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); - if (sta->eapol_sm == NULL) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_INFO, - "failed to allocate state machine"); - return; - } - reassoc = 0; - } - -#ifdef CONFIG_WPS - sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; - if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) { - /* - * 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 */ - - sta->eapol_sm->eap_if->portEnabled = TRUE; - -#ifdef CONFIG_IEEE80211R - if (sta->auth_alg == WLAN_AUTH_FT) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, - "PMK from FT - skip IEEE 802.1X/EAP"); - /* Setup EAPOL state machines to already authenticated state - * because of existing FT information from R0KH. */ - sta->eapol_sm->keyRun = TRUE; - sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; - sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; - sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; - sta->eapol_sm->authSuccess = TRUE; - sta->eapol_sm->authFail = FALSE; - if (sta->eapol_sm->eap) - eap_sm_notify_cached(sta->eapol_sm->eap); - /* TODO: get vlan_id from R0KH using RRB message */ - return; - } -#endif /* CONFIG_IEEE80211R */ - - pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); - if (pmksa) { - int old_vlanid; - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, - "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); - /* Setup EAPOL state machines to already authenticated state - * because of existing PMKSA information in the cache. */ - sta->eapol_sm->keyRun = TRUE; - sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; - sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; - sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; - sta->eapol_sm->authSuccess = TRUE; - sta->eapol_sm->authFail = FALSE; - if (sta->eapol_sm->eap) - eap_sm_notify_cached(sta->eapol_sm->eap); - old_vlanid = sta->vlan_id; - pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm); - if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) - sta->vlan_id = 0; - ap_sta_bind_vlan(hapd, sta, old_vlanid); - } else { - if (reassoc) { - /* - * Force EAPOL state machines to start - * re-authentication without having to wait for the - * Supplicant to send EAPOL-Start. - */ - sta->eapol_sm->reAuthenticate = TRUE; - } - eapol_auth_step(sta->eapol_sm); - } -} - - -void ieee802_1x_free_station(struct sta_info *sta) -{ - struct eapol_state_machine *sm = sta->eapol_sm; - - if (sm == NULL) - return; - - sta->eapol_sm = NULL; - -#ifndef CONFIG_NO_RADIUS - radius_msg_free(sm->last_recv_radius); - radius_free_class(&sm->radius_class); - wpabuf_free(sm->radius_cui); -#endif /* CONFIG_NO_RADIUS */ - - os_free(sm->identity); - eapol_auth_free(sm); -} - - -#ifndef CONFIG_NO_RADIUS -static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, - struct sta_info *sta) -{ - struct wpabuf *eap; - const struct eap_hdr *hdr; - int eap_type = -1; - char buf[64]; - struct radius_msg *msg; - struct eapol_state_machine *sm = sta->eapol_sm; - - if (sm == NULL || sm->last_recv_radius == NULL) { - if (sm) - sm->eap_if->aaaEapNoReq = TRUE; - return; - } - - msg = sm->last_recv_radius; - - eap = radius_msg_get_eap(msg); - if (eap == NULL) { - /* RFC 3579, Chap. 2.6.3: - * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message - * attribute */ - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_WARNING, "could not extract " - "EAP-Message from RADIUS message"); - sm->eap_if->aaaEapNoReq = TRUE; - return; - } - - if (wpabuf_len(eap) < sizeof(*hdr)) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_WARNING, "too short EAP packet " - "received from authentication server"); - wpabuf_free(eap); - sm->eap_if->aaaEapNoReq = TRUE; - return; - } - - if (wpabuf_len(eap) > sizeof(*hdr)) - eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)]; - - hdr = wpabuf_head(eap); - switch (hdr->code) { - case EAP_CODE_REQUEST: - if (eap_type >= 0) - sm->eap_type_authsrv = eap_type; - os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", - eap_type >= 0 ? eap_server_get_name(0, eap_type) : - "??", - eap_type); - break; - case EAP_CODE_RESPONSE: - os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", - eap_type >= 0 ? eap_server_get_name(0, eap_type) : - "??", - eap_type); - break; - case EAP_CODE_SUCCESS: - os_strlcpy(buf, "EAP Success", sizeof(buf)); - break; - case EAP_CODE_FAILURE: - os_strlcpy(buf, "EAP Failure", sizeof(buf)); - break; - default: - os_strlcpy(buf, "unknown EAP code", sizeof(buf)); - break; - } - buf[sizeof(buf) - 1] = '\0'; - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d " - "id=%d len=%d) from RADIUS server: %s", - hdr->code, hdr->identifier, be_to_host16(hdr->length), - buf); - sm->eap_if->aaaEapReq = TRUE; - - wpabuf_free(sm->eap_if->aaaEapReqData); - sm->eap_if->aaaEapReqData = eap; -} - - -static void ieee802_1x_get_keys(struct hostapd_data *hapd, - struct sta_info *sta, struct radius_msg *msg, - struct radius_msg *req, - const u8 *shared_secret, - size_t shared_secret_len) -{ - struct radius_ms_mppe_keys *keys; - struct eapol_state_machine *sm = sta->eapol_sm; - if (sm == NULL) - return; - - keys = radius_msg_get_ms_keys(msg, req, shared_secret, - shared_secret_len); - - if (keys && keys->send && keys->recv) { - size_t len = keys->send_len + keys->recv_len; - wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key", - keys->send, keys->send_len); - wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key", - keys->recv, keys->recv_len); - - os_free(sm->eap_if->aaaEapKeyData); - sm->eap_if->aaaEapKeyData = os_malloc(len); - if (sm->eap_if->aaaEapKeyData) { - os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv, - keys->recv_len); - os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len, - keys->send, keys->send_len); - sm->eap_if->aaaEapKeyDataLen = len; - sm->eap_if->aaaEapKeyAvailable = TRUE; - } - } - - if (keys) { - os_free(keys->send); - os_free(keys->recv); - os_free(keys); - } -} - - -static void ieee802_1x_store_radius_class(struct hostapd_data *hapd, - struct sta_info *sta, - struct radius_msg *msg) -{ - u8 *class; - size_t class_len; - struct eapol_state_machine *sm = sta->eapol_sm; - int count, i; - struct radius_attr_data *nclass; - size_t nclass_count; - - if (!hapd->conf->radius->acct_server || hapd->radius == NULL || - sm == NULL) - return; - - radius_free_class(&sm->radius_class); - count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1); - if (count <= 0) - return; - - nclass = os_calloc(count, sizeof(struct radius_attr_data)); - if (nclass == NULL) - return; - - nclass_count = 0; - - class = NULL; - for (i = 0; i < count; i++) { - do { - if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, - &class, &class_len, - class) < 0) { - i = count; - break; - } - } while (class_len < 1); - - nclass[nclass_count].data = os_malloc(class_len); - if (nclass[nclass_count].data == NULL) - break; - - os_memcpy(nclass[nclass_count].data, class, class_len); - nclass[nclass_count].len = class_len; - nclass_count++; - } - - sm->radius_class.attr = nclass; - sm->radius_class.count = nclass_count; - wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class " - "attributes for " MACSTR, - (unsigned long) sm->radius_class.count, - MAC2STR(sta->addr)); -} - - -/* Update sta->identity based on User-Name attribute in Access-Accept */ -static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd, - struct sta_info *sta, - struct radius_msg *msg) -{ - u8 *buf, *identity; - size_t len; - struct eapol_state_machine *sm = sta->eapol_sm; - - if (sm == NULL) - return; - - if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, - NULL) < 0) - return; - - identity = (u8 *) dup_binstr(buf, len); - if (identity == NULL) - return; - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with " - "User-Name from Access-Accept '%s'", - sm->identity ? (char *) sm->identity : "N/A", - (char *) identity); - - os_free(sm->identity); - sm->identity = identity; - sm->identity_len = len; -} - - -/* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */ -static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd, - struct sta_info *sta, - struct radius_msg *msg) -{ - struct eapol_state_machine *sm = sta->eapol_sm; - struct wpabuf *cui; - u8 *buf; - size_t len; - - if (sm == NULL) - return; - - if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, - &buf, &len, NULL) < 0) - return; - - cui = wpabuf_alloc_copy(buf, len); - if (cui == NULL) - return; - - wpabuf_free(sm->radius_cui); - sm->radius_cui = cui; -} - - -struct sta_id_search { - u8 identifier; - struct eapol_state_machine *sm; -}; - - -static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd, - struct sta_info *sta, - void *ctx) -{ - struct sta_id_search *id_search = ctx; - struct eapol_state_machine *sm = sta->eapol_sm; - - if (sm && sm->radius_identifier >= 0 && - sm->radius_identifier == id_search->identifier) { - id_search->sm = sm; - return 1; - } - return 0; -} - - -static struct eapol_state_machine * -ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier) -{ - struct sta_id_search id_search; - id_search.identifier = identifier; - id_search.sm = NULL; - ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search); - return id_search.sm; -} - - -/** - * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server - * @msg: RADIUS response message - * @req: RADIUS request message - * @shared_secret: RADIUS shared secret - * @shared_secret_len: Length of shared_secret in octets - * @data: Context data (struct hostapd_data *) - * Returns: Processing status - */ -static RadiusRxResult -ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, - const u8 *shared_secret, size_t shared_secret_len, - void *data) -{ - struct hostapd_data *hapd = data; - struct sta_info *sta; - u32 session_timeout = 0, termination_action, acct_interim_interval; - int session_timeout_set, old_vlanid = 0; - struct eapol_state_machine *sm; - int override_eapReq = 0; - struct radius_hdr *hdr = radius_msg_get_hdr(msg); - - sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier); - if (sm == NULL) { - wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching " - "station for this RADIUS message"); - return RADIUS_RX_UNKNOWN; - } - sta = sm->sta; - - /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be - * present when packet contains an EAP-Message attribute */ - if (hdr->code == RADIUS_CODE_ACCESS_REJECT && - radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, - 0) < 0 && - radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { - wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without " - "Message-Authenticator since it does not include " - "EAP-Message"); - } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, - req, 1)) { - wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped"); - return RADIUS_RX_INVALID_AUTHENTICATOR; - } - - if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && - hdr->code != RADIUS_CODE_ACCESS_REJECT && - hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { - wpa_printf(MSG_INFO, "Unknown RADIUS message code"); - return RADIUS_RX_UNKNOWN; - } - - sm->radius_identifier = -1; - wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR, - MAC2STR(sta->addr)); - - radius_msg_free(sm->last_recv_radius); - sm->last_recv_radius = msg; - - session_timeout_set = - !radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, - &session_timeout); - if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION, - &termination_action)) - termination_action = RADIUS_TERMINATION_ACTION_DEFAULT; - - if (hapd->conf->acct_interim_interval == 0 && - hdr->code == RADIUS_CODE_ACCESS_ACCEPT && - radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, - &acct_interim_interval) == 0) { - if (acct_interim_interval < 60) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_INFO, - "ignored too small " - "Acct-Interim-Interval %d", - acct_interim_interval); - } else - sta->acct_interim_interval = acct_interim_interval; - } - - - switch (hdr->code) { - case RADIUS_CODE_ACCESS_ACCEPT: - if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) - sta->vlan_id = 0; -#ifndef CONFIG_NO_VLAN - else { - old_vlanid = sta->vlan_id; - sta->vlan_id = radius_msg_get_vlanid(msg); - } - if (sta->vlan_id > 0 && - hostapd_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_INFO, - "VLAN ID %d", sta->vlan_id); - } else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) { - sta->eapol_sm->authFail = TRUE; - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_INFO, "authentication " - "server did not include required VLAN " - "ID in Access-Accept"); - break; - } -#endif /* CONFIG_NO_VLAN */ - - if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0) - break; - - /* RFC 3580, Ch. 3.17 */ - if (session_timeout_set && termination_action == - RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) { - sm->reAuthPeriod = session_timeout; - } else if (session_timeout_set) - ap_sta_session_timeout(hapd, sta, session_timeout); - - sm->eap_if->aaaSuccess = TRUE; - override_eapReq = 1; - ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret, - shared_secret_len); - ieee802_1x_store_radius_class(hapd, sta, msg); - ieee802_1x_update_sta_identity(hapd, sta, msg); - ieee802_1x_update_sta_cui(hapd, sta, msg); - if (sm->eap_if->eapKeyAvailable && - wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt, - session_timeout_set ? - (int) session_timeout : -1, sm) == 0) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, - HOSTAPD_LEVEL_DEBUG, - "Added PMKSA cache entry"); - } - break; - case RADIUS_CODE_ACCESS_REJECT: - sm->eap_if->aaaFail = TRUE; - override_eapReq = 1; - break; - case RADIUS_CODE_ACCESS_CHALLENGE: - sm->eap_if->aaaEapReq = TRUE; - if (session_timeout_set) { - /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */ - sm->eap_if->aaaMethodTimeout = session_timeout; - hostapd_logger(hapd, sm->addr, - HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, - "using EAP timeout of %d seconds (from " - "RADIUS)", - sm->eap_if->aaaMethodTimeout); - } else { - /* - * Use dynamic retransmission behavior per EAP - * specification. - */ - sm->eap_if->aaaMethodTimeout = 0; - } - break; - } - - ieee802_1x_decapsulate_radius(hapd, sta); - if (override_eapReq) - sm->eap_if->aaaEapReq = FALSE; - - eapol_auth_step(sm); - - return RADIUS_RX_QUEUED; -} -#endif /* CONFIG_NO_RADIUS */ - - -void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) -{ - struct eapol_state_machine *sm = sta->eapol_sm; - if (sm == NULL) - return; - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, "aborting authentication"); - -#ifndef CONFIG_NO_RADIUS - radius_msg_free(sm->last_recv_radius); - sm->last_recv_radius = NULL; -#endif /* CONFIG_NO_RADIUS */ - - if (sm->eap_if->eapTimeout) { - /* - * Disconnect the STA since it did not reply to the last EAP - * 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); - } -} - - -static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd) -{ - struct eapol_authenticator *eapol = hapd->eapol_auth; - - if (hapd->conf->default_wep_key_len < 1) - return 0; - - os_free(eapol->default_wep_key); - eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len); - if (eapol->default_wep_key == NULL || - random_get_bytes(eapol->default_wep_key, - hapd->conf->default_wep_key_len)) { - wpa_printf(MSG_INFO, "Could not generate random WEP key"); - os_free(eapol->default_wep_key); - eapol->default_wep_key = NULL; - return -1; - } - - wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key", - eapol->default_wep_key, - hapd->conf->default_wep_key_len); - - return 0; -} - - -static int ieee802_1x_sta_key_available(struct hostapd_data *hapd, - struct sta_info *sta, void *ctx) -{ - if (sta->eapol_sm) { - sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; - eapol_auth_step(sta->eapol_sm); - } - return 0; -} - - -static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - struct eapol_authenticator *eapol = hapd->eapol_auth; - - if (eapol->default_wep_key_idx >= 3) - eapol->default_wep_key_idx = - hapd->conf->individual_wep_key_len > 0 ? 1 : 0; - else - eapol->default_wep_key_idx++; - - wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d", - eapol->default_wep_key_idx); - - if (ieee802_1x_rekey_broadcast(hapd)) { - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_WARNING, "failed to generate a " - "new broadcast key"); - os_free(eapol->default_wep_key); - eapol->default_wep_key = NULL; - return; - } - - /* TODO: Could setup key for RX here, but change default TX keyid only - * after new broadcast key has been sent to all stations. */ - if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, - broadcast_ether_addr, - eapol->default_wep_key_idx, 1, NULL, 0, - eapol->default_wep_key, - hapd->conf->default_wep_key_len)) { - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_WARNING, "failed to configure a " - "new broadcast key"); - os_free(eapol->default_wep_key); - eapol->default_wep_key = NULL; - return; - } - - ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL); - - if (hapd->conf->wep_rekeying_period > 0) { - eloop_register_timeout(hapd->conf->wep_rekeying_period, 0, - ieee802_1x_rekey, hapd, NULL); - } -} - - -static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, - const u8 *data, size_t datalen) -{ -#ifdef CONFIG_WPS - struct sta_info *sta = sta_ctx; - - if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == - WLAN_STA_MAYBE_WPS) { - const u8 *identity; - size_t identity_len; - struct eapol_state_machine *sm = sta->eapol_sm; - - identity = eap_get_identity(sm->eap, &identity_len); - if (identity && - ((identity_len == WSC_ID_ENROLLEE_LEN && - os_memcmp(identity, WSC_ID_ENROLLEE, - WSC_ID_ENROLLEE_LEN) == 0) || - (identity_len == WSC_ID_REGISTRAR_LEN && - os_memcmp(identity, WSC_ID_REGISTRAR, - WSC_ID_REGISTRAR_LEN) == 0))) { - wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> " - "WLAN_STA_WPS"); - sta->flags |= WLAN_STA_WPS; - } - } -#endif /* CONFIG_WPS */ - - ieee802_1x_send(ctx, sta_ctx, type, data, datalen); -} - - -static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, - const u8 *data, size_t datalen) -{ -#ifndef CONFIG_NO_RADIUS - struct hostapd_data *hapd = ctx; - struct sta_info *sta = sta_ctx; - - ieee802_1x_encapsulate_radius(hapd, sta, data, datalen); -#endif /* CONFIG_NO_RADIUS */ -} - - -static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, - int preauth) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta = sta_ctx; - if (preauth) - rsn_preauth_finished(hapd, sta, success); - else - ieee802_1x_finished(hapd, sta, success); -} - - -static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, - size_t identity_len, int phase2, - struct eap_user *user) -{ - struct hostapd_data *hapd = ctx; - const struct hostapd_eap_user *eap_user; - int i; - - eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2); - if (eap_user == NULL) - return -1; - - os_memset(user, 0, sizeof(*user)); - user->phase2 = phase2; - 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; - } - - if (eap_user->password) { - user->password = os_malloc(eap_user->password_len); - if (user->password == NULL) - return -1; - 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; - - return 0; -} - - -static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta; - sta = ap_get_sta(hapd, addr); - if (sta == NULL || sta->eapol_sm == NULL) - return 0; - return 1; -} - - -static void ieee802_1x_logger(void *ctx, const u8 *addr, - eapol_logger_level level, const char *txt) -{ -#ifndef CONFIG_NO_HOSTAPD_LOGGER - struct hostapd_data *hapd = ctx; - int hlevel; - - switch (level) { - case EAPOL_LOGGER_WARNING: - hlevel = HOSTAPD_LEVEL_WARNING; - break; - case EAPOL_LOGGER_INFO: - hlevel = HOSTAPD_LEVEL_INFO; - break; - case EAPOL_LOGGER_DEBUG: - default: - hlevel = HOSTAPD_LEVEL_DEBUG; - break; - } - - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s", - txt); -#endif /* CONFIG_NO_HOSTAPD_LOGGER */ -} - - -static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx, - int authorized) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta = sta_ctx; - ieee802_1x_set_sta_authorized(hapd, sta, authorized); -} - - -static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta = sta_ctx; - ieee802_1x_abort_auth(hapd, sta); -} - - -static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta = sta_ctx; - ieee802_1x_tx_key(hapd, sta); -} - - -static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, - enum eapol_event type) -{ - /* struct hostapd_data *hapd = ctx; */ - struct sta_info *sta = sta_ctx; - switch (type) { - case EAPOL_AUTH_SM_CHANGE: - wpa_auth_sm_notify(sta->wpa_sm); - break; - case EAPOL_AUTH_REAUTHENTICATE: - wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); - break; - } -} - - -int ieee802_1x_init(struct hostapd_data *hapd) -{ - int i; - struct eapol_auth_config conf; - struct eapol_auth_cb cb; - - os_memset(&conf, 0, sizeof(conf)); - conf.ctx = hapd; - conf.eap_reauth_period = hapd->conf->eap_reauth_period; - conf.wpa = hapd->conf->wpa; - conf.individual_wep_key_len = hapd->conf->individual_wep_key_len; - conf.eap_server = hapd->conf->eap_server; - conf.ssl_ctx = hapd->ssl_ctx; - conf.msg_ctx = hapd->msg_ctx; - conf.eap_sim_db_priv = hapd->eap_sim_db_priv; - conf.eap_req_id_text = hapd->conf->eap_req_id_text; - conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; - conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key; - conf.eap_fast_a_id = hapd->conf->eap_fast_a_id; - conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len; - conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info; - conf.eap_fast_prov = hapd->conf->eap_fast_prov; - conf.pac_key_lifetime = hapd->conf->pac_key_lifetime; - conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time; - conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind; - conf.tnc = hapd->conf->tnc; - conf.wps = hapd->wps; - conf.fragment_size = hapd->conf->fragment_size; - conf.pwd_group = hapd->conf->pwd_group; - conf.pbc_in_m1 = hapd->conf->pbc_in_m1; - if (hapd->conf->server_id) { - conf.server_id = (const u8 *) hapd->conf->server_id; - conf.server_id_len = os_strlen(hapd->conf->server_id); - } else { - conf.server_id = (const u8 *) "hostapd"; - conf.server_id_len = 7; - } - - os_memset(&cb, 0, sizeof(cb)); - cb.eapol_send = ieee802_1x_eapol_send; - cb.aaa_send = ieee802_1x_aaa_send; - cb.finished = _ieee802_1x_finished; - cb.get_eap_user = ieee802_1x_get_eap_user; - cb.sta_entry_alive = ieee802_1x_sta_entry_alive; - cb.logger = ieee802_1x_logger; - cb.set_port_authorized = ieee802_1x_set_port_authorized; - cb.abort_auth = _ieee802_1x_abort_auth; - cb.tx_key = _ieee802_1x_tx_key; - cb.eapol_event = ieee802_1x_eapol_event; - - hapd->eapol_auth = eapol_auth_init(&conf, &cb); - if (hapd->eapol_auth == NULL) - return -1; - - if ((hapd->conf->ieee802_1x || hapd->conf->wpa) && - hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1)) - return -1; - -#ifndef CONFIG_NO_RADIUS - if (radius_client_register(hapd->radius, RADIUS_AUTH, - ieee802_1x_receive_auth, hapd)) - return -1; -#endif /* CONFIG_NO_RADIUS */ - - if (hapd->conf->default_wep_key_len) { - for (i = 0; i < 4; i++) - hostapd_drv_set_key(hapd->conf->iface, hapd, - WPA_ALG_NONE, NULL, i, 0, NULL, 0, - NULL, 0); - - ieee802_1x_rekey(hapd, NULL); - - if (hapd->eapol_auth->default_wep_key == NULL) - return -1; - } - - return 0; -} - - -void ieee802_1x_deinit(struct hostapd_data *hapd) -{ - eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL); - - if (hapd->driver != NULL && - (hapd->conf->ieee802_1x || hapd->conf->wpa)) - hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); - - eapol_auth_deinit(hapd->eapol_auth); - hapd->eapol_auth = NULL; -} - - -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; - 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) - return 0; - - hdr = (struct ieee80211_hdr *) buf; - pos = (u8 *) (hdr + 1); - if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0) - return 0; - pos += sizeof(rfc1042_hdr); - if (WPA_GET_BE16(pos) != ETH_P_PAE) - return 0; - pos += 2; - - 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) - 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 || - wpa->type == EAPOL_KEY_TYPE_WPA) - wpa_auth_eapol_key_tx_status(hapd->wpa_auth, - sta->wpa_sm, ack); - } - - /* 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-send failed EAPOL-Key - * packets couple of times because otherwise STA keys become - * unsynchronized with AP. */ - 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 " - "frame (%scast index=%d)", - key->key_index & BIT(7) ? "uni" : "broad", - key->key_index & ~BIT(7)); - /* TODO: re-send EAPOL-Key couple of times (with short delay - * between them?). If all attempt fail, report error and - * deauthenticate STA so that it will get new keys when - * authenticating again (e.g., after returning in range). - * Separate limit/transmit state needed both for unicast and - * broadcast keys(?) */ - } - /* TODO: could move unicast key configuration from ieee802_1x_tx_key() - * to here and change the key only if the EAPOL-Key packet was Acked. - */ - - return 1; -} - - -u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len) -{ - if (sm == NULL || sm->identity == NULL) - return NULL; - - *len = sm->identity_len; - return sm->identity; -} - - -u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, - int idx) -{ - if (sm == NULL || sm->radius_class.attr == NULL || - idx >= (int) sm->radius_class.count) - return NULL; - - *len = sm->radius_class.attr[idx].len; - return sm->radius_class.attr[idx].data; -} - - -struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm) -{ - if (sm == NULL) - return NULL; - return sm->radius_cui; -} - - -const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len) -{ - *len = 0; - if (sm == NULL) - return NULL; - - *len = sm->eap_if->eapKeyDataLen; - return sm->eap_if->eapKeyData; -} - - -void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, - int enabled) -{ - if (sm == NULL) - return; - sm->eap_if->portEnabled = enabled ? TRUE : FALSE; - eapol_auth_step(sm); -} - - -void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, - int valid) -{ - if (sm == NULL) - return; - sm->portValid = valid ? TRUE : FALSE; - eapol_auth_step(sm); -} - - -void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth) -{ - if (sm == NULL) - return; - if (pre_auth) - sm->flags |= EAPOL_SM_PREAUTH; - else - sm->flags &= ~EAPOL_SM_PREAUTH; -} - - -static const char * bool_txt(Boolean bool) -{ - return bool ? "TRUE" : "FALSE"; -} - - -int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) -{ - /* TODO */ - return 0; -} - - -int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, - char *buf, size_t buflen) -{ - int len = 0, ret; - struct eapol_state_machine *sm = sta->eapol_sm; - struct os_reltime diff; - - if (sm == NULL) - return 0; - - ret = os_snprintf(buf + len, buflen - len, - "dot1xPaePortNumber=%d\n" - "dot1xPaePortProtocolVersion=%d\n" - "dot1xPaePortCapabilities=1\n" - "dot1xPaePortInitialize=%d\n" - "dot1xPaePortReauthenticate=FALSE\n", - sta->aid, - EAPOL_VERSION, - sm->initialize); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - /* dot1xAuthConfigTable */ - ret = os_snprintf(buf + len, buflen - len, - "dot1xAuthPaeState=%d\n" - "dot1xAuthBackendAuthState=%d\n" - "dot1xAuthAdminControlledDirections=%d\n" - "dot1xAuthOperControlledDirections=%d\n" - "dot1xAuthAuthControlledPortStatus=%d\n" - "dot1xAuthAuthControlledPortControl=%d\n" - "dot1xAuthQuietPeriod=%u\n" - "dot1xAuthServerTimeout=%u\n" - "dot1xAuthReAuthPeriod=%u\n" - "dot1xAuthReAuthEnabled=%s\n" - "dot1xAuthKeyTxEnabled=%s\n", - sm->auth_pae_state + 1, - sm->be_auth_state + 1, - sm->adminControlledDirections, - sm->operControlledDirections, - sm->authPortStatus, - sm->portControl, - sm->quietPeriod, - sm->serverTimeout, - sm->reAuthPeriod, - bool_txt(sm->reAuthEnabled), - bool_txt(sm->keyTxEnabled)); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - /* dot1xAuthStatsTable */ - ret = os_snprintf(buf + len, buflen - len, - "dot1xAuthEapolFramesRx=%u\n" - "dot1xAuthEapolFramesTx=%u\n" - "dot1xAuthEapolStartFramesRx=%u\n" - "dot1xAuthEapolLogoffFramesRx=%u\n" - "dot1xAuthEapolRespIdFramesRx=%u\n" - "dot1xAuthEapolRespFramesRx=%u\n" - "dot1xAuthEapolReqIdFramesTx=%u\n" - "dot1xAuthEapolReqFramesTx=%u\n" - "dot1xAuthInvalidEapolFramesRx=%u\n" - "dot1xAuthEapLengthErrorFramesRx=%u\n" - "dot1xAuthLastEapolFrameVersion=%u\n" - "dot1xAuthLastEapolFrameSource=" MACSTR "\n", - sm->dot1xAuthEapolFramesRx, - sm->dot1xAuthEapolFramesTx, - sm->dot1xAuthEapolStartFramesRx, - sm->dot1xAuthEapolLogoffFramesRx, - sm->dot1xAuthEapolRespIdFramesRx, - sm->dot1xAuthEapolRespFramesRx, - sm->dot1xAuthEapolReqIdFramesTx, - sm->dot1xAuthEapolReqFramesTx, - sm->dot1xAuthInvalidEapolFramesRx, - sm->dot1xAuthEapLengthErrorFramesRx, - sm->dot1xAuthLastEapolFrameVersion, - MAC2STR(sm->addr)); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - /* dot1xAuthDiagTable */ - ret = os_snprintf(buf + len, buflen - len, - "dot1xAuthEntersConnecting=%u\n" - "dot1xAuthEapLogoffsWhileConnecting=%u\n" - "dot1xAuthEntersAuthenticating=%u\n" - "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n" - "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n" - "dot1xAuthAuthFailWhileAuthenticating=%u\n" - "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n" - "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n" - "dot1xAuthAuthReauthsWhileAuthenticated=%u\n" - "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n" - "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n" - "dot1xAuthBackendResponses=%u\n" - "dot1xAuthBackendAccessChallenges=%u\n" - "dot1xAuthBackendOtherRequestsToSupplicant=%u\n" - "dot1xAuthBackendAuthSuccesses=%u\n" - "dot1xAuthBackendAuthFails=%u\n", - sm->authEntersConnecting, - sm->authEapLogoffsWhileConnecting, - sm->authEntersAuthenticating, - sm->authAuthSuccessesWhileAuthenticating, - sm->authAuthTimeoutsWhileAuthenticating, - sm->authAuthFailWhileAuthenticating, - sm->authAuthEapStartsWhileAuthenticating, - sm->authAuthEapLogoffWhileAuthenticating, - sm->authAuthReauthsWhileAuthenticated, - sm->authAuthEapStartsWhileAuthenticated, - sm->authAuthEapLogoffWhileAuthenticated, - sm->backendResponses, - sm->backendAccessChallenges, - sm->backendOtherRequestsToSupplicant, - sm->backendAuthSuccesses, - sm->backendAuthFails); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - /* dot1xAuthSessionStatsTable */ - os_reltime_age(&sta->acct_session_start, &diff); - ret = os_snprintf(buf + len, buflen - len, - /* TODO: dot1xAuthSessionOctetsRx */ - /* TODO: dot1xAuthSessionOctetsTx */ - /* TODO: dot1xAuthSessionFramesRx */ - /* TODO: dot1xAuthSessionFramesTx */ - "dot1xAuthSessionId=%08X-%08X\n" - "dot1xAuthSessionAuthenticMethod=%d\n" - "dot1xAuthSessionTime=%u\n" - "dot1xAuthSessionTerminateCause=999\n" - "dot1xAuthSessionUserName=%s\n", - sta->acct_session_id_hi, sta->acct_session_id_lo, - (wpa_key_mgmt_wpa_ieee8021x( - wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? - 1 : 2, - (unsigned int) diff.sec, - sm->identity); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - ret = os_snprintf(buf + len, buflen - len, - "last_eap_type_as=%d (%s)\n" - "last_eap_type_sta=%d (%s)\n", - sm->eap_type_authsrv, - eap_server_get_name(0, sm->eap_type_authsrv), - sm->eap_type_supp, - eap_server_get_name(0, sm->eap_type_supp)); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - return len; -} - - -static void ieee802_1x_finished(struct hostapd_data *hapd, - struct sta_info *sta, int success) -{ - const u8 *key; - size_t len; - /* TODO: get PMKLifetime from WPA parameters */ - static const int dot11RSNAConfigPMKLifetime = 43200; - - key = ieee802_1x_get_key(sta->eapol_sm, &len); - if (success && key && len >= PMK_LEN && - wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime, - sta->eapol_sm) == 0) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, - HOSTAPD_LEVEL_DEBUG, - "Added PMKSA cache entry (IEEE 802.1X)"); - } - - 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. 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_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_IEEE_802_1X_AUTH_FAILED); - hostapd_wps_eap_completed(hapd); - } -} diff --git a/contrib/hostapd/src/ap/ieee802_1x.h b/contrib/hostapd/src/ap/ieee802_1x.h deleted file mode 100644 index e1df94057d..0000000000 --- a/contrib/hostapd/src/ap/ieee802_1x.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * hostapd / IEEE 802.1X-2004 Authenticator - * Copyright (c) 2002-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef IEEE802_1X_H -#define IEEE802_1X_H - -struct hostapd_data; -struct sta_info; -struct eapol_state_machine; -struct hostapd_config; -struct hostapd_bss_config; -struct hostapd_radius_attr; -struct radius_msg; - - -void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, - size_t len); -void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta); -void ieee802_1x_free_station(struct sta_info *sta); - -void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta); -void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta); -void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, - struct sta_info *sta, int authorized); -void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta); -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); -struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm); -const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len); -void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, - int enabled); -void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, - int valid); -void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth); -int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen); -int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, - char *buf, size_t buflen); -void hostapd_get_ntp_timestamp(u8 *buf); -char *eap_type_text(u8 type); - -const char *radius_mode_txt(struct hostapd_data *hapd); -int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta); - -int add_common_radius_attr(struct hostapd_data *hapd, - struct hostapd_radius_attr *req_attr, - struct sta_info *sta, - struct radius_msg *msg); - -#endif /* IEEE802_1X_H */ diff --git a/contrib/hostapd/src/ap/p2p_hostapd.c b/contrib/hostapd/src/ap/p2p_hostapd.c deleted file mode 100644 index 795d313b8c..0000000000 --- a/contrib/hostapd/src/ap/p2p_hostapd.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * hostapd / P2P integration - * Copyright (c) 2009-2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "common/ieee802_11_defs.h" -#include "p2p/p2p.h" -#include "hostapd.h" -#include "ap_config.h" -#include "ap_drv_ops.h" -#include "sta_info.h" -#include "p2p_hostapd.h" - - -#ifdef CONFIG_P2P - -int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, - char *buf, size_t buflen) -{ - if (sta->p2p_ie == NULL) - return 0; - - return p2p_ie_text(sta->p2p_ie, buf, buf + buflen); -} - - -int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start, - int duration) -{ - wpa_printf(MSG_DEBUG, "P2P: Set NoA parameters: count=%u start=%d " - "duration=%d", count, start, duration); - - if (count == 0) { - hapd->noa_enabled = 0; - hapd->noa_start = 0; - hapd->noa_duration = 0; - } - - if (count != 255) { - wpa_printf(MSG_DEBUG, "P2P: Non-periodic NoA - set " - "NoA parameters"); - return hostapd_driver_set_noa(hapd, count, start, duration); - } - - hapd->noa_enabled = 1; - hapd->noa_start = start; - hapd->noa_duration = duration; - - if (hapd->num_sta_no_p2p == 0) { - wpa_printf(MSG_DEBUG, "P2P: No legacy STAs connected - update " - "periodic NoA parameters"); - return hostapd_driver_set_noa(hapd, count, start, duration); - } - - wpa_printf(MSG_DEBUG, "P2P: Legacy STA(s) connected - do not enable " - "periodic NoA"); - - return 0; -} - - -void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd) -{ - wpa_printf(MSG_DEBUG, "P2P: First non-P2P device connected"); - - if (hapd->noa_enabled) { - wpa_printf(MSG_DEBUG, "P2P: Disable periodic NoA"); - hostapd_driver_set_noa(hapd, 0, 0, 0); - } -} - - -void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd) -{ - wpa_printf(MSG_DEBUG, "P2P: Last non-P2P device disconnected"); - - if (hapd->noa_enabled) { - wpa_printf(MSG_DEBUG, "P2P: Enable periodic NoA"); - hostapd_driver_set_noa(hapd, 255, hapd->noa_start, - hapd->noa_duration); - } -} - -#endif /* CONFIG_P2P */ - - -#ifdef CONFIG_P2P_MANAGER -u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid) -{ - u8 bitmap; - *eid++ = WLAN_EID_VENDOR_SPECIFIC; - *eid++ = 4 + 3 + 1; - WPA_PUT_BE24(eid, OUI_WFA); - eid += 3; - *eid++ = P2P_OUI_TYPE; - - *eid++ = P2P_ATTR_MANAGEABILITY; - WPA_PUT_LE16(eid, 1); - eid += 2; - bitmap = P2P_MAN_DEVICE_MANAGEMENT; - if (hapd->conf->p2p & P2P_ALLOW_CROSS_CONNECTION) - bitmap |= P2P_MAN_CROSS_CONNECTION_PERMITTED; - bitmap |= P2P_MAN_COEXISTENCE_OPTIONAL; - *eid++ = bitmap; - - return eid; -} -#endif /* CONFIG_P2P_MANAGER */ diff --git a/contrib/hostapd/src/ap/p2p_hostapd.h b/contrib/hostapd/src/ap/p2p_hostapd.h deleted file mode 100644 index 0e3921c614..0000000000 --- a/contrib/hostapd/src/ap/p2p_hostapd.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * hostapd / P2P integration - * Copyright (c) 2009-2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef P2P_HOSTAPD_H -#define P2P_HOSTAPD_H - -#ifdef CONFIG_P2P - -int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, - char *buf, size_t buflen); -int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start, - int duration); -void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd); -void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd); - - -#else /* CONFIG_P2P */ - -static inline int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, - struct sta_info *sta, - char *buf, size_t buflen) -{ - return 0; -} - -#endif /* CONFIG_P2P */ - -u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid); - -#endif /* P2P_HOSTAPD_H */ diff --git a/contrib/hostapd/src/ap/peerkey_auth.c b/contrib/hostapd/src/ap/peerkey_auth.c deleted file mode 100644 index ba5c606442..0000000000 --- a/contrib/hostapd/src/ap/peerkey_auth.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * hostapd - PeerKey for Direct Link Setup (DLS) - * Copyright (c) 2006-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "crypto/random.h" -#include "wpa_auth.h" -#include "wpa_auth_i.h" -#include "wpa_auth_ie.h" - -#ifdef CONFIG_PEERKEY - -static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx) -{ -#if 0 - struct wpa_authenticator *wpa_auth = eloop_ctx; - struct wpa_stsl_negotiation *neg = timeout_ctx; -#endif - - /* TODO: ? */ -} - - -struct wpa_stsl_search { - const u8 *addr; - struct wpa_state_machine *sm; -}; - - -static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx) -{ - struct wpa_stsl_search *search = ctx; - if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) { - search->sm = sm; - return 1; - } - return 0; -} - - -static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, const u8 *peer, - u16 mui, u16 error_type) -{ - u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN + - 2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)]; - u8 *pos; - struct rsn_error_kde error; - - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, - "Sending SMK Error"); - - pos = kde; - - if (peer) { - pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, - NULL, 0); - } - - error.mui = host_to_be16(mui); - error.error_type = host_to_be16(error_type); - pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR, - (u8 *) &error, sizeof(error), NULL, 0); - - __wpa_send_eapol(wpa_auth, sm, - WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | - WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR, - NULL, NULL, kde, pos - kde, 0, 0, 0); -} - - -void wpa_smk_m1(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, struct wpa_eapol_key *key) -{ - struct wpa_eapol_ie_parse kde; - struct wpa_stsl_search search; - u8 *buf, *pos; - size_t buf_len; - - if (wpa_parse_kde_ies((const u8 *) (key + 1), - WPA_GET_BE16(key->key_data_length), &kde) < 0) { - wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1"); - return; - } - - if (kde.rsn_ie == NULL || kde.mac_addr == NULL || - kde.mac_addr_len < ETH_ALEN) { - wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in " - "SMK M1"); - return; - } - - /* Initiator = sm->addr; Peer = kde.mac_addr */ - - search.addr = kde.mac_addr; - search.sm = NULL; - if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) == - 0 || search.sm == NULL) { - wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR - " aborted - STA not associated anymore", - MAC2STR(kde.mac_addr)); - wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK, - STK_ERR_STA_NR); - /* FIX: wpa_stsl_remove(wpa_auth, neg); */ - return; - } - - buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN; - buf = os_malloc(buf_len); - if (buf == NULL) - return; - /* Initiator RSN IE */ - os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len); - pos = buf + kde.rsn_ie_len; - /* Initiator MAC Address */ - pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN, - NULL, 0); - - /* SMK M2: - * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce, - * MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE) - */ - - wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG, - "Sending SMK M2"); - - __wpa_send_eapol(wpa_auth, search.sm, - WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | - WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE, - NULL, key->key_nonce, buf, pos - buf, 0, 0, 0); - - os_free(buf); -} - - -static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, - struct wpa_eapol_key *key, - struct wpa_eapol_ie_parse *kde, - const u8 *smk) -{ - u8 *buf, *pos; - size_t buf_len; - u32 lifetime; - - /* SMK M4: - * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce, - * MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE, - * Lifetime KDE) - */ - - buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN + - 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN + - 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN + - 2 + RSN_SELECTOR_LEN + sizeof(lifetime); - pos = buf = os_malloc(buf_len); - if (buf == NULL) - return; - - /* Initiator MAC Address */ - pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN, - NULL, 0); - - /* Initiator Nonce */ - pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN, - NULL, 0); - - /* SMK with PNonce */ - pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN, - key->key_nonce, WPA_NONCE_LEN); - - /* Lifetime */ - lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */ - pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME, - (u8 *) &lifetime, sizeof(lifetime), NULL, 0); - - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "Sending SMK M4"); - - __wpa_send_eapol(wpa_auth, sm, - WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | - WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE, - NULL, key->key_nonce, buf, pos - buf, 0, 1, 0); - - os_free(buf); -} - - -static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, - struct wpa_eapol_key *key, - struct wpa_eapol_ie_parse *kde, - const u8 *smk, const u8 *peer) -{ - u8 *buf, *pos; - size_t buf_len; - u32 lifetime; - - /* SMK M5: - * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce, - * MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE, - * Lifetime KDE)) - */ - - buf_len = kde->rsn_ie_len + - 2 + RSN_SELECTOR_LEN + ETH_ALEN + - 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN + - 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN + - 2 + RSN_SELECTOR_LEN + sizeof(lifetime); - pos = buf = os_malloc(buf_len); - if (buf == NULL) - return; - - /* Peer RSN IE */ - os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len); - pos = buf + kde->rsn_ie_len; - - /* Peer MAC Address */ - pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0); - - /* PNonce */ - pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce, - WPA_NONCE_LEN, NULL, 0); - - /* SMK and INonce */ - pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN, - kde->nonce, WPA_NONCE_LEN); - - /* Lifetime */ - lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */ - pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME, - (u8 *) &lifetime, sizeof(lifetime), NULL, 0); - - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "Sending SMK M5"); - - __wpa_send_eapol(wpa_auth, sm, - WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | - WPA_KEY_INFO_SMK_MESSAGE, - NULL, kde->nonce, buf, pos - buf, 0, 1, 0); - - os_free(buf); -} - - -void wpa_smk_m3(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, struct wpa_eapol_key *key) -{ - struct wpa_eapol_ie_parse kde; - struct wpa_stsl_search search; - u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos; - - if (wpa_parse_kde_ies((const u8 *) (key + 1), - WPA_GET_BE16(key->key_data_length), &kde) < 0) { - wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3"); - return; - } - - if (kde.rsn_ie == NULL || - kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN || - kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) { - wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or " - "Nonce KDE in SMK M3"); - return; - } - - /* Peer = sm->addr; Initiator = kde.mac_addr; - * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */ - - search.addr = kde.mac_addr; - search.sm = NULL; - if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) == - 0 || search.sm == NULL) { - wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR - " aborted - STA not associated anymore", - MAC2STR(kde.mac_addr)); - wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK, - STK_ERR_STA_NR); - /* FIX: wpa_stsl_remove(wpa_auth, neg); */ - return; - } - - if (random_get_bytes(smk, PMK_LEN)) { - wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK"); - return; - } - - /* SMK = PRF-256(Random number, "SMK Derivation", - * AA || Time || INonce || PNonce) - */ - os_memcpy(buf, wpa_auth->addr, ETH_ALEN); - pos = buf + ETH_ALEN; - wpa_get_ntp_timestamp(pos); - pos += 8; - os_memcpy(pos, kde.nonce, WPA_NONCE_LEN); - pos += WPA_NONCE_LEN; - os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN); -#ifdef CONFIG_IEEE80211W - sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf), - smk, PMK_LEN); -#else /* CONFIG_IEEE80211W */ - sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf), - smk, PMK_LEN); -#endif /* CONFIG_IEEE80211W */ - - wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN); - - wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk); - wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr); - - /* Authenticator does not need SMK anymore and it is required to forget - * it. */ - os_memset(smk, 0, sizeof(*smk)); -} - - -void wpa_smk_error(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, struct wpa_eapol_key *key) -{ - struct wpa_eapol_ie_parse kde; - struct wpa_stsl_search search; - struct rsn_error_kde error; - u16 mui, error_type; - - if (wpa_parse_kde_ies((const u8 *) (key + 1), - WPA_GET_BE16(key->key_data_length), &kde) < 0) { - wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error"); - return; - } - - if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN || - kde.error == NULL || kde.error_len < sizeof(error)) { - wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in " - "SMK Error"); - return; - } - - search.addr = kde.mac_addr; - search.sm = NULL; - if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) == - 0 || search.sm == NULL) { - wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not " - "associated for SMK Error message from " MACSTR, - MAC2STR(kde.mac_addr), MAC2STR(sm->addr)); - return; - } - - os_memcpy(&error, kde.error, sizeof(error)); - mui = be_to_host16(error.mui); - error_type = be_to_host16(error.error_type); - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, - "STA reported SMK Error: Peer " MACSTR - " MUI %d Error Type %d", - MAC2STR(kde.mac_addr), mui, error_type); - - wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type); -} - - -int wpa_stsl_remove(struct wpa_authenticator *wpa_auth, - struct wpa_stsl_negotiation *neg) -{ - struct wpa_stsl_negotiation *pos, *prev; - - if (wpa_auth == NULL) - return -1; - pos = wpa_auth->stsl_negotiations; - prev = NULL; - while (pos) { - if (pos == neg) { - if (prev) - prev->next = pos->next; - else - wpa_auth->stsl_negotiations = pos->next; - - eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos); - os_free(pos); - return 0; - } - prev = pos; - pos = pos->next; - } - - return -1; -} - -#endif /* CONFIG_PEERKEY */ diff --git a/contrib/hostapd/src/ap/pmksa_cache_auth.c b/contrib/hostapd/src/ap/pmksa_cache_auth.c deleted file mode 100644 index 4720b59c05..0000000000 --- a/contrib/hostapd/src/ap/pmksa_cache_auth.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * hostapd - PMKSA cache for IEEE 802.11i RSN - * Copyright (c) 2004-2008, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "eapol_auth/eapol_auth_sm.h" -#include "eapol_auth/eapol_auth_sm_i.h" -#include "sta_info.h" -#include "ap_config.h" -#include "pmksa_cache_auth.h" - - -static const int pmksa_cache_max_entries = 1024; -static const int dot11RSNAConfigPMKLifetime = 43200; - -struct rsn_pmksa_cache { -#define PMKID_HASH_SIZE 128 -#define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f) - struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE]; - struct rsn_pmksa_cache_entry *pmksa; - int pmksa_count; - - void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx); - void *ctx; -}; - - -static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); - - -static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) -{ - if (entry == NULL) - return; - os_free(entry->identity); - wpabuf_free(entry->cui); -#ifndef CONFIG_NO_RADIUS - radius_free_class(&entry->radius_class); -#endif /* CONFIG_NO_RADIUS */ - os_free(entry); -} - - -void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, - struct rsn_pmksa_cache_entry *entry) -{ - struct rsn_pmksa_cache_entry *pos, *prev; - - pmksa->pmksa_count--; - pmksa->free_cb(entry, pmksa->ctx); - pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)]; - prev = NULL; - while (pos) { - if (pos == entry) { - if (prev != NULL) { - prev->hnext = pos->hnext; - } else { - pmksa->pmkid[PMKID_HASH(entry->pmkid)] = - pos->hnext; - } - break; - } - prev = pos; - pos = pos->hnext; - } - - pos = pmksa->pmksa; - prev = NULL; - while (pos) { - if (pos == entry) { - if (prev != NULL) - prev->next = pos->next; - else - pmksa->pmksa = pos->next; - break; - } - prev = pos; - pos = pos->next; - } - _pmksa_cache_free_entry(entry); -} - - -static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) -{ - struct rsn_pmksa_cache *pmksa = eloop_ctx; - struct os_reltime now; - - os_get_reltime(&now); - while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { - wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " - MACSTR, MAC2STR(pmksa->pmksa->spa)); - pmksa_cache_free_entry(pmksa, pmksa->pmksa); - } - - pmksa_cache_set_expiration(pmksa); -} - - -static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) -{ - int sec; - struct os_reltime now; - - eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); - if (pmksa->pmksa == NULL) - return; - os_get_reltime(&now); - sec = pmksa->pmksa->expiration - now.sec; - if (sec < 0) - sec = 0; - eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL); -} - - -static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry, - struct eapol_state_machine *eapol) -{ - if (eapol == NULL) - return; - - if (eapol->identity) { - entry->identity = os_malloc(eapol->identity_len); - if (entry->identity) { - entry->identity_len = eapol->identity_len; - os_memcpy(entry->identity, eapol->identity, - eapol->identity_len); - } - } - - if (eapol->radius_cui) - entry->cui = wpabuf_dup(eapol->radius_cui); - -#ifndef CONFIG_NO_RADIUS - radius_copy_class(&entry->radius_class, &eapol->radius_class); -#endif /* CONFIG_NO_RADIUS */ - - entry->eap_type_authsrv = eapol->eap_type_authsrv; - entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id; -} - - -void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry, - struct eapol_state_machine *eapol) -{ - if (entry == NULL || eapol == NULL) - return; - - if (entry->identity) { - os_free(eapol->identity); - eapol->identity = os_malloc(entry->identity_len); - if (eapol->identity) { - eapol->identity_len = entry->identity_len; - os_memcpy(eapol->identity, entry->identity, - entry->identity_len); - } - wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA", - eapol->identity, eapol->identity_len); - } - - if (entry->cui) { - wpabuf_free(eapol->radius_cui); - eapol->radius_cui = wpabuf_dup(entry->cui); - } - -#ifndef CONFIG_NO_RADIUS - radius_free_class(&eapol->radius_class); - radius_copy_class(&eapol->radius_class, &entry->radius_class); -#endif /* CONFIG_NO_RADIUS */ - if (eapol->radius_class.attr) { - wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from " - "PMKSA", (unsigned long) eapol->radius_class.count); - } - - eapol->eap_type_authsrv = entry->eap_type_authsrv; - ((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id; -} - - -static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa, - struct rsn_pmksa_cache_entry *entry) -{ - struct rsn_pmksa_cache_entry *pos, *prev; - - /* Add the new entry; order by expiration time */ - pos = pmksa->pmksa; - prev = NULL; - while (pos) { - if (pos->expiration > entry->expiration) - break; - prev = pos; - pos = pos->next; - } - if (prev == NULL) { - entry->next = pmksa->pmksa; - pmksa->pmksa = entry; - } else { - entry->next = prev->next; - prev->next = entry; - } - entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)]; - pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry; - - pmksa->pmksa_count++; - if (prev == NULL) - pmksa_cache_set_expiration(pmksa); - wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR, - MAC2STR(entry->spa)); - wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN); -} - - -/** - * pmksa_cache_auth_add - Add a PMKSA cache entry - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() - * @pmk: The new pairwise master key - * @pmk_len: PMK length in bytes, usually PMK_LEN (32) - * @aa: Authenticator address - * @spa: Supplicant address - * @session_timeout: Session timeout - * @eapol: Pointer to EAPOL state machine data - * @akmp: WPA_KEY_MGMT_* used in key derivation - * Returns: Pointer to the added PMKSA cache entry or %NULL on error - * - * This function create a PMKSA entry for a new PMK and adds it to the PMKSA - * cache. If an old entry is already in the cache for the same Supplicant, - * this entry will be replaced with the new entry. PMKID will be calculated - * based on the PMK. - */ -struct rsn_pmksa_cache_entry * -pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, - const u8 *pmk, size_t pmk_len, - const u8 *aa, const u8 *spa, int session_timeout, - struct eapol_state_machine *eapol, int akmp) -{ - struct rsn_pmksa_cache_entry *entry, *pos; - struct os_reltime now; - - if (pmk_len > PMK_LEN) - return NULL; - - entry = os_zalloc(sizeof(*entry)); - if (entry == NULL) - return NULL; - os_memcpy(entry->pmk, pmk, pmk_len); - entry->pmk_len = pmk_len; - rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, - wpa_key_mgmt_sha256(akmp)); - os_get_reltime(&now); - entry->expiration = now.sec; - if (session_timeout > 0) - entry->expiration += session_timeout; - else - entry->expiration += dot11RSNAConfigPMKLifetime; - entry->akmp = akmp; - os_memcpy(entry->spa, spa, ETH_ALEN); - pmksa_cache_from_eapol_data(entry, eapol); - - /* Replace an old entry for the same STA (if found) with the new entry - */ - pos = pmksa_cache_auth_get(pmksa, spa, NULL); - if (pos) - pmksa_cache_free_entry(pmksa, pos); - - if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) { - /* Remove the oldest entry to make room for the new entry */ - wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache " - "entry (for " MACSTR ") to make room for new one", - MAC2STR(pmksa->pmksa->spa)); - pmksa_cache_free_entry(pmksa, pmksa->pmksa); - } - - pmksa_cache_link_entry(pmksa, entry); - - return entry; -} - - -struct rsn_pmksa_cache_entry * -pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa, - const struct rsn_pmksa_cache_entry *old_entry, - const u8 *aa, const u8 *pmkid) -{ - struct rsn_pmksa_cache_entry *entry; - - entry = os_zalloc(sizeof(*entry)); - if (entry == NULL) - return NULL; - os_memcpy(entry->pmkid, pmkid, PMKID_LEN); - os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len); - entry->pmk_len = old_entry->pmk_len; - entry->expiration = old_entry->expiration; - entry->akmp = old_entry->akmp; - os_memcpy(entry->spa, old_entry->spa, ETH_ALEN); - entry->opportunistic = 1; - if (old_entry->identity) { - entry->identity = os_malloc(old_entry->identity_len); - if (entry->identity) { - entry->identity_len = old_entry->identity_len; - os_memcpy(entry->identity, old_entry->identity, - old_entry->identity_len); - } - } - if (old_entry->cui) - entry->cui = wpabuf_dup(old_entry->cui); -#ifndef CONFIG_NO_RADIUS - radius_copy_class(&entry->radius_class, &old_entry->radius_class); -#endif /* CONFIG_NO_RADIUS */ - entry->eap_type_authsrv = old_entry->eap_type_authsrv; - entry->vlan_id = old_entry->vlan_id; - entry->opportunistic = 1; - - pmksa_cache_link_entry(pmksa, entry); - - return entry; -} - - -/** - * pmksa_cache_auth_deinit - Free all entries in PMKSA cache - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() - */ -void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa) -{ - struct rsn_pmksa_cache_entry *entry, *prev; - int i; - - if (pmksa == NULL) - return; - - entry = pmksa->pmksa; - while (entry) { - prev = entry; - entry = entry->next; - _pmksa_cache_free_entry(prev); - } - eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); - for (i = 0; i < PMKID_HASH_SIZE; i++) - pmksa->pmkid[i] = NULL; - os_free(pmksa); -} - - -/** - * pmksa_cache_auth_get - Fetch a PMKSA cache entry - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() - * @spa: Supplicant address or %NULL to match any - * @pmkid: PMKID or %NULL to match any - * Returns: Pointer to PMKSA cache entry or %NULL if no match was found - */ -struct rsn_pmksa_cache_entry * -pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa, - const u8 *spa, const u8 *pmkid) -{ - struct rsn_pmksa_cache_entry *entry; - - if (pmkid) - entry = pmksa->pmkid[PMKID_HASH(pmkid)]; - else - entry = pmksa->pmksa; - while (entry) { - if ((spa == NULL || - os_memcmp(entry->spa, spa, ETH_ALEN) == 0) && - (pmkid == NULL || - os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)) - return entry; - entry = pmkid ? entry->hnext : entry->next; - } - return NULL; -} - - -/** - * pmksa_cache_get_okc - Fetch a PMKSA cache entry using OKC - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() - * @aa: Authenticator address - * @spa: Supplicant address - * @pmkid: PMKID - * Returns: Pointer to PMKSA cache entry or %NULL if no match was found - * - * Use opportunistic key caching (OKC) to find a PMK for a supplicant. - */ -struct rsn_pmksa_cache_entry * pmksa_cache_get_okc( - struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa, - const u8 *pmkid) -{ - struct rsn_pmksa_cache_entry *entry; - u8 new_pmkid[PMKID_LEN]; - - entry = pmksa->pmksa; - while (entry) { - if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0) - continue; - rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid, - wpa_key_mgmt_sha256(entry->akmp)); - if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0) - return entry; - entry = entry->next; - } - return NULL; -} - - -/** - * pmksa_cache_auth_init - Initialize PMKSA cache - * @free_cb: Callback function to be called when a PMKSA cache entry is freed - * @ctx: Context pointer for free_cb function - * Returns: Pointer to PMKSA cache data or %NULL on failure - */ -struct rsn_pmksa_cache * -pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, - void *ctx), void *ctx) -{ - struct rsn_pmksa_cache *pmksa; - - pmksa = os_zalloc(sizeof(*pmksa)); - if (pmksa) { - pmksa->free_cb = free_cb; - pmksa->ctx = ctx; - } - - return pmksa; -} diff --git a/contrib/hostapd/src/ap/pmksa_cache_auth.h b/contrib/hostapd/src/ap/pmksa_cache_auth.h deleted file mode 100644 index aa90024d7d..0000000000 --- a/contrib/hostapd/src/ap/pmksa_cache_auth.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * hostapd - PMKSA cache for IEEE 802.11i RSN - * Copyright (c) 2004-2008, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef PMKSA_CACHE_H -#define PMKSA_CACHE_H - -#include "radius/radius.h" - -/** - * struct rsn_pmksa_cache_entry - PMKSA cache entry - */ -struct rsn_pmksa_cache_entry { - struct rsn_pmksa_cache_entry *next, *hnext; - u8 pmkid[PMKID_LEN]; - u8 pmk[PMK_LEN]; - size_t pmk_len; - os_time_t expiration; - int akmp; /* WPA_KEY_MGMT_* */ - u8 spa[ETH_ALEN]; - - u8 *identity; - size_t identity_len; - struct wpabuf *cui; - struct radius_class_data radius_class; - u8 eap_type_authsrv; - int vlan_id; - int opportunistic; -}; - -struct rsn_pmksa_cache; - -struct rsn_pmksa_cache * -pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, - void *ctx), void *ctx); -void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa); -struct rsn_pmksa_cache_entry * -pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa, - const u8 *spa, const u8 *pmkid); -struct rsn_pmksa_cache_entry * pmksa_cache_get_okc( - struct rsn_pmksa_cache *pmksa, const u8 *spa, const u8 *aa, - const u8 *pmkid); -struct rsn_pmksa_cache_entry * -pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, - const u8 *pmk, size_t pmk_len, - const u8 *aa, const u8 *spa, int session_timeout, - struct eapol_state_machine *eapol, int akmp); -struct rsn_pmksa_cache_entry * -pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa, - const struct rsn_pmksa_cache_entry *old_entry, - const u8 *aa, const u8 *pmkid); -void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry, - struct eapol_state_machine *eapol); -void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, - struct rsn_pmksa_cache_entry *entry); - -#endif /* PMKSA_CACHE_H */ diff --git a/contrib/hostapd/src/ap/preauth_auth.c b/contrib/hostapd/src/ap/preauth_auth.c deleted file mode 100644 index 3e0c8000d0..0000000000 --- a/contrib/hostapd/src/ap/preauth_auth.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#ifdef CONFIG_RSN_PREAUTH - -#include "utils/common.h" -#include "utils/eloop.h" -#include "l2_packet/l2_packet.h" -#include "common/wpa_common.h" -#include "eapol_auth/eapol_auth_sm.h" -#include "eapol_auth/eapol_auth_sm_i.h" -#include "hostapd.h" -#include "ap_config.h" -#include "ieee802_1x.h" -#include "sta_info.h" -#include "wpa_auth.h" -#include "preauth_auth.h" - -#ifndef ETH_P_PREAUTH -#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ -#endif /* ETH_P_PREAUTH */ - -static const int dot11RSNAConfigPMKLifetime = 43200; - -struct rsn_preauth_interface { - struct rsn_preauth_interface *next; - struct hostapd_data *hapd; - struct l2_packet_data *l2; - char *ifname; - int ifindex; -}; - - -static void rsn_preauth_receive(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len) -{ - struct rsn_preauth_interface *piface = ctx; - struct hostapd_data *hapd = piface->hapd; - struct ieee802_1x_hdr *hdr; - struct sta_info *sta; - struct l2_ethhdr *ethhdr; - - wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet " - "from interface '%s'", piface->ifname); - if (len < sizeof(*ethhdr) + sizeof(*hdr)) { - wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet " - "(len=%lu)", (unsigned long) len); - return; - } - - ethhdr = (struct l2_ethhdr *) buf; - hdr = (struct ieee802_1x_hdr *) (ethhdr + 1); - - if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address " - MACSTR, MAC2STR(ethhdr->h_dest)); - return; - } - - sta = ap_get_sta(hapd, ethhdr->h_source); - if (sta && (sta->flags & WLAN_STA_ASSOC)) { - wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association " - "STA " MACSTR, MAC2STR(sta->addr)); - return; - } - if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) { - sta = ap_sta_add(hapd, ethhdr->h_source); - if (sta == NULL) - return; - sta->flags = WLAN_STA_PREAUTH; - - ieee802_1x_new_station(hapd, sta); - if (sta->eapol_sm == NULL) { - ap_free_sta(hapd, sta); - sta = NULL; - } else { - sta->eapol_sm->radius_identifier = -1; - sta->eapol_sm->portValid = TRUE; - sta->eapol_sm->flags |= EAPOL_SM_PREAUTH; - } - } - if (sta == NULL) - return; - sta->preauth_iface = piface; - ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1), - len - sizeof(*ethhdr)); -} - - -static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname) -{ - struct rsn_preauth_interface *piface; - - wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname); - - piface = os_zalloc(sizeof(*piface)); - if (piface == NULL) - return -1; - piface->hapd = hapd; - - piface->ifname = os_strdup(ifname); - if (piface->ifname == NULL) { - goto fail1; - } - - piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH, - rsn_preauth_receive, piface, 1); - if (piface->l2 == NULL) { - wpa_printf(MSG_ERROR, "Failed to open register layer 2 access " - "to ETH_P_PREAUTH"); - goto fail2; - } - - piface->next = hapd->preauth_iface; - hapd->preauth_iface = piface; - return 0; - -fail2: - os_free(piface->ifname); -fail1: - os_free(piface); - return -1; -} - - -void rsn_preauth_iface_deinit(struct hostapd_data *hapd) -{ - struct rsn_preauth_interface *piface, *prev; - - piface = hapd->preauth_iface; - hapd->preauth_iface = NULL; - while (piface) { - prev = piface; - piface = piface->next; - l2_packet_deinit(prev->l2); - os_free(prev->ifname); - os_free(prev); - } -} - - -int rsn_preauth_iface_init(struct hostapd_data *hapd) -{ - char *tmp, *start, *end; - - if (hapd->conf->rsn_preauth_interfaces == NULL) - return 0; - - tmp = os_strdup(hapd->conf->rsn_preauth_interfaces); - if (tmp == NULL) - return -1; - start = tmp; - for (;;) { - while (*start == ' ') - start++; - if (*start == '\0') - break; - end = os_strchr(start, ' '); - if (end) - *end = '\0'; - - if (rsn_preauth_iface_add(hapd, start)) { - rsn_preauth_iface_deinit(hapd); - os_free(tmp); - return -1; - } - - if (end) - start = end + 1; - else - break; - } - os_free(tmp); - return 0; -} - - -static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - struct sta_info *sta = timeout_ctx; - wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for " - MACSTR, MAC2STR(sta->addr)); - ap_free_sta(hapd, sta); -} - - -void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta, - int success) -{ - const u8 *key; - size_t len; - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, - HOSTAPD_LEVEL_INFO, "pre-authentication %s", - success ? "succeeded" : "failed"); - - key = ieee802_1x_get_key(sta->eapol_sm, &len); - if (len > PMK_LEN) - len = PMK_LEN; - if (success && key) { - if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len, - sta->addr, - dot11RSNAConfigPMKLifetime, - sta->eapol_sm) == 0) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, - HOSTAPD_LEVEL_DEBUG, - "added PMKSA cache entry (pre-auth)"); - } else { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, - HOSTAPD_LEVEL_DEBUG, - "failed to add PMKSA cache entry " - "(pre-auth)"); - } - } - - /* - * Finish STA entry removal from timeout in order to avoid freeing - * STA data before the caller has finished processing. - */ - eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta); -} - - -void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta, - u8 *buf, size_t len) -{ - struct rsn_preauth_interface *piface; - struct l2_ethhdr *ethhdr; - - piface = hapd->preauth_iface; - while (piface) { - if (piface == sta->preauth_iface) - break; - piface = piface->next; - } - - if (piface == NULL) { - wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication " - "interface for " MACSTR, MAC2STR(sta->addr)); - return; - } - - ethhdr = os_malloc(sizeof(*ethhdr) + len); - if (ethhdr == NULL) - return; - - os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN); - os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN); - ethhdr->h_proto = host_to_be16(ETH_P_PREAUTH); - os_memcpy(ethhdr + 1, buf, len); - - if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr, - sizeof(*ethhdr) + len) < 0) { - wpa_printf(MSG_ERROR, "Failed to send preauth packet using " - "l2_packet_send\n"); - } - os_free(ethhdr); -} - - -void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta) -{ - eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta); -} - -#endif /* CONFIG_RSN_PREAUTH */ diff --git a/contrib/hostapd/src/ap/preauth_auth.h b/contrib/hostapd/src/ap/preauth_auth.h deleted file mode 100644 index 69fb3566e0..0000000000 --- a/contrib/hostapd/src/ap/preauth_auth.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication - * Copyright (c) 2004-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef PREAUTH_H -#define PREAUTH_H - -#ifdef CONFIG_RSN_PREAUTH - -int rsn_preauth_iface_init(struct hostapd_data *hapd); -void rsn_preauth_iface_deinit(struct hostapd_data *hapd); -void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta, - int success); -void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta, - u8 *buf, size_t len); -void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta); - -#else /* CONFIG_RSN_PREAUTH */ - -static inline int rsn_preauth_iface_init(struct hostapd_data *hapd) -{ - return 0; -} - -static inline void rsn_preauth_iface_deinit(struct hostapd_data *hapd) -{ -} - -static inline void rsn_preauth_finished(struct hostapd_data *hapd, - struct sta_info *sta, - int success) -{ -} - -static inline void rsn_preauth_send(struct hostapd_data *hapd, - struct sta_info *sta, - u8 *buf, size_t len) -{ -} - -static inline void rsn_preauth_free_station(struct hostapd_data *hapd, - struct sta_info *sta) -{ -} - -#endif /* CONFIG_RSN_PREAUTH */ - -#endif /* PREAUTH_H */ diff --git a/contrib/hostapd/src/ap/sta_info.c b/contrib/hostapd/src/ap/sta_info.c deleted file mode 100644 index 24e764d66b..0000000000 --- a/contrib/hostapd/src/ap/sta_info.c +++ /dev/null @@ -1,1057 +0,0 @@ -/* - * hostapd / Station table - * Copyright (c) 2002-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "common/ieee802_11_defs.h" -#include "common/wpa_ctrl.h" -#include "common/sae.h" -#include "radius/radius.h" -#include "radius/radius_client.h" -#include "p2p/p2p.h" -#include "hostapd.h" -#include "accounting.h" -#include "ieee802_1x.h" -#include "ieee802_11.h" -#include "ieee802_11_auth.h" -#include "wpa_auth.h" -#include "preauth_auth.h" -#include "ap_config.h" -#include "beacon.h" -#include "ap_mlme.h" -#include "vlan_init.h" -#include "p2p_hostapd.h" -#include "ap_drv_ops.h" -#include "gas_serv.h" -#include "sta_info.h" - -static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, - 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, - void *ctx), - void *ctx) -{ - struct sta_info *sta; - - for (sta = hapd->sta_list; sta; sta = sta->next) { - if (cb(hapd, sta, ctx)) - return 1; - } - - return 0; -} - - -struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta) -{ - struct sta_info *s; - - s = hapd->sta_hash[STA_HASH(sta)]; - while (s != NULL && os_memcmp(s->addr, sta, 6) != 0) - s = s->hnext; - return s; -} - - -#ifdef CONFIG_P2P -struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr) -{ - struct sta_info *sta; - - for (sta = hapd->sta_list; sta; sta = sta->next) { - const u8 *p2p_dev_addr; - - if (sta->p2p_ie == NULL) - continue; - - p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); - if (p2p_dev_addr == NULL) - continue; - - if (os_memcmp(p2p_dev_addr, addr, ETH_ALEN) == 0) - return sta; - } - - return NULL; -} -#endif /* CONFIG_P2P */ - - -static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta) -{ - struct sta_info *tmp; - - if (hapd->sta_list == sta) { - hapd->sta_list = sta->next; - return; - } - - tmp = hapd->sta_list; - while (tmp != NULL && tmp->next != sta) - tmp = tmp->next; - if (tmp == NULL) { - wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from " - "list.", MAC2STR(sta->addr)); - } else - tmp->next = sta->next; -} - - -void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta) -{ - sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)]; - hapd->sta_hash[STA_HASH(sta->addr)] = sta; -} - - -static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta) -{ - struct sta_info *s; - - s = hapd->sta_hash[STA_HASH(sta->addr)]; - if (s == NULL) return; - if (os_memcmp(s->addr, sta->addr, 6) == 0) { - hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext; - return; - } - - while (s->hnext != NULL && - os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0) - s = s->hnext; - if (s->hnext != NULL) - s->hnext = s->hnext->hnext; - else - wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR - " from hash table", MAC2STR(sta->addr)); -} - - -void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) -{ - int set_beacon = 0; - - accounting_sta_stop(hapd, sta); - - /* just in case */ - ap_sta_set_authorized(hapd, sta, 0); - - if (sta->flags & WLAN_STA_WDS) - hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0); - - if (!(sta->flags & WLAN_STA_PREAUTH)) - hostapd_drv_sta_remove(hapd, sta->addr); - - ap_sta_hash_del(hapd, sta); - ap_sta_list_del(hapd, sta); - - if (sta->aid > 0) - hapd->sta_aid[(sta->aid - 1) / 32] &= - ~BIT((sta->aid - 1) % 32); - - hapd->num_sta--; - if (sta->nonerp_set) { - sta->nonerp_set = 0; - hapd->iface->num_sta_non_erp--; - if (hapd->iface->num_sta_non_erp == 0) - set_beacon++; - } - - if (sta->no_short_slot_time_set) { - sta->no_short_slot_time_set = 0; - hapd->iface->num_sta_no_short_slot_time--; - if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G - && hapd->iface->num_sta_no_short_slot_time == 0) - set_beacon++; - } - - if (sta->no_short_preamble_set) { - sta->no_short_preamble_set = 0; - hapd->iface->num_sta_no_short_preamble--; - if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G - && hapd->iface->num_sta_no_short_preamble == 0) - set_beacon++; - } - - if (sta->no_ht_gf_set) { - sta->no_ht_gf_set = 0; - hapd->iface->num_sta_ht_no_gf--; - } - - if (sta->no_ht_set) { - sta->no_ht_set = 0; - hapd->iface->num_sta_no_ht--; - } - - if (sta->ht_20mhz_set) { - sta->ht_20mhz_set = 0; - hapd->iface->num_sta_ht_20mhz--; - } - -#ifdef CONFIG_P2P - if (sta->no_p2p_set) { - sta->no_p2p_set = 0; - hapd->num_sta_no_p2p--; - if (hapd->num_sta_no_p2p == 0) - hostapd_p2p_non_p2p_sta_disconnected(hapd); - } -#endif /* CONFIG_P2P */ - -#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N) - if (hostapd_ht_operation_update(hapd->iface) > 0) - set_beacon++; -#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */ - - if (set_beacon) - ieee802_11_set_beacons(hapd->iface); - - wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR, - __func__, MAC2STR(sta->addr)); - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); - eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); - eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); - - ieee802_1x_free_station(sta); - wpa_auth_sta_deinit(sta->wpa_sm); - rsn_preauth_free_station(hapd, sta); -#ifndef CONFIG_NO_RADIUS - if (hapd->radius) - radius_client_flush_auth(hapd->radius, sta->addr); -#endif /* CONFIG_NO_RADIUS */ - - os_free(sta->last_assoc_req); - os_free(sta->challenge); - -#ifdef CONFIG_IEEE80211W - os_free(sta->sa_query_trans_id); - eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); -#endif /* CONFIG_IEEE80211W */ - -#ifdef CONFIG_P2P - p2p_group_notif_disassoc(hapd->p2p_group, sta->addr); -#endif /* CONFIG_P2P */ - -#ifdef CONFIG_INTERWORKING - if (sta->gas_dialog) { - int i; - for (i = 0; i < GAS_DIALOG_MAX; i++) - gas_serv_dialog_clear(&sta->gas_dialog[i]); - os_free(sta->gas_dialog); - } -#endif /* CONFIG_INTERWORKING */ - - wpabuf_free(sta->wps_ie); - wpabuf_free(sta->p2p_ie); - wpabuf_free(sta->hs20_ie); - - os_free(sta->ht_capabilities); - os_free(sta->vht_capabilities); - hostapd_free_psk_list(sta->psk); - os_free(sta->identity); - os_free(sta->radius_cui); - -#ifdef CONFIG_SAE - sae_clear_data(sta->sae); - os_free(sta->sae); -#endif /* CONFIG_SAE */ - - os_free(sta); -} - - -void hostapd_free_stas(struct hostapd_data *hapd) -{ - struct sta_info *sta, *prev; - - sta = hapd->sta_list; - - while (sta) { - prev = sta; - if (sta->flags & WLAN_STA_AUTH) { - mlme_deauthenticate_indication( - hapd, sta, WLAN_REASON_UNSPECIFIED); - } - sta = sta->next; - wpa_printf(MSG_DEBUG, "Removing station " MACSTR, - MAC2STR(prev->addr)); - ap_free_sta(hapd, prev); - } -} - - -/** - * ap_handle_timer - Per STA timer handler - * @eloop_ctx: struct hostapd_data * - * @timeout_ctx: struct sta_info * - * - * This function is called to check station activity and to remove inactive - * stations. - */ -void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - struct sta_info *sta = timeout_ctx; - unsigned long next_time = 0; - int reason; - - wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d", - __func__, MAC2STR(sta->addr), sta->flags, - sta->timeout_next); - if (sta->timeout_next == STA_REMOVE) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "deauthenticated due to " - "local deauth request"); - ap_free_sta(hapd, sta); - return; - } - - if ((sta->flags & WLAN_STA_ASSOC) && - (sta->timeout_next == STA_NULLFUNC || - sta->timeout_next == STA_DISASSOC)) { - int inactive_sec; - /* - * Add random value to timeout so that we don't end up bouncing - * all stations at the same time if we have lots of associated - * stations that are idle (but keep re-associating). - */ - int fuzz = os_random() % 20; - inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr); - if (inactive_sec == -1) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, - "Check inactivity: Could not " - "get station info from kernel driver for " - MACSTR, MAC2STR(sta->addr)); - /* - * The driver may not support this functionality. - * Anyway, try again after the next inactivity timeout, - * but do not disconnect the station now. - */ - next_time = hapd->conf->ap_max_inactivity + fuzz; - } else if (inactive_sec < hapd->conf->ap_max_inactivity && - sta->flags & WLAN_STA_ASSOC) { - /* station activity detected; reset timeout state */ - 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 + fuzz - - inactive_sec; - } else { - 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) && - !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; - next_time = hapd->conf->ap_max_inactivity; - } - - if (next_time) { - wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " - "for " MACSTR " (%lu seconds)", - __func__, MAC2STR(sta->addr), next_time); - eloop_register_timeout(next_time, 0, ap_handle_timer, hapd, - sta); - return; - } - - if (sta->timeout_next == STA_NULLFUNC && - (sta->flags & WLAN_STA_ASSOC)) { - wpa_printf(MSG_DEBUG, " Polling STA"); - sta->flags |= WLAN_STA_PENDING_POLL; - 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_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( - hapd, sta->addr, - WLAN_REASON_PREV_AUTH_NOT_VALID); - } else { - reason = (sta->timeout_next == STA_DISASSOC) ? - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY : - WLAN_REASON_PREV_AUTH_NOT_VALID; - - hostapd_drv_sta_disassoc(hapd, sta->addr, reason); - } - } - - switch (sta->timeout_next) { - case STA_NULLFUNC: - sta->timeout_next = STA_DISASSOC; - wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " - "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)", - __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY); - eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer, - hapd, sta); - break; - case STA_DISASSOC: - case STA_DISASSOC_FROM_CLI: - 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) - sta->acct_terminate_cause = - RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; - accounting_sta_stop(hapd, sta); - ieee802_1x_free_station(sta); - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "disassociated due to " - "inactivity"); - reason = (sta->timeout_next == STA_DISASSOC) ? - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY : - WLAN_REASON_PREV_AUTH_NOT_VALID; - sta->timeout_next = STA_DEAUTH; - wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " - "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)", - __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY); - eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, - hapd, sta); - mlme_disassociate_indication(hapd, sta, reason); - break; - case STA_DEAUTH: - case STA_REMOVE: - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "deauthenticated due to " - "inactivity (timer DEAUTH/REMOVE)"); - if (!sta->acct_terminate_cause) - sta->acct_terminate_cause = - RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; - mlme_deauthenticate_indication( - hapd, sta, - WLAN_REASON_PREV_AUTH_NOT_VALID); - ap_free_sta(hapd, sta); - break; - } -} - - -static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - struct sta_info *sta = timeout_ctx; - u8 addr[ETH_ALEN]; - - if (!(sta->flags & WLAN_STA_AUTH)) { - if (sta->flags & WLAN_STA_GAS) { - wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA " - "entry " MACSTR, MAC2STR(sta->addr)); - ap_free_sta(hapd, sta); - } - return; - } - - mlme_deauthenticate_indication(hapd, sta, - WLAN_REASON_PREV_AUTH_NOT_VALID); - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "deauthenticated due to " - "session timeout"); - sta->acct_terminate_cause = - RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT; - os_memcpy(addr, sta->addr, ETH_ALEN); - ap_free_sta(hapd, sta); - hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); -} - - -void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta, - u32 session_timeout) -{ - if (eloop_replenish_timeout(session_timeout, 0, - ap_handle_session_timer, hapd, sta) == 1) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "setting session timeout " - "to %d seconds", session_timeout); - } -} - - -void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, - u32 session_timeout) -{ - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d " - "seconds", session_timeout); - eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); - eloop_register_timeout(session_timeout, 0, ap_handle_session_timer, - hapd, sta); -} - - -void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta) -{ - eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); -} - - -struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) -{ - struct sta_info *sta; - - sta = ap_get_sta(hapd, addr); - if (sta) - return sta; - - wpa_printf(MSG_DEBUG, " New STA"); - if (hapd->num_sta >= hapd->conf->max_num_sta) { - /* FIX: might try to remove some old STAs first? */ - wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)", - hapd->num_sta, hapd->conf->max_num_sta); - return NULL; - } - - sta = os_zalloc(sizeof(struct sta_info)); - if (sta == NULL) { - wpa_printf(MSG_ERROR, "malloc failed"); - return NULL; - } - sta->acct_interim_interval = hapd->conf->acct_interim_interval; - accounting_sta_get_id(hapd, sta); - - if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) { - wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " - "for " MACSTR " (%d seconds - ap_max_inactivity)", - __func__, MAC2STR(addr), - hapd->conf->ap_max_inactivity); - eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, - ap_handle_timer, hapd, sta); - } - - /* initialize STA info data */ - os_memcpy(sta->addr, addr, ETH_ALEN); - sta->next = hapd->sta_list; - hapd->sta_list = sta; - hapd->num_sta++; - ap_sta_hash_add(hapd, sta); - sta->ssid = &hapd->conf->ssid; - ap_sta_remove_in_other_bss(hapd, sta); - - return sta; -} - - -static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta) -{ - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - - wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver", - MAC2STR(sta->addr)); - if (hostapd_drv_sta_remove(hapd, sta->addr) && - sta->flags & WLAN_STA_ASSOC) { - wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR - " from kernel driver.", MAC2STR(sta->addr)); - return -1; - } - return 0; -} - - -static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, - struct sta_info *sta) -{ - struct hostapd_iface *iface = hapd->iface; - size_t i; - - for (i = 0; i < iface->num_bss; i++) { - struct hostapd_data *bss = iface->bss[i]; - struct sta_info *sta2; - /* bss should always be set during operation, but it may be - * NULL during reconfiguration. Assume the STA is not - * associated to another BSS in that case to avoid NULL pointer - * dereferences. */ - if (bss == hapd || bss == NULL) - continue; - sta2 = ap_get_sta(bss, sta->addr); - if (!sta2) - continue; - - ap_sta_disconnect(bss, sta2, sta2->addr, - WLAN_REASON_PREV_AUTH_NOT_VALID); - } -} - - -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 | WLAN_STA_ASSOC_REQ_OK); - ap_sta_set_authorized(hapd, sta, 0); - sta->timeout_next = STA_DEAUTH; - wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " - "for " MACSTR " (%d seconds - " - "AP_MAX_INACTIVITY_AFTER_DISASSOC)", - __func__, MAC2STR(sta->addr), - AP_MAX_INACTIVITY_AFTER_DISASSOC); - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0, - ap_handle_timer, hapd, sta); - accounting_sta_stop(hapd, sta); - ieee802_1x_free_station(sta); - - 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); -} - - -void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, - u16 reason) -{ - wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR, - hapd->conf->iface, MAC2STR(sta->addr)); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - ap_sta_set_authorized(hapd, sta, 0); - sta->timeout_next = STA_REMOVE; - wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " - "for " MACSTR " (%d seconds - " - "AP_MAX_INACTIVITY_AFTER_DEAUTH)", - __func__, MAC2STR(sta->addr), - AP_MAX_INACTIVITY_AFTER_DEAUTH); - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, - ap_handle_timer, hapd, sta); - accounting_sta_stop(hapd, sta); - ieee802_1x_free_station(sta); - - 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); -} - - -#ifdef CONFIG_WPS -int ap_sta_wps_cancel(struct hostapd_data *hapd, - struct sta_info *sta, void *ctx) -{ - if (sta && (sta->flags & WLAN_STA_WPS)) { - ap_sta_deauthenticate(hapd, sta, - WLAN_REASON_PREV_AUTH_NOT_VALID); - wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR, - __func__, MAC2STR(sta->addr)); - return 1; - } - - return 0; -} -#endif /* CONFIG_WPS */ - - -int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, - int old_vlanid) -{ -#ifndef CONFIG_NO_VLAN - const char *iface; - struct hostapd_vlan *vlan = NULL; - int ret; - - /* - * Do not proceed furthur if the vlan id remains same. We do not want - * duplicate dynamic vlan entries. - */ - if (sta->vlan_id == old_vlanid) - return 0; - - /* - * During 1x reauth, if the vlan id changes, then remove the old id and - * proceed furthur to add the new one. - */ - if (old_vlanid > 0) - vlan_remove_dynamic(hapd, old_vlanid); - - iface = hapd->conf->iface; - if (sta->ssid->vlan[0]) - iface = sta->ssid->vlan; - - if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) - sta->vlan_id = 0; - else if (sta->vlan_id > 0) { - struct hostapd_vlan *wildcard_vlan = NULL; - vlan = hapd->conf->vlan; - while (vlan) { - if (vlan->vlan_id == sta->vlan_id) - break; - if (vlan->vlan_id == VLAN_ID_WILDCARD) - wildcard_vlan = vlan; - vlan = vlan->next; - } - if (!vlan) - vlan = wildcard_vlan; - if (vlan) - iface = vlan->ifname; - } - - if (sta->vlan_id > 0 && vlan == NULL) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "could not find VLAN for " - "binding station to (vlan_id=%d)", - sta->vlan_id); - return -1; - } else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) { - vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id); - if (vlan == NULL) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "could not add " - "dynamic VLAN interface for vlan_id=%d", - sta->vlan_id); - return -1; - } - - iface = vlan->ifname; - if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "could not " - "configure encryption for dynamic VLAN " - "interface for vlan_id=%d", - sta->vlan_id); - } - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN " - "interface '%s'", iface); - } else if (vlan && vlan->vlan_id == sta->vlan_id) { - if (sta->vlan_id > 0) { - vlan->dynamic_vlan++; - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "updated existing " - "dynamic VLAN interface '%s'", iface); - } - - /* - * Update encryption configuration for statically generated - * VLAN interface. This is only used for static WEP - * configuration for the case where hostapd did not yet know - * which keys are to be used when the interface was added. - */ - if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "could not " - "configure encryption for VLAN " - "interface for vlan_id=%d", - sta->vlan_id); - } - } - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "binding station to interface " - "'%s'", iface); - - if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0) - wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA"); - - ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id); - if (ret < 0) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "could not bind the STA " - "entry to vlan_id=%d", sta->vlan_id); - } - return ret; -#else /* CONFIG_NO_VLAN */ - return 0; -#endif /* CONFIG_NO_VLAN */ -} - - -#ifdef CONFIG_IEEE80211W - -int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta) -{ - u32 tu; - struct os_reltime now, passed; - os_get_reltime(&now); - os_reltime_sub(&now, &sta->sa_query_start, &passed); - tu = (passed.sec * 1000000 + passed.usec) / 1024; - if (hapd->conf->assoc_sa_query_max_timeout < tu) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "association SA Query timed out"); - sta->sa_query_timed_out = 1; - os_free(sta->sa_query_trans_id); - sta->sa_query_trans_id = NULL; - sta->sa_query_count = 0; - eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); - return 1; - } - - return 0; -} - - -static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - struct sta_info *sta = timeout_ctx; - unsigned int timeout, sec, usec; - u8 *trans_id, *nbuf; - - if (sta->sa_query_count > 0 && - ap_check_sa_query_timeout(hapd, sta)) - return; - - nbuf = os_realloc_array(sta->sa_query_trans_id, - sta->sa_query_count + 1, - WLAN_SA_QUERY_TR_ID_LEN); - if (nbuf == NULL) - return; - if (sta->sa_query_count == 0) { - /* Starting a new SA Query procedure */ - os_get_reltime(&sta->sa_query_start); - } - trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN; - sta->sa_query_trans_id = nbuf; - sta->sa_query_count++; - - os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN); - - timeout = hapd->conf->assoc_sa_query_retry_timeout; - sec = ((timeout / 1000) * 1024) / 1000; - usec = (timeout % 1000) * 1024; - eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta); - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "association SA Query attempt %d", sta->sa_query_count); - - ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id); -} - - -void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta) -{ - ap_sa_query_timer(hapd, sta); -} - - -void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta) -{ - eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); - os_free(sta->sa_query_trans_id); - sta->sa_query_trans_id = NULL; - sta->sa_query_count = 0; -} - -#endif /* CONFIG_IEEE80211W */ - - -void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, - int authorized) -{ - const u8 *dev_addr = NULL; - char buf[100]; -#ifdef CONFIG_P2P - u8 addr[ETH_ALEN]; - u8 ip_addr_buf[4]; -#endif /* CONFIG_P2P */ - - if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED)) - return; - -#ifdef CONFIG_P2P - if (hapd->p2p_group == NULL) { - if (sta->p2p_ie != NULL && - p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0) - dev_addr = addr; - } else - dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr); -#endif /* CONFIG_P2P */ - - if (dev_addr) - os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR, - MAC2STR(sta->addr), MAC2STR(dev_addr)); - else - os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr)); - - if (authorized) { - char ip_addr[100]; - ip_addr[0] = '\0'; -#ifdef CONFIG_P2P - if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) { - os_snprintf(ip_addr, sizeof(ip_addr), - " ip_addr=%u.%u.%u.%u", - ip_addr_buf[0], ip_addr_buf[1], - ip_addr_buf[2], ip_addr_buf[3]); - } -#endif /* CONFIG_P2P */ - - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s", - buf, ip_addr); - - if (hapd->msg_ctx_parent && - hapd->msg_ctx_parent != hapd->msg_ctx) - wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_CONNECTED "%s%s", - buf, ip_addr); - - sta->flags |= WLAN_STA_AUTHORIZED; - } else { - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf); - - if (hapd->msg_ctx_parent && - hapd->msg_ctx_parent != hapd->msg_ctx) - wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_DISCONNECTED "%s", buf); - - sta->flags &= ~WLAN_STA_AUTHORIZED; - } - - if (hapd->sta_authorized_cb) - hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx, - sta->addr, authorized, dev_addr); -} - - -void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *addr, u16 reason) -{ - - if (sta == NULL && addr) - sta = ap_get_sta(hapd, addr); - - if (addr) - hostapd_drv_sta_deauth(hapd, addr, reason); - - if (sta == NULL) - return; - ap_sta_set_authorized(hapd, sta, 0); - wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " - "for " MACSTR " (%d seconds - " - "AP_MAX_INACTIVITY_AFTER_DEAUTH)", - __func__, MAC2STR(sta->addr), - AP_MAX_INACTIVITY_AFTER_DEAUTH); - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, - ap_handle_timer, hapd, sta); - 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); -} - - -int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen) -{ - int res; - - buf[0] = '\0'; - res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", - (flags & WLAN_STA_AUTH ? "[AUTH]" : ""), - (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""), - (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""), - (flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" : - ""), - (flags & WLAN_STA_SHORT_PREAMBLE ? - "[SHORT_PREAMBLE]" : ""), - (flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""), - (flags & WLAN_STA_WMM ? "[WMM]" : ""), - (flags & WLAN_STA_MFP ? "[MFP]" : ""), - (flags & WLAN_STA_WPS ? "[WPS]" : ""), - (flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""), - (flags & WLAN_STA_WDS ? "[WDS]" : ""), - (flags & WLAN_STA_NONERP ? "[NonERP]" : ""), - (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""), - (flags & WLAN_STA_GAS ? "[GAS]" : ""), - (flags & WLAN_STA_VHT ? "[VHT]" : ""), - (flags & WLAN_STA_WNM_SLEEP_MODE ? - "[WNM_SLEEP_MODE]" : "")); - - return res; -} diff --git a/contrib/hostapd/src/ap/sta_info.h b/contrib/hostapd/src/ap/sta_info.h deleted file mode 100644 index 9b77e06091..0000000000 --- a/contrib/hostapd/src/ap/sta_info.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * hostapd / Station table - * Copyright (c) 2002-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef STA_INFO_H -#define STA_INFO_H - -/* STA flags */ -#define WLAN_STA_AUTH BIT(0) -#define WLAN_STA_ASSOC BIT(1) -#define WLAN_STA_AUTHORIZED BIT(5) -#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ -#define WLAN_STA_SHORT_PREAMBLE BIT(7) -#define WLAN_STA_PREAUTH BIT(8) -#define WLAN_STA_WMM BIT(9) -#define WLAN_STA_MFP BIT(10) -#define WLAN_STA_HT BIT(11) -#define WLAN_STA_WPS BIT(12) -#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_GAS BIT(17) -#define WLAN_STA_VHT BIT(18) -#define WLAN_STA_WNM_SLEEP_MODE BIT(19) -#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 - * Supported Rates IEs). */ -#define WLAN_SUPP_RATES_MAX 32 - - -struct sta_info { - struct sta_info *next; /* next entry in sta list */ - struct sta_info *hnext; /* next entry in hash table list */ - u8 addr[6]; - u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ - u32 flags; /* Bitfield of WLAN_STA_* */ - u16 capability; - 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; - unsigned int no_short_preamble_set:1; - unsigned int no_ht_gf_set:1; - unsigned int no_ht_set:1; - unsigned int ht_20mhz_set:1; - unsigned int no_p2p_set:1; - unsigned int qos_map_enabled:1; - - u16 auth_alg; - u8 previous_ap[6]; - - enum { - STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE, - STA_DISASSOC_FROM_CLI - } timeout_next; - - u16 deauth_reason; - u16 disassoc_reason; - - /* IEEE 802.1X related data */ - struct eapol_state_machine *eapol_sm; - - /* IEEE 802.11f (IAPP) related data */ - struct ieee80211_mgmt *last_assoc_req; - - u32 acct_session_id_hi; - u32 acct_session_id_lo; - struct os_reltime acct_session_start; - int acct_session_started; - int acct_terminate_cause; /* Acct-Terminate-Cause */ - int acct_interim_interval; /* Acct-Interim-Interval */ - - unsigned long last_rx_bytes; - unsigned long last_tx_bytes; - u32 acct_input_gigawords; /* Acct-Input-Gigawords */ - u32 acct_output_gigawords; /* Acct-Output-Gigawords */ - - u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */ - - struct wpa_state_machine *wpa_sm; - struct rsn_preauth_interface *preauth_iface; - - struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */ - struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */ - - int vlan_id; - /* PSKs from RADIUS authentication server */ - struct hostapd_sta_wpa_psk_short *psk; - - char *identity; /* User-Name from RADIUS */ - char *radius_cui; /* Chargeable-User-Identity from RADIUS */ - - struct ieee80211_ht_capabilities *ht_capabilities; - struct ieee80211_vht_capabilities *vht_capabilities; - -#ifdef CONFIG_IEEE80211W - int sa_query_count; /* number of pending SA Query requests; - * 0 = no SA Query in progress */ - int sa_query_timed_out; - u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN * - * sa_query_count octets of pending SA Query - * transaction identifiers */ - struct os_reltime sa_query_start; -#endif /* CONFIG_IEEE80211W */ - -#ifdef CONFIG_INTERWORKING -#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */ - struct gas_dialog_info *gas_dialog; - u8 gas_dialog_next; -#endif /* CONFIG_INTERWORKING */ - - struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */ - struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */ - struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */ - - struct os_reltime connected_time; - -#ifdef CONFIG_SAE - struct sae_data *sae; -#endif /* CONFIG_SAE */ -}; - - -/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has - * 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. 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) -#define AP_DEAUTH_DELAY (1) -/* Number of seconds to keep STA entry with Authenticated flag after it has - * been disassociated. */ -#define AP_MAX_INACTIVITY_AFTER_DISASSOC (1 * 30) -/* Number of seconds to keep STA entry after it has been deauthenticated. */ -#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5) - - -struct hostapd_data; - -int ap_for_each_sta(struct hostapd_data *hapd, - int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, - void *ctx), - void *ctx); -struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta); -struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr); -void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta); -void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta); -void hostapd_free_stas(struct hostapd_data *hapd); -void ap_handle_timer(void *eloop_ctx, void *timeout_ctx); -void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta, - u32 session_timeout); -void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, - u32 session_timeout); -void ap_sta_no_session_timeout(struct hostapd_data *hapd, - struct sta_info *sta); -struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr); -void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, - u16 reason); -void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, - u16 reason); -#ifdef CONFIG_WPS -int ap_sta_wps_cancel(struct hostapd_data *hapd, - struct sta_info *sta, void *ctx); -#endif /* CONFIG_WPS */ -int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, - int old_vlanid); -void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta); -void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta); -int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta); -void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *addr, u16 reason); - -void ap_sta_set_authorized(struct hostapd_data *hapd, - struct sta_info *sta, int authorized); -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); - -int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen); - -#endif /* STA_INFO_H */ diff --git a/contrib/hostapd/src/ap/tkip_countermeasures.c b/contrib/hostapd/src/ap/tkip_countermeasures.c deleted file mode 100644 index 4725e2b3e8..0000000000 --- a/contrib/hostapd/src/ap/tkip_countermeasures.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * hostapd / TKIP countermeasures - * Copyright (c) 2002-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "common/ieee802_11_defs.h" -#include "radius/radius.h" -#include "hostapd.h" -#include "sta_info.h" -#include "ap_mlme.h" -#include "wpa_auth.h" -#include "ap_drv_ops.h" -#include "tkip_countermeasures.h" - - -static void ieee80211_tkip_countermeasures_stop(void *eloop_ctx, - void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - hapd->tkip_countermeasures = 0; - hostapd_drv_set_countermeasures(hapd, 0); - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "TKIP countermeasures ended"); -} - - -static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd) -{ - struct sta_info *sta; - - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "TKIP countermeasures initiated"); - - wpa_auth_countermeasures_start(hapd->wpa_auth); - hapd->tkip_countermeasures = 1; - hostapd_drv_set_countermeasures(hapd, 1); - wpa_gtk_rekey(hapd->wpa_auth); - eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL); - eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop, - hapd, NULL); - while ((sta = hapd->sta_list)) { - sta->acct_terminate_cause = - RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET; - if (sta->flags & WLAN_STA_AUTH) { - mlme_deauthenticate_indication( - hapd, sta, - WLAN_REASON_MICHAEL_MIC_FAILURE); - } - hostapd_drv_sta_deauth(hapd, sta->addr, - WLAN_REASON_MICHAEL_MIC_FAILURE); - ap_free_sta(hapd, sta); - } -} - - -void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd) -{ - eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL); -} - - -int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local) -{ - struct os_reltime now; - int ret = 0; - - if (addr && local) { - struct sta_info *sta = ap_get_sta(hapd, addr); - if (sta != NULL) { - wpa_auth_sta_local_mic_failure_report(sta->wpa_sm); - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, - "Michael MIC failure detected in " - "received frame"); - mlme_michaelmicfailure_indication(hapd, addr); - } else { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "for not associated STA (" MACSTR - ") ignored", MAC2STR(addr)); - return ret; - } - } - - os_get_reltime(&now); - if (os_reltime_expired(&now, &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); - ret = 1; - } - } - hapd->michael_mic_failure = now; - - return ret; -} diff --git a/contrib/hostapd/src/ap/tkip_countermeasures.h b/contrib/hostapd/src/ap/tkip_countermeasures.h deleted file mode 100644 index d3eaed3cf9..0000000000 --- a/contrib/hostapd/src/ap/tkip_countermeasures.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * hostapd / TKIP countermeasures - * Copyright (c) 2002-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef TKIP_COUNTERMEASURES_H -#define TKIP_COUNTERMEASURES_H - -int 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/contrib/hostapd/src/ap/utils.c b/contrib/hostapd/src/ap/utils.c deleted file mode 100644 index 931968c84b..0000000000 --- a/contrib/hostapd/src/ap/utils.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * AP mode helper functions - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "common/ieee802_11_defs.h" -#include "sta_info.h" -#include "hostapd.h" - - -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, - int ssi_signal), - void *ctx) -{ - struct hostapd_probereq_cb *n; - - n = os_realloc_array(hapd->probereq_cb, hapd->num_probereq_cb + 1, - sizeof(struct hostapd_probereq_cb)); - if (n == NULL) - return -1; - - hapd->probereq_cb = n; - n = &hapd->probereq_cb[hapd->num_probereq_cb]; - hapd->num_probereq_cb++; - - n->cb = cb; - n->ctx = ctx; - - return 0; -} - - -struct prune_data { - struct hostapd_data *hapd; - const u8 *addr; -}; - -static int prune_associations(struct hostapd_iface *iface, void *ctx) -{ - struct prune_data *data = ctx; - struct sta_info *osta; - struct hostapd_data *ohapd; - size_t j; - - for (j = 0; j < iface->num_bss; j++) { - ohapd = iface->bss[j]; - if (ohapd == data->hapd) - continue; - osta = ap_get_sta(ohapd, data->addr); - if (!osta) - continue; - - ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED); - } - - return 0; -} - -/** - * hostapd_prune_associations - Remove extraneous associations - * @hapd: Pointer to BSS data for the most recent association - * @addr: Associated STA address - * - * This function looks through all radios and BSS's for previous - * (stale) associations of STA. If any are found they are removed. - */ -void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr) -{ - struct prune_data data; - data.hapd = hapd; - data.addr = addr; - if (hapd->iface->interfaces && - hapd->iface->interfaces->for_each_interface) - hapd->iface->interfaces->for_each_interface( - hapd->iface->interfaces, prune_associations, &data); -} diff --git a/contrib/hostapd/src/ap/vlan_init.c b/contrib/hostapd/src/ap/vlan_init.c deleted file mode 100644 index 509e557cee..0000000000 --- a/contrib/hostapd/src/ap/vlan_init.c +++ /dev/null @@ -1,1100 +0,0 @@ -/* - * hostapd / VLAN initialization - * Copyright 2003, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "hostapd.h" -#include "ap_config.h" -#include "ap_drv_ops.h" -#include "vlan_init.h" -#include "vlan_util.h" - - -#ifdef CONFIG_FULL_DYNAMIC_VLAN - -#include -#include -#include -#include -#include - -#include "drivers/priv_netlink.h" -#include "utils/eloop.h" - - -struct full_dynamic_vlan { - int s; /* socket on which to listen for new/removed interfaces. */ -}; - - -static int ifconfig_helper(const char *if_name, int up) -{ - int fd; - struct ifreq ifr; - - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " - "failed: %s", __func__, strerror(errno)); - return -1; - } - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ); - - if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed " - "for interface %s: %s", - __func__, if_name, strerror(errno)); - close(fd); - return -1; - } - - if (up) - ifr.ifr_flags |= IFF_UP; - else - ifr.ifr_flags &= ~IFF_UP; - - if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed " - "for interface %s (up=%d): %s", - __func__, if_name, up, strerror(errno)); - close(fd); - return -1; - } - - close(fd); - return 0; -} - - -static int ifconfig_up(const char *if_name) -{ - wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name); - return ifconfig_helper(if_name, 1); -} - - -static int ifconfig_down(const char *if_name) -{ - wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name); - return ifconfig_helper(if_name, 0); -} - - -/* - * These are only available in recent linux headers (without the leading - * underscore). - */ -#define _GET_VLAN_REALDEV_NAME_CMD 8 -#define _GET_VLAN_VID_CMD 9 - -/* This value should be 256 ONLY. If it is something else, then hostapd - * might crash!, as this value has been hard-coded in 2.4.x kernel - * bridging code. - */ -#define MAX_BR_PORTS 256 - -static int br_delif(const char *br_name, const char *if_name) -{ - int fd; - struct ifreq ifr; - unsigned long args[2]; - int if_index; - - wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name); - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " - "failed: %s", __func__, strerror(errno)); - return -1; - } - - if_index = if_nametoindex(if_name); - - if (if_index == 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining " - "interface index for '%s'", - __func__, if_name); - close(fd); - return -1; - } - - args[0] = BRCTL_DEL_IF; - args[1] = if_index; - - os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name)); - ifr.ifr_data = (__caddr_t) args; - - if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) { - /* No error if interface already removed. */ - wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE," - "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: " - "%s", __func__, br_name, if_name, strerror(errno)); - close(fd); - return -1; - } - - close(fd); - return 0; -} - - -/* - Add interface 'if_name' to the bridge 'br_name' - - returns -1 on error - returns 1 if the interface is already part of the bridge - returns 0 otherwise -*/ -static int br_addif(const char *br_name, const char *if_name) -{ - int fd; - struct ifreq ifr; - unsigned long args[2]; - int if_index; - - wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name); - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " - "failed: %s", __func__, strerror(errno)); - return -1; - } - - if_index = if_nametoindex(if_name); - - if (if_index == 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining " - "interface index for '%s'", - __func__, if_name); - close(fd); - return -1; - } - - args[0] = BRCTL_ADD_IF; - args[1] = if_index; - - os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name)); - ifr.ifr_data = (__caddr_t) args; - - if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { - if (errno == EBUSY) { - /* The interface is already added. */ - close(fd); - return 1; - } - - wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE," - "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: " - "%s", __func__, br_name, if_name, strerror(errno)); - close(fd); - return -1; - } - - close(fd); - return 0; -} - - -static int br_delbr(const char *br_name) -{ - int fd; - unsigned long arg[2]; - - wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name); - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " - "failed: %s", __func__, strerror(errno)); - return -1; - } - - arg[0] = BRCTL_DEL_BRIDGE; - arg[1] = (unsigned long) br_name; - - if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) { - /* No error if bridge already removed. */ - wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for " - "%s: %s", __func__, br_name, strerror(errno)); - close(fd); - return -1; - } - - close(fd); - return 0; -} - - -/* - Add a bridge with the name 'br_name'. - - returns -1 on error - returns 1 if the bridge already exists - returns 0 otherwise -*/ -static int br_addbr(const char *br_name) -{ - int fd; - unsigned long arg[4]; - struct ifreq ifr; - - wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name); - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " - "failed: %s", __func__, strerror(errno)); - return -1; - } - - arg[0] = BRCTL_ADD_BRIDGE; - arg[1] = (unsigned long) br_name; - - if (ioctl(fd, SIOCGIFBR, arg) < 0) { - if (errno == EEXIST) { - /* The bridge is already added. */ - close(fd); - return 1; - } else { - wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE " - "failed for %s: %s", - __func__, br_name, strerror(errno)); - close(fd); - return -1; - } - } - - /* Decrease forwarding delay to avoid EAPOL timeouts. */ - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ); - arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY; - arg[1] = 1; - arg[2] = 0; - arg[3] = 0; - ifr.ifr_data = (char *) &arg; - if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: " - "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for " - "%s: %s", __func__, br_name, strerror(errno)); - /* Continue anyway */ - } - - close(fd); - return 0; -} - - -static int br_getnumports(const char *br_name) -{ - int fd; - int i; - int port_cnt = 0; - unsigned long arg[4]; - int ifindices[MAX_BR_PORTS]; - struct ifreq ifr; - - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " - "failed: %s", __func__, strerror(errno)); - return -1; - } - - arg[0] = BRCTL_GET_PORT_LIST; - arg[1] = (unsigned long) ifindices; - arg[2] = MAX_BR_PORTS; - arg[3] = 0; - - os_memset(ifindices, 0, sizeof(ifindices)); - os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name)); - ifr.ifr_data = (__caddr_t) arg; - - if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST " - "failed for %s: %s", - __func__, br_name, strerror(errno)); - close(fd); - return -1; - } - - for (i = 1; i < MAX_BR_PORTS; i++) { - if (ifindices[i] > 0) { - port_cnt++; - } - } - - close(fd); - return port_cnt; -} - - -#ifndef CONFIG_VLAN_NETLINK - -int vlan_rem(const char *if_name) -{ - int fd; - struct vlan_ioctl_args if_request; - - wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name); - if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) { - wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", - if_name); - return -1; - } - - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " - "failed: %s", __func__, strerror(errno)); - return -1; - } - - os_memset(&if_request, 0, sizeof(if_request)); - - os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1)); - if_request.cmd = DEL_VLAN_CMD; - - if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: " - "%s", __func__, if_name, strerror(errno)); - close(fd); - return -1; - } - - close(fd); - return 0; -} - - -/* - Add a vlan interface with VLAN ID 'vid' and tagged interface - 'if_name'. - - returns -1 on error - returns 1 if the interface already exists - returns 0 otherwise -*/ -int vlan_add(const char *if_name, int vid, const char *vlan_if_name) -{ - int fd; - struct vlan_ioctl_args if_request; - - wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)", - if_name, vid); - ifconfig_up(if_name); - - if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) { - wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", - if_name); - return -1; - } - - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " - "failed: %s", __func__, strerror(errno)); - return -1; - } - - os_memset(&if_request, 0, sizeof(if_request)); - - /* Determine if a suitable vlan device already exists. */ - - os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d", - vid); - - if_request.cmd = _GET_VLAN_VID_CMD; - - if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) { - - if (if_request.u.VID == vid) { - if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD; - - if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 && - os_strncmp(if_request.u.device2, if_name, - sizeof(if_request.u.device2)) == 0) { - close(fd); - wpa_printf(MSG_DEBUG, "VLAN: vlan_add: " - "if_name %s exists already", - if_request.device1); - return 1; - } - } - } - - /* A suitable vlan device does not already exist, add one. */ - - os_memset(&if_request, 0, sizeof(if_request)); - os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1)); - if_request.u.VID = vid; - if_request.cmd = ADD_VLAN_CMD; - - if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: " - "%s", - __func__, if_request.device1, strerror(errno)); - close(fd); - return -1; - } - - close(fd); - return 0; -} - - -static int vlan_set_name_type(unsigned int name_type) -{ - int fd; - struct vlan_ioctl_args if_request; - - wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)", - name_type); - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " - "failed: %s", __func__, strerror(errno)); - return -1; - } - - os_memset(&if_request, 0, sizeof(if_request)); - - if_request.u.name_type = name_type; - if_request.cmd = SET_VLAN_NAME_TYPE_CMD; - if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD " - "name_type=%u failed: %s", - __func__, name_type, strerror(errno)); - close(fd); - return -1; - } - - close(fd); - return 0; -} - -#endif /* CONFIG_VLAN_NETLINK */ - - -/** - * Increase the usage counter for given parent/ifname combination. - * If create is set, then this iface is added to the global list. - * Returns - * -1 on error - * 0 if iface is not in list - * 1 if iface is in list (was there or has been added) - */ -static int hapd_get_dynamic_iface(const char *parent, const char *ifname, - int create, struct hostapd_data *hapd) -{ - size_t i; - struct hostapd_dynamic_iface *j = NULL, **tmp; - struct hapd_interfaces *hapd_global = hapd->iface->interfaces; - - if (!parent) - parent = ""; - - for (i = 0; i < hapd_global->count_dynamic; i++) { - j = hapd_global->dynamic_iface[i]; - if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 && - os_strncmp(j->parent, parent, sizeof(j->parent)) == 0) - break; - } - if (i < hapd_global->count_dynamic) { - j->usage++; - return 1; - } - - /* new entry required */ - if (!create) - return 0; - - j = os_zalloc(sizeof(*j)); - if (!j) - return -1; - os_strlcpy(j->iface, ifname, sizeof(j->iface)); - os_strlcpy(j->parent, parent, sizeof(j->parent)); - - tmp = os_realloc_array(hapd_global->dynamic_iface, i + 1, - sizeof(*hapd_global->dynamic_iface)); - if (!tmp) { - wpa_printf(MSG_ERROR, "VLAN: Failed to allocate memory in %s", - __func__); - return -1; - } - hapd_global->count_dynamic++; - hapd_global->dynamic_iface = tmp; - hapd_global->dynamic_iface[i] = j; - - return 1; -} - - -/** - * Decrease the usage counter for given ifname. - * Returns - * -1 on error or if iface was not found - * 0 if iface was found and is still present - * 1 if iface was removed from global list - */ -static int hapd_put_dynamic_iface(const char *parent, const char *ifname, - struct hostapd_data *hapd) -{ - size_t i; - struct hostapd_dynamic_iface *j = NULL, **tmp; - struct hapd_interfaces *hapd_glob = hapd->iface->interfaces; - - if (!parent) - parent = ""; - - for (i = 0; i < hapd_glob->count_dynamic; i++) { - j = hapd_glob->dynamic_iface[i]; - if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 && - os_strncmp(j->parent, parent, sizeof(j->parent)) == 0) - break; - } - - if (i == hapd_glob->count_dynamic) { - /* - * Interface not in global list. This can happen if alloc in - * _get_ failed. - */ - return -1; - } - - if (j->usage > 0) { - j->usage--; - return 0; - } - - os_free(j); - for (; i < hapd_glob->count_dynamic - 1; i++) - hapd_glob->dynamic_iface[i] = hapd_glob->dynamic_iface[i + 1]; - hapd_glob->dynamic_iface[hapd_glob->count_dynamic - 1] = NULL; - hapd_glob->count_dynamic--; - - if (hapd_glob->count_dynamic == 0) { - os_free(hapd_glob->dynamic_iface); - hapd_glob->dynamic_iface = NULL; - return 1; - } - - tmp = os_realloc_array(hapd_glob->dynamic_iface, - hapd_glob->count_dynamic, - sizeof(*hapd_glob->dynamic_iface)); - if (!tmp) { - wpa_printf(MSG_ERROR, "VLAN: Failed to release memory in %s", - __func__); - return -1; - } - hapd_glob->dynamic_iface = tmp; - - return 1; -} - - -static void vlan_newlink(char *ifname, struct hostapd_data *hapd) -{ - char vlan_ifname[IFNAMSIZ]; - char br_name[IFNAMSIZ]; - struct hostapd_vlan *vlan = hapd->conf->vlan; - char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface; - int vlan_naming = hapd->conf->ssid.vlan_naming; - int ret; - - wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname); - - while (vlan) { - if (os_strcmp(ifname, vlan->ifname) == 0) { - - if (hapd->conf->vlan_bridge[0]) { - os_snprintf(br_name, sizeof(br_name), "%s%d", - hapd->conf->vlan_bridge, - vlan->vlan_id); - } else if (tagged_interface) { - os_snprintf(br_name, sizeof(br_name), - "br%s.%d", tagged_interface, - vlan->vlan_id); - } else { - os_snprintf(br_name, sizeof(br_name), - "brvlan%d", vlan->vlan_id); - } - - ret = br_addbr(br_name); - if (hapd_get_dynamic_iface(NULL, br_name, ret == 0, - hapd)) - vlan->clean |= DVLAN_CLEAN_BR; - - ifconfig_up(br_name); - - if (tagged_interface) { - if (vlan_naming == - DYNAMIC_VLAN_NAMING_WITH_DEVICE) - os_snprintf(vlan_ifname, - sizeof(vlan_ifname), - "%s.%d", tagged_interface, - vlan->vlan_id); - else - os_snprintf(vlan_ifname, - sizeof(vlan_ifname), - "vlan%d", vlan->vlan_id); - - ifconfig_up(tagged_interface); - ret = vlan_add(tagged_interface, vlan->vlan_id, - vlan_ifname); - if (hapd_get_dynamic_iface(NULL, vlan_ifname, - ret == 0, hapd)) - vlan->clean |= DVLAN_CLEAN_VLAN; - - ret = br_addif(br_name, vlan_ifname); - if (hapd_get_dynamic_iface(br_name, - vlan_ifname, - ret == 0, hapd)) - vlan->clean |= DVLAN_CLEAN_VLAN_PORT; - - ifconfig_up(vlan_ifname); - } - - ret = br_addif(br_name, ifname); - if (hapd_get_dynamic_iface(br_name, ifname, ret == 0, - hapd)) - vlan->clean |= DVLAN_CLEAN_WLAN_PORT; - - ifconfig_up(ifname); - - break; - } - vlan = vlan->next; - } -} - - -static void vlan_dellink(char *ifname, struct hostapd_data *hapd) -{ - char vlan_ifname[IFNAMSIZ]; - char br_name[IFNAMSIZ]; - struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan; - char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface; - int vlan_naming = hapd->conf->ssid.vlan_naming; - - wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname); - - first = prev = vlan; - - while (vlan) { - if (os_strcmp(ifname, vlan->ifname) == 0) { - if (hapd->conf->vlan_bridge[0]) { - os_snprintf(br_name, sizeof(br_name), "%s%d", - hapd->conf->vlan_bridge, - vlan->vlan_id); - } else if (tagged_interface) { - os_snprintf(br_name, sizeof(br_name), - "br%s.%d", tagged_interface, - vlan->vlan_id); - } else { - os_snprintf(br_name, sizeof(br_name), - "brvlan%d", vlan->vlan_id); - } - - if ((vlan->clean & DVLAN_CLEAN_WLAN_PORT) && - hapd_put_dynamic_iface(br_name, vlan->ifname, hapd)) - br_delif(br_name, vlan->ifname); - - if (tagged_interface) { - if (vlan_naming == - DYNAMIC_VLAN_NAMING_WITH_DEVICE) - os_snprintf(vlan_ifname, - sizeof(vlan_ifname), - "%s.%d", tagged_interface, - vlan->vlan_id); - else - os_snprintf(vlan_ifname, - sizeof(vlan_ifname), - "vlan%d", vlan->vlan_id); - if ((vlan->clean & DVLAN_CLEAN_VLAN_PORT) && - hapd_put_dynamic_iface(br_name, vlan_ifname, - hapd)) - br_delif(br_name, vlan_ifname); - ifconfig_down(vlan_ifname); - - if ((vlan->clean & DVLAN_CLEAN_VLAN) && - hapd_put_dynamic_iface(NULL, vlan_ifname, - hapd)) - vlan_rem(vlan_ifname); - } - - if ((vlan->clean & DVLAN_CLEAN_BR) && - hapd_put_dynamic_iface(NULL, br_name, hapd) && - br_getnumports(br_name) == 0) { - ifconfig_down(br_name); - br_delbr(br_name); - } - - if (vlan == first) { - hapd->conf->vlan = vlan->next; - } else { - prev->next = vlan->next; - } - os_free(vlan); - - break; - } - prev = vlan; - vlan = vlan->next; - } -} - - -static void -vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del, - struct hostapd_data *hapd) -{ - struct ifinfomsg *ifi; - int attrlen, nlmsg_len, rta_len; - struct rtattr *attr; - - if (len < sizeof(*ifi)) - return; - - ifi = NLMSG_DATA(h); - - nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); - - attrlen = h->nlmsg_len - nlmsg_len; - if (attrlen < 0) - return; - - attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - char ifname[IFNAMSIZ + 1]; - - if (attr->rta_type == IFLA_IFNAME) { - int n = attr->rta_len - rta_len; - if (n < 0) - break; - - os_memset(ifname, 0, sizeof(ifname)); - - if ((size_t) n > sizeof(ifname)) - n = sizeof(ifname); - os_memcpy(ifname, ((char *) attr) + rta_len, n); - - if (del) - vlan_dellink(ifname, hapd); - else - vlan_newlink(ifname, hapd); - } - - attr = RTA_NEXT(attr, attrlen); - } -} - - -static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx) -{ - char buf[8192]; - int left; - struct sockaddr_nl from; - socklen_t fromlen; - struct nlmsghdr *h; - struct hostapd_data *hapd = eloop_ctx; - - fromlen = sizeof(from); - left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, - (struct sockaddr *) &from, &fromlen); - if (left < 0) { - if (errno != EINTR && errno != EAGAIN) - wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s", - __func__, strerror(errno)); - return; - } - - h = (struct nlmsghdr *) buf; - while (left >= (int) sizeof(*h)) { - int len, plen; - - len = h->nlmsg_len; - plen = len - sizeof(*h); - if (len > left || plen < 0) { - wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink " - "message: len=%d left=%d plen=%d", - len, left, plen); - break; - } - - switch (h->nlmsg_type) { - case RTM_NEWLINK: - vlan_read_ifnames(h, plen, 0, hapd); - break; - case RTM_DELLINK: - vlan_read_ifnames(h, plen, 1, hapd); - break; - } - - len = NLMSG_ALIGN(len); - left -= len; - h = (struct nlmsghdr *) ((char *) h + len); - } - - if (left > 0) { - wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of " - "netlink message", __func__, left); - } -} - - -static struct full_dynamic_vlan * -full_dynamic_vlan_init(struct hostapd_data *hapd) -{ - struct sockaddr_nl local; - struct full_dynamic_vlan *priv; - - priv = os_zalloc(sizeof(*priv)); - if (priv == NULL) - return NULL; - -#ifndef CONFIG_VLAN_NETLINK - vlan_set_name_type(hapd->conf->ssid.vlan_naming == - DYNAMIC_VLAN_NAMING_WITH_DEVICE ? - VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD : - VLAN_NAME_TYPE_PLUS_VID_NO_PAD); -#endif /* CONFIG_VLAN_NETLINK */ - - priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (priv->s < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW," - "NETLINK_ROUTE) failed: %s", - __func__, strerror(errno)); - os_free(priv); - return NULL; - } - - os_memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) { - wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s", - __func__, strerror(errno)); - close(priv->s); - os_free(priv); - return NULL; - } - - if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL)) - { - close(priv->s); - os_free(priv); - return NULL; - } - - return priv; -} - - -static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv) -{ - if (priv == NULL) - return; - eloop_unregister_read_sock(priv->s); - close(priv->s); - os_free(priv); -} -#endif /* CONFIG_FULL_DYNAMIC_VLAN */ - - -int vlan_setup_encryption_dyn(struct hostapd_data *hapd, - struct hostapd_ssid *mssid, const char *dyn_vlan) -{ - int i; - - if (dyn_vlan == NULL) - return 0; - - /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own - * functions for setting up dynamic broadcast keys. */ - for (i = 0; i < 4; i++) { - if (mssid->wep.key[i] && - hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i, - i == mssid->wep.idx, NULL, 0, - mssid->wep.key[i], mssid->wep.len[i])) - { - wpa_printf(MSG_ERROR, "VLAN: Could not set WEP " - "encryption for dynamic VLAN"); - return -1; - } - } - - return 0; -} - - -static int vlan_dynamic_add(struct hostapd_data *hapd, - struct hostapd_vlan *vlan) -{ - while (vlan) { - if (vlan->vlan_id != VLAN_ID_WILDCARD) { - if (hostapd_vlan_if_add(hapd, vlan->ifname)) { - if (errno != EEXIST) { - wpa_printf(MSG_ERROR, "VLAN: Could " - "not add VLAN %s: %s", - vlan->ifname, - strerror(errno)); - return -1; - } - } -#ifdef CONFIG_FULL_DYNAMIC_VLAN - ifconfig_up(vlan->ifname); -#endif /* CONFIG_FULL_DYNAMIC_VLAN */ - } - - vlan = vlan->next; - } - - return 0; -} - - -static void vlan_dynamic_remove(struct hostapd_data *hapd, - struct hostapd_vlan *vlan) -{ - struct hostapd_vlan *next; - - while (vlan) { - next = vlan->next; - - if (vlan->vlan_id != VLAN_ID_WILDCARD && - hostapd_vlan_if_remove(hapd, vlan->ifname)) { - wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN " - "iface: %s: %s", - vlan->ifname, strerror(errno)); - } -#ifdef CONFIG_FULL_DYNAMIC_VLAN - if (vlan->clean) - vlan_dellink(vlan->ifname, hapd); -#endif /* CONFIG_FULL_DYNAMIC_VLAN */ - - vlan = next; - } -} - - -int vlan_init(struct hostapd_data *hapd) -{ -#ifdef CONFIG_FULL_DYNAMIC_VLAN - hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd); -#endif /* CONFIG_FULL_DYNAMIC_VLAN */ - - if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED && - !hapd->conf->vlan) { - /* dynamic vlans enabled but no (or empty) vlan_file given */ - struct hostapd_vlan *vlan; - vlan = os_zalloc(sizeof(*vlan)); - if (vlan == NULL) { - wpa_printf(MSG_ERROR, "Out of memory while assigning " - "VLAN interfaces"); - return -1; - } - - vlan->vlan_id = VLAN_ID_WILDCARD; - os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#", - hapd->conf->iface); - vlan->next = hapd->conf->vlan; - hapd->conf->vlan = vlan; - } - - if (vlan_dynamic_add(hapd, hapd->conf->vlan)) - return -1; - - return 0; -} - - -void vlan_deinit(struct hostapd_data *hapd) -{ - vlan_dynamic_remove(hapd, hapd->conf->vlan); - -#ifdef CONFIG_FULL_DYNAMIC_VLAN - full_dynamic_vlan_deinit(hapd->full_dynamic_vlan); - hapd->full_dynamic_vlan = NULL; -#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -} - - -struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, - struct hostapd_vlan *vlan, - int vlan_id) -{ - struct hostapd_vlan *n; - char *ifname, *pos; - - if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID || - vlan->vlan_id != VLAN_ID_WILDCARD) - return NULL; - - wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)", - __func__, vlan_id, vlan->ifname); - ifname = os_strdup(vlan->ifname); - if (ifname == NULL) - return NULL; - pos = os_strchr(ifname, '#'); - if (pos == NULL) { - os_free(ifname); - return NULL; - } - *pos++ = '\0'; - - n = os_zalloc(sizeof(*n)); - if (n == NULL) { - os_free(ifname); - return NULL; - } - - n->vlan_id = vlan_id; - n->dynamic_vlan = 1; - - os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id, - pos); - os_free(ifname); - - if (hostapd_vlan_if_add(hapd, n->ifname)) { - os_free(n); - return NULL; - } - - n->next = hapd->conf->vlan; - hapd->conf->vlan = n; - -#ifdef CONFIG_FULL_DYNAMIC_VLAN - ifconfig_up(n->ifname); -#endif /* CONFIG_FULL_DYNAMIC_VLAN */ - - return n; -} - - -int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) -{ - struct hostapd_vlan *vlan; - - if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID) - return 1; - - wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id); - - vlan = hapd->conf->vlan; - while (vlan) { - if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) { - vlan->dynamic_vlan--; - break; - } - vlan = vlan->next; - } - - if (vlan == NULL) - return 1; - - if (vlan->dynamic_vlan == 0) - hostapd_vlan_if_remove(hapd, vlan->ifname); - - return 0; -} diff --git a/contrib/hostapd/src/ap/vlan_init.h b/contrib/hostapd/src/ap/vlan_init.h deleted file mode 100644 index 781eaac441..0000000000 --- a/contrib/hostapd/src/ap/vlan_init.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * hostapd / VLAN initialization - * Copyright 2003, Instant802 Networks, Inc. - * Copyright 2005, Devicescape Software, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef VLAN_INIT_H -#define VLAN_INIT_H - -#ifndef CONFIG_NO_VLAN -int vlan_init(struct hostapd_data *hapd); -void vlan_deinit(struct hostapd_data *hapd); -struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, - struct hostapd_vlan *vlan, - int vlan_id); -int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id); -int vlan_setup_encryption_dyn(struct hostapd_data *hapd, - struct hostapd_ssid *mssid, - const char *dyn_vlan); -#else /* CONFIG_NO_VLAN */ -static inline int vlan_init(struct hostapd_data *hapd) -{ - return 0; -} - -static inline void vlan_deinit(struct hostapd_data *hapd) -{ -} - -static inline struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, - struct hostapd_vlan *vlan, - int vlan_id) -{ - return NULL; -} - -static inline int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) -{ - return -1; -} - -static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd, - struct hostapd_ssid *mssid, - const char *dyn_vlan) -{ - return -1; -} -#endif /* CONFIG_NO_VLAN */ - -#endif /* VLAN_INIT_H */ diff --git a/contrib/hostapd/src/ap/vlan_util.c b/contrib/hostapd/src/ap/vlan_util.c deleted file mode 100644 index cc54051b1e..0000000000 --- a/contrib/hostapd/src/ap/vlan_util.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * hostapd / VLAN netlink api - * Copyright (c) 2012, Michael Braun - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utils/common.h" -#include "utils/eloop.h" -#include "hostapd.h" -#include "vlan_util.h" - -/* - * Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and - * tagged interface 'if_name'. - * - * returns -1 on error - * returns 1 if the interface already exists - * returns 0 otherwise -*/ -int vlan_add(const char *if_name, int vid, const char *vlan_if_name) -{ - int ret = -1; - struct nl_sock *handle = NULL; - struct nl_cache *cache = NULL; - struct rtnl_link *rlink = NULL; - int if_idx = 0; - - wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, " - "vlan_if_name=%s)", if_name, vid, vlan_if_name); - - if ((os_strlen(if_name) + 1) > IFNAMSIZ) { - wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", - if_name); - return -1; - } - - if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) { - wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", - vlan_if_name); - return -1; - } - - handle = nl_socket_alloc(); - if (!handle) { - wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket"); - goto vlan_add_error; - } - - if (nl_connect(handle, NETLINK_ROUTE) < 0) { - wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink"); - goto vlan_add_error; - } - - if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) { - cache = NULL; - wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache"); - goto vlan_add_error; - } - - if (!(if_idx = rtnl_link_name2i(cache, if_name))) { - /* link does not exist */ - wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist", - if_name); - goto vlan_add_error; - } - - if ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) { - /* link does exist */ - rtnl_link_put(rlink); - rlink = NULL; - wpa_printf(MSG_ERROR, "VLAN: interface %s already exists", - vlan_if_name); - ret = 1; - goto vlan_add_error; - } - - rlink = rtnl_link_alloc(); - if (!rlink) { - wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link"); - goto vlan_add_error; - } - - if (rtnl_link_set_type(rlink, "vlan") < 0) { - wpa_printf(MSG_ERROR, "VLAN: failed to set link type"); - goto vlan_add_error; - } - - rtnl_link_set_link(rlink, if_idx); - rtnl_link_set_name(rlink, vlan_if_name); - - if (rtnl_link_vlan_set_id(rlink, vid) < 0) { - wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id"); - goto vlan_add_error; - } - - if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 0) { - wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for " - "vlan %d on %s (%d)", - vlan_if_name, vid, if_name, if_idx); - goto vlan_add_error; - } - - ret = 0; - -vlan_add_error: - if (rlink) - rtnl_link_put(rlink); - if (cache) - nl_cache_free(cache); - if (handle) - nl_socket_free(handle); - return ret; -} - - -int vlan_rem(const char *if_name) -{ - int ret = -1; - struct nl_sock *handle = NULL; - struct nl_cache *cache = NULL; - struct rtnl_link *rlink = NULL; - - wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name); - - handle = nl_socket_alloc(); - if (!handle) { - wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket"); - goto vlan_rem_error; - } - - if (nl_connect(handle, NETLINK_ROUTE) < 0) { - wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink"); - goto vlan_rem_error; - } - - if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) { - cache = NULL; - wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache"); - goto vlan_rem_error; - } - - if (!(rlink = rtnl_link_get_by_name(cache, if_name))) { - /* link does not exist */ - wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists", - if_name); - goto vlan_rem_error; - } - - if (rtnl_link_delete(handle, rlink) < 0) { - wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s", - if_name); - goto vlan_rem_error; - } - - ret = 0; - -vlan_rem_error: - if (rlink) - rtnl_link_put(rlink); - if (cache) - nl_cache_free(cache); - if (handle) - nl_socket_free(handle); - return ret; -} diff --git a/contrib/hostapd/src/ap/vlan_util.h b/contrib/hostapd/src/ap/vlan_util.h deleted file mode 100644 index bef5a16f6c..0000000000 --- a/contrib/hostapd/src/ap/vlan_util.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * hostapd / VLAN netlink api - * Copyright (c) 2012, Michael Braun - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef VLAN_UTIL_H -#define VLAN_UTIL_H - -int vlan_add(const char *if_name, int vid, const char *vlan_if_name); -int vlan_rem(const char *if_name); - -#endif /* VLAN_UTIL_H */ diff --git a/contrib/hostapd/src/ap/wmm.c b/contrib/hostapd/src/ap/wmm.c deleted file mode 100644 index 6d4177c2a8..0000000000 --- a/contrib/hostapd/src/ap/wmm.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * hostapd / WMM (Wi-Fi Multimedia) - * Copyright 2002-2003, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "hostapd.h" -#include "ieee802_11.h" -#include "sta_info.h" -#include "ap_config.h" -#include "ap_drv_ops.h" -#include "wmm.h" - - -/* TODO: maintain separate sequence and fragment numbers for each AC - * TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA - * if only WMM stations are receiving a certain group */ - - -static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci) -{ - u8 ret; - ret = (aifsn << WMM_AC_AIFNS_SHIFT) & WMM_AC_AIFSN_MASK; - if (acm) - ret |= WMM_AC_ACM; - ret |= (aci << WMM_AC_ACI_SHIFT) & WMM_AC_ACI_MASK; - return ret; -} - - -static inline u8 wmm_ecw(int ecwmin, int ecwmax) -{ - return ((ecwmin << WMM_AC_ECWMIN_SHIFT) & WMM_AC_ECWMIN_MASK) | - ((ecwmax << WMM_AC_ECWMAX_SHIFT) & WMM_AC_ECWMAX_MASK); -} - - -/* - * Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association - * Response frames. - */ -u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid) -{ - u8 *pos = eid; - struct wmm_parameter_element *wmm = - (struct wmm_parameter_element *) (pos + 2); - int e; - - if (!hapd->conf->wmm_enabled) - return eid; - eid[0] = WLAN_EID_VENDOR_SPECIFIC; - wmm->oui[0] = 0x00; - wmm->oui[1] = 0x50; - wmm->oui[2] = 0xf2; - wmm->oui_type = WMM_OUI_TYPE; - wmm->oui_subtype = WMM_OUI_SUBTYPE_PARAMETER_ELEMENT; - wmm->version = WMM_VERSION; - wmm->qos_info = hapd->parameter_set_count & 0xf; - - if (hapd->conf->wmm_uapsd && - (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD)) - wmm->qos_info |= 0x80; - - wmm->reserved = 0; - - /* fill in a parameter set record for each AC */ - for (e = 0; e < 4; e++) { - struct wmm_ac_parameter *ac = &wmm->ac[e]; - struct hostapd_wmm_ac_params *acp = - &hapd->iconf->wmm_ac_params[e]; - - ac->aci_aifsn = wmm_aci_aifsn(acp->aifs, - acp->admission_control_mandatory, - e); - ac->cw = wmm_ecw(acp->cwmin, acp->cwmax); - ac->txop_limit = host_to_le16(acp->txop_limit); - } - - pos = (u8 *) (wmm + 1); - eid[1] = pos - eid - 2; /* element length */ - - return pos; -} - - -/* - * 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; - - wpa_hexdump(MSG_MSGDUMP, "WMM IE", eid, len); - - if (len < sizeof(struct wmm_information_element)) { - wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)", - (unsigned long) len); - return 0; - } - - wmm = (struct wmm_information_element *) eid; - wpa_printf(MSG_DEBUG, "Validating WMM IE: OUI %02x:%02x:%02x " - "OUI type %d OUI sub-type %d version %d QoS info 0x%x", - wmm->oui[0], wmm->oui[1], wmm->oui[2], wmm->oui_type, - wmm->oui_subtype, wmm->version, wmm->qos_info); - if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT || - wmm->version != WMM_VERSION) { - wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version"); - return 0; - } - - return 1; -} - - -static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr, - const struct wmm_tspec_element *tspec, - u8 action_code, u8 dialogue_token, u8 status_code) -{ - u8 buf[256]; - struct ieee80211_mgmt *m = (struct ieee80211_mgmt *) buf; - struct wmm_tspec_element *t = (struct wmm_tspec_element *) - m->u.action.u.wmm_action.variable; - int len; - - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "action response - reason %d", status_code); - os_memset(buf, 0, sizeof(buf)); - m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(m->da, addr, ETH_ALEN); - os_memcpy(m->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN); - m->u.action.category = WLAN_ACTION_WMM; - m->u.action.u.wmm_action.action_code = action_code; - m->u.action.u.wmm_action.dialog_token = dialogue_token; - m->u.action.u.wmm_action.status_code = status_code; - os_memcpy(t, tspec, sizeof(struct wmm_tspec_element)); - len = ((u8 *) (t + 1)) - buf; - - if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0) - wpa_printf(MSG_INFO, "wmm_send_action: send failed"); -} - - -int wmm_process_tspec(struct wmm_tspec_element *tspec) -{ - int medium_time, pps, duration; - int up, psb, dir, tid; - u16 val, surplus; - - up = (tspec->ts_info[1] >> 3) & 0x07; - psb = (tspec->ts_info[1] >> 2) & 0x01; - dir = (tspec->ts_info[0] >> 5) & 0x03; - tid = (tspec->ts_info[0] >> 1) & 0x0f; - wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d", - up, psb, dir, tid); - val = le_to_host16(tspec->nominal_msdu_size); - wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s", - val & 0x7fff, val & 0x8000 ? " (fixed)" : ""); - wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps", - le_to_host32(tspec->mean_data_rate)); - wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps", - le_to_host32(tspec->minimum_phy_rate)); - val = le_to_host16(tspec->surplus_bandwidth_allowance); - wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u", - val >> 13, 10000 * (val & 0x1fff) / 0x2000); - - val = le_to_host16(tspec->nominal_msdu_size); - if (val == 0) { - wpa_printf(MSG_DEBUG, "WMM: Invalid Nominal MSDU Size (0)"); - return WMM_ADDTS_STATUS_INVALID_PARAMETERS; - } - /* pps = Ceiling((Mean Data Rate / 8) / Nominal MSDU Size) */ - pps = ((le_to_host32(tspec->mean_data_rate) / 8) + val - 1) / val; - wpa_printf(MSG_DEBUG, "WMM: Packets-per-second estimate for TSPEC: %d", - pps); - - if (le_to_host32(tspec->minimum_phy_rate) < 1000000) { - wpa_printf(MSG_DEBUG, "WMM: Too small Minimum PHY Rate"); - return WMM_ADDTS_STATUS_INVALID_PARAMETERS; - } - - duration = (le_to_host16(tspec->nominal_msdu_size) & 0x7fff) * 8 / - (le_to_host32(tspec->minimum_phy_rate) / 1000000) + - 50 /* FIX: proper SIFS + ACK duration */; - - /* unsigned binary number with an implicit binary point after the - * leftmost 3 bits, i.e., 0x2000 = 1.0 */ - surplus = le_to_host16(tspec->surplus_bandwidth_allowance); - if (surplus <= 0x2000) { - wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance not " - "greater than unity"); - return WMM_ADDTS_STATUS_INVALID_PARAMETERS; - } - - medium_time = surplus * pps * duration / 0x2000; - wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time); - - /* - * TODO: store list of granted (and still active) TSPECs and check - * whether there is available medium time for this request. For now, - * just refuse requests that would by themselves take very large - * portion of the available bandwidth. - */ - if (medium_time > 750000) { - wpa_printf(MSG_DEBUG, "WMM: Refuse TSPEC request for over " - "75%% of available bandwidth"); - return WMM_ADDTS_STATUS_REFUSED; - } - - /* Convert to 32 microseconds per second unit */ - tspec->medium_time = host_to_le16(medium_time / 32); - - return WMM_ADDTS_STATUS_ADMISSION_ACCEPTED; -} - - -static void wmm_addts_req(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, - struct wmm_tspec_element *tspec, size_t len) -{ - const u8 *end = ((const u8 *) mgmt) + len; - int res; - - if ((const u8 *) (tspec + 1) > end) { - wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request"); - return; - } - - wpa_printf(MSG_DEBUG, "WMM: ADDTS Request (Dialog Token %d) for TSPEC " - "from " MACSTR, - mgmt->u.action.u.wmm_action.dialog_token, - MAC2STR(mgmt->sa)); - - res = wmm_process_tspec(tspec); - wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res); - - wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP, - mgmt->u.action.u.wmm_action.dialog_token, res); -} - - -void hostapd_wmm_action(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len) -{ - int action_code; - int left = len - IEEE80211_HDRLEN - 4; - const u8 *pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 4; - struct ieee802_11_elems elems; - struct sta_info *sta = ap_get_sta(hapd, mgmt->sa); - - /* check that the request comes from a valid station */ - if (!sta || - (sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WMM)) != - (WLAN_STA_ASSOC | WLAN_STA_WMM)) { - hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "wmm action received is not from associated wmm" - " station"); - /* TODO: respond with action frame refused status code */ - return; - } - - /* extract the tspec info element */ - if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) { - hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "hostapd_wmm_action - could not parse wmm " - "action"); - /* TODO: respond with action frame invalid parameters status - * code */ - return; - } - - if (!elems.wmm_tspec || - elems.wmm_tspec_len != (sizeof(struct wmm_tspec_element) - 2)) { - hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "hostapd_wmm_action - missing or wrong length " - "tspec"); - /* TODO: respond with action frame invalid parameters status - * code */ - return; - } - - /* TODO: check the request is for an AC with ACM set, if not, refuse - * request */ - - action_code = mgmt->u.action.u.wmm_action.action_code; - switch (action_code) { - case WMM_ACTION_CODE_ADDTS_REQ: - wmm_addts_req(hapd, mgmt, (struct wmm_tspec_element *) - (elems.wmm_tspec - 2), len); - return; -#if 0 - /* TODO: needed for client implementation */ - case WMM_ACTION_CODE_ADDTS_RESP: - wmm_setup_request(hapd, mgmt, len); - return; - /* TODO: handle station teardown requests */ - case WMM_ACTION_CODE_DELTS: - wmm_teardown(hapd, mgmt, len); - return; -#endif - } - - hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "hostapd_wmm_action - unknown action code %d", - action_code); -} diff --git a/contrib/hostapd/src/ap/wmm.h b/contrib/hostapd/src/ap/wmm.h deleted file mode 100644 index b70b863603..0000000000 --- a/contrib/hostapd/src/ap/wmm.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * hostapd / WMM (Wi-Fi Multimedia) - * Copyright 2002-2003, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WME_H -#define WME_H - -struct ieee80211_mgmt; -struct wmm_tspec_element; - -u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid); -int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, - size_t len); -void hostapd_wmm_action(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len); -int wmm_process_tspec(struct wmm_tspec_element *tspec); - -#endif /* WME_H */ diff --git a/contrib/hostapd/src/ap/wnm_ap.c b/contrib/hostapd/src/ap/wnm_ap.c deleted file mode 100644 index 8e5bdcb068..0000000000 --- a/contrib/hostapd/src/ap/wnm_ap.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * hostapd - WNM - * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "common/ieee802_11_defs.h" -#include "ap/hostapd.h" -#include "ap/sta_info.h" -#include "ap/ap_config.h" -#include "ap/ap_drv_ops.h" -#include "ap/wpa_auth.h" -#include "wnm_ap.h" - -#define MAX_TFS_IE_LEN 1024 - - -/* get the TFS IE from driver */ -static int ieee80211_11_get_tfs_ie(struct hostapd_data *hapd, const u8 *addr, - u8 *buf, u16 *buf_len, enum wnm_oper oper) -{ - wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); - - return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len); -} - - -/* set the TFS IE to driver */ -static int ieee80211_11_set_tfs_ie(struct hostapd_data *hapd, const u8 *addr, - u8 *buf, u16 *buf_len, enum wnm_oper oper) -{ - wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); - - return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len); -} - - -/* MLME-SLEEPMODE.response */ -static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, - const u8 *addr, u8 dialog_token, - u8 action_type, u16 intval) -{ - struct ieee80211_mgmt *mgmt; - int res; - size_t len; - size_t gtk_elem_len = 0; - size_t igtk_elem_len = 0; - struct wnm_sleep_element wnmsleep_ie; - u8 *wnmtfs_ie; - u8 wnmsleep_ie_len; - u16 wnmtfs_ie_len; - u8 *pos; - struct sta_info *sta; - enum wnm_oper tfs_oper = action_type == WNM_SLEEP_MODE_ENTER ? - WNM_SLEEP_TFS_RESP_IE_ADD : WNM_SLEEP_TFS_RESP_IE_NONE; - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "%s: station not found", __func__); - return -EINVAL; - } - - /* WNM-Sleep Mode IE */ - os_memset(&wnmsleep_ie, 0, sizeof(struct wnm_sleep_element)); - wnmsleep_ie_len = sizeof(struct wnm_sleep_element); - wnmsleep_ie.eid = WLAN_EID_WNMSLEEP; - wnmsleep_ie.len = wnmsleep_ie_len - 2; - wnmsleep_ie.action_type = action_type; - wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT; - wnmsleep_ie.intval = host_to_le16(intval); - - /* TFS IE(s) */ - wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); - if (wnmtfs_ie == NULL) - return -1; - if (ieee80211_11_get_tfs_ie(hapd, addr, wnmtfs_ie, &wnmtfs_ie_len, - tfs_oper)) { - wnmtfs_ie_len = 0; - os_free(wnmtfs_ie); - wnmtfs_ie = NULL; - } - -#define MAX_GTK_SUBELEM_LEN 45 -#define MAX_IGTK_SUBELEM_LEN 26 - mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + - MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN); - if (mgmt == NULL) { - wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " - "WNM-Sleep Response action frame"); - return -1; - } - 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->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.wnm_sleep_resp.action = WNM_SLEEP_MODE_RESP; - mgmt->u.action.u.wnm_sleep_resp.dialogtoken = dialog_token; - pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable; - /* add key data if MFP is enabled */ - if (!wpa_auth_uses_mfp(sta->wpa_sm) || - action_type != WNM_SLEEP_MODE_EXIT) { - mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0; - } else { - gtk_elem_len = wpa_wnmsleep_gtk_subelem(sta->wpa_sm, pos); - pos += gtk_elem_len; - wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d", - (int) gtk_elem_len); -#ifdef CONFIG_IEEE80211W - res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos); - if (res < 0) { - os_free(wnmtfs_ie); - os_free(mgmt); - return -1; - } - igtk_elem_len = res; - pos += igtk_elem_len; - wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d", - (int) igtk_elem_len); -#endif /* CONFIG_IEEE80211W */ - - WPA_PUT_LE16((u8 *) - &mgmt->u.action.u.wnm_sleep_resp.keydata_len, - gtk_elem_len + igtk_elem_len); - } - os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len); - /* copy TFS IE here */ - pos += wnmsleep_ie_len; - if (wnmtfs_ie) - os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len); - - len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len + - igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len; - - /* In driver, response frame should be forced to sent when STA is in - * PS mode */ - res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, - mgmt->da, &mgmt->u.action.category, len); - - if (!res) { - wpa_printf(MSG_DEBUG, "Successfully send WNM-Sleep Response " - "frame"); - - /* when entering wnmsleep - * 1. pause the node in driver - * 2. mark the node so that AP won't update GTK/IGTK during - * WNM Sleep - */ - if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT && - wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) { - sta->flags |= WLAN_STA_WNM_SLEEP_MODE; - hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM, - addr, NULL, NULL); - wpa_set_wnmsleep(sta->wpa_sm, 1); - } - /* when exiting wnmsleep - * 1. unmark the node - * 2. start GTK/IGTK update if MFP is not used - * 3. unpause the node in driver - */ - if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT || - wnmsleep_ie.status == - WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) && - wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) { - sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; - wpa_set_wnmsleep(sta->wpa_sm, 0); - hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM, - addr, NULL, NULL); - if (!wpa_auth_uses_mfp(sta->wpa_sm)) - wpa_wnmsleep_rekey_gtk(sta->wpa_sm); - } - } else - wpa_printf(MSG_DEBUG, "Fail to send WNM-Sleep Response frame"); - -#undef MAX_GTK_SUBELEM_LEN -#undef MAX_IGTK_SUBELEM_LEN - os_free(wnmtfs_ie); - os_free(mgmt); - return res; -} - - -static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd, - const u8 *addr, const u8 *frm, int len) -{ - /* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */ - const u8 *pos = frm; - u8 dialog_token; - struct wnm_sleep_element *wnmsleep_ie = NULL; - /* multiple TFS Req IE (assuming consecutive) */ - u8 *tfsreq_ie_start = NULL; - u8 *tfsreq_ie_end = NULL; - u16 tfsreq_ie_len = 0; - - dialog_token = *pos++; - while (pos + 1 < frm + len) { - u8 ie_len = pos[1]; - if (pos + 2 + ie_len > frm + len) - break; - if (*pos == WLAN_EID_WNMSLEEP) - wnmsleep_ie = (struct wnm_sleep_element *) pos; - else if (*pos == WLAN_EID_TFS_REQ) { - if (!tfsreq_ie_start) - tfsreq_ie_start = (u8 *) pos; - tfsreq_ie_end = (u8 *) pos; - } else - wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized", - *pos); - pos += ie_len + 2; - } - - if (!wnmsleep_ie) { - wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); - return; - } - - if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER && - tfsreq_ie_start && tfsreq_ie_end && - tfsreq_ie_end - tfsreq_ie_start >= 0) { - tfsreq_ie_len = (tfsreq_ie_end + tfsreq_ie_end[1] + 2) - - tfsreq_ie_start; - wpa_printf(MSG_DEBUG, "TFS Req IE(s) found"); - /* pass the TFS Req IE(s) to driver for processing */ - if (ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start, - &tfsreq_ie_len, - WNM_SLEEP_TFS_REQ_IE_SET)) - wpa_printf(MSG_DEBUG, "Fail to set TFS Req IE"); - } - - ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token, - wnmsleep_ie->action_type, - le_to_host16(wnmsleep_ie->intval)); - - if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { - /* clear the tfs after sending the resp frame */ - ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start, - &tfsreq_ie_len, WNM_SLEEP_TFS_IE_DEL); - } -} - - -static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd, - const u8 *addr, - u8 dialog_token, - const char *url) -{ - struct ieee80211_mgmt *mgmt; - size_t url_len, len; - u8 *pos; - int res; - - if (url) - url_len = os_strlen(url); - else - url_len = 0; - - mgmt = os_zalloc(sizeof(*mgmt) + (url_len ? 1 + url_len : 0)); - if (mgmt == NULL) - return -1; - 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->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; - mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token; - mgmt->u.action.u.bss_tm_req.req_mode = 0; - mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0); - mgmt->u.action.u.bss_tm_req.validity_interval = 1; - pos = mgmt->u.action.u.bss_tm_req.variable; - if (url) { - *pos++ += url_len; - os_memcpy(pos, url, url_len); - pos += url_len; - } - - wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to " - MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u " - "validity_interval=%u", - MAC2STR(addr), dialog_token, - mgmt->u.action.u.bss_tm_req.req_mode, - le_to_host16(mgmt->u.action.u.bss_tm_req.disassoc_timer), - mgmt->u.action.u.bss_tm_req.validity_interval); - - len = pos - &mgmt->u.action.category; - res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, - mgmt->da, &mgmt->u.action.category, len); - os_free(mgmt); - return res; -} - - -static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd, - const u8 *addr, const u8 *frm, - size_t len) -{ - u8 dialog_token, reason; - const u8 *pos, *end; - - if (len < 2) { - wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Query from " - MACSTR, MAC2STR(addr)); - return; - } - - pos = frm; - end = pos + len; - dialog_token = *pos++; - reason = *pos++; - - wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query from " - MACSTR " dialog_token=%u reason=%u", - MAC2STR(addr), dialog_token, reason); - - wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", - pos, end - pos); - - ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token, NULL); -} - - -static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd, - const u8 *addr, const u8 *frm, - size_t len) -{ - u8 dialog_token, status_code, bss_termination_delay; - const u8 *pos, *end; - - if (len < 3) { - wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Response from " - MACSTR, MAC2STR(addr)); - return; - } - - pos = frm; - end = pos + len; - dialog_token = *pos++; - status_code = *pos++; - bss_termination_delay = *pos++; - - wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Response from " - MACSTR " dialog_token=%u status_code=%u " - "bss_termination_delay=%u", MAC2STR(addr), dialog_token, - status_code, bss_termination_delay); - - if (status_code == WNM_BSS_TM_ACCEPT) { - if (end - pos < ETH_ALEN) { - wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field"); - return; - } - wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR, - MAC2STR(pos)); - pos += ETH_ALEN; - } - - wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", - pos, end - pos); -} - - -int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len) -{ - u8 action; - const u8 *payload; - size_t plen; - - if (len < IEEE80211_HDRLEN + 2) - return -1; - - payload = &mgmt->u.action.category; - payload++; - action = *payload++; - plen = (((const u8 *) mgmt) + len) - payload; - - switch (action) { - case WNM_BSS_TRANS_MGMT_QUERY: - ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload, - plen); - return 0; - case WNM_BSS_TRANS_MGMT_RESP: - ieee802_11_rx_bss_trans_mgmt_resp(hapd, mgmt->sa, payload, - plen); - return 0; - case WNM_SLEEP_MODE_REQ: - ieee802_11_rx_wnmsleep_req(hapd, mgmt->sa, payload, plen); - return 0; - } - - wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR, - action, MAC2STR(mgmt->sa)); - return -1; -} - - -int wnm_send_disassoc_imminent(struct hostapd_data *hapd, - struct sta_info *sta, int disassoc_timer) -{ - u8 buf[1000], *pos; - struct ieee80211_mgmt *mgmt; - - os_memset(buf, 0, sizeof(buf)); - mgmt = (struct ieee80211_mgmt *) buf; - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(mgmt->da, sta->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_WNM; - mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; - mgmt->u.action.u.bss_tm_req.dialog_token = 1; - mgmt->u.action.u.bss_tm_req.req_mode = - WNM_BSS_TM_REQ_DISASSOC_IMMINENT; - mgmt->u.action.u.bss_tm_req.disassoc_timer = - host_to_le16(disassoc_timer); - mgmt->u.action.u.bss_tm_req.validity_interval = 0; - - pos = mgmt->u.action.u.bss_tm_req.variable; - - wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to " - MACSTR, disassoc_timer, MAC2STR(sta->addr)); - if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { - wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " - "Management Request frame"); - return -1; - } - - return 0; -} - - -int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd, - struct sta_info *sta, const char *url, - int disassoc_timer) -{ - u8 buf[1000], *pos; - struct ieee80211_mgmt *mgmt; - size_t url_len; - - os_memset(buf, 0, sizeof(buf)); - mgmt = (struct ieee80211_mgmt *) buf; - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(mgmt->da, sta->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_WNM; - mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; - mgmt->u.action.u.bss_tm_req.dialog_token = 1; - mgmt->u.action.u.bss_tm_req.req_mode = - WNM_BSS_TM_REQ_DISASSOC_IMMINENT | - WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; - mgmt->u.action.u.bss_tm_req.disassoc_timer = - host_to_le16(disassoc_timer); - mgmt->u.action.u.bss_tm_req.validity_interval = 0x01; - - pos = mgmt->u.action.u.bss_tm_req.variable; - - /* Session Information URL */ - url_len = os_strlen(url); - if (url_len > 255) - return -1; - *pos++ = url_len; - os_memcpy(pos, url, url_len); - pos += url_len; - - if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { - wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " - "Management Request frame"); - return -1; - } - - /* send disassociation frame after time-out */ - if (disassoc_timer) { - int timeout, beacon_int; - - /* - * Prevent STA from reconnecting using cached PMKSA to force - * full authentication with the authentication server (which may - * decide to reject the connection), - */ - wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr); - - beacon_int = hapd->iconf->beacon_int; - if (beacon_int < 1) - beacon_int = 100; /* best guess */ - /* Calculate timeout in ms based on beacon_int in TU */ - timeout = disassoc_timer * beacon_int * 128 / 125; - wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR - " set to %d ms", MAC2STR(sta->addr), timeout); - - sta->timeout_next = STA_DISASSOC_FROM_CLI; - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(timeout / 1000, - timeout % 1000 * 1000, - ap_handle_timer, hapd, sta); - } - - return 0; -} diff --git a/contrib/hostapd/src/ap/wnm_ap.h b/contrib/hostapd/src/ap/wnm_ap.h deleted file mode 100644 index eeaf5eca3a..0000000000 --- a/contrib/hostapd/src/ap/wnm_ap.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * IEEE 802.11v WNM related functions and structures - * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WNM_AP_H -#define WNM_AP_H - -struct sta_info; - -int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len); -int wnm_send_disassoc_imminent(struct hostapd_data *hapd, - struct sta_info *sta, int disassoc_timer); -int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd, - struct sta_info *sta, const char *url, - int disassoc_timer); - -#endif /* WNM_AP_H */ diff --git a/contrib/hostapd/src/ap/wpa_auth.c b/contrib/hostapd/src/ap/wpa_auth.c deleted file mode 100644 index 707a63f0cf..0000000000 --- a/contrib/hostapd/src/ap/wpa_auth.c +++ /dev/null @@ -1,3180 +0,0 @@ -/* - * IEEE 802.11 RSN / WPA Authenticator - * Copyright (c) 2004-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "utils/state_machine.h" -#include "utils/bitfield.h" -#include "common/ieee802_11_defs.h" -#include "crypto/aes_wrap.h" -#include "crypto/crypto.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "crypto/random.h" -#include "eapol_auth/eapol_auth_sm.h" -#include "ap_config.h" -#include "ieee802_11.h" -#include "wpa_auth.h" -#include "pmksa_cache_auth.h" -#include "wpa_auth_i.h" -#include "wpa_auth_ie.h" - -#define STATE_MACHINE_DATA struct wpa_state_machine -#define STATE_MACHINE_DEBUG_PREFIX "WPA" -#define STATE_MACHINE_ADDR sm->addr - - -static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx); -static int wpa_sm_step(struct wpa_state_machine *sm); -static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len); -static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx); -static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, - struct wpa_group *group); -static void wpa_request_new_ptk(struct wpa_state_machine *sm); -static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, - struct wpa_group *group); -static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, - struct wpa_group *group); - -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; -static const int dot11RSNAConfigPMKReauthThreshold = 70; -static const int dot11RSNAConfigSATimeout = 60; - - -static inline int wpa_auth_mic_failure_report( - struct wpa_authenticator *wpa_auth, const u8 *addr) -{ - if (wpa_auth->cb.mic_failure_report) - return wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr); - return 0; -} - - -static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth, - const u8 *addr, wpa_eapol_variable var, - int value) -{ - if (wpa_auth->cb.set_eapol) - wpa_auth->cb.set_eapol(wpa_auth->cb.ctx, addr, var, value); -} - - -static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth, - const u8 *addr, wpa_eapol_variable var) -{ - if (wpa_auth->cb.get_eapol == NULL) - return -1; - return wpa_auth->cb.get_eapol(wpa_auth->cb.ctx, addr, var); -} - - -static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth, - const u8 *addr, - const u8 *p2p_dev_addr, - const u8 *prev_psk) -{ - if (wpa_auth->cb.get_psk == NULL) - return NULL; - return wpa_auth->cb.get_psk(wpa_auth->cb.ctx, addr, p2p_dev_addr, - prev_psk); -} - - -static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth, - const u8 *addr, u8 *msk, size_t *len) -{ - if (wpa_auth->cb.get_msk == NULL) - return -1; - return wpa_auth->cb.get_msk(wpa_auth->cb.ctx, addr, msk, len); -} - - -static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, - int vlan_id, - enum wpa_alg alg, const u8 *addr, int idx, - u8 *key, size_t key_len) -{ - if (wpa_auth->cb.set_key == NULL) - return -1; - return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx, - key, key_len); -} - - -static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth, - const u8 *addr, int idx, u8 *seq) -{ - if (wpa_auth->cb.get_seqnum == NULL) - return -1; - return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq); -} - - -static inline int -wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr, - const u8 *data, size_t data_len, int encrypt) -{ - if (wpa_auth->cb.send_eapol == NULL) - return -1; - return wpa_auth->cb.send_eapol(wpa_auth->cb.ctx, addr, data, data_len, - encrypt); -} - - -int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth, - int (*cb)(struct wpa_state_machine *sm, void *ctx), - void *cb_ctx) -{ - if (wpa_auth->cb.for_each_sta == NULL) - return 0; - return wpa_auth->cb.for_each_sta(wpa_auth->cb.ctx, cb, cb_ctx); -} - - -int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth, - int (*cb)(struct wpa_authenticator *a, void *ctx), - void *cb_ctx) -{ - if (wpa_auth->cb.for_each_auth == NULL) - return 0; - return wpa_auth->cb.for_each_auth(wpa_auth->cb.ctx, cb, cb_ctx); -} - - -void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr, - logger_level level, const char *txt) -{ - if (wpa_auth->cb.logger == NULL) - return; - wpa_auth->cb.logger(wpa_auth->cb.ctx, addr, level, txt); -} - - -void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr, - logger_level level, const char *fmt, ...) -{ - char *format; - int maxlen; - va_list ap; - - if (wpa_auth->cb.logger == NULL) - return; - - maxlen = os_strlen(fmt) + 100; - format = os_malloc(maxlen); - if (!format) - return; - - va_start(ap, fmt); - vsnprintf(format, maxlen, fmt, ap); - va_end(ap); - - wpa_auth_logger(wpa_auth, addr, level, format); - - os_free(format); -} - - -static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth, - const u8 *addr) -{ - 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); -} - - -static int wpa_use_aes_cmac(struct wpa_state_machine *sm) -{ - int ret = 0; -#ifdef CONFIG_IEEE80211R - if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) - ret = 1; -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt)) - ret = 1; -#endif /* CONFIG_IEEE80211W */ - return ret; -} - - -static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_authenticator *wpa_auth = eloop_ctx; - - if (random_get_bytes(wpa_auth->group->GMK, WPA_GMK_LEN)) { - wpa_printf(MSG_ERROR, "Failed to get random data for WPA " - "initialization."); - } else { - wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd"); - wpa_hexdump_key(MSG_DEBUG, "GMK", - wpa_auth->group->GMK, WPA_GMK_LEN); - } - - if (wpa_auth->conf.wpa_gmk_rekey) { - eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0, - wpa_rekey_gmk, wpa_auth, NULL); - } -} - - -static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_authenticator *wpa_auth = eloop_ctx; - struct wpa_group *group; - - wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK"); - for (group = wpa_auth->group; group; group = group->next) { - group->GTKReKey = TRUE; - do { - group->changed = FALSE; - wpa_group_sm_step(wpa_auth, group); - } while (group->changed); - } - - if (wpa_auth->conf.wpa_group_rekey) { - eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, - 0, wpa_rekey_gtk, wpa_auth, NULL); - } -} - - -static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_authenticator *wpa_auth = eloop_ctx; - struct wpa_state_machine *sm = timeout_ctx; - - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK"); - wpa_request_new_ptk(sm); - wpa_sm_step(sm); -} - - -static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx) -{ - if (sm->pmksa == ctx) - sm->pmksa = NULL; - return 0; -} - - -static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry, - void *ctx) -{ - struct wpa_authenticator *wpa_auth = ctx; - wpa_auth_for_each_sta(wpa_auth, wpa_auth_pmksa_clear_cb, entry); -} - - -static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth, - struct wpa_group *group) -{ - u8 buf[ETH_ALEN + 8 + sizeof(unsigned long)]; - u8 rkey[32]; - unsigned long ptr; - - if (random_get_bytes(group->GMK, WPA_GMK_LEN) < 0) - return -1; - wpa_hexdump_key(MSG_DEBUG, "GMK", group->GMK, WPA_GMK_LEN); - - /* - * Counter = PRF-256(Random number, "Init Counter", - * Local MAC Address || Time) - */ - os_memcpy(buf, wpa_auth->addr, ETH_ALEN); - wpa_get_ntp_timestamp(buf + ETH_ALEN); - ptr = (unsigned long) group; - os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr)); - if (random_get_bytes(rkey, sizeof(rkey)) < 0) - return -1; - - if (sha1_prf(rkey, sizeof(rkey), "Init Counter", buf, sizeof(buf), - group->Counter, WPA_NONCE_LEN) < 0) - return -1; - wpa_hexdump_key(MSG_DEBUG, "Key Counter", - group->Counter, WPA_NONCE_LEN); - - return 0; -} - - -static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, - int vlan_id, int delay_init) -{ - struct wpa_group *group; - - group = os_zalloc(sizeof(struct wpa_group)); - if (group == NULL) - return NULL; - - group->GTKAuthenticator = TRUE; - group->vlan_id = vlan_id; - group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group); - - if (random_pool_ready() != 1) { - wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool " - "for secure operations - update keys later when " - "the first station connects"); - } - - /* - * Set initial GMK/Counter value here. The actual values that will be - * used in negotiations will be set once the first station tries to - * connect. This allows more time for collecting additional randomness - * on embedded devices. - */ - if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) { - wpa_printf(MSG_ERROR, "Failed to get random data for WPA " - "initialization."); - os_free(group); - return NULL; - } - - group->GInit = TRUE; - 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; -} - - -/** - * wpa_init - Initialize WPA authenticator - * @addr: Authenticator address - * @conf: Configuration for WPA authenticator - * @cb: Callback functions for WPA authenticator - * Returns: Pointer to WPA authenticator data or %NULL on failure - */ -struct wpa_authenticator * wpa_init(const u8 *addr, - struct wpa_auth_config *conf, - struct wpa_auth_callbacks *cb) -{ - struct wpa_authenticator *wpa_auth; - - wpa_auth = os_zalloc(sizeof(struct wpa_authenticator)); - if (wpa_auth == NULL) - return NULL; - os_memcpy(wpa_auth->addr, addr, ETH_ALEN); - os_memcpy(&wpa_auth->conf, conf, sizeof(*conf)); - os_memcpy(&wpa_auth->cb, cb, sizeof(*cb)); - - if (wpa_auth_gen_wpa_ie(wpa_auth)) { - wpa_printf(MSG_ERROR, "Could not generate WPA IE."); - os_free(wpa_auth); - return NULL; - } - - 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); - return NULL; - } - - wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb, - wpa_auth); - if (wpa_auth->pmksa == NULL) { - wpa_printf(MSG_ERROR, "PMKSA cache initialization failed."); - os_free(wpa_auth->wpa_ie); - os_free(wpa_auth); - return NULL; - } - -#ifdef CONFIG_IEEE80211R - wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init(); - if (wpa_auth->ft_pmk_cache == NULL) { - wpa_printf(MSG_ERROR, "FT PMK cache initialization failed."); - os_free(wpa_auth->wpa_ie); - pmksa_cache_auth_deinit(wpa_auth->pmksa); - os_free(wpa_auth); - return NULL; - } -#endif /* CONFIG_IEEE80211R */ - - if (wpa_auth->conf.wpa_gmk_rekey) { - eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0, - wpa_rekey_gmk, wpa_auth, NULL); - } - - if (wpa_auth->conf.wpa_group_rekey) { - eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0, - wpa_rekey_gtk, wpa_auth, NULL); - } - -#ifdef CONFIG_P2P - if (WPA_GET_BE32(conf->ip_addr_start)) { - int count = WPA_GET_BE32(conf->ip_addr_end) - - WPA_GET_BE32(conf->ip_addr_start) + 1; - if (count > 1000) - count = 1000; - if (count > 0) - wpa_auth->ip_pool = bitfield_alloc(count); - } -#endif /* CONFIG_P2P */ - - return wpa_auth; -} - - -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); - if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) - return -1; - return 0; -} - - -/** - * wpa_deinit - Deinitialize WPA authenticator - * @wpa_auth: Pointer to WPA authenticator data from wpa_init() - */ -void wpa_deinit(struct wpa_authenticator *wpa_auth) -{ - struct wpa_group *group, *prev; - - eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL); - eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); - -#ifdef CONFIG_PEERKEY - while (wpa_auth->stsl_negotiations) - wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations); -#endif /* CONFIG_PEERKEY */ - - pmksa_cache_auth_deinit(wpa_auth->pmksa); - -#ifdef CONFIG_IEEE80211R - wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache); - wpa_auth->ft_pmk_cache = NULL; -#endif /* CONFIG_IEEE80211R */ - -#ifdef CONFIG_P2P - bitfield_free(wpa_auth->ip_pool); -#endif /* CONFIG_P2P */ - - - os_free(wpa_auth->wpa_ie); - - group = wpa_auth->group; - while (group) { - prev = group; - group = group->next; - os_free(prev); - } - - os_free(wpa_auth); -} - - -/** - * wpa_reconfig - Update WPA authenticator configuration - * @wpa_auth: Pointer to WPA authenticator data from wpa_init() - * @conf: Configuration for WPA authenticator - */ -int wpa_reconfig(struct wpa_authenticator *wpa_auth, - struct wpa_auth_config *conf) -{ - struct wpa_group *group; - if (wpa_auth == NULL) - return 0; - - os_memcpy(&wpa_auth->conf, conf, sizeof(*conf)); - if (wpa_auth_gen_wpa_ie(wpa_auth)) { - wpa_printf(MSG_ERROR, "Could not generate WPA IE."); - return -1; - } - - /* - * Reinitialize GTK to make sure it is suitable for the new - * configuration. - */ - group = wpa_auth->group; - group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group); - group->GInit = TRUE; - wpa_group_sm_step(wpa_auth, group); - group->GInit = FALSE; - wpa_group_sm_step(wpa_auth, group); - - return 0; -} - - -struct wpa_state_machine * -wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr, - const u8 *p2p_dev_addr) -{ - struct wpa_state_machine *sm; - - if (wpa_auth->group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) - return NULL; - - sm = os_zalloc(sizeof(struct wpa_state_machine)); - if (sm == NULL) - return NULL; - os_memcpy(sm->addr, addr, ETH_ALEN); - if (p2p_dev_addr) - os_memcpy(sm->p2p_dev_addr, p2p_dev_addr, ETH_ALEN); - - sm->wpa_auth = wpa_auth; - sm->group = wpa_auth->group; - - return sm; -} - - -int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm) -{ - if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL) - return -1; - -#ifdef CONFIG_IEEE80211R - if (sm->ft_completed) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, - "FT authentication already completed - do not " - "start 4-way handshake"); - return 0; - } -#endif /* CONFIG_IEEE80211R */ - - if (sm->started) { - os_memset(&sm->key_replay, 0, sizeof(sm->key_replay)); - sm->ReAuthenticationRequest = TRUE; - return wpa_sm_step(sm); - } - - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, - "start authentication"); - sm->started = 1; - - sm->Init = TRUE; - if (wpa_sm_step(sm) == 1) - return 1; /* should not really happen */ - sm->Init = FALSE; - sm->AuthenticationRequest = TRUE; - return wpa_sm_step(sm); -} - - -void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm) -{ - /* WPA/RSN was not used - clear WPA state. This is needed if the STA - * reassociates back to the same AP while the previous entry for the - * STA has not yet been removed. */ - if (sm == NULL) - return; - - sm->wpa_key_mgmt = 0; -} - - -static void wpa_free_sta_sm(struct wpa_state_machine *sm) -{ -#ifdef CONFIG_P2P - if (WPA_GET_BE32(sm->ip_addr)) { - u32 start; - wpa_printf(MSG_DEBUG, "P2P: Free assigned IP " - "address %u.%u.%u.%u from " MACSTR, - sm->ip_addr[0], sm->ip_addr[1], - sm->ip_addr[2], sm->ip_addr[3], - MAC2STR(sm->addr)); - start = WPA_GET_BE32(sm->wpa_auth->conf.ip_addr_start); - bitfield_clear(sm->wpa_auth->ip_pool, - WPA_GET_BE32(sm->ip_addr) - start); - } -#endif /* CONFIG_P2P */ - if (sm->GUpdateStationKeys) { - sm->group->GKeyDoneStations--; - sm->GUpdateStationKeys = FALSE; - } -#ifdef CONFIG_IEEE80211R - os_free(sm->assoc_resp_ftie); -#endif /* CONFIG_IEEE80211R */ - os_free(sm->last_rx_eapol_key); - os_free(sm->wpa_ie); - os_free(sm); -} - - -void wpa_auth_sta_deinit(struct wpa_state_machine *sm) -{ - if (sm == NULL) - return; - - if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) { - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "strict rekeying - force GTK rekey since STA " - "is leaving"); - eloop_cancel_timeout(wpa_rekey_gtk, sm->wpa_auth, NULL); - eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth, - NULL); - } - - eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); - sm->pending_1_of_4_timeout = 0; - eloop_cancel_timeout(wpa_sm_call_step, sm, NULL); - eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); - if (sm->in_step_loop) { - /* Must not free state machine while wpa_sm_step() is running. - * Freeing will be completed in the end of wpa_sm_step(). */ - wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state " - "machine deinit for " MACSTR, MAC2STR(sm->addr)); - sm->pending_deinit = 1; - } else - wpa_free_sta_sm(sm); -} - - -static void wpa_request_new_ptk(struct wpa_state_machine *sm) -{ - if (sm == NULL) - return; - - sm->PTKRequest = TRUE; - sm->PTK_valid = 0; -} - - -static int wpa_replay_counter_valid(struct wpa_key_replay_counter *ctr, - const u8 *replay_counter) -{ - int i; - for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { - if (!ctr[i].valid) - break; - if (os_memcmp(replay_counter, ctr[i].counter, - WPA_REPLAY_COUNTER_LEN) == 0) - return 1; - } - return 0; -} - - -static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr, - const u8 *replay_counter) -{ - int i; - for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { - if (ctr[i].valid && - (replay_counter == NULL || - os_memcmp(replay_counter, ctr[i].counter, - WPA_REPLAY_COUNTER_LEN) == 0)) - ctr[i].valid = FALSE; - } -} - - -#ifdef CONFIG_IEEE80211R -static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, - struct wpa_eapol_ie_parse *kde) -{ - struct wpa_ie_data ie; - struct rsn_mdie *mdie; - - if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 || - ie.num_pmkid != 1 || ie.pmkid == NULL) { - wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in " - "FT 4-way handshake message 2/4"); - return -1; - } - - os_memcpy(sm->sup_pmk_r1_name, ie.pmkid, PMKID_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Supplicant", - sm->sup_pmk_r1_name, PMKID_LEN); - - if (!kde->mdie || !kde->ftie) { - wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake " - "message 2/4", kde->mdie ? "FTIE" : "MDIE"); - return -1; - } - - mdie = (struct rsn_mdie *) (kde->mdie + 2); - if (kde->mdie[1] < sizeof(struct rsn_mdie) || - os_memcmp(wpa_auth->conf.mobility_domain, mdie->mobility_domain, - MOBILITY_DOMAIN_ID_LEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: MDIE mismatch"); - return -1; - } - - if (sm->assoc_resp_ftie && - (kde->ftie[1] != sm->assoc_resp_ftie[1] || - os_memcmp(kde->ftie, sm->assoc_resp_ftie, - 2 + sm->assoc_resp_ftie[1]) != 0)) { - wpa_printf(MSG_DEBUG, "FT: FTIE mismatch"); - wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 2/4", - kde->ftie, kde->ftie_len); - wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)AssocResp", - sm->assoc_resp_ftie, 2 + sm->assoc_resp_ftie[1]); - return -1; - } - - return 0; -} -#endif /* CONFIG_IEEE80211R */ - - -static int 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 { - if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0) - return 1; /* STA entry was removed */ - 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); - return 0; -} - - -void wpa_receive(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, - u8 *data, size_t data_len) -{ - struct ieee802_1x_hdr *hdr; - struct wpa_eapol_key *key; - u16 key_info, key_data_length; - enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST, - SMK_M1, SMK_M3, SMK_ERROR } msg; - char *msgtxt; - struct wpa_eapol_ie_parse kde; - int ft; - const u8 *eapol_key_ie; - size_t eapol_key_ie_len; - - if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL) - return; - - if (data_len < sizeof(*hdr) + sizeof(*key)) - return; - - hdr = (struct ieee802_1x_hdr *) data; - 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)", - key_data_length, - (unsigned long) (data_len - sizeof(*hdr) - - sizeof(*key))); - return; - } - - if (sm->wpa == WPA_VERSION_WPA2) { - if (key->type == EAPOL_KEY_TYPE_WPA) { - /* - * Some deployed station implementations seem to send - * msg 4/4 with incorrect type value in WPA2 mode. - */ - wpa_printf(MSG_DEBUG, "Workaround: Allow EAPOL-Key " - "with unexpected WPA type in RSN mode"); - } else if (key->type != EAPOL_KEY_TYPE_RSN) { - wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with " - "unexpected type %d in RSN mode", - key->type); - return; - } - } else { - if (key->type != EAPOL_KEY_TYPE_WPA) { - wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with " - "unexpected type %d in WPA mode", - key->type); - return; - } - } - - wpa_hexdump(MSG_DEBUG, "WPA: Received Key Nonce", key->key_nonce, - WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, "WPA: Received Replay Counter", - key->replay_counter, WPA_REPLAY_COUNTER_LEN); - - /* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys - * are set */ - - if ((key_info & (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) == - (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) { - if (key_info & WPA_KEY_INFO_ERROR) { - msg = SMK_ERROR; - msgtxt = "SMK Error"; - } else { - msg = SMK_M1; - msgtxt = "SMK M1"; - } - } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) { - msg = SMK_M3; - msgtxt = "SMK M3"; - } else if (key_info & WPA_KEY_INFO_REQUEST) { - msg = REQUEST; - msgtxt = "Request"; - } else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) { - msg = GROUP_2; - msgtxt = "2/2 Group"; - } else if (key_data_length == 0) { - msg = PAIRWISE_4; - msgtxt = "4/4 Pairwise"; - } else { - msg = PAIRWISE_2; - msgtxt = "2/4 Pairwise"; - } - - /* TODO: key_info type validation for PeerKey */ - if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 || - msg == GROUP_2) { - u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK; - if (sm->pairwise == WPA_CIPHER_CCMP || - sm->pairwise == WPA_CIPHER_GCMP) { - if (wpa_use_aes_cmac(sm) && - ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { - wpa_auth_logger(wpa_auth, sm->addr, - LOGGER_WARNING, - "advertised support for " - "AES-128-CMAC, but did not " - "use it"); - return; - } - - if (!wpa_use_aes_cmac(sm) && - ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { - wpa_auth_logger(wpa_auth, sm->addr, - LOGGER_WARNING, - "did not use HMAC-SHA1-AES " - "with CCMP/GCMP"); - return; - } - } - } - - if (key_info & WPA_KEY_INFO_REQUEST) { - if (sm->req_replay_counter_used && - os_memcmp(key->replay_counter, sm->req_replay_counter, - WPA_REPLAY_COUNTER_LEN) <= 0) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, - "received EAPOL-Key request with " - "replayed counter"); - return; - } - } - - if (!(key_info & WPA_KEY_INFO_REQUEST) && - !wpa_replay_counter_valid(sm->key_replay, key->replay_counter)) { - int i; - - if (msg == PAIRWISE_2 && - wpa_replay_counter_valid(sm->prev_key_replay, - key->replay_counter) && - sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING && - os_memcmp(sm->SNonce, key->key_nonce, WPA_NONCE_LEN) != 0) - { - /* - * Some supplicant implementations (e.g., Windows XP - * WZC) update SNonce for each EAPOL-Key 2/4. This - * breaks the workaround on accepting any of the - * pending requests, so allow the SNonce to be updated - * even if we have already sent out EAPOL-Key 3/4. - */ - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "Process SNonce update from STA " - "based on retransmitted EAPOL-Key " - "1/4"); - sm->update_snonce = 1; - wpa_replay_counter_mark_invalid(sm->prev_key_replay, - key->replay_counter); - goto continue_processing; - } - - if (msg == PAIRWISE_2 && - wpa_replay_counter_valid(sm->prev_key_replay, - key->replay_counter) && - sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "ignore retransmitted EAPOL-Key %s - " - "SNonce did not change", msgtxt); - } else { - 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++) { - if (!sm->key_replay[i].valid) - break; - wpa_hexdump(MSG_DEBUG, "pending replay counter", - sm->key_replay[i].counter, - WPA_REPLAY_COUNTER_LEN); - } - wpa_hexdump(MSG_DEBUG, "received replay counter", - key->replay_counter, WPA_REPLAY_COUNTER_LEN); - return; - } - -continue_processing: - switch (msg) { - case PAIRWISE_2: - if (sm->wpa_ptk_state != WPA_PTK_PTKSTART && - sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING && - (!sm->update_snonce || - sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key msg 2/4 in " - "invalid state (%d) - dropped", - sm->wpa_ptk_state); - return; - } - random_add_randomness(key->key_nonce, WPA_NONCE_LEN); - if (sm->group->reject_4way_hs_for_entropy) { - /* - * The system did not have enough entropy to generate - * strong random numbers. Reject the first 4-way - * handshake(s) and collect some entropy based on the - * information from it. Once enough entropy is - * available, the next atempt will trigger GMK/Key - * Counter update and the station will be allowed to - * continue. - */ - wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to " - "collect more entropy for random number " - "generation"); - random_mark_pool_ready(); - wpa_sta_disconnect(wpa_auth, sm->addr); - return; - } - if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length, - &kde) < 0) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key msg 2/4 with " - "invalid Key Data contents"); - return; - } - if (kde.rsn_ie) { - eapol_key_ie = kde.rsn_ie; - eapol_key_ie_len = kde.rsn_ie_len; - } else { - eapol_key_ie = kde.wpa_ie; - eapol_key_ie_len = kde.wpa_ie_len; - } - ft = sm->wpa == WPA_VERSION_WPA2 && - wpa_key_mgmt_ft(sm->wpa_key_mgmt); - if (sm->wpa_ie == NULL || - wpa_compare_rsn_ie(ft, - sm->wpa_ie, sm->wpa_ie_len, - eapol_key_ie, eapol_key_ie_len)) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "WPA IE from (Re)AssocReq did not " - "match with msg 2/4"); - if (sm->wpa_ie) { - wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq", - sm->wpa_ie, sm->wpa_ie_len); - } - wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4", - eapol_key_ie, eapol_key_ie_len); - /* MLME-DEAUTHENTICATE.request */ - wpa_sta_disconnect(wpa_auth, sm->addr); - return; - } -#ifdef CONFIG_IEEE80211R - if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) { - wpa_sta_disconnect(wpa_auth, sm->addr); - return; - } -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_P2P - if (kde.ip_addr_req && kde.ip_addr_req[0] && - wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) { - int idx; - wpa_printf(MSG_DEBUG, "P2P: IP address requested in " - "EAPOL-Key exchange"); - idx = bitfield_get_first_zero(wpa_auth->ip_pool); - if (idx >= 0) { - u32 start = WPA_GET_BE32(wpa_auth->conf. - ip_addr_start); - bitfield_set(wpa_auth->ip_pool, idx); - WPA_PUT_BE32(sm->ip_addr, start + idx); - wpa_printf(MSG_DEBUG, "P2P: Assigned IP " - "address %u.%u.%u.%u to " MACSTR, - sm->ip_addr[0], sm->ip_addr[1], - sm->ip_addr[2], sm->ip_addr[3], - MAC2STR(sm->addr)); - } - } -#endif /* CONFIG_P2P */ - break; - case PAIRWISE_4: - if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING || - !sm->PTK_valid) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key msg 4/4 in " - "invalid state (%d) - dropped", - sm->wpa_ptk_state); - return; - } - break; - case GROUP_2: - if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING - || !sm->PTK_valid) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key msg 2/2 in " - "invalid state (%d) - dropped", - sm->wpa_ptk_group_state); - return; - } - break; -#ifdef CONFIG_PEERKEY - case SMK_M1: - case SMK_M3: - case SMK_ERROR: - if (!wpa_auth->conf.peerkey) { - wpa_printf(MSG_DEBUG, "RSN: SMK M1/M3/Error, but " - "PeerKey use disabled - ignoring message"); - return; - } - if (!sm->PTK_valid) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key msg SMK in " - "invalid state - dropped"); - return; - } - break; -#else /* CONFIG_PEERKEY */ - case SMK_M1: - case SMK_M3: - case SMK_ERROR: - return; /* STSL disabled - ignore SMK messages */ -#endif /* CONFIG_PEERKEY */ - case REQUEST: - break; - } - - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "received EAPOL-Key frame (%s)", msgtxt); - - if (key_info & WPA_KEY_INFO_ACK) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "received invalid EAPOL-Key: Key Ack set"); - return; - } - - if (!(key_info & WPA_KEY_INFO_MIC)) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "received invalid EAPOL-Key: Key MIC not set"); - return; - } - - sm->MICVerified = FALSE; - if (sm->PTK_valid && !sm->update_snonce) { - if (wpa_verify_key_mic(&sm->PTK, data, data_len)) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key with invalid MIC"); - return; - } - sm->MICVerified = TRUE; - eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm); - sm->pending_1_of_4_timeout = 0; - } - - if (key_info & WPA_KEY_INFO_REQUEST) { - if (sm->MICVerified) { - sm->req_replay_counter_used = 1; - os_memcpy(sm->req_replay_counter, key->replay_counter, - WPA_REPLAY_COUNTER_LEN); - } else { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key request with " - "invalid MIC"); - return; - } - - /* - * TODO: should decrypt key data field if encryption was used; - * even though MAC address KDE is not normally encrypted, - * supplicant is allowed to encrypt it. - */ - if (msg == SMK_ERROR) { -#ifdef CONFIG_PEERKEY - wpa_smk_error(wpa_auth, sm, key); -#endif /* CONFIG_PEERKEY */ - return; - } else if (key_info & WPA_KEY_INFO_ERROR) { - if (wpa_receive_error_report( - wpa_auth, sm, - !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0) - return; /* STA entry was removed */ - } else if (key_info & WPA_KEY_INFO_KEY_TYPE) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key Request for new " - "4-Way Handshake"); - wpa_request_new_ptk(sm); -#ifdef CONFIG_PEERKEY - } else if (msg == SMK_M1) { - wpa_smk_m1(wpa_auth, sm, key); -#endif /* CONFIG_PEERKEY */ - } else if (key_data_length > 0 && - wpa_parse_kde_ies((const u8 *) (key + 1), - key_data_length, &kde) == 0 && - kde.mac_addr) { - } else { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key Request for GTK " - "rekeying"); - eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); - wpa_rekey_gtk(wpa_auth, NULL); - } - } else { - /* Do not allow the same key replay counter to be reused. */ - wpa_replay_counter_mark_invalid(sm->key_replay, - key->replay_counter); - - if (msg == PAIRWISE_2) { - /* - * Maintain a copy of the pending EAPOL-Key frames in - * case the EAPOL-Key frame was retransmitted. This is - * needed to allow EAPOL-Key msg 2/4 reply to another - * pending msg 1/4 to update the SNonce to work around - * unexpected supplicant behavior. - */ - os_memcpy(sm->prev_key_replay, sm->key_replay, - sizeof(sm->key_replay)); - } else { - os_memset(sm->prev_key_replay, 0, - sizeof(sm->prev_key_replay)); - } - - /* - * Make sure old valid counters are not accepted anymore and - * do not get copied again. - */ - wpa_replay_counter_mark_invalid(sm->key_replay, NULL); - } - -#ifdef CONFIG_PEERKEY - if (msg == SMK_M3) { - wpa_smk_m3(wpa_auth, sm, key); - return; - } -#endif /* CONFIG_PEERKEY */ - - os_free(sm->last_rx_eapol_key); - sm->last_rx_eapol_key = os_malloc(data_len); - if (sm->last_rx_eapol_key == NULL) - return; - 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); - os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN); - wpa_sm_step(sm); -} - - -static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr, - const u8 *gnonce, u8 *gtk, size_t gtk_len) -{ - u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + 16]; - u8 *pos; - int ret = 0; - - /* GTK = PRF-X(GMK, "Group key expansion", - * AA || GNonce || Time || random data) - * The example described in the IEEE 802.11 standard uses only AA and - * GNonce as inputs here. Add some more entropy since this derivation - * is done only at the Authenticator and as such, does not need to be - * exactly same. - */ - os_memcpy(data, addr, ETH_ALEN); - os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN); - pos = data + ETH_ALEN + WPA_NONCE_LEN; - wpa_get_ntp_timestamp(pos); - pos += 8; - if (random_get_bytes(pos, 16) < 0) - ret = -1; - -#ifdef CONFIG_IEEE80211W - sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len); -#else /* CONFIG_IEEE80211W */ - if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len) - < 0) - ret = -1; -#endif /* CONFIG_IEEE80211W */ - - return ret; -} - - -static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_authenticator *wpa_auth = eloop_ctx; - struct wpa_state_machine *sm = timeout_ctx; - - sm->pending_1_of_4_timeout = 0; - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout"); - sm->TimeoutEvt = TRUE; - wpa_sm_step(sm); -} - - -void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, int key_info, - const u8 *key_rsc, const u8 *nonce, - const u8 *kde, size_t kde_len, - int keyidx, int encr, int force_version) -{ - struct ieee802_1x_hdr *hdr; - struct wpa_eapol_key *key; - size_t len; - int alg; - int key_data_len, pad_len = 0; - u8 *buf, *pos; - int version, pairwise; - int i; - - len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key); - - if (force_version) - version = force_version; - else if (wpa_use_aes_cmac(sm)) - version = WPA_KEY_INFO_TYPE_AES_128_CMAC; - else if (sm->pairwise != WPA_CIPHER_TKIP) - version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; - else - version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; - - pairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE); - - wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d " - "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d " - "encr=%d)", - version, - (key_info & WPA_KEY_INFO_SECURE) ? 1 : 0, - (key_info & WPA_KEY_INFO_MIC) ? 1 : 0, - (key_info & WPA_KEY_INFO_ACK) ? 1 : 0, - (key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0, - pairwise, (unsigned long) kde_len, keyidx, encr); - - key_data_len = kde_len; - - if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || - version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) { - pad_len = key_data_len % 8; - if (pad_len) - pad_len = 8 - pad_len; - key_data_len += pad_len + 8; - } - - len += key_data_len; - - hdr = os_zalloc(len); - if (hdr == NULL) - return; - hdr->version = wpa_auth->conf.eapol_version; - hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; - hdr->length = host_to_be16(len - sizeof(*hdr)); - key = (struct wpa_eapol_key *) (hdr + 1); - - key->type = sm->wpa == WPA_VERSION_WPA2 ? - EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; - key_info |= version; - if (encr && sm->wpa == WPA_VERSION_WPA2) - key_info |= WPA_KEY_INFO_ENCR_KEY_DATA; - if (sm->wpa != WPA_VERSION_WPA2) - key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT; - WPA_PUT_BE16(key->key_info, key_info); - - alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group; - WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg)); - if (key_info & WPA_KEY_INFO_SMK_MESSAGE) - WPA_PUT_BE16(key->key_length, 0); - - /* FIX: STSL: what to use as key_replay_counter? */ - for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) { - sm->key_replay[i].valid = sm->key_replay[i - 1].valid; - os_memcpy(sm->key_replay[i].counter, - sm->key_replay[i - 1].counter, - WPA_REPLAY_COUNTER_LEN); - } - inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN); - os_memcpy(key->replay_counter, sm->key_replay[0].counter, - WPA_REPLAY_COUNTER_LEN); - sm->key_replay[0].valid = TRUE; - - if (nonce) - os_memcpy(key->key_nonce, nonce, WPA_NONCE_LEN); - - if (key_rsc) - os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN); - - if (kde && !encr) { - os_memcpy(key + 1, kde, kde_len); - WPA_PUT_BE16(key->key_data_length, kde_len); - } else if (encr && kde) { - buf = os_zalloc(key_data_len); - if (buf == NULL) { - os_free(hdr); - return; - } - pos = buf; - os_memcpy(pos, kde, kde_len); - pos += kde_len; - - if (pad_len) - *pos++ = 0xdd; - - wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data", - buf, key_data_len); - if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || - version == WPA_KEY_INFO_TYPE_AES_128_CMAC) { - if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf, - (u8 *) (key + 1))) { - os_free(hdr); - os_free(buf); - return; - } - WPA_PUT_BE16(key->key_data_length, key_data_len); - } else { - u8 ek[32]; - os_memcpy(key->key_iv, - sm->group->Counter + WPA_NONCE_LEN - 16, 16); - inc_byte_array(sm->group->Counter, WPA_NONCE_LEN); - os_memcpy(ek, key->key_iv, 16); - os_memcpy(ek + 16, sm->PTK.kek, 16); - os_memcpy(key + 1, buf, key_data_len); - rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len); - WPA_PUT_BE16(key->key_data_length, key_data_len); - } - os_free(buf); - } - - if (key_info & WPA_KEY_INFO_MIC) { - if (!sm->PTK_valid) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, - "PTK not valid when sending EAPOL-Key " - "frame"); - os_free(hdr); - return; - } - wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len, - key->key_mic); -#ifdef CONFIG_TESTING_OPTIONS - if (!pairwise && - wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0d && - drand48() < - wpa_auth->conf.corrupt_gtk_rekey_mic_probability) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "Corrupting group EAPOL-Key Key MIC"); - key->key_mic[0]++; - } -#endif /* CONFIG_TESTING_OPTIONS */ - } - - wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, - 1); - wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len, - sm->pairwise_set); - os_free(hdr); -} - - -static void wpa_send_eapol(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, int key_info, - const u8 *key_rsc, const u8 *nonce, - const u8 *kde, size_t kde_len, - int keyidx, int encr) -{ - int timeout_ms; - int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE; - int ctr; - - if (sm == NULL) - return; - - __wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len, - keyidx, encr, 0); - - ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr; - if (ctr == 1 && wpa_auth->conf.tx_status) - 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)) - sm->pending_1_of_4_timeout = 1; - wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry " - "counter %d)", timeout_ms, ctr); - eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000, - wpa_send_eapol_timeout, wpa_auth, sm); -} - - -static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len) -{ - struct ieee802_1x_hdr *hdr; - struct wpa_eapol_key *key; - u16 key_info; - int ret = 0; - u8 mic[16]; - - if (data_len < sizeof(*hdr) + sizeof(*key)) - return -1; - - hdr = (struct ieee802_1x_hdr *) data; - key = (struct wpa_eapol_key *) (hdr + 1); - key_info = WPA_GET_BE16(key->key_info); - os_memcpy(mic, key->key_mic, 16); - os_memset(key->key_mic, 0, 16); - if (wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK, - data, data_len, key->key_mic) || - os_memcmp(mic, key->key_mic, 16) != 0) - ret = -1; - os_memcpy(key->key_mic, mic, 16); - return ret; -} - - -void wpa_remove_ptk(struct wpa_state_machine *sm) -{ - sm->PTK_valid = FALSE; - os_memset(&sm->PTK, 0, sizeof(sm->PTK)); - wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL, 0); - sm->pairwise_set = FALSE; - eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); -} - - -int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) -{ - int remove_ptk = 1; - - if (sm == NULL) - return -1; - - wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "event %d notification", event); - - switch (event) { - case WPA_AUTH: - case WPA_ASSOC: - break; - case WPA_DEAUTH: - case WPA_DISASSOC: - sm->DeauthenticationRequest = TRUE; - break; - case WPA_REAUTH: - case WPA_REAUTH_EAPOL: - if (!sm->started) { - /* - * When using WPS, we may end up here if the STA - * manages to re-associate without the previous STA - * entry getting removed. Consequently, we need to make - * sure that the WPA state machines gets initialized - * properly at this point. - */ - wpa_printf(MSG_DEBUG, "WPA state machine had not been " - "started - initialize now"); - sm->started = 1; - sm->Init = TRUE; - if (wpa_sm_step(sm) == 1) - return 1; /* should not really happen */ - sm->Init = FALSE; - sm->AuthenticationRequest = TRUE; - break; - } - if (sm->GUpdateStationKeys) { - /* - * Reauthentication cancels the pending group key - * update for this STA. - */ - sm->group->GKeyDoneStations--; - sm->GUpdateStationKeys = FALSE; - sm->PtkGroupInit = TRUE; - } - sm->ReAuthenticationRequest = TRUE; - break; - case WPA_ASSOC_FT: -#ifdef CONFIG_IEEE80211R - wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration " - "after association"); - wpa_ft_install_ptk(sm); - - /* Using FT protocol, not WPA auth state machine */ - sm->ft_completed = 1; - return 0; -#else /* CONFIG_IEEE80211R */ - break; -#endif /* CONFIG_IEEE80211R */ - } - -#ifdef CONFIG_IEEE80211R - sm->ft_completed = 0; -#endif /* CONFIG_IEEE80211R */ - -#ifdef CONFIG_IEEE80211W - if (sm->mgmt_frame_prot && event == WPA_AUTH) - remove_ptk = 0; -#endif /* CONFIG_IEEE80211W */ - - if (remove_ptk) { - sm->PTK_valid = FALSE; - os_memset(&sm->PTK, 0, sizeof(sm->PTK)); - - if (event != WPA_REAUTH_EAPOL) - wpa_remove_ptk(sm); - } - - return wpa_sm_step(sm); -} - - -SM_STATE(WPA_PTK, INITIALIZE) -{ - SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk); - if (sm->Init) { - /* Init flag is not cleared here, so avoid busy - * loop by claiming nothing changed. */ - sm->changed = FALSE; - } - - sm->keycount = 0; - if (sm->GUpdateStationKeys) - sm->group->GKeyDoneStations--; - sm->GUpdateStationKeys = FALSE; - if (sm->wpa == WPA_VERSION_WPA) - sm->PInitAKeys = FALSE; - if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and - * Local AA > Remote AA)) */) { - sm->Pair = TRUE; - } - wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0); - wpa_remove_ptk(sm); - wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0); - sm->TimeoutCtr = 0; - if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { - wpa_auth_set_eapol(sm->wpa_auth, sm->addr, - WPA_EAPOL_authorized, 0); - } -} - - -SM_STATE(WPA_PTK, DISCONNECT) -{ - SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk); - sm->Disconnect = FALSE; - wpa_sta_disconnect(sm->wpa_auth, sm->addr); -} - - -SM_STATE(WPA_PTK, DISCONNECTED) -{ - SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk); - sm->DeauthenticationRequest = FALSE; -} - - -SM_STATE(WPA_PTK, AUTHENTICATION) -{ - SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk); - os_memset(&sm->PTK, 0, sizeof(sm->PTK)); - sm->PTK_valid = FALSE; - wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto, - 1); - wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1); - sm->AuthenticationRequest = FALSE; -} - - -static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth, - struct wpa_group *group) -{ - if (group->first_sta_seen) - return; - /* - * System has run bit further than at the time hostapd was started - * potentially very early during boot up. This provides better chances - * of collecting more randomness on embedded systems. Re-initialize the - * GMK and Counter here to improve their strength if there was not - * enough entropy available immediately after system startup. - */ - wpa_printf(MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first " - "station"); - if (random_pool_ready() != 1) { - wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool " - "to proceed - reject first 4-way handshake"); - group->reject_4way_hs_for_entropy = TRUE; - } else { - group->first_sta_seen = TRUE; - group->reject_4way_hs_for_entropy = FALSE; - } - - wpa_group_init_gmk_and_counter(wpa_auth, group); - wpa_gtk_update(wpa_auth, group); - wpa_group_config_group_keys(wpa_auth, group); -} - - -SM_STATE(WPA_PTK, AUTHENTICATION2) -{ - SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk); - - wpa_group_ensure_init(sm->wpa_auth, sm->group); - sm->ReAuthenticationRequest = FALSE; - - /* - * Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat - * ambiguous. The Authenticator state machine uses a counter that is - * incremented by one for each 4-way handshake. However, the security - * analysis of 4-way handshake points out that unpredictable nonces - * help in preventing precomputation attacks. Instead of the state - * machine definition, use an unpredictable nonce value here to provide - * stronger protection against potential precomputation attacks. - */ - if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) { - wpa_printf(MSG_ERROR, "WPA: Failed to get random data for " - "ANonce."); - sm->Disconnect = TRUE; - return; - } - wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce, - WPA_NONCE_LEN); - /* IEEE 802.11i does not clear TimeoutCtr here, but this is more - * logical place than INITIALIZE since AUTHENTICATION2 can be - * re-entered on ReAuthenticationRequest without going through - * INITIALIZE. */ - sm->TimeoutCtr = 0; -} - - -SM_STATE(WPA_PTK, INITPMK) -{ - u8 msk[2 * PMK_LEN]; - size_t len = 2 * PMK_LEN; - - SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk); -#ifdef CONFIG_IEEE80211R - sm->xxkey_len = 0; -#endif /* CONFIG_IEEE80211R */ - if (sm->pmksa) { - wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache"); - os_memcpy(sm->PMK, sm->pmksa->pmk, PMK_LEN); - } else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) { - wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine " - "(len=%lu)", (unsigned long) len); - os_memcpy(sm->PMK, msk, PMK_LEN); -#ifdef CONFIG_IEEE80211R - if (len >= 2 * PMK_LEN) { - os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN); - sm->xxkey_len = PMK_LEN; - } -#endif /* CONFIG_IEEE80211R */ - } else { - wpa_printf(MSG_DEBUG, "WPA: Could not get PMK"); - } - - sm->req_replay_counter_used = 0; - /* IEEE 802.11i does not set keyRun to FALSE, but not doing this - * will break reauthentication since EAPOL state machines may not be - * get into AUTHENTICATING state that clears keyRun before WPA state - * machine enters AUTHENTICATION2 state and goes immediately to INITPMK - * state and takes PMK from the previously used AAA Key. This will - * eventually fail in 4-Way Handshake because Supplicant uses PMK - * derived from the new AAA Key. Setting keyRun = FALSE here seems to - * be good workaround for this issue. */ - wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, 0); -} - - -SM_STATE(WPA_PTK, INITPSK) -{ - const u8 *psk; - SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk); - psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL); - if (psk) { - os_memcpy(sm->PMK, psk, PMK_LEN); -#ifdef CONFIG_IEEE80211R - os_memcpy(sm->xxkey, psk, PMK_LEN); - sm->xxkey_len = PMK_LEN; -#endif /* CONFIG_IEEE80211R */ - } - sm->req_replay_counter_used = 0; -} - - -SM_STATE(WPA_PTK, PTKSTART) -{ - u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN], *pmkid = NULL; - size_t pmkid_len = 0; - - SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk); - sm->PTKRequest = FALSE; - sm->TimeoutEvt = FALSE; - - sm->TimeoutCtr++; - if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) { - /* No point in sending the EAPOL-Key - we will disconnect - * immediately following this. */ - return; - } - - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "sending 1/4 msg of 4-Way Handshake"); - /* - * TODO: Could add PMKID even with WPA2-PSK, but only if there is only - * one possible PSK for this STA. - */ - if (sm->wpa == WPA_VERSION_WPA2 && - wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt)) { - pmkid = buf; - pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN; - pmkid[0] = WLAN_EID_VENDOR_SPECIFIC; - pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN; - RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID); - if (sm->pmksa) - os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN], - sm->pmksa->pmkid, PMKID_LEN); - else { - /* - * Calculate PMKID since no PMKSA cache entry was - * available with pre-calculated PMKID. - */ - rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr, - sm->addr, &pmkid[2 + RSN_SELECTOR_LEN], - wpa_key_mgmt_sha256(sm->wpa_key_mgmt)); - } - } - wpa_send_eapol(sm->wpa_auth, sm, - WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL, - sm->ANonce, pmkid, pmkid_len, 0, 0); -} - - -static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk, - struct wpa_ptk *ptk) -{ - size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64; -#ifdef CONFIG_IEEE80211R - if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) - return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len); -#endif /* CONFIG_IEEE80211R */ - - wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion", - sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce, - (u8 *) ptk, ptk_len, - wpa_key_mgmt_sha256(sm->wpa_key_mgmt)); - - return 0; -} - - -SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) -{ - struct wpa_ptk PTK; - int ok = 0; - const u8 *pmk = NULL; - - SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk); - sm->EAPOLKeyReceived = FALSE; - sm->update_snonce = FALSE; - - /* WPA with IEEE 802.1X: use the derived PMK from EAP - * WPA-PSK: iterate through possible PSKs and select the one matching - * the packet */ - for (;;) { - if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { - pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, - sm->p2p_dev_addr, pmk); - if (pmk == NULL) - break; - } else - pmk = sm->PMK; - - wpa_derive_ptk(sm, pmk, &PTK); - - if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key, - sm->last_rx_eapol_key_len) == 0) { - ok = 1; - break; - } - - if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) - break; - } - - if (!ok) { - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "invalid MIC in msg 2/4 of 4-Way Handshake"); - return; - } - -#ifdef CONFIG_IEEE80211R - if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { - /* - * Verify that PMKR1Name from EAPOL-Key message 2/4 matches - * with the value we derived. - */ - if (os_memcmp(sm->sup_pmk_r1_name, sm->pmk_r1_name, - WPA_PMK_NAME_LEN) != 0) { - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "PMKR1Name mismatch in FT 4-way " - "handshake"); - wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from " - "Supplicant", - sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN); - wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", - sm->pmk_r1_name, WPA_PMK_NAME_LEN); - return; - } - } -#endif /* CONFIG_IEEE80211R */ - - sm->pending_1_of_4_timeout = 0; - eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); - - if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { - /* PSK may have changed from the previous choice, so update - * state machine data based on whatever PSK was selected here. - */ - os_memcpy(sm->PMK, pmk, PMK_LEN); - } - - sm->MICVerified = TRUE; - - os_memcpy(&sm->PTK, &PTK, sizeof(PTK)); - sm->PTK_valid = TRUE; -} - - -SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2) -{ - SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING2, wpa_ptk); - sm->TimeoutCtr = 0; -} - - -#ifdef CONFIG_IEEE80211W - -static int ieee80211w_kde_len(struct wpa_state_machine *sm) -{ - if (sm->mgmt_frame_prot) { - return 2 + RSN_SELECTOR_LEN + sizeof(struct wpa_igtk_kde); - } - - return 0; -} - - -static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) -{ - struct wpa_igtk_kde igtk; - struct wpa_group *gsm = sm->group; - u8 rsc[WPA_KEY_RSC_LEN]; - - if (!sm->mgmt_frame_prot) - return pos; - - igtk.keyid[0] = gsm->GN_igtk; - igtk.keyid[1] = 0; - if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE || - wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, rsc) < 0) - os_memset(igtk.pn, 0, sizeof(igtk.pn)); - else - os_memcpy(igtk.pn, rsc, sizeof(igtk.pn)); - os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); - if (sm->wpa_auth->conf.disable_gtk) { - /* - * Provide unique random IGTK to each STA to prevent use of - * IGTK in the BSS. - */ - if (random_get_bytes(igtk.igtk, WPA_IGTK_LEN) < 0) - return pos; - } - pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK, - (const u8 *) &igtk, sizeof(igtk), NULL, 0); - - return pos; -} - -#else /* CONFIG_IEEE80211W */ - -static int ieee80211w_kde_len(struct wpa_state_machine *sm) -{ - return 0; -} - - -static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) -{ - return pos; -} - -#endif /* CONFIG_IEEE80211W */ - - -SM_STATE(WPA_PTK, PTKINITNEGOTIATING) -{ - u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32]; - size_t gtk_len, kde_len; - struct wpa_group *gsm = sm->group; - u8 *wpa_ie; - int wpa_ie_len, secure, keyidx, encr = 0; - - SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk); - sm->TimeoutEvt = FALSE; - - sm->TimeoutCtr++; - if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) { - /* No point in sending the EAPOL-Key - we will disconnect - * immediately following this. */ - return; - } - - /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE], - GTK[GN], IGTK, [FTIE], [TIE * 2]) - */ - os_memset(rsc, 0, WPA_KEY_RSC_LEN); - wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc); - /* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */ - wpa_ie = sm->wpa_auth->wpa_ie; - wpa_ie_len = sm->wpa_auth->wpa_ie_len; - if (sm->wpa == WPA_VERSION_WPA && - (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) && - wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) { - /* WPA-only STA, remove RSN IE */ - wpa_ie = wpa_ie + wpa_ie[1] + 2; - wpa_ie_len = wpa_ie[1] + 2; - } - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "sending 3/4 msg of 4-Way Handshake"); - if (sm->wpa == WPA_VERSION_WPA2) { - /* WPA2 send GTK in the 4-way handshake */ - secure = 1; - gtk = gsm->GTK[gsm->GN - 1]; - gtk_len = gsm->GTK_len; - if (sm->wpa_auth->conf.disable_gtk) { - /* - * Provide unique random GTK to each STA to prevent use - * of GTK in the BSS. - */ - if (random_get_bytes(dummy_gtk, gtk_len) < 0) - return; - gtk = dummy_gtk; - } - keyidx = gsm->GN; - _rsc = rsc; - encr = 1; - } else { - /* WPA does not include GTK in msg 3/4 */ - secure = 0; - gtk = NULL; - 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); - if (gtk) - kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len; -#ifdef CONFIG_IEEE80211R - if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { - kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */ - kde_len += 300; /* FTIE + 2 * TIE */ - } -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_P2P - if (WPA_GET_BE32(sm->ip_addr) > 0) - kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4; -#endif /* CONFIG_P2P */ - kde = os_malloc(kde_len); - if (kde == NULL) - return; - - pos = kde; - os_memcpy(pos, wpa_ie, wpa_ie_len); - pos += wpa_ie_len; -#ifdef CONFIG_IEEE80211R - if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { - int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name); - if (res < 0) { - wpa_printf(MSG_ERROR, "FT: Failed to insert " - "PMKR1Name into RSN IE in EAPOL-Key data"); - os_free(kde); - return; - } - pos += res; - } -#endif /* CONFIG_IEEE80211R */ - if (gtk) { - u8 hdr[2]; - hdr[0] = keyidx & 0x03; - hdr[1] = 0; - pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, - gtk, gtk_len); - } - pos = ieee80211w_kde_add(sm, pos); - -#ifdef CONFIG_IEEE80211R - if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { - int res; - struct wpa_auth_config *conf; - - conf = &sm->wpa_auth->conf; - res = wpa_write_ftie(conf, conf->r0_key_holder, - conf->r0_key_holder_len, - NULL, NULL, pos, kde + kde_len - pos, - NULL, 0); - if (res < 0) { - wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE " - "into EAPOL-Key Key Data"); - os_free(kde); - return; - } - pos += res; - - /* TIE[ReassociationDeadline] (TU) */ - *pos++ = WLAN_EID_TIMEOUT_INTERVAL; - *pos++ = 5; - *pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE; - WPA_PUT_LE32(pos, conf->reassociation_deadline); - pos += 4; - - /* TIE[KeyLifetime] (seconds) */ - *pos++ = WLAN_EID_TIMEOUT_INTERVAL; - *pos++ = 5; - *pos++ = WLAN_TIMEOUT_KEY_LIFETIME; - WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60); - pos += 4; - } -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_P2P - if (WPA_GET_BE32(sm->ip_addr) > 0) { - u8 addr[3 * 4]; - os_memcpy(addr, sm->ip_addr, 4); - os_memcpy(addr + 4, sm->wpa_auth->conf.ip_addr_mask, 4); - os_memcpy(addr + 8, sm->wpa_auth->conf.ip_addr_go, 4); - pos = wpa_add_kde(pos, WFA_KEY_DATA_IP_ADDR_ALLOC, - addr, sizeof(addr), NULL, 0); - } -#endif /* CONFIG_P2P */ - - wpa_send_eapol(sm->wpa_auth, sm, - (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC | - WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL | - WPA_KEY_INFO_KEY_TYPE, - _rsc, sm->ANonce, kde, pos - kde, keyidx, encr); - os_free(kde); -} - - -SM_STATE(WPA_PTK, PTKINITDONE) -{ - SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk); - sm->EAPOLKeyReceived = FALSE; - if (sm->Pair) { - enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise); - int klen = wpa_cipher_key_len(sm->pairwise); - if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, - sm->PTK.tk1, klen)) { - wpa_sta_disconnect(sm->wpa_auth, sm->addr); - return; - } - /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ - sm->pairwise_set = TRUE; - - if (sm->wpa_auth->conf.wpa_ptk_rekey) { - eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); - eloop_register_timeout(sm->wpa_auth->conf. - wpa_ptk_rekey, 0, wpa_rekey_ptk, - sm->wpa_auth, sm); - } - - if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { - wpa_auth_set_eapol(sm->wpa_auth, sm->addr, - WPA_EAPOL_authorized, 1); - } - } - - if (0 /* IBSS == TRUE */) { - sm->keycount++; - if (sm->keycount == 2) { - wpa_auth_set_eapol(sm->wpa_auth, sm->addr, - WPA_EAPOL_portValid, 1); - } - } else { - wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, - 1); - } - wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable, 0); - wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, 1); - if (sm->wpa == WPA_VERSION_WPA) - sm->PInitAKeys = TRUE; - else - sm->has_GTK = TRUE; - wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO, - "pairwise key handshake completed (%s)", - sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN"); - -#ifdef CONFIG_IEEE80211R - wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr); -#endif /* CONFIG_IEEE80211R */ -} - - -SM_STEP(WPA_PTK) -{ - struct wpa_authenticator *wpa_auth = sm->wpa_auth; - - if (sm->Init) - SM_ENTER(WPA_PTK, INITIALIZE); - else if (sm->Disconnect - /* || FIX: dot11RSNAConfigSALifetime timeout */) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, - "WPA_PTK: sm->Disconnect"); - SM_ENTER(WPA_PTK, DISCONNECT); - } - else if (sm->DeauthenticationRequest) - SM_ENTER(WPA_PTK, DISCONNECTED); - else if (sm->AuthenticationRequest) - SM_ENTER(WPA_PTK, AUTHENTICATION); - else if (sm->ReAuthenticationRequest) - SM_ENTER(WPA_PTK, AUTHENTICATION2); - else if (sm->PTKRequest) - SM_ENTER(WPA_PTK, PTKSTART); - else switch (sm->wpa_ptk_state) { - case WPA_PTK_INITIALIZE: - break; - case WPA_PTK_DISCONNECT: - SM_ENTER(WPA_PTK, DISCONNECTED); - break; - case WPA_PTK_DISCONNECTED: - SM_ENTER(WPA_PTK, INITIALIZE); - break; - case WPA_PTK_AUTHENTICATION: - SM_ENTER(WPA_PTK, AUTHENTICATION2); - break; - case WPA_PTK_AUTHENTICATION2: - if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) && - wpa_auth_get_eapol(sm->wpa_auth, sm->addr, - WPA_EAPOL_keyRun) > 0) - SM_ENTER(WPA_PTK, INITPMK); - else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) - /* FIX: && 802.1X::keyRun */) - SM_ENTER(WPA_PTK, INITPSK); - break; - case WPA_PTK_INITPMK: - if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr, - WPA_EAPOL_keyAvailable) > 0) - SM_ENTER(WPA_PTK, PTKSTART); - else { - wpa_auth->dot11RSNA4WayHandshakeFailures++; - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO, - "INITPMK - keyAvailable = false"); - SM_ENTER(WPA_PTK, DISCONNECT); - } - break; - case WPA_PTK_INITPSK: - if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, - NULL)) - SM_ENTER(WPA_PTK, PTKSTART); - else { - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO, - "no PSK configured for the STA"); - wpa_auth->dot11RSNA4WayHandshakeFailures++; - SM_ENTER(WPA_PTK, DISCONNECT); - } - break; - case WPA_PTK_PTKSTART: - if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && - sm->EAPOLKeyPairwise) - SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING); - else if (sm->TimeoutCtr > - (int) dot11RSNAConfigPairwiseUpdateCount) { - wpa_auth->dot11RSNA4WayHandshakeFailures++; - wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "PTKSTART: Retry limit %d reached", - dot11RSNAConfigPairwiseUpdateCount); - SM_ENTER(WPA_PTK, DISCONNECT); - } else if (sm->TimeoutEvt) - SM_ENTER(WPA_PTK, PTKSTART); - break; - case WPA_PTK_PTKCALCNEGOTIATING: - if (sm->MICVerified) - SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING2); - else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && - sm->EAPOLKeyPairwise) - SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING); - else if (sm->TimeoutEvt) - SM_ENTER(WPA_PTK, PTKSTART); - break; - case WPA_PTK_PTKCALCNEGOTIATING2: - SM_ENTER(WPA_PTK, PTKINITNEGOTIATING); - break; - case WPA_PTK_PTKINITNEGOTIATING: - if (sm->update_snonce) - SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING); - else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && - sm->EAPOLKeyPairwise && sm->MICVerified) - SM_ENTER(WPA_PTK, PTKINITDONE); - else if (sm->TimeoutCtr > - (int) dot11RSNAConfigPairwiseUpdateCount) { - wpa_auth->dot11RSNA4WayHandshakeFailures++; - wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "PTKINITNEGOTIATING: Retry limit %d " - "reached", - dot11RSNAConfigPairwiseUpdateCount); - SM_ENTER(WPA_PTK, DISCONNECT); - } else if (sm->TimeoutEvt) - SM_ENTER(WPA_PTK, PTKINITNEGOTIATING); - break; - case WPA_PTK_PTKINITDONE: - break; - } -} - - -SM_STATE(WPA_PTK_GROUP, IDLE) -{ - SM_ENTRY_MA(WPA_PTK_GROUP, IDLE, wpa_ptk_group); - if (sm->Init) { - /* Init flag is not cleared here, so avoid busy - * loop by claiming nothing changed. */ - sm->changed = FALSE; - } - sm->GTimeoutCtr = 0; -} - - -SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) -{ - u8 rsc[WPA_KEY_RSC_LEN]; - struct wpa_group *gsm = sm->group; - u8 *kde, *pos, hdr[2]; - size_t kde_len; - u8 *gtk, dummy_gtk[32]; - - SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group); - - sm->GTimeoutCtr++; - if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) { - /* No point in sending the EAPOL-Key - we will disconnect - * immediately following this. */ - return; - } - - if (sm->wpa == WPA_VERSION_WPA) - sm->PInitAKeys = FALSE; - sm->TimeoutEvt = FALSE; - /* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */ - os_memset(rsc, 0, WPA_KEY_RSC_LEN); - if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE) - wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc); - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "sending 1/2 msg of Group Key Handshake"); - - gtk = gsm->GTK[gsm->GN - 1]; - if (sm->wpa_auth->conf.disable_gtk) { - /* - * Provide unique random GTK to each STA to prevent use - * of GTK in the BSS. - */ - if (random_get_bytes(dummy_gtk, gsm->GTK_len) < 0) - return; - gtk = dummy_gtk; - } - if (sm->wpa == WPA_VERSION_WPA2) { - kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len + - ieee80211w_kde_len(sm); - kde = os_malloc(kde_len); - if (kde == NULL) - return; - - pos = kde; - hdr[0] = gsm->GN & 0x03; - hdr[1] = 0; - pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, - gtk, gsm->GTK_len); - pos = ieee80211w_kde_add(sm, pos); - } else { - kde = gtk; - pos = kde + gsm->GTK_len; - } - - wpa_send_eapol(sm->wpa_auth, sm, - WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | - WPA_KEY_INFO_ACK | - (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0), - rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1); - if (sm->wpa == WPA_VERSION_WPA2) - os_free(kde); -} - - -SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED) -{ - SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group); - sm->EAPOLKeyReceived = FALSE; - if (sm->GUpdateStationKeys) - sm->group->GKeyDoneStations--; - sm->GUpdateStationKeys = FALSE; - sm->GTimeoutCtr = 0; - /* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */ - wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO, - "group key handshake completed (%s)", - sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN"); - sm->has_GTK = TRUE; -} - - -SM_STATE(WPA_PTK_GROUP, KEYERROR) -{ - SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group); - if (sm->GUpdateStationKeys) - sm->group->GKeyDoneStations--; - sm->GUpdateStationKeys = FALSE; - sm->Disconnect = TRUE; -} - - -SM_STEP(WPA_PTK_GROUP) -{ - if (sm->Init || sm->PtkGroupInit) { - SM_ENTER(WPA_PTK_GROUP, IDLE); - sm->PtkGroupInit = FALSE; - } else switch (sm->wpa_ptk_group_state) { - case WPA_PTK_GROUP_IDLE: - if (sm->GUpdateStationKeys || - (sm->wpa == WPA_VERSION_WPA && sm->PInitAKeys)) - SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING); - break; - case WPA_PTK_GROUP_REKEYNEGOTIATING: - if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && - !sm->EAPOLKeyPairwise && sm->MICVerified) - SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED); - else if (sm->GTimeoutCtr > - (int) dot11RSNAConfigGroupUpdateCount) - SM_ENTER(WPA_PTK_GROUP, KEYERROR); - else if (sm->TimeoutEvt) - SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING); - break; - case WPA_PTK_GROUP_KEYERROR: - SM_ENTER(WPA_PTK_GROUP, IDLE); - break; - case WPA_PTK_GROUP_REKEYESTABLISHED: - SM_ENTER(WPA_PTK_GROUP, IDLE); - break; - } -} - - -static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, - struct wpa_group *group) -{ - int ret = 0; - - os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); - inc_byte_array(group->Counter, WPA_NONCE_LEN); - if (wpa_gmk_to_gtk(group->GMK, "Group key expansion", - wpa_auth->addr, group->GNonce, - group->GTK[group->GN - 1], group->GTK_len) < 0) - ret = -1; - wpa_hexdump_key(MSG_DEBUG, "GTK", - group->GTK[group->GN - 1], group->GTK_len); - -#ifdef CONFIG_IEEE80211W - if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) { - os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); - inc_byte_array(group->Counter, WPA_NONCE_LEN); - if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion", - wpa_auth->addr, group->GNonce, - group->IGTK[group->GN_igtk - 4], - WPA_IGTK_LEN) < 0) - ret = -1; - wpa_hexdump_key(MSG_DEBUG, "IGTK", - group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN); - } -#endif /* CONFIG_IEEE80211W */ - - return ret; -} - - -static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth, - struct wpa_group *group) -{ - wpa_printf(MSG_DEBUG, "WPA: group state machine entering state " - "GTK_INIT (VLAN-ID %d)", group->vlan_id); - group->changed = FALSE; /* GInit is not cleared here; avoid loop */ - group->wpa_group_state = WPA_GROUP_GTK_INIT; - - /* GTK[0..N] = 0 */ - os_memset(group->GTK, 0, sizeof(group->GTK)); - group->GN = 1; - group->GM = 2; -#ifdef CONFIG_IEEE80211W - group->GN_igtk = 4; - group->GM_igtk = 5; -#endif /* CONFIG_IEEE80211W */ - /* GTK[GN] = CalcGTK() */ - wpa_gtk_update(wpa_auth, group); -} - - -static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx) -{ - if (ctx != NULL && ctx != sm->group) - return 0; - - if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) { - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "Not in PTKINITDONE; skip Group Key update"); - sm->GUpdateStationKeys = FALSE; - return 0; - } - if (sm->GUpdateStationKeys) { - /* - * This should not really happen, so add a debug log entry. - * Since we clear the GKeyDoneStations before the loop, the - * station needs to be counted here anyway. - */ - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "GUpdateStationKeys was already set when " - "marking station for GTK rekeying"); - } - - /* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */ - if (sm->is_wnmsleep) - return 0; - - sm->group->GKeyDoneStations++; - sm->GUpdateStationKeys = TRUE; - - wpa_sm_step(sm); - return 0; -} - - -#ifdef CONFIG_WNM -/* update GTK when exiting WNM-Sleep Mode */ -void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm) -{ - if (sm == NULL || sm->is_wnmsleep) - return; - - wpa_group_update_sta(sm, NULL); -} - - -void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag) -{ - if (sm) - sm->is_wnmsleep = !!flag; -} - - -int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos) -{ - struct wpa_group *gsm = sm->group; - u8 *start = pos; - - /* - * GTK subelement: - * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] | - * Key[5..32] - */ - *pos++ = WNM_SLEEP_SUBELEM_GTK; - *pos++ = 11 + gsm->GTK_len; - /* Key ID in B0-B1 of Key Info */ - WPA_PUT_LE16(pos, gsm->GN & 0x03); - pos += 2; - *pos++ = gsm->GTK_len; - if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, pos) != 0) - return 0; - pos += 8; - os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len); - pos += gsm->GTK_len; - - wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit", - gsm->GN); - wpa_hexdump_key(MSG_DEBUG, "WNM: GTK in WNM-Sleep Mode exit", - gsm->GTK[gsm->GN - 1], gsm->GTK_len); - - return pos - start; -} - - -#ifdef CONFIG_IEEE80211W -int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos) -{ - struct wpa_group *gsm = sm->group; - u8 *start = pos; - - /* - * IGTK subelement: - * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16] - */ - *pos++ = WNM_SLEEP_SUBELEM_IGTK; - *pos++ = 2 + 6 + WPA_IGTK_LEN; - WPA_PUT_LE16(pos, gsm->GN_igtk); - pos += 2; - if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0) - return 0; - pos += 6; - - os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); - pos += WPA_IGTK_LEN; - - wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit", - gsm->GN_igtk); - wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit", - gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); - - return pos - start; -} -#endif /* CONFIG_IEEE80211W */ -#endif /* CONFIG_WNM */ - - -static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth, - struct wpa_group *group) -{ - int tmp; - - wpa_printf(MSG_DEBUG, "WPA: group state machine entering state " - "SETKEYS (VLAN-ID %d)", group->vlan_id); - group->changed = TRUE; - group->wpa_group_state = WPA_GROUP_SETKEYS; - group->GTKReKey = FALSE; - tmp = group->GM; - group->GM = group->GN; - group->GN = tmp; -#ifdef CONFIG_IEEE80211W - tmp = group->GM_igtk; - group->GM_igtk = group->GN_igtk; - group->GN_igtk = tmp; -#endif /* CONFIG_IEEE80211W */ - /* "GKeyDoneStations = GNoStations" is done in more robust way by - * counting the STAs that are marked with GUpdateStationKeys instead of - * including all STAs that could be in not-yet-completed state. */ - wpa_gtk_update(wpa_auth, group); - - if (group->GKeyDoneStations) { - wpa_printf(MSG_DEBUG, "wpa_group_setkeys: Unexpected " - "GKeyDoneStations=%d when starting new GTK rekey", - group->GKeyDoneStations); - group->GKeyDoneStations = 0; - } - wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group); - wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d", - group->GKeyDoneStations); -} - - -static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, - struct wpa_group *group) -{ - int ret = 0; - - if (wpa_auth_set_key(wpa_auth, group->vlan_id, - wpa_cipher_to_alg(wpa_auth->conf.wpa_group), - broadcast_ether_addr, group->GN, - group->GTK[group->GN - 1], group->GTK_len) < 0) - ret = -1; - -#ifdef CONFIG_IEEE80211W - if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION && - wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK, - broadcast_ether_addr, group->GN_igtk, - group->IGTK[group->GN_igtk - 4], - WPA_IGTK_LEN) < 0) - ret = -1; -#endif /* CONFIG_IEEE80211W */ - - return ret; -} - - -static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx) -{ - if (sm->group == ctx) { - wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR - " for discconnection due to fatal failure", - MAC2STR(sm->addr)); - sm->Disconnect = TRUE; - } - - return 0; -} - - -static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth, - struct wpa_group *group) -{ - wpa_printf(MSG_DEBUG, "WPA: group state machine entering state FATAL_FAILURE"); - group->changed = TRUE; - group->wpa_group_state = WPA_GROUP_FATAL_FAILURE; - wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group); -} - - -static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth, - struct wpa_group *group) -{ - wpa_printf(MSG_DEBUG, "WPA: group state machine entering state " - "SETKEYSDONE (VLAN-ID %d)", group->vlan_id); - group->changed = TRUE; - group->wpa_group_state = WPA_GROUP_SETKEYSDONE; - - if (wpa_group_config_group_keys(wpa_auth, group) < 0) { - wpa_group_fatal_failure(wpa_auth, group); - return -1; - } - - return 0; -} - - -static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, - struct wpa_group *group) -{ - if (group->GInit) { - wpa_group_gtk_init(wpa_auth, group); - } else if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) { - /* Do not allow group operations */ - } else if (group->wpa_group_state == WPA_GROUP_GTK_INIT && - group->GTKAuthenticator) { - wpa_group_setkeysdone(wpa_auth, group); - } else if (group->wpa_group_state == WPA_GROUP_SETKEYSDONE && - group->GTKReKey) { - wpa_group_setkeys(wpa_auth, group); - } else if (group->wpa_group_state == WPA_GROUP_SETKEYS) { - if (group->GKeyDoneStations == 0) - wpa_group_setkeysdone(wpa_auth, group); - else if (group->GTKReKey) - wpa_group_setkeys(wpa_auth, group); - } -} - - -static int wpa_sm_step(struct wpa_state_machine *sm) -{ - if (sm == NULL) - return 0; - - if (sm->in_step_loop) { - /* This should not happen, but if it does, make sure we do not - * end up freeing the state machine too early by exiting the - * recursive call. */ - wpa_printf(MSG_ERROR, "WPA: wpa_sm_step() called recursively"); - return 0; - } - - sm->in_step_loop = 1; - do { - if (sm->pending_deinit) - break; - - sm->changed = FALSE; - sm->wpa_auth->group->changed = FALSE; - - SM_STEP_RUN(WPA_PTK); - if (sm->pending_deinit) - break; - SM_STEP_RUN(WPA_PTK_GROUP); - if (sm->pending_deinit) - break; - wpa_group_sm_step(sm->wpa_auth, sm->group); - } while (sm->changed || sm->wpa_auth->group->changed); - sm->in_step_loop = 0; - - if (sm->pending_deinit) { - wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state " - "machine deinit for " MACSTR, MAC2STR(sm->addr)); - wpa_free_sta_sm(sm); - return 1; - } - return 0; -} - - -static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_state_machine *sm = eloop_ctx; - wpa_sm_step(sm); -} - - -void wpa_auth_sm_notify(struct wpa_state_machine *sm) -{ - if (sm == NULL) - return; - eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL); -} - - -void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth) -{ - int tmp, i; - struct wpa_group *group; - - if (wpa_auth == NULL) - return; - - group = wpa_auth->group; - - for (i = 0; i < 2; i++) { - tmp = group->GM; - group->GM = group->GN; - group->GN = tmp; -#ifdef CONFIG_IEEE80211W - tmp = group->GM_igtk; - group->GM_igtk = group->GN_igtk; - group->GN_igtk = tmp; -#endif /* CONFIG_IEEE80211W */ - wpa_gtk_update(wpa_auth, group); - wpa_group_config_group_keys(wpa_auth, group); - } -} - - -static const char * wpa_bool_txt(int bool) -{ - return bool ? "TRUE" : "FALSE"; -} - - -#define RSN_SUITE "%02x-%02x-%02x-%d" -#define RSN_SUITE_ARG(s) \ -((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff - -int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen) -{ - int len = 0, ret; - char pmkid_txt[PMKID_LEN * 2 + 1]; -#ifdef CONFIG_RSN_PREAUTH - const int preauth = 1; -#else /* CONFIG_RSN_PREAUTH */ - const int preauth = 0; -#endif /* CONFIG_RSN_PREAUTH */ - - if (wpa_auth == NULL) - return len; - - ret = os_snprintf(buf + len, buflen - len, - "dot11RSNAOptionImplemented=TRUE\n" - "dot11RSNAPreauthenticationImplemented=%s\n" - "dot11RSNAEnabled=%s\n" - "dot11RSNAPreauthenticationEnabled=%s\n", - wpa_bool_txt(preauth), - wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN), - wpa_bool_txt(wpa_auth->conf.rsn_preauth)); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt), - wpa_auth->dot11RSNAPMKIDUsed, PMKID_LEN); - - ret = os_snprintf( - buf + len, buflen - len, - "dot11RSNAConfigVersion=%u\n" - "dot11RSNAConfigPairwiseKeysSupported=9999\n" - /* FIX: dot11RSNAConfigGroupCipher */ - /* FIX: dot11RSNAConfigGroupRekeyMethod */ - /* FIX: dot11RSNAConfigGroupRekeyTime */ - /* FIX: dot11RSNAConfigGroupRekeyPackets */ - "dot11RSNAConfigGroupRekeyStrict=%u\n" - "dot11RSNAConfigGroupUpdateCount=%u\n" - "dot11RSNAConfigPairwiseUpdateCount=%u\n" - "dot11RSNAConfigGroupCipherSize=%u\n" - "dot11RSNAConfigPMKLifetime=%u\n" - "dot11RSNAConfigPMKReauthThreshold=%u\n" - "dot11RSNAConfigNumberOfPTKSAReplayCounters=0\n" - "dot11RSNAConfigSATimeout=%u\n" - "dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n" - "dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n" - "dot11RSNAGroupCipherSelected=" RSN_SUITE "\n" - "dot11RSNAPMKIDUsed=%s\n" - "dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n" - "dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n" - "dot11RSNAGroupCipherRequested=" RSN_SUITE "\n" - "dot11RSNATKIPCounterMeasuresInvoked=%u\n" - "dot11RSNA4WayHandshakeFailures=%u\n" - "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n", - RSN_VERSION, - !!wpa_auth->conf.wpa_strict_rekey, - dot11RSNAConfigGroupUpdateCount, - dot11RSNAConfigPairwiseUpdateCount, - wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8, - dot11RSNAConfigPMKLifetime, - dot11RSNAConfigPMKReauthThreshold, - dot11RSNAConfigSATimeout, - RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteSelected), - RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherSelected), - RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherSelected), - pmkid_txt, - RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteRequested), - RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherRequested), - RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherRequested), - wpa_auth->dot11RSNATKIPCounterMeasuresInvoked, - wpa_auth->dot11RSNA4WayHandshakeFailures); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - /* TODO: dot11RSNAConfigPairwiseCiphersTable */ - /* TODO: dot11RSNAConfigAuthenticationSuitesTable */ - - /* Private MIB */ - ret = os_snprintf(buf + len, buflen - len, "hostapdWPAGroupState=%d\n", - wpa_auth->group->wpa_group_state); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - return len; -} - - -int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen) -{ - int len = 0, ret; - u32 pairwise = 0; - - if (sm == NULL) - return 0; - - /* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */ - - /* dot11RSNAStatsEntry */ - - pairwise = wpa_cipher_to_suite(sm->wpa == WPA_VERSION_WPA2 ? - WPA_PROTO_RSN : WPA_PROTO_WPA, - sm->pairwise); - if (pairwise == 0) - return 0; - - ret = os_snprintf( - buf + len, buflen - len, - /* TODO: dot11RSNAStatsIndex */ - "dot11RSNAStatsSTAAddress=" MACSTR "\n" - "dot11RSNAStatsVersion=1\n" - "dot11RSNAStatsSelectedPairwiseCipher=" RSN_SUITE "\n" - /* TODO: dot11RSNAStatsTKIPICVErrors */ - "dot11RSNAStatsTKIPLocalMICFailures=%u\n" - "dot11RSNAStatsTKIPRemoteMICFailures=%u\n" - /* TODO: dot11RSNAStatsCCMPReplays */ - /* TODO: dot11RSNAStatsCCMPDecryptErrors */ - /* TODO: dot11RSNAStatsTKIPReplays */, - MAC2STR(sm->addr), - RSN_SUITE_ARG(pairwise), - sm->dot11RSNAStatsTKIPLocalMICFailures, - sm->dot11RSNAStatsTKIPRemoteMICFailures); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - /* Private MIB */ - ret = os_snprintf(buf + len, buflen - len, - "hostapdWPAPTKState=%d\n" - "hostapdWPAPTKGroupState=%d\n", - sm->wpa_ptk_state, - sm->wpa_ptk_group_state); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - return len; -} - - -void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth) -{ - if (wpa_auth) - wpa_auth->dot11RSNATKIPCounterMeasuresInvoked++; -} - - -int wpa_auth_pairwise_set(struct wpa_state_machine *sm) -{ - return sm && sm->pairwise_set; -} - - -int wpa_auth_get_pairwise(struct wpa_state_machine *sm) -{ - return sm->pairwise; -} - - -int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm) -{ - if (sm == NULL) - return -1; - return sm->wpa_key_mgmt; -} - - -int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm) -{ - if (sm == NULL) - return 0; - return sm->wpa; -} - - -int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, - struct rsn_pmksa_cache_entry *entry) -{ - if (sm == NULL || sm->pmksa != entry) - return -1; - sm->pmksa = NULL; - return 0; -} - - -struct rsn_pmksa_cache_entry * -wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm) -{ - return sm ? sm->pmksa : NULL; -} - - -void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm) -{ - if (sm) - sm->dot11RSNAStatsTKIPLocalMICFailures++; -} - - -const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len) -{ - if (wpa_auth == NULL) - return NULL; - *len = wpa_auth->wpa_ie_len; - return wpa_auth->wpa_ie; -} - - -int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk, - int session_timeout, struct eapol_state_machine *eapol) -{ - if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 || - sm->wpa_auth->conf.disable_pmksa_caching) - return -1; - - if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN, - sm->wpa_auth->addr, sm->addr, session_timeout, - eapol, sm->wpa_key_mgmt)) - return 0; - - return -1; -} - - -int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, - const u8 *pmk, size_t len, const u8 *sta_addr, - int session_timeout, - struct eapol_state_machine *eapol) -{ - if (wpa_auth == NULL) - return -1; - - if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr, - sta_addr, session_timeout, eapol, - WPA_KEY_MGMT_IEEE8021X)) - return 0; - - return -1; -} - - -void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth, - const u8 *sta_addr) -{ - struct rsn_pmksa_cache_entry *pmksa; - - if (wpa_auth == NULL || wpa_auth->pmksa == NULL) - return; - pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL); - if (pmksa) { - wpa_printf(MSG_DEBUG, "WPA: Remove PMKSA cache entry for " - MACSTR " based on request", MAC2STR(sta_addr)); - pmksa_cache_free_entry(wpa_auth->pmksa, pmksa); - } -} - - -static struct wpa_group * -wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id) -{ - struct wpa_group *group; - - if (wpa_auth == NULL || wpa_auth->group == NULL) - return NULL; - - wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d", - vlan_id); - group = wpa_group_init(wpa_auth, vlan_id, 0); - if (group == NULL) - return NULL; - - group->next = wpa_auth->group->next; - wpa_auth->group->next = group; - - return group; -} - - -int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id) -{ - struct wpa_group *group; - - if (sm == NULL || sm->wpa_auth == NULL) - return 0; - - group = sm->wpa_auth->group; - while (group) { - if (group->vlan_id == vlan_id) - break; - group = group->next; - } - - if (group == NULL) { - group = wpa_auth_add_group(sm->wpa_auth, vlan_id); - if (group == NULL) - return -1; - } - - if (sm->group == group) - return 0; - - if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) - return -1; - - wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state " - "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id); - - sm->group = group; - return 0; -} - - -void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, int ack) -{ - if (wpa_auth == NULL || sm == NULL) - return; - wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR - " ack=%d", MAC2STR(sm->addr), ack); - if (sm->pending_1_of_4_timeout && ack) { - /* - * Some deployed supplicant implementations update their SNonce - * for each EAPOL-Key 2/4 message even within the same 4-way - * handshake and then fail to use the first SNonce when - * deriving the PTK. This results in unsuccessful 4-way - * handshake whenever the relatively short initial timeout is - * reached and EAPOL-Key 1/4 is retransmitted. Try to work - * around this by increasing the timeout now that we know that - * the station has received the frame. - */ - int timeout_ms = eapol_key_timeout_subseq; - wpa_printf(MSG_DEBUG, "WPA: Increase initial EAPOL-Key 1/4 " - "timeout by %u ms because of acknowledged frame", - timeout_ms); - eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm); - eloop_register_timeout(timeout_ms / 1000, - (timeout_ms % 1000) * 1000, - wpa_send_eapol_timeout, wpa_auth, sm); - } -} - - -int wpa_auth_uses_sae(struct wpa_state_machine *sm) -{ - if (sm == NULL) - return 0; - return wpa_key_mgmt_sae(sm->wpa_key_mgmt); -} - - -int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm) -{ - if (sm == NULL) - return 0; - return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE; -} - - -#ifdef CONFIG_P2P -int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr) -{ - if (sm == NULL || WPA_GET_BE32(sm->ip_addr) == 0) - return -1; - os_memcpy(addr, sm->ip_addr, 4); - return 0; -} -#endif /* CONFIG_P2P */ diff --git a/contrib/hostapd/src/ap/wpa_auth.h b/contrib/hostapd/src/ap/wpa_auth.h deleted file mode 100644 index bc3dec45a0..0000000000 --- a/contrib/hostapd/src/ap/wpa_auth.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * hostapd - IEEE 802.11i-2004 / WPA Authenticator - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_AUTH_H -#define WPA_AUTH_H - -#include "common/defs.h" -#include "common/eapol_common.h" -#include "common/wpa_common.h" - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -/* IEEE Std 802.11r-2008, 11A.10.3 - Remote request/response frame definition - */ -struct ft_rrb_frame { - u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ - u8 packet_type; /* FT_PACKET_REQUEST/FT_PACKET_RESPONSE */ - le16 action_length; /* little endian length of action_frame */ - u8 ap_address[ETH_ALEN]; - /* - * Followed by action_length bytes of FT Action frame (from Category - * field to the end of Action Frame body. - */ -} STRUCT_PACKED; - -#define RSN_REMOTE_FRAME_TYPE_FT_RRB 1 - -#define FT_PACKET_REQUEST 0 -#define FT_PACKET_RESPONSE 1 -/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */ -#define FT_PACKET_R0KH_R1KH_PULL 200 -#define FT_PACKET_R0KH_R1KH_RESP 201 -#define FT_PACKET_R0KH_R1KH_PUSH 202 - -#define FT_R0KH_R1KH_PULL_DATA_LEN 44 -#define FT_R0KH_R1KH_RESP_DATA_LEN 76 -#define FT_R0KH_R1KH_PUSH_DATA_LEN 88 - -struct ft_r0kh_r1kh_pull_frame { - u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ - u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */ - le16 data_length; /* little endian length of data (44) */ - u8 ap_address[ETH_ALEN]; - - u8 nonce[16]; - u8 pmk_r0_name[WPA_PMK_NAME_LEN]; - u8 r1kh_id[FT_R1KH_ID_LEN]; - u8 s1kh_id[ETH_ALEN]; - u8 pad[4]; /* 8-octet boundary for AES key wrap */ - u8 key_wrap_extra[8]; -} STRUCT_PACKED; - -struct ft_r0kh_r1kh_resp_frame { - u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ - u8 packet_type; /* FT_PACKET_R0KH_R1KH_RESP */ - le16 data_length; /* little endian length of data (76) */ - u8 ap_address[ETH_ALEN]; - - u8 nonce[16]; /* copied from pull */ - u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */ - u8 s1kh_id[ETH_ALEN]; /* copied from pull */ - u8 pmk_r1[PMK_LEN]; - u8 pmk_r1_name[WPA_PMK_NAME_LEN]; - le16 pairwise; - u8 pad[2]; /* 8-octet boundary for AES key wrap */ - u8 key_wrap_extra[8]; -} STRUCT_PACKED; - -struct ft_r0kh_r1kh_push_frame { - u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ - u8 packet_type; /* FT_PACKET_R0KH_R1KH_PUSH */ - le16 data_length; /* little endian length of data (88) */ - u8 ap_address[ETH_ALEN]; - - /* Encrypted with AES key-wrap */ - u8 timestamp[4]; /* current time in seconds since unix epoch, little - * endian */ - u8 r1kh_id[FT_R1KH_ID_LEN]; - u8 s1kh_id[ETH_ALEN]; - u8 pmk_r0_name[WPA_PMK_NAME_LEN]; - u8 pmk_r1[PMK_LEN]; - u8 pmk_r1_name[WPA_PMK_NAME_LEN]; - le16 pairwise; - u8 pad[6]; /* 8-octet boundary for AES key wrap */ - u8 key_wrap_extra[8]; -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - - -/* per STA state machine data */ - -struct wpa_authenticator; -struct wpa_state_machine; -struct rsn_pmksa_cache_entry; -struct eapol_state_machine; - - -struct ft_remote_r0kh { - struct ft_remote_r0kh *next; - u8 addr[ETH_ALEN]; - u8 id[FT_R0KH_ID_MAX_LEN]; - size_t id_len; - u8 key[16]; -}; - - -struct ft_remote_r1kh { - struct ft_remote_r1kh *next; - u8 addr[ETH_ALEN]; - u8 id[FT_R1KH_ID_LEN]; - u8 key[16]; -}; - - -struct wpa_auth_config { - int wpa; - int wpa_key_mgmt; - int wpa_pairwise; - int wpa_group; - int wpa_group_rekey; - int wpa_strict_rekey; - int wpa_gmk_rekey; - int wpa_ptk_rekey; - int rsn_pairwise; - int rsn_preauth; - int eapol_version; - int peerkey; - int wmm_enabled; - int wmm_uapsd; - int disable_pmksa_caching; - int okc; - int tx_status; -#ifdef CONFIG_IEEE80211W - enum mfp_options ieee80211w; -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_IEEE80211R -#define SSID_LEN 32 - u8 ssid[SSID_LEN]; - size_t ssid_len; - u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; - u8 r0_key_holder[FT_R0KH_ID_MAX_LEN]; - size_t r0_key_holder_len; - u8 r1_key_holder[FT_R1KH_ID_LEN]; - u32 r0_key_lifetime; - u32 reassociation_deadline; - struct ft_remote_r0kh *r0kh_list; - struct ft_remote_r1kh *r1kh_list; - int pmk_r1_push; - int ft_over_ds; -#endif /* CONFIG_IEEE80211R */ - int disable_gtk; - int ap_mlme; -#ifdef CONFIG_TESTING_OPTIONS - double corrupt_gtk_rekey_mic_probability; -#endif /* CONFIG_TESTING_OPTIONS */ -#ifdef CONFIG_P2P - u8 ip_addr_go[4]; - u8 ip_addr_mask[4]; - u8 ip_addr_start[4]; - u8 ip_addr_end[4]; -#endif /* CONFIG_P2P */ -}; - -typedef enum { - LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING -} logger_level; - -typedef enum { - WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized, - WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable, - WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx -} wpa_eapol_variable; - -struct wpa_auth_callbacks { - void *ctx; - void (*logger)(void *ctx, const u8 *addr, logger_level level, - const char *txt); - void (*disconnect)(void *ctx, const u8 *addr, u16 reason); - int (*mic_failure_report)(void *ctx, const u8 *addr); - void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var, - int value); - int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var); - const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *p2p_dev_addr, - const u8 *prev_psk); - int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len); - int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg, - const u8 *addr, int idx, u8 *key, size_t key_len); - int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq); - int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data, - size_t data_len, int encrypt); - int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm, - void *ctx), void *cb_ctx); - int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a, - void *ctx), void *cb_ctx); - int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data, - size_t data_len); -#ifdef CONFIG_IEEE80211R - struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr); - int (*send_ft_action)(void *ctx, const u8 *dst, - const u8 *data, size_t data_len); - int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie, - size_t tspec_ielen); -#endif /* CONFIG_IEEE80211R */ -}; - -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); - -enum { - WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE, - WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL, - WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER, - WPA_INVALID_MDIE, WPA_INVALID_PROTO -}; - -int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, - const u8 *wpa_ie, size_t wpa_ie_len, - const u8 *mdie, size_t mdie_len); -int wpa_auth_uses_mfp(struct wpa_state_machine *sm); -struct wpa_state_machine * -wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr, - const u8 *p2p_dev_addr); -int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm); -void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm); -void wpa_auth_sta_deinit(struct wpa_state_machine *sm); -void wpa_receive(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, - u8 *data, size_t data_len); -typedef enum { - WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH, - WPA_REAUTH_EAPOL, WPA_ASSOC_FT -} wpa_event; -void wpa_remove_ptk(struct wpa_state_machine *sm); -int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event); -void wpa_auth_sm_notify(struct wpa_state_machine *sm); -void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth); -int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen); -int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen); -void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth); -int wpa_auth_pairwise_set(struct wpa_state_machine *sm); -int wpa_auth_get_pairwise(struct wpa_state_machine *sm); -int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm); -int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm); -int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, - struct rsn_pmksa_cache_entry *entry); -struct rsn_pmksa_cache_entry * -wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm); -void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm); -const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, - size_t *len); -int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk, - int session_timeout, struct eapol_state_machine *eapol); -int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, - const u8 *pmk, size_t len, const u8 *sta_addr, - int session_timeout, - struct eapol_state_machine *eapol); -void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth, - const u8 *sta_addr); -int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id); -void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, int ack); - -#ifdef CONFIG_IEEE80211R -u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, - size_t max_len, int auth_alg, - const u8 *req_ies, size_t req_ies_len); -void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, - u16 auth_transaction, const u8 *ies, size_t ies_len, - void (*cb)(void *ctx, const u8 *dst, const u8 *bssid, - u16 auth_transaction, u16 resp, - const u8 *ies, size_t ies_len), - void *ctx); -u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, - size_t ies_len); -int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len); -int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, - const u8 *data, size_t data_len); -void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr); -#endif /* CONFIG_IEEE80211R */ - -void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm); -void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag); -int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos); -int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos); - -int wpa_auth_uses_sae(struct wpa_state_machine *sm); -int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm); - -int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr); - -#endif /* WPA_AUTH_H */ diff --git a/contrib/hostapd/src/ap/wpa_auth_ft.c b/contrib/hostapd/src/ap/wpa_auth_ft.c deleted file mode 100644 index c22c4ccae3..0000000000 --- a/contrib/hostapd/src/ap/wpa_auth_ft.c +++ /dev/null @@ -1,1662 +0,0 @@ -/* - * hostapd - IEEE 802.11r - Fast BSS Transition - * Copyright (c) 2004-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "crypto/aes_wrap.h" -#include "crypto/random.h" -#include "ap_config.h" -#include "ieee802_11.h" -#include "wmm.h" -#include "wpa_auth.h" -#include "wpa_auth_i.h" - - -#ifdef CONFIG_IEEE80211R - -static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst, - const u8 *data, size_t data_len) -{ - if (wpa_auth->cb.send_ether == NULL) - return -1; - wpa_printf(MSG_DEBUG, "FT: RRB send to " MACSTR, MAC2STR(dst)); - return wpa_auth->cb.send_ether(wpa_auth->cb.ctx, dst, ETH_P_RRB, - data, data_len); -} - - -static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth, - const u8 *dst, const u8 *data, size_t data_len) -{ - if (wpa_auth->cb.send_ft_action == NULL) - return -1; - return wpa_auth->cb.send_ft_action(wpa_auth->cb.ctx, dst, - data, data_len); -} - - -static struct wpa_state_machine * -wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr) -{ - if (wpa_auth->cb.add_sta == NULL) - return NULL; - return wpa_auth->cb.add_sta(wpa_auth->cb.ctx, sta_addr); -} - - -static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth, - const u8 *sta_addr, - u8 *tspec_ie, size_t tspec_ielen) -{ - if (wpa_auth->cb.add_tspec == NULL) { - wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized"); - return -1; - } - return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie, - tspec_ielen); -} - - -int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len) -{ - u8 *pos = buf; - u8 capab; - if (len < 2 + sizeof(struct rsn_mdie)) - return -1; - - *pos++ = WLAN_EID_MOBILITY_DOMAIN; - *pos++ = MOBILITY_DOMAIN_ID_LEN + 1; - os_memcpy(pos, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN); - pos += MOBILITY_DOMAIN_ID_LEN; - capab = 0; - if (conf->ft_over_ds) - capab |= RSN_FT_CAPAB_FT_OVER_DS; - *pos++ = capab; - - return pos - buf; -} - - -int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id, - size_t r0kh_id_len, - const u8 *anonce, const u8 *snonce, - u8 *buf, size_t len, const u8 *subelem, - size_t subelem_len) -{ - u8 *pos = buf, *ielen; - struct rsn_ftie *hdr; - - if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len + - subelem_len) - return -1; - - *pos++ = WLAN_EID_FAST_BSS_TRANSITION; - ielen = pos++; - - hdr = (struct rsn_ftie *) pos; - os_memset(hdr, 0, sizeof(*hdr)); - pos += sizeof(*hdr); - WPA_PUT_LE16(hdr->mic_control, 0); - if (anonce) - os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN); - if (snonce) - os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN); - - /* Optional Parameters */ - *pos++ = FTIE_SUBELEM_R1KH_ID; - *pos++ = FT_R1KH_ID_LEN; - os_memcpy(pos, conf->r1_key_holder, FT_R1KH_ID_LEN); - pos += FT_R1KH_ID_LEN; - - if (r0kh_id) { - *pos++ = FTIE_SUBELEM_R0KH_ID; - *pos++ = r0kh_id_len; - os_memcpy(pos, r0kh_id, r0kh_id_len); - pos += r0kh_id_len; - } - - if (subelem) { - os_memcpy(pos, subelem, subelem_len); - pos += subelem_len; - } - - *ielen = pos - buf - 2; - - return pos - buf; -} - - -struct wpa_ft_pmk_r0_sa { - struct wpa_ft_pmk_r0_sa *next; - u8 pmk_r0[PMK_LEN]; - u8 pmk_r0_name[WPA_PMK_NAME_LEN]; - u8 spa[ETH_ALEN]; - int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ - /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */ - int pmk_r1_pushed; -}; - -struct wpa_ft_pmk_r1_sa { - struct wpa_ft_pmk_r1_sa *next; - u8 pmk_r1[PMK_LEN]; - u8 pmk_r1_name[WPA_PMK_NAME_LEN]; - u8 spa[ETH_ALEN]; - int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ - /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */ -}; - -struct wpa_ft_pmk_cache { - struct wpa_ft_pmk_r0_sa *pmk_r0; - struct wpa_ft_pmk_r1_sa *pmk_r1; -}; - -struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void) -{ - struct wpa_ft_pmk_cache *cache; - - cache = os_zalloc(sizeof(*cache)); - - return cache; -} - - -void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache) -{ - struct wpa_ft_pmk_r0_sa *r0, *r0prev; - struct wpa_ft_pmk_r1_sa *r1, *r1prev; - - r0 = cache->pmk_r0; - while (r0) { - r0prev = r0; - r0 = r0->next; - os_memset(r0prev->pmk_r0, 0, PMK_LEN); - os_free(r0prev); - } - - r1 = cache->pmk_r1; - while (r1) { - r1prev = r1; - r1 = r1->next; - os_memset(r1prev->pmk_r1, 0, PMK_LEN); - os_free(r1prev); - } - - os_free(cache); -} - - -static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth, - const u8 *spa, const u8 *pmk_r0, - const u8 *pmk_r0_name, int pairwise) -{ - struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; - struct wpa_ft_pmk_r0_sa *r0; - - /* TODO: add expiration and limit on number of entries in cache */ - - r0 = os_zalloc(sizeof(*r0)); - if (r0 == NULL) - return -1; - - os_memcpy(r0->pmk_r0, pmk_r0, PMK_LEN); - os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN); - os_memcpy(r0->spa, spa, ETH_ALEN); - r0->pairwise = pairwise; - - r0->next = cache->pmk_r0; - cache->pmk_r0 = r0; - - return 0; -} - - -static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth, - const u8 *spa, const u8 *pmk_r0_name, - u8 *pmk_r0, int *pairwise) -{ - struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; - struct wpa_ft_pmk_r0_sa *r0; - - r0 = cache->pmk_r0; - while (r0) { - if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 && - os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN) - == 0) { - os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN); - if (pairwise) - *pairwise = r0->pairwise; - return 0; - } - - r0 = r0->next; - } - - return -1; -} - - -static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth, - const u8 *spa, const u8 *pmk_r1, - const u8 *pmk_r1_name, int pairwise) -{ - struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; - struct wpa_ft_pmk_r1_sa *r1; - - /* TODO: add expiration and limit on number of entries in cache */ - - r1 = os_zalloc(sizeof(*r1)); - if (r1 == NULL) - return -1; - - os_memcpy(r1->pmk_r1, pmk_r1, PMK_LEN); - os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN); - os_memcpy(r1->spa, spa, ETH_ALEN); - r1->pairwise = pairwise; - - r1->next = cache->pmk_r1; - cache->pmk_r1 = r1; - - return 0; -} - - -static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth, - const u8 *spa, const u8 *pmk_r1_name, - u8 *pmk_r1, int *pairwise) -{ - struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; - struct wpa_ft_pmk_r1_sa *r1; - - r1 = cache->pmk_r1; - while (r1) { - if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 && - os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN) - == 0) { - os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN); - if (pairwise) - *pairwise = r1->pairwise; - return 0; - } - - r1 = r1->next; - } - - return -1; -} - - -static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth, - const u8 *s1kh_id, const u8 *r0kh_id, - size_t r0kh_id_len, const u8 *pmk_r0_name) -{ - struct ft_remote_r0kh *r0kh; - struct ft_r0kh_r1kh_pull_frame frame, f; - - r0kh = wpa_auth->conf.r0kh_list; - while (r0kh) { - if (r0kh->id_len == r0kh_id_len && - os_memcmp(r0kh->id, r0kh_id, r0kh_id_len) == 0) - break; - r0kh = r0kh->next; - } - if (r0kh == NULL) - return -1; - - wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH " - "address " MACSTR, MAC2STR(r0kh->addr)); - - os_memset(&frame, 0, sizeof(frame)); - frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB; - frame.packet_type = FT_PACKET_R0KH_R1KH_PULL; - frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN); - os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN); - - /* aes_wrap() does not support inplace encryption, so use a temporary - * buffer for the data. */ - if (random_get_bytes(f.nonce, sizeof(f.nonce))) { - wpa_printf(MSG_DEBUG, "FT: Failed to get random data for " - "nonce"); - return -1; - } - os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN); - os_memcpy(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN); - os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN); - os_memset(f.pad, 0, sizeof(f.pad)); - - if (aes_wrap(r0kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8, - f.nonce, frame.nonce) < 0) - return -1; - - wpa_ft_rrb_send(wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame)); - - return 0; -} - - -int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, - struct wpa_ptk *ptk, size_t ptk_len) -{ - u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN]; - u8 pmk_r1[PMK_LEN]; - u8 ptk_name[WPA_PMK_NAME_LEN]; - const u8 *mdid = sm->wpa_auth->conf.mobility_domain; - const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder; - size_t r0kh_len = sm->wpa_auth->conf.r0_key_holder_len; - const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder; - const u8 *ssid = sm->wpa_auth->conf.ssid; - size_t ssid_len = sm->wpa_auth->conf.ssid_len; - - - if (sm->xxkey_len == 0) { - wpa_printf(MSG_DEBUG, "FT: XXKey not available for key " - "derivation"); - return -1; - } - - wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid, - r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name); - wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN); - wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name, - sm->pairwise); - - wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr, - pmk_r1, sm->pmk_r1_name); - wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name, - WPA_PMK_NAME_LEN); - wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name, - sm->pairwise); - - wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr, - sm->wpa_auth->addr, sm->pmk_r1_name, - (u8 *) ptk, ptk_len, ptk_name); - wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len); - wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); - - return 0; -} - - -static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth, - const u8 *addr, int idx, u8 *seq) -{ - if (wpa_auth->cb.get_seqnum == NULL) - return -1; - return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq); -} - - -static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len) -{ - u8 *subelem; - struct wpa_group *gsm = sm->group; - size_t subelem_len, pad_len; - const u8 *key; - size_t key_len; - u8 keybuf[32]; - - key_len = gsm->GTK_len; - if (key_len > sizeof(keybuf)) - return NULL; - - /* - * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less - * than 16 bytes. - */ - pad_len = key_len % 8; - if (pad_len) - pad_len = 8 - pad_len; - if (key_len + pad_len < 16) - pad_len += 8; - if (pad_len && key_len < sizeof(keybuf)) { - os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len); - os_memset(keybuf + key_len, 0, pad_len); - keybuf[key_len] = 0xdd; - key_len += pad_len; - key = keybuf; - } else - key = gsm->GTK[gsm->GN - 1]; - - /* - * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] | - * Key[5..32]. - */ - subelem_len = 13 + key_len + 8; - subelem = os_zalloc(subelem_len); - if (subelem == NULL) - return NULL; - - subelem[0] = FTIE_SUBELEM_GTK; - subelem[1] = 11 + key_len + 8; - /* Key ID in B0-B1 of Key Info */ - WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03); - subelem[4] = gsm->GTK_len; - wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5); - if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) { - os_free(subelem); - return NULL; - } - - *len = subelem_len; - return subelem; -} - - -#ifdef CONFIG_IEEE80211W -static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len) -{ - u8 *subelem, *pos; - struct wpa_group *gsm = sm->group; - size_t subelem_len; - - /* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] | - * Key[16+8] */ - subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8; - subelem = os_zalloc(subelem_len); - if (subelem == NULL) - return NULL; - - pos = subelem; - *pos++ = FTIE_SUBELEM_IGTK; - *pos++ = subelem_len - 2; - WPA_PUT_LE16(pos, gsm->GN_igtk); - pos += 2; - wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos); - pos += 6; - *pos++ = WPA_IGTK_LEN; - if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8, - gsm->IGTK[gsm->GN_igtk - 4], pos)) { - os_free(subelem); - return NULL; - } - - *len = subelem_len; - return subelem; -} -#endif /* CONFIG_IEEE80211W */ - - -static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm, - u8 *pos, u8 *end, u8 id, u8 descr_count, - const u8 *ies, size_t ies_len) -{ - struct ieee802_11_elems parse; - struct rsn_rdie *rdie; - - wpa_printf(MSG_DEBUG, "FT: Resource Request: id=%d descr_count=%d", - id, descr_count); - wpa_hexdump(MSG_MSGDUMP, "FT: Resource descriptor IE(s)", - ies, ies_len); - - if (end - pos < (int) sizeof(*rdie)) { - wpa_printf(MSG_ERROR, "FT: Not enough room for response RDIE"); - return pos; - } - - *pos++ = WLAN_EID_RIC_DATA; - *pos++ = sizeof(*rdie); - rdie = (struct rsn_rdie *) pos; - rdie->id = id; - rdie->descr_count = 0; - rdie->status_code = host_to_le16(WLAN_STATUS_SUCCESS); - pos += sizeof(*rdie); - - if (ieee802_11_parse_elems((u8 *) ies, ies_len, &parse, 1) == - ParseFailed) { - wpa_printf(MSG_DEBUG, "FT: Failed to parse request IEs"); - rdie->status_code = - host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); - return pos; - } - -#ifdef NEED_AP_MLME - if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) { - struct wmm_tspec_element *tspec; - int res; - - if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) { - wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE " - "(%d)", (int) parse.wmm_tspec_len); - rdie->status_code = - host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); - return pos; - } - if (end - pos < (int) sizeof(*tspec)) { - wpa_printf(MSG_ERROR, "FT: Not enough room for " - "response TSPEC"); - rdie->status_code = - host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); - return pos; - } - tspec = (struct wmm_tspec_element *) pos; - os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec)); - res = wmm_process_tspec(tspec); - wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res); - if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS) - rdie->status_code = - host_to_le16(WLAN_STATUS_INVALID_PARAMETERS); - else if (res == WMM_ADDTS_STATUS_REFUSED) - rdie->status_code = - host_to_le16(WLAN_STATUS_REQUEST_DECLINED); - else { - /* TSPEC accepted; include updated TSPEC in response */ - rdie->descr_count = 1; - pos += sizeof(*tspec); - } - return pos; - } -#endif /* NEED_AP_MLME */ - - if (parse.wmm_tspec && !sm->wpa_auth->conf.ap_mlme) { - struct wmm_tspec_element *tspec; - int res; - - tspec = (struct wmm_tspec_element *) pos; - os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec)); - res = wpa_ft_add_tspec(sm->wpa_auth, sm->addr, pos, - sizeof(*tspec)); - if (res >= 0) { - if (res) - rdie->status_code = host_to_le16(res); - else { - /* TSPEC accepted; include updated TSPEC in - * response */ - rdie->descr_count = 1; - pos += sizeof(*tspec); - } - return pos; - } - } - - wpa_printf(MSG_DEBUG, "FT: No supported resource requested"); - rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); - return pos; -} - - -static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end, - const u8 *ric, size_t ric_len) -{ - const u8 *rpos, *start; - const struct rsn_rdie *rdie; - - wpa_hexdump(MSG_MSGDUMP, "FT: RIC Request", ric, ric_len); - - rpos = ric; - while (rpos + sizeof(*rdie) < ric + ric_len) { - if (rpos[0] != WLAN_EID_RIC_DATA || rpos[1] < sizeof(*rdie) || - rpos + 2 + rpos[1] > ric + ric_len) - break; - rdie = (const struct rsn_rdie *) (rpos + 2); - rpos += 2 + rpos[1]; - start = rpos; - - while (rpos + 2 <= ric + ric_len && - rpos + 2 + rpos[1] <= ric + ric_len) { - if (rpos[0] == WLAN_EID_RIC_DATA) - break; - rpos += 2 + rpos[1]; - } - pos = wpa_ft_process_rdie(sm, pos, end, rdie->id, - rdie->descr_count, - start, rpos - start); - } - - return pos; -} - - -u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, - size_t max_len, int auth_alg, - const u8 *req_ies, size_t req_ies_len) -{ - u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL; - size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0; - int res; - struct wpa_auth_config *conf; - struct rsn_ftie *_ftie; - struct wpa_ft_ies parse; - u8 *ric_start; - u8 *anonce, *snonce; - - if (sm == NULL) - return pos; - - conf = &sm->wpa_auth->conf; - - if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt)) - return pos; - - end = pos + max_len; - - if (auth_alg == WLAN_AUTH_FT) { - /* - * RSN (only present if this is a Reassociation Response and - * part of a fast BSS transition) - */ - res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name); - if (res < 0) - return pos; - rsnie = pos; - rsnie_len = res; - pos += res; - } - - /* Mobility Domain Information */ - res = wpa_write_mdie(conf, pos, end - pos); - if (res < 0) - return pos; - mdie = pos; - mdie_len = res; - pos += res; - - /* Fast BSS Transition Information */ - if (auth_alg == WLAN_AUTH_FT) { - subelem = wpa_ft_gtk_subelem(sm, &subelem_len); - r0kh_id = sm->r0kh_id; - r0kh_id_len = sm->r0kh_id_len; - anonce = sm->ANonce; - snonce = sm->SNonce; -#ifdef CONFIG_IEEE80211W - if (sm->mgmt_frame_prot) { - u8 *igtk; - size_t igtk_len; - u8 *nbuf; - igtk = wpa_ft_igtk_subelem(sm, &igtk_len); - if (igtk == NULL) { - os_free(subelem); - return pos; - } - nbuf = os_realloc(subelem, subelem_len + igtk_len); - if (nbuf == NULL) { - os_free(subelem); - os_free(igtk); - return pos; - } - subelem = nbuf; - os_memcpy(subelem + subelem_len, igtk, igtk_len); - subelem_len += igtk_len; - os_free(igtk); - } -#endif /* CONFIG_IEEE80211W */ - } else { - r0kh_id = conf->r0_key_holder; - r0kh_id_len = conf->r0_key_holder_len; - anonce = NULL; - snonce = NULL; - } - res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, anonce, snonce, pos, - end - pos, subelem, subelem_len); - os_free(subelem); - if (res < 0) - return pos; - ftie = pos; - ftie_len = res; - pos += res; - - os_free(sm->assoc_resp_ftie); - sm->assoc_resp_ftie = os_malloc(ftie_len); - if (sm->assoc_resp_ftie) - os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len); - - _ftie = (struct rsn_ftie *) (ftie + 2); - if (auth_alg == WLAN_AUTH_FT) - _ftie->mic_control[1] = 3; /* Information element count */ - - ric_start = pos; - if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) { - pos = wpa_ft_process_ric(sm, pos, end, parse.ric, - parse.ric_len); - if (auth_alg == WLAN_AUTH_FT) - _ftie->mic_control[1] += - ieee802_11_ie_count(ric_start, - pos - ric_start); - } - if (ric_start == pos) - ric_start = NULL; - - if (auth_alg == WLAN_AUTH_FT && - wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6, - mdie, mdie_len, ftie, ftie_len, - rsnie, rsnie_len, - ric_start, ric_start ? pos - ric_start : 0, - _ftie->mic) < 0) - wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); - - return pos; -} - - -static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, - int vlan_id, - enum wpa_alg alg, const u8 *addr, int idx, - u8 *key, size_t key_len) -{ - if (wpa_auth->cb.set_key == NULL) - return -1; - return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx, - key, key_len); -} - - -void wpa_ft_install_ptk(struct wpa_state_machine *sm) -{ - enum wpa_alg alg; - int klen; - - /* MLME-SETKEYS.request(PTK) */ - alg = wpa_cipher_to_alg(sm->pairwise); - klen = wpa_cipher_key_len(sm->pairwise); - if (!wpa_cipher_valid_pairwise(sm->pairwise)) { - wpa_printf(MSG_DEBUG, "FT: Unknown pairwise alg 0x%x - skip " - "PTK configuration", sm->pairwise); - return; - } - - /* FIX: add STA entry to kernel/driver here? The set_key will fail - * most likely without this.. At the moment, STA entry is added only - * after association has been completed. This function will be called - * again after association to get the PTK configured, but that could be - * optimized by adding the STA entry earlier. - */ - if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, - sm->PTK.tk1, klen)) - return; - - /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ - sm->pairwise_set = TRUE; -} - - -static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm, - const u8 *ies, size_t ies_len, - u8 **resp_ies, size_t *resp_ies_len) -{ - struct rsn_mdie *mdie; - struct rsn_ftie *ftie; - u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN]; - u8 ptk_name[WPA_PMK_NAME_LEN]; - struct wpa_auth_config *conf; - struct wpa_ft_ies parse; - size_t buflen, ptk_len; - int ret; - u8 *pos, *end; - int pairwise; - - *resp_ies = NULL; - *resp_ies_len = 0; - - sm->pmk_r1_name_valid = 0; - conf = &sm->wpa_auth->conf; - - wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs", - ies, ies_len); - - if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { - wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - mdie = (struct rsn_mdie *) parse.mdie; - if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || - os_memcmp(mdie->mobility_domain, - sm->wpa_auth->conf.mobility_domain, - MOBILITY_DOMAIN_ID_LEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); - return WLAN_STATUS_INVALID_MDIE; - } - - ftie = (struct rsn_ftie *) parse.ftie; - if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); - return WLAN_STATUS_INVALID_FTIE; - } - - os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN); - - if (parse.r0kh_id == NULL) { - wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID"); - return WLAN_STATUS_INVALID_FTIE; - } - - wpa_hexdump(MSG_DEBUG, "FT: STA R0KH-ID", - parse.r0kh_id, parse.r0kh_id_len); - os_memcpy(sm->r0kh_id, parse.r0kh_id, parse.r0kh_id_len); - sm->r0kh_id_len = parse.r0kh_id_len; - - if (parse.rsn_pmkid == NULL) { - wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE"); - return WLAN_STATUS_INVALID_PMKID; - } - - wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name", - parse.rsn_pmkid, WPA_PMK_NAME_LEN); - wpa_derive_pmk_r1_name(parse.rsn_pmkid, - sm->wpa_auth->conf.r1_key_holder, sm->addr, - pmk_r1_name); - wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name", - pmk_r1_name, WPA_PMK_NAME_LEN); - - if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1, - &pairwise) < 0) { - if (wpa_ft_pull_pmk_r1(sm->wpa_auth, sm->addr, sm->r0kh_id, - sm->r0kh_id_len, parse.rsn_pmkid) < 0) { - wpa_printf(MSG_DEBUG, "FT: Did not have matching " - "PMK-R1 and unknown R0KH-ID"); - return WLAN_STATUS_INVALID_PMKID; - } - - /* - * TODO: Should return "status pending" (and the caller should - * not send out response now). The real response will be sent - * once the response from R0KH is received. - */ - return WLAN_STATUS_INVALID_PMKID; - } - - wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN); - sm->pmk_r1_name_valid = 1; - os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN); - - if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) { - wpa_printf(MSG_DEBUG, "FT: Failed to get random data for " - "ANonce"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", - sm->SNonce, WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce", - sm->ANonce, WPA_NONCE_LEN); - - ptk_len = pairwise == WPA_CIPHER_TKIP ? 64 : 48; - wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr, - sm->wpa_auth->addr, pmk_r1_name, - (u8 *) &sm->PTK, ptk_len, ptk_name); - wpa_hexdump_key(MSG_DEBUG, "FT: PTK", - (u8 *) &sm->PTK, ptk_len); - wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); - - sm->pairwise = pairwise; - wpa_ft_install_ptk(sm); - - buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + - 2 + FT_R1KH_ID_LEN + 200; - *resp_ies = os_zalloc(buflen); - if (*resp_ies == NULL) { - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - pos = *resp_ies; - end = *resp_ies + buflen; - - ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid); - if (ret < 0) { - os_free(*resp_ies); - *resp_ies = NULL; - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - pos += ret; - - ret = wpa_write_mdie(conf, pos, end - pos); - if (ret < 0) { - os_free(*resp_ies); - *resp_ies = NULL; - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - pos += ret; - - ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len, - sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0); - if (ret < 0) { - os_free(*resp_ies); - *resp_ies = NULL; - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - pos += ret; - - *resp_ies_len = pos - *resp_ies; - - return WLAN_STATUS_SUCCESS; -} - - -void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, - u16 auth_transaction, const u8 *ies, size_t ies_len, - void (*cb)(void *ctx, const u8 *dst, const u8 *bssid, - u16 auth_transaction, u16 status, - const u8 *ies, size_t ies_len), - void *ctx) -{ - u16 status; - u8 *resp_ies; - size_t resp_ies_len; - - if (sm == NULL) { - wpa_printf(MSG_DEBUG, "FT: Received authentication frame, but " - "WPA SM not available"); - return; - } - - wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR - " BSSID=" MACSTR " transaction=%d", - MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction); - status = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies, - &resp_ies_len); - - wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR - " auth_transaction=%d status=%d", - MAC2STR(sm->addr), auth_transaction + 1, status); - wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len); - cb(ctx, sm->addr, bssid, auth_transaction + 1, status, - resp_ies, resp_ies_len); - os_free(resp_ies); -} - - -u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, - size_t ies_len) -{ - struct wpa_ft_ies parse; - struct rsn_mdie *mdie; - struct rsn_ftie *ftie; - u8 mic[16]; - unsigned int count; - - if (sm == NULL) - return WLAN_STATUS_UNSPECIFIED_FAILURE; - - wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len); - - if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { - wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - if (parse.rsn == NULL) { - wpa_printf(MSG_DEBUG, "FT: No RSNIE in Reassoc Req"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - if (parse.rsn_pmkid == NULL) { - wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE"); - return WLAN_STATUS_INVALID_PMKID; - } - - if (os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) - { - wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match " - "with the PMKR1Name derived from auth request"); - return WLAN_STATUS_INVALID_PMKID; - } - - mdie = (struct rsn_mdie *) parse.mdie; - if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || - os_memcmp(mdie->mobility_domain, - sm->wpa_auth->conf.mobility_domain, - MOBILITY_DOMAIN_ID_LEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); - return WLAN_STATUS_INVALID_MDIE; - } - - ftie = (struct rsn_ftie *) parse.ftie; - if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); - return WLAN_STATUS_INVALID_FTIE; - } - - if (os_memcmp(ftie->snonce, sm->SNonce, WPA_NONCE_LEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); - wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", - ftie->snonce, WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", - sm->SNonce, WPA_NONCE_LEN); - return -1; - } - - if (os_memcmp(ftie->anonce, sm->ANonce, WPA_NONCE_LEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE"); - wpa_hexdump(MSG_DEBUG, "FT: Received ANonce", - ftie->anonce, WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce", - sm->ANonce, WPA_NONCE_LEN); - return -1; - } - - - if (parse.r0kh_id == NULL) { - wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); - return -1; - } - - if (parse.r0kh_id_len != sm->r0kh_id_len || - os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { - wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " - "the current R0KH-ID"); - wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", - parse.r0kh_id, parse.r0kh_id_len); - wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", - sm->r0kh_id, sm->r0kh_id_len); - return -1; - } - - if (parse.r1kh_id == NULL) { - wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); - return -1; - } - - if (os_memcmp(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder, - FT_R1KH_ID_LEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in " - "ReassocReq"); - wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE", - parse.r1kh_id, FT_R1KH_ID_LEN); - wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID", - sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN); - return -1; - } - - if (parse.rsn_pmkid == NULL || - os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) { - wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in " - "RSNIE (pmkid=%d)", !!parse.rsn_pmkid); - return -1; - } - - count = 3; - 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", - ftie->mic_control[1], count); - return -1; - } - - if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5, - parse.mdie - 2, parse.mdie_len + 2, - parse.ftie - 2, parse.ftie_len + 2, - parse.rsn - 2, parse.rsn_len + 2, - parse.ric, parse.ric_len, - mic) < 0) { - wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - if (os_memcmp(mic, ftie->mic, 16) != 0) { - wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE"); - wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR, - MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr)); - wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16); - wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16); - wpa_hexdump(MSG_MSGDUMP, "FT: MDIE", - parse.mdie - 2, parse.mdie_len + 2); - wpa_hexdump(MSG_MSGDUMP, "FT: FTIE", - parse.ftie - 2, parse.ftie_len + 2); - wpa_hexdump(MSG_MSGDUMP, "FT: RSN", - parse.rsn - 2, parse.rsn_len + 2); - return WLAN_STATUS_INVALID_FTIE; - } - - return WLAN_STATUS_SUCCESS; -} - - -int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len) -{ - const u8 *sta_addr, *target_ap; - const u8 *ies; - size_t ies_len; - u8 action; - struct ft_rrb_frame *frame; - - if (sm == NULL) - return -1; - - /* - * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6] - * FT Request action frame body[variable] - */ - - if (len < 14) { - wpa_printf(MSG_DEBUG, "FT: Too short FT Action frame " - "(len=%lu)", (unsigned long) len); - return -1; - } - - action = data[1]; - sta_addr = data + 2; - target_ap = data + 8; - ies = data + 14; - ies_len = len - 14; - - wpa_printf(MSG_DEBUG, "FT: Received FT Action frame (STA=" MACSTR - " Target AP=" MACSTR " Action=%d)", - MAC2STR(sta_addr), MAC2STR(target_ap), action); - - if (os_memcmp(sta_addr, sm->addr, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: Mismatch in FT Action STA address: " - "STA=" MACSTR " STA-Address=" MACSTR, - MAC2STR(sm->addr), MAC2STR(sta_addr)); - return -1; - } - - /* - * Do some sanity checking on the target AP address (not own and not - * broadcast. This could be extended to filter based on a list of known - * APs in the MD (if such a list were configured). - */ - if ((target_ap[0] & 0x01) || - os_memcmp(target_ap, sm->wpa_auth->addr, ETH_ALEN) == 0) { - wpa_printf(MSG_DEBUG, "FT: Invalid Target AP in FT Action " - "frame"); - return -1; - } - - wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len); - - /* RRB - Forward action frame to the target AP */ - frame = os_malloc(sizeof(*frame) + len); - if (frame == NULL) - return -1; - frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB; - frame->packet_type = FT_PACKET_REQUEST; - frame->action_length = host_to_le16(len); - os_memcpy(frame->ap_address, sm->wpa_auth->addr, ETH_ALEN); - os_memcpy(frame + 1, data, len); - - wpa_ft_rrb_send(sm->wpa_auth, target_ap, (u8 *) frame, - sizeof(*frame) + len); - os_free(frame); - - return 0; -} - - -static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth, - const u8 *current_ap, const u8 *sta_addr, - const u8 *body, size_t len) -{ - struct wpa_state_machine *sm; - u16 status; - u8 *resp_ies, *pos; - size_t resp_ies_len, rlen; - struct ft_rrb_frame *frame; - - sm = wpa_ft_add_sta(wpa_auth, sta_addr); - if (sm == NULL) { - wpa_printf(MSG_DEBUG, "FT: Failed to add new STA based on " - "RRB Request"); - return -1; - } - - wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len); - - status = wpa_ft_process_auth_req(sm, body, len, &resp_ies, - &resp_ies_len); - - wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR - " CurrentAP=" MACSTR " status=%d", - MAC2STR(sm->addr), MAC2STR(current_ap), status); - wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len); - - /* RRB - Forward action frame response to the Current AP */ - - /* - * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6] - * Status_Code[2] FT Request action frame body[variable] - */ - rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len; - - frame = os_malloc(sizeof(*frame) + rlen); - if (frame == NULL) { - os_free(resp_ies); - return -1; - } - frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB; - frame->packet_type = FT_PACKET_RESPONSE; - frame->action_length = host_to_le16(rlen); - os_memcpy(frame->ap_address, wpa_auth->addr, ETH_ALEN); - pos = (u8 *) (frame + 1); - *pos++ = WLAN_ACTION_FT; - *pos++ = 2; /* Action: Response */ - os_memcpy(pos, sta_addr, ETH_ALEN); - pos += ETH_ALEN; - os_memcpy(pos, wpa_auth->addr, ETH_ALEN); - pos += ETH_ALEN; - WPA_PUT_LE16(pos, status); - pos += 2; - if (resp_ies) { - os_memcpy(pos, resp_ies, resp_ies_len); - os_free(resp_ies); - } - - wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame, - sizeof(*frame) + rlen); - os_free(frame); - - return 0; -} - - -static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, - const u8 *src_addr, - const u8 *data, size_t data_len) -{ - struct ft_r0kh_r1kh_pull_frame *frame, f; - struct ft_remote_r1kh *r1kh; - struct ft_r0kh_r1kh_resp_frame resp, r; - u8 pmk_r0[PMK_LEN]; - int pairwise; - - wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull"); - - if (data_len < sizeof(*frame)) - return -1; - - r1kh = wpa_auth->conf.r1kh_list; - while (r1kh) { - if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0) - break; - r1kh = r1kh->next; - } - if (r1kh == NULL) { - wpa_printf(MSG_DEBUG, "FT: No matching R1KH address found for " - "PMK-R1 pull source address " MACSTR, - MAC2STR(src_addr)); - return -1; - } - - frame = (struct ft_r0kh_r1kh_pull_frame *) data; - /* aes_unwrap() does not support inplace decryption, so use a temporary - * buffer for the data. */ - if (aes_unwrap(r1kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8, - frame->nonce, f.nonce) < 0) { - wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull " - "request from " MACSTR, MAC2STR(src_addr)); - return -1; - } - - wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce", - f.nonce, sizeof(f.nonce)); - wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name", - f.pmk_r0_name, WPA_PMK_NAME_LEN); - wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID=" - MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id)); - - os_memset(&resp, 0, sizeof(resp)); - resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB; - resp.packet_type = FT_PACKET_R0KH_R1KH_RESP; - resp.data_length = host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN); - os_memcpy(resp.ap_address, wpa_auth->addr, ETH_ALEN); - - /* aes_wrap() does not support inplace encryption, so use a temporary - * buffer for the data. */ - os_memcpy(r.nonce, f.nonce, sizeof(f.nonce)); - os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN); - os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN); - if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0, - &pairwise) < 0) { - wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for " - "PMK-R1 pull"); - return -1; - } - - wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id, - r.pmk_r1, r.pmk_r1_name); - wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name, - WPA_PMK_NAME_LEN); - r.pairwise = host_to_le16(pairwise); - os_memset(r.pad, 0, sizeof(r.pad)); - - if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8, - r.nonce, resp.nonce) < 0) { - os_memset(pmk_r0, 0, PMK_LEN); - return -1; - } - - os_memset(pmk_r0, 0, PMK_LEN); - - wpa_ft_rrb_send(wpa_auth, src_addr, (u8 *) &resp, sizeof(resp)); - - return 0; -} - - -static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth, - const u8 *src_addr, - const u8 *data, size_t data_len) -{ - struct ft_r0kh_r1kh_resp_frame *frame, f; - struct ft_remote_r0kh *r0kh; - int pairwise; - - wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response"); - - if (data_len < sizeof(*frame)) - return -1; - - r0kh = wpa_auth->conf.r0kh_list; - while (r0kh) { - if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0) - break; - r0kh = r0kh->next; - } - if (r0kh == NULL) { - wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for " - "PMK-R0 pull response source address " MACSTR, - MAC2STR(src_addr)); - return -1; - } - - frame = (struct ft_r0kh_r1kh_resp_frame *) data; - /* aes_unwrap() does not support inplace decryption, so use a temporary - * buffer for the data. */ - if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8, - frame->nonce, f.nonce) < 0) { - wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull " - "response from " MACSTR, MAC2STR(src_addr)); - return -1; - } - - if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN) - != 0) { - wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a " - "matching R1KH-ID"); - return -1; - } - - /* TODO: verify that matches with a pending request - * and call this requests callback function to finish request - * processing */ - - pairwise = le_to_host16(f.pairwise); - wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce", - f.nonce, sizeof(f.nonce)); - wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID=" - MACSTR " pairwise=0x%x", - MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise); - wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1", - f.pmk_r1, PMK_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name", - f.pmk_r1_name, WPA_PMK_NAME_LEN); - - wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name, - pairwise); - os_memset(f.pmk_r1, 0, PMK_LEN); - - return 0; -} - - -static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth, - const u8 *src_addr, - const u8 *data, size_t data_len) -{ - struct ft_r0kh_r1kh_push_frame *frame, f; - struct ft_remote_r0kh *r0kh; - struct os_time now; - os_time_t tsend; - int pairwise; - - wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push"); - - if (data_len < sizeof(*frame)) - return -1; - - r0kh = wpa_auth->conf.r0kh_list; - while (r0kh) { - if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0) - break; - r0kh = r0kh->next; - } - if (r0kh == NULL) { - wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for " - "PMK-R0 push source address " MACSTR, - MAC2STR(src_addr)); - return -1; - } - - frame = (struct ft_r0kh_r1kh_push_frame *) data; - /* aes_unwrap() does not support inplace decryption, so use a temporary - * buffer for the data. */ - if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8, - frame->timestamp, f.timestamp) < 0) { - wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from " - MACSTR, MAC2STR(src_addr)); - return -1; - } - - os_get_time(&now); - tsend = WPA_GET_LE32(f.timestamp); - if ((now.sec > tsend && now.sec - tsend > 60) || - (now.sec < tsend && tsend - now.sec > 60)) { - wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not have a valid " - "timestamp: sender time %d own time %d\n", - (int) tsend, (int) now.sec); - return -1; - } - - if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN) - != 0) { - wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching " - "R1KH-ID (received " MACSTR " own " MACSTR ")", - MAC2STR(f.r1kh_id), - MAC2STR(wpa_auth->conf.r1_key_holder)); - return -1; - } - - pairwise = le_to_host16(f.pairwise); - wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID=" - MACSTR " pairwise=0x%x", - MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise); - wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1", - f.pmk_r1, PMK_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name", - f.pmk_r1_name, WPA_PMK_NAME_LEN); - - wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name, - pairwise); - os_memset(f.pmk_r1, 0, PMK_LEN); - - return 0; -} - - -int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, - const u8 *data, size_t data_len) -{ - struct ft_rrb_frame *frame; - u16 alen; - const u8 *pos, *end, *start; - u8 action; - const u8 *sta_addr, *target_ap_addr; - - wpa_printf(MSG_DEBUG, "FT: RRB received frame from remote AP " MACSTR, - MAC2STR(src_addr)); - - if (data_len < sizeof(*frame)) { - wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (data_len=%lu)", - (unsigned long) data_len); - return -1; - } - - pos = data; - frame = (struct ft_rrb_frame *) pos; - pos += sizeof(*frame); - - alen = le_to_host16(frame->action_length); - wpa_printf(MSG_DEBUG, "FT: RRB frame - frame_type=%d packet_type=%d " - "action_length=%d ap_address=" MACSTR, - frame->frame_type, frame->packet_type, alen, - MAC2STR(frame->ap_address)); - - if (frame->frame_type != RSN_REMOTE_FRAME_TYPE_FT_RRB) { - /* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */ - wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with " - "unrecognized type %d", frame->frame_type); - return -1; - } - - if (alen > data_len - sizeof(*frame)) { - wpa_printf(MSG_DEBUG, "FT: RRB frame too short for action " - "frame"); - return -1; - } - - if (frame->packet_type == FT_PACKET_R0KH_R1KH_PULL) - return wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len); - if (frame->packet_type == FT_PACKET_R0KH_R1KH_RESP) - return wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len); - if (frame->packet_type == FT_PACKET_R0KH_R1KH_PUSH) - return wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len); - - wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen); - - if (alen < 1 + 1 + 2 * ETH_ALEN) { - wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (not enough " - "room for Action Frame body); alen=%lu", - (unsigned long) alen); - return -1; - } - start = pos; - end = pos + alen; - - if (*pos != WLAN_ACTION_FT) { - wpa_printf(MSG_DEBUG, "FT: Unexpected Action frame category " - "%d", *pos); - return -1; - } - - pos++; - action = *pos++; - sta_addr = pos; - pos += ETH_ALEN; - target_ap_addr = pos; - pos += ETH_ALEN; - wpa_printf(MSG_DEBUG, "FT: RRB Action Frame: action=%d sta_addr=" - MACSTR " target_ap_addr=" MACSTR, - action, MAC2STR(sta_addr), MAC2STR(target_ap_addr)); - - if (frame->packet_type == FT_PACKET_REQUEST) { - wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Request"); - - if (action != 1) { - wpa_printf(MSG_DEBUG, "FT: Unexpected Action %d in " - "RRB Request", action); - return -1; - } - - if (os_memcmp(target_ap_addr, wpa_auth->addr, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: Target AP address in the " - "RRB Request does not match with own " - "address"); - return -1; - } - - if (wpa_ft_rrb_rx_request(wpa_auth, frame->ap_address, - sta_addr, pos, end - pos) < 0) - return -1; - } else if (frame->packet_type == FT_PACKET_RESPONSE) { - u16 status_code; - - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "FT: Not enough room for status " - "code in RRB Response"); - return -1; - } - status_code = WPA_GET_LE16(pos); - pos += 2; - - wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response " - "(status_code=%d)", status_code); - - if (wpa_ft_action_send(wpa_auth, sta_addr, start, alen) < 0) - return -1; - } else { - wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with unknown " - "packet_type %d", frame->packet_type); - return -1; - } - - return 0; -} - - -static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth, - struct wpa_ft_pmk_r0_sa *pmk_r0, - struct ft_remote_r1kh *r1kh, - const u8 *s1kh_id, int pairwise) -{ - struct ft_r0kh_r1kh_push_frame frame, f; - struct os_time now; - - os_memset(&frame, 0, sizeof(frame)); - frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB; - frame.packet_type = FT_PACKET_R0KH_R1KH_PUSH; - frame.data_length = host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN); - os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN); - - /* aes_wrap() does not support inplace encryption, so use a temporary - * buffer for the data. */ - os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN); - os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN); - os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN); - wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id, - s1kh_id, f.pmk_r1, f.pmk_r1_name); - wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id)); - wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name, - WPA_PMK_NAME_LEN); - os_get_time(&now); - WPA_PUT_LE32(f.timestamp, now.sec); - f.pairwise = host_to_le16(pairwise); - os_memset(f.pad, 0, sizeof(f.pad)); - if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8, - f.timestamp, frame.timestamp) < 0) - return; - - wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame)); -} - - -void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr) -{ - struct wpa_ft_pmk_r0_sa *r0; - struct ft_remote_r1kh *r1kh; - - if (!wpa_auth->conf.pmk_r1_push) - return; - - r0 = wpa_auth->ft_pmk_cache->pmk_r0; - while (r0) { - if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0) - break; - r0 = r0->next; - } - - if (r0 == NULL || r0->pmk_r1_pushed) - return; - r0->pmk_r1_pushed = 1; - - wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs " - "for STA " MACSTR, MAC2STR(addr)); - - r1kh = wpa_auth->conf.r1kh_list; - while (r1kh) { - wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr, r0->pairwise); - r1kh = r1kh->next; - } -} - -#endif /* CONFIG_IEEE80211R */ diff --git a/contrib/hostapd/src/ap/wpa_auth_glue.c b/contrib/hostapd/src/ap/wpa_auth_glue.c deleted file mode 100644 index 5af1495030..0000000000 --- a/contrib/hostapd/src/ap/wpa_auth_glue.c +++ /dev/null @@ -1,628 +0,0 @@ -/* - * hostapd / WPA authenticator glue code - * Copyright (c) 2002-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "common/ieee802_11_defs.h" -#include "common/sae.h" -#include "eapol_auth/eapol_auth_sm.h" -#include "eapol_auth/eapol_auth_sm_i.h" -#include "eap_server/eap.h" -#include "l2_packet/l2_packet.h" -#include "hostapd.h" -#include "ieee802_1x.h" -#include "preauth_auth.h" -#include "sta_info.h" -#include "tkip_countermeasures.h" -#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 hostapd_config *iconf, - 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; - wconf->wpa_group = conf->wpa_group; - wconf->wpa_group_rekey = conf->wpa_group_rekey; - wconf->wpa_strict_rekey = conf->wpa_strict_rekey; - wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey; - wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey; - wconf->rsn_pairwise = conf->rsn_pairwise; - wconf->rsn_preauth = conf->rsn_preauth; - wconf->eapol_version = conf->eapol_version; - wconf->peerkey = conf->peerkey; - wconf->wmm_enabled = conf->wmm_enabled; - wconf->wmm_uapsd = conf->wmm_uapsd; - wconf->disable_pmksa_caching = conf->disable_pmksa_caching; - wconf->okc = conf->okc; -#ifdef CONFIG_IEEE80211W - wconf->ieee80211w = conf->ieee80211w; -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_IEEE80211R - wconf->ssid_len = conf->ssid.ssid_len; - if (wconf->ssid_len > SSID_LEN) - wconf->ssid_len = SSID_LEN; - os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len); - os_memcpy(wconf->mobility_domain, conf->mobility_domain, - MOBILITY_DOMAIN_ID_LEN); - if (conf->nas_identifier && - os_strlen(conf->nas_identifier) <= FT_R0KH_ID_MAX_LEN) { - wconf->r0_key_holder_len = os_strlen(conf->nas_identifier); - os_memcpy(wconf->r0_key_holder, conf->nas_identifier, - wconf->r0_key_holder_len); - } - os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN); - wconf->r0_key_lifetime = conf->r0_key_lifetime; - wconf->reassociation_deadline = conf->reassociation_deadline; - wconf->r0kh_list = conf->r0kh_list; - wconf->r1kh_list = conf->r1kh_list; - wconf->pmk_r1_push = conf->pmk_r1_push; - wconf->ft_over_ds = conf->ft_over_ds; -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_HS20 - wconf->disable_gtk = conf->disable_dgaf; -#endif /* CONFIG_HS20 */ -#ifdef CONFIG_TESTING_OPTIONS - wconf->corrupt_gtk_rekey_mic_probability = - iconf->corrupt_gtk_rekey_mic_probability; -#endif /* CONFIG_TESTING_OPTIONS */ -#ifdef CONFIG_P2P - os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4); - os_memcpy(wconf->ip_addr_mask, conf->ip_addr_mask, 4); - os_memcpy(wconf->ip_addr_start, conf->ip_addr_start, 4); - os_memcpy(wconf->ip_addr_end, conf->ip_addr_end, 4); -#endif /* CONFIG_P2P */ -} - - -static void hostapd_wpa_auth_logger(void *ctx, const u8 *addr, - logger_level level, const char *txt) -{ -#ifndef CONFIG_NO_HOSTAPD_LOGGER - struct hostapd_data *hapd = ctx; - int hlevel; - - switch (level) { - case LOGGER_WARNING: - hlevel = HOSTAPD_LEVEL_WARNING; - break; - case LOGGER_INFO: - hlevel = HOSTAPD_LEVEL_INFO; - break; - case LOGGER_DEBUG: - default: - hlevel = HOSTAPD_LEVEL_DEBUG; - break; - } - - hostapd_logger(hapd, addr, HOSTAPD_MODULE_WPA, hlevel, "%s", txt); -#endif /* CONFIG_NO_HOSTAPD_LOGGER */ -} - - -static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr, - u16 reason) -{ - struct hostapd_data *hapd = ctx; - wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: " - "STA " MACSTR " reason %d", - __func__, MAC2STR(addr), reason); - ap_sta_disconnect(hapd, NULL, addr, reason); -} - - -static int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr) -{ - struct hostapd_data *hapd = ctx; - return michael_mic_failure(hapd, addr, 0); -} - - -static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr, - wpa_eapol_variable var, int value) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta = ap_get_sta(hapd, addr); - if (sta == NULL) - return; - switch (var) { - case WPA_EAPOL_portEnabled: - ieee802_1x_notify_port_enabled(sta->eapol_sm, value); - break; - case WPA_EAPOL_portValid: - ieee802_1x_notify_port_valid(sta->eapol_sm, value); - break; - case WPA_EAPOL_authorized: - ieee802_1x_set_sta_authorized(hapd, sta, value); - break; - case WPA_EAPOL_portControl_Auto: - if (sta->eapol_sm) - sta->eapol_sm->portControl = Auto; - break; - case WPA_EAPOL_keyRun: - if (sta->eapol_sm) - sta->eapol_sm->keyRun = value ? TRUE : FALSE; - break; - case WPA_EAPOL_keyAvailable: - if (sta->eapol_sm) - sta->eapol_sm->eap_if->eapKeyAvailable = - value ? TRUE : FALSE; - break; - case WPA_EAPOL_keyDone: - if (sta->eapol_sm) - sta->eapol_sm->keyDone = value ? TRUE : FALSE; - break; - case WPA_EAPOL_inc_EapolFramesTx: - if (sta->eapol_sm) - sta->eapol_sm->dot1xAuthEapolFramesTx++; - break; - } -} - - -static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr, - wpa_eapol_variable var) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta = ap_get_sta(hapd, addr); - if (sta == NULL || sta->eapol_sm == NULL) - return -1; - switch (var) { - case WPA_EAPOL_keyRun: - return sta->eapol_sm->keyRun; - case WPA_EAPOL_keyAvailable: - return sta->eapol_sm->eap_if->eapKeyAvailable; - default: - return -1; - } -} - - -static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, - const u8 *p2p_dev_addr, - const u8 *prev_psk) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta = ap_get_sta(hapd, addr); - const u8 *psk; - -#ifdef CONFIG_SAE - if (sta && sta->auth_alg == WLAN_AUTH_SAE) { - if (!sta->sae || prev_psk) - return NULL; - return sta->sae->pmk; - } -#endif /* CONFIG_SAE */ - - psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk); - /* - * This is about to iterate over all psks, prev_psk gives the last - * returned psk which should not be returned again. - * logic list (all hostapd_get_psk; all sta->psk) - */ - if (sta && sta->psk && !psk) { - struct hostapd_sta_wpa_psk_short *pos; - psk = sta->psk->psk; - for (pos = sta->psk; pos; pos = pos->next) { - if (pos->psk == prev_psk) { - psk = pos->next ? pos->next->psk : NULL; - break; - } - } - } - return psk; -} - - -static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk, - size_t *len) -{ - struct hostapd_data *hapd = ctx; - const u8 *key; - size_t keylen; - struct sta_info *sta; - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) - return -1; - - key = ieee802_1x_get_key(sta->eapol_sm, &keylen); - if (key == NULL) - return -1; - - if (keylen > *len) - keylen = *len; - os_memcpy(msk, key, keylen); - *len = keylen; - - return 0; -} - - -static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, - const u8 *addr, int idx, u8 *key, - size_t key_len) -{ - struct hostapd_data *hapd = ctx; - const char *ifname = hapd->conf->iface; - - if (vlan_id > 0) { - ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id); - if (ifname == NULL) - return -1; - } - - return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0, - key, key_len); -} - - -static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx, - u8 *seq) -{ - struct hostapd_data *hapd = ctx; - return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq); -} - - -static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr, - const u8 *data, size_t data_len, - int encrypt) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta; - u32 flags = 0; - - sta = ap_get_sta(hapd, addr); - if (sta) - flags = hostapd_sta_flags_to_drv(sta->flags); - - return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len, - encrypt, flags); -} - - -static int hostapd_wpa_auth_for_each_sta( - void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx), - void *cb_ctx) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta; - - for (sta = hapd->sta_list; sta; sta = sta->next) { - if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx)) - return 1; - } - return 0; -} - - -struct wpa_auth_iface_iter_data { - int (*cb)(struct wpa_authenticator *sm, void *ctx); - void *cb_ctx; -}; - -static int wpa_auth_iface_iter(struct hostapd_iface *iface, void *ctx) -{ - struct wpa_auth_iface_iter_data *data = ctx; - size_t i; - for (i = 0; i < iface->num_bss; i++) { - if (iface->bss[i]->wpa_auth && - data->cb(iface->bss[i]->wpa_auth, data->cb_ctx)) - return 1; - } - return 0; -} - - -static int hostapd_wpa_auth_for_each_auth( - void *ctx, int (*cb)(struct wpa_authenticator *sm, void *ctx), - void *cb_ctx) -{ - struct hostapd_data *hapd = ctx; - struct wpa_auth_iface_iter_data data; - if (hapd->iface->interfaces == NULL || - hapd->iface->interfaces->for_each_interface == NULL) - return -1; - data.cb = cb; - data.cb_ctx = cb_ctx; - return hapd->iface->interfaces->for_each_interface( - hapd->iface->interfaces, wpa_auth_iface_iter, &data); -} - - -#ifdef CONFIG_IEEE80211R - -struct wpa_auth_ft_iface_iter_data { - struct hostapd_data *src_hapd; - const u8 *dst; - const u8 *data; - size_t data_len; -}; - - -static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx) -{ - struct wpa_auth_ft_iface_iter_data *idata = ctx; - struct hostapd_data *hapd; - size_t j; - - for (j = 0; j < iface->num_bss; j++) { - hapd = iface->bss[j]; - if (hapd == idata->src_hapd) - continue; - if (os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) == 0) { - wpa_printf(MSG_DEBUG, "FT: Send RRB data directly to " - "locally managed BSS " MACSTR "@%s -> " - MACSTR "@%s", - MAC2STR(idata->src_hapd->own_addr), - idata->src_hapd->conf->iface, - MAC2STR(hapd->own_addr), hapd->conf->iface); - wpa_ft_rrb_rx(hapd->wpa_auth, - idata->src_hapd->own_addr, - idata->data, idata->data_len); - return 1; - } - } - - return 0; -} - -#endif /* CONFIG_IEEE80211R */ - - -static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto, - const u8 *data, size_t data_len) -{ - struct hostapd_data *hapd = ctx; - struct l2_ethhdr *buf; - int ret; - -#ifdef CONFIG_IEEE80211R - if (proto == ETH_P_RRB && hapd->iface->interfaces && - hapd->iface->interfaces->for_each_interface) { - int res; - struct wpa_auth_ft_iface_iter_data idata; - idata.src_hapd = hapd; - idata.dst = dst; - idata.data = data; - idata.data_len = data_len; - res = hapd->iface->interfaces->for_each_interface( - hapd->iface->interfaces, hostapd_wpa_auth_ft_iter, - &idata); - if (res == 1) - return data_len; - } -#endif /* CONFIG_IEEE80211R */ - - if (hapd->driver && hapd->driver->send_ether) - return hapd->driver->send_ether(hapd->drv_priv, dst, - hapd->own_addr, proto, - data, data_len); - if (hapd->l2 == NULL) - return -1; - - buf = os_malloc(sizeof(*buf) + data_len); - if (buf == NULL) - return -1; - os_memcpy(buf->h_dest, dst, ETH_ALEN); - os_memcpy(buf->h_source, hapd->own_addr, ETH_ALEN); - buf->h_proto = host_to_be16(proto); - os_memcpy(buf + 1, data, data_len); - ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf, - sizeof(*buf) + data_len); - os_free(buf); - return ret; -} - - -#ifdef CONFIG_IEEE80211R - -static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst, - const u8 *data, size_t data_len) -{ - struct hostapd_data *hapd = ctx; - int res; - struct ieee80211_mgmt *m; - size_t mlen; - struct sta_info *sta; - - sta = ap_get_sta(hapd, dst); - if (sta == NULL || sta->wpa_sm == NULL) - return -1; - - m = os_zalloc(sizeof(*m) + data_len); - if (m == NULL) - return -1; - mlen = ((u8 *) &m->u - (u8 *) m) + data_len; - m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(m->da, dst, ETH_ALEN); - os_memcpy(m->sa, hapd->own_addr, ETH_ALEN); - 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, 0); - os_free(m); - return res; -} - - -static struct wpa_state_machine * -hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr) -{ - struct hostapd_data *hapd = ctx; - struct sta_info *sta; - - if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0) - return NULL; - - sta = ap_sta_add(hapd, sta_addr); - if (sta == NULL) - return NULL; - if (sta->wpa_sm) { - sta->auth_alg = WLAN_AUTH_FT; - return sta->wpa_sm; - } - - sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, NULL); - if (sta->wpa_sm == NULL) { - ap_free_sta(hapd, sta); - return NULL; - } - sta->auth_alg = WLAN_AUTH_FT; - - return sta->wpa_sm; -} - - -static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf, - size_t len) -{ - struct hostapd_data *hapd = ctx; - struct l2_ethhdr *ethhdr; - if (len < sizeof(*ethhdr)) - return; - ethhdr = (struct l2_ethhdr *) buf; - wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> " - MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest)); - wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr), - len - sizeof(*ethhdr)); -} - - -static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr, - u8 *tspec_ie, size_t tspec_ielen) -{ - struct hostapd_data *hapd = ctx; - return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen); -} - -#endif /* CONFIG_IEEE80211R */ - - -int hostapd_setup_wpa(struct hostapd_data *hapd) -{ - struct wpa_auth_config _conf; - struct wpa_auth_callbacks cb; - const u8 *wpa_ie; - size_t wpa_ie_len; - - hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf); - if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS) - _conf.tx_status = 1; - if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME) - _conf.ap_mlme = 1; - os_memset(&cb, 0, sizeof(cb)); - cb.ctx = hapd; - cb.logger = hostapd_wpa_auth_logger; - cb.disconnect = hostapd_wpa_auth_disconnect; - cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report; - cb.set_eapol = hostapd_wpa_auth_set_eapol; - cb.get_eapol = hostapd_wpa_auth_get_eapol; - cb.get_psk = hostapd_wpa_auth_get_psk; - cb.get_msk = hostapd_wpa_auth_get_msk; - cb.set_key = hostapd_wpa_auth_set_key; - cb.get_seqnum = hostapd_wpa_auth_get_seqnum; - cb.send_eapol = hostapd_wpa_auth_send_eapol; - cb.for_each_sta = hostapd_wpa_auth_for_each_sta; - cb.for_each_auth = hostapd_wpa_auth_for_each_auth; - cb.send_ether = hostapd_wpa_auth_send_ether; -#ifdef CONFIG_IEEE80211R - cb.send_ft_action = hostapd_wpa_auth_send_ft_action; - cb.add_sta = hostapd_wpa_auth_add_sta; - cb.add_tspec = hostapd_wpa_auth_add_tspec; -#endif /* CONFIG_IEEE80211R */ - hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb); - if (hapd->wpa_auth == NULL) { - wpa_printf(MSG_ERROR, "WPA initialization failed."); - return -1; - } - - if (hostapd_set_privacy(hapd, 1)) { - wpa_printf(MSG_ERROR, "Could not set PrivacyInvoked " - "for interface %s", hapd->conf->iface); - return -1; - } - - wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len); - if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) { - wpa_printf(MSG_ERROR, "Failed to configure WPA IE for " - "the kernel driver."); - return -1; - } - - if (rsn_preauth_iface_init(hapd)) { - wpa_printf(MSG_ERROR, "Initialization of RSN " - "pre-authentication failed."); - return -1; - } - -#ifdef CONFIG_IEEE80211R - if (!hostapd_drv_none(hapd)) { - hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ? - hapd->conf->bridge : - hapd->conf->iface, NULL, ETH_P_RRB, - hostapd_rrb_receive, hapd, 1); - if (hapd->l2 == NULL && - (hapd->driver == NULL || - hapd->driver->send_ether == NULL)) { - wpa_printf(MSG_ERROR, "Failed to open l2_packet " - "interface"); - return -1; - } - } -#endif /* CONFIG_IEEE80211R */ - - return 0; - -} - - -void hostapd_reconfig_wpa(struct hostapd_data *hapd) -{ - struct wpa_auth_config wpa_auth_conf; - hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &wpa_auth_conf); - wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf); -} - - -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); - hapd->wpa_auth = NULL; - - if (hostapd_set_privacy(hapd, 0)) { - wpa_printf(MSG_DEBUG, "Could not disable " - "PrivacyInvoked for interface %s", - hapd->conf->iface); - } - - if (hostapd_set_generic_elem(hapd, (u8 *) "", 0)) { - wpa_printf(MSG_DEBUG, "Could not remove generic " - "information element from interface %s", - hapd->conf->iface); - } - } - ieee802_1x_deinit(hapd); - -#ifdef CONFIG_IEEE80211R - l2_packet_deinit(hapd->l2); - hapd->l2 = NULL; -#endif /* CONFIG_IEEE80211R */ -} diff --git a/contrib/hostapd/src/ap/wpa_auth_glue.h b/contrib/hostapd/src/ap/wpa_auth_glue.h deleted file mode 100644 index 1b13ae7bef..0000000000 --- a/contrib/hostapd/src/ap/wpa_auth_glue.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * hostapd / WPA authenticator glue code - * Copyright (c) 2002-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_AUTH_GLUE_H -#define WPA_AUTH_GLUE_H - -int hostapd_setup_wpa(struct hostapd_data *hapd); -void hostapd_reconfig_wpa(struct hostapd_data *hapd); -void hostapd_deinit_wpa(struct hostapd_data *hapd); - -#endif /* WPA_AUTH_GLUE_H */ diff --git a/contrib/hostapd/src/ap/wpa_auth_i.h b/contrib/hostapd/src/ap/wpa_auth_i.h deleted file mode 100644 index fcd5878e74..0000000000 --- a/contrib/hostapd/src/ap/wpa_auth_i.h +++ /dev/null @@ -1,242 +0,0 @@ -/* - * hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_AUTH_I_H -#define WPA_AUTH_I_H - -/* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */ -#define RSNA_MAX_EAPOL_RETRIES 4 - -struct wpa_group; - -struct wpa_stsl_negotiation { - struct wpa_stsl_negotiation *next; - u8 initiator[ETH_ALEN]; - u8 peer[ETH_ALEN]; -}; - - -struct wpa_state_machine { - struct wpa_authenticator *wpa_auth; - struct wpa_group *group; - - u8 addr[ETH_ALEN]; - u8 p2p_dev_addr[ETH_ALEN]; - - enum { - WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED, - WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2, - WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART, - WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2, - WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE - } wpa_ptk_state; - - enum { - WPA_PTK_GROUP_IDLE = 0, - WPA_PTK_GROUP_REKEYNEGOTIATING, - WPA_PTK_GROUP_REKEYESTABLISHED, - WPA_PTK_GROUP_KEYERROR - } wpa_ptk_group_state; - - Boolean Init; - Boolean DeauthenticationRequest; - Boolean AuthenticationRequest; - Boolean ReAuthenticationRequest; - Boolean Disconnect; - int TimeoutCtr; - int GTimeoutCtr; - Boolean TimeoutEvt; - Boolean EAPOLKeyReceived; - Boolean EAPOLKeyPairwise; - Boolean EAPOLKeyRequest; - Boolean MICVerified; - Boolean GUpdateStationKeys; - u8 ANonce[WPA_NONCE_LEN]; - u8 SNonce[WPA_NONCE_LEN]; - u8 PMK[PMK_LEN]; - struct wpa_ptk PTK; - Boolean PTK_valid; - Boolean pairwise_set; - int keycount; - Boolean Pair; - struct wpa_key_replay_counter { - u8 counter[WPA_REPLAY_COUNTER_LEN]; - Boolean valid; - } key_replay[RSNA_MAX_EAPOL_RETRIES], - prev_key_replay[RSNA_MAX_EAPOL_RETRIES]; - Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */ - Boolean PTKRequest; /* not in IEEE 802.11i state machine */ - Boolean has_GTK; - Boolean PtkGroupInit; /* init request for PTK Group state machine */ - - u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */ - size_t last_rx_eapol_key_len; - - unsigned int changed:1; - unsigned int in_step_loop:1; - unsigned int pending_deinit:1; - unsigned int started:1; - unsigned int mgmt_frame_prot:1; - unsigned int rx_eapol_key_secure:1; - unsigned int update_snonce:1; -#ifdef CONFIG_IEEE80211R - unsigned int ft_completed:1; - unsigned int pmk_r1_name_valid:1; -#endif /* CONFIG_IEEE80211R */ - unsigned int is_wnmsleep:1; - - u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN]; - int req_replay_counter_used; - - u8 *wpa_ie; - size_t wpa_ie_len; - - enum { - WPA_VERSION_NO_WPA = 0 /* WPA not used */, - WPA_VERSION_WPA = 1 /* WPA / IEEE 802.11i/D3.0 */, - WPA_VERSION_WPA2 = 2 /* WPA2 / IEEE 802.11i */ - } wpa; - int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ - int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */ - struct rsn_pmksa_cache_entry *pmksa; - - u32 dot11RSNAStatsTKIPLocalMICFailures; - u32 dot11RSNAStatsTKIPRemoteMICFailures; - -#ifdef CONFIG_IEEE80211R - u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */ - size_t xxkey_len; - u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth - * Request */ - u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */ - size_t r0kh_id_len; - u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key - * message 2/4 */ - u8 *assoc_resp_ftie; -#endif /* CONFIG_IEEE80211R */ - - int pending_1_of_4_timeout; - -#ifdef CONFIG_P2P - u8 ip_addr[4]; -#endif /* CONFIG_P2P */ -}; - - -/* per group key state machine data */ -struct wpa_group { - struct wpa_group *next; - int vlan_id; - - Boolean GInit; - int GKeyDoneStations; - Boolean GTKReKey; - int GTK_len; - int GN, GM; - Boolean GTKAuthenticator; - u8 Counter[WPA_NONCE_LEN]; - - enum { - WPA_GROUP_GTK_INIT = 0, - WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE, - WPA_GROUP_FATAL_FAILURE - } wpa_group_state; - - u8 GMK[WPA_GMK_LEN]; - u8 GTK[2][WPA_GTK_MAX_LEN]; - u8 GNonce[WPA_NONCE_LEN]; - Boolean changed; - Boolean first_sta_seen; - Boolean reject_4way_hs_for_entropy; -#ifdef CONFIG_IEEE80211W - u8 IGTK[2][WPA_IGTK_LEN]; - int GN_igtk, GM_igtk; -#endif /* CONFIG_IEEE80211W */ -}; - - -struct wpa_ft_pmk_cache; - -/* per authenticator data */ -struct wpa_authenticator { - struct wpa_group *group; - - unsigned int dot11RSNAStatsTKIPRemoteMICFailures; - u32 dot11RSNAAuthenticationSuiteSelected; - u32 dot11RSNAPairwiseCipherSelected; - u32 dot11RSNAGroupCipherSelected; - u8 dot11RSNAPMKIDUsed[PMKID_LEN]; - u32 dot11RSNAAuthenticationSuiteRequested; /* FIX: update */ - u32 dot11RSNAPairwiseCipherRequested; /* FIX: update */ - u32 dot11RSNAGroupCipherRequested; /* FIX: update */ - unsigned int dot11RSNATKIPCounterMeasuresInvoked; - unsigned int dot11RSNA4WayHandshakeFailures; - - struct wpa_stsl_negotiation *stsl_negotiations; - - struct wpa_auth_config conf; - struct wpa_auth_callbacks cb; - - u8 *wpa_ie; - size_t wpa_ie_len; - - u8 addr[ETH_ALEN]; - - struct rsn_pmksa_cache *pmksa; - struct wpa_ft_pmk_cache *ft_pmk_cache; - -#ifdef CONFIG_P2P - struct bitfield *ip_pool; -#endif /* CONFIG_P2P */ -}; - - -int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, - const u8 *pmkid); -void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr, - logger_level level, const char *txt); -void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr, - logger_level level, const char *fmt, ...); -void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, int key_info, - const u8 *key_rsc, const u8 *nonce, - const u8 *kde, size_t kde_len, - int keyidx, int encr, int force_version); -int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth, - int (*cb)(struct wpa_state_machine *sm, void *ctx), - void *cb_ctx); -int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth, - int (*cb)(struct wpa_authenticator *a, void *ctx), - void *cb_ctx); - -#ifdef CONFIG_PEERKEY -int wpa_stsl_remove(struct wpa_authenticator *wpa_auth, - struct wpa_stsl_negotiation *neg); -void wpa_smk_error(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, struct wpa_eapol_key *key); -void wpa_smk_m1(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, struct wpa_eapol_key *key); -void wpa_smk_m3(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, struct wpa_eapol_key *key); -#endif /* CONFIG_PEERKEY */ - -#ifdef CONFIG_IEEE80211R -int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len); -int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id, - size_t r0kh_id_len, - const u8 *anonce, const u8 *snonce, - u8 *buf, size_t len, const u8 *subelem, - size_t subelem_len); -int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, - struct wpa_ptk *ptk, size_t ptk_len); -struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void); -void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache); -void wpa_ft_install_ptk(struct wpa_state_machine *sm); -#endif /* CONFIG_IEEE80211R */ - -#endif /* WPA_AUTH_I_H */ diff --git a/contrib/hostapd/src/ap/wpa_auth_ie.c b/contrib/hostapd/src/ap/wpa_auth_ie.c deleted file mode 100644 index 274f4d6216..0000000000 --- a/contrib/hostapd/src/ap/wpa_auth_ie.c +++ /dev/null @@ -1,794 +0,0 @@ -/* - * hostapd - WPA/RSN IE and KDE definitions - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "common/ieee802_11_defs.h" -#include "eapol_auth/eapol_auth_sm.h" -#include "ap_config.h" -#include "ieee802_11.h" -#include "wpa_auth.h" -#include "pmksa_cache_auth.h" -#include "wpa_auth_ie.h" -#include "wpa_auth_i.h" - - -#ifdef CONFIG_RSN_TESTING -int rsn_testing = 0; -#endif /* CONFIG_RSN_TESTING */ - - -static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len) -{ - struct wpa_ie_hdr *hdr; - int num_suites; - u8 *pos, *count; - u32 suite; - - hdr = (struct wpa_ie_hdr *) buf; - hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; - RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); - WPA_PUT_LE16(hdr->version, WPA_VERSION); - pos = (u8 *) (hdr + 1); - - suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group); - if (suite == 0) { - wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", - conf->wpa_group); - return -1; - } - RSN_SELECTOR_PUT(pos, suite); - pos += WPA_SELECTOR_LEN; - - count = pos; - pos += 2; - - num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise); - if (num_suites == 0) { - wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", - conf->wpa_pairwise); - return -1; - } - pos += num_suites * WPA_SELECTOR_LEN; - WPA_PUT_LE16(count, num_suites); - - num_suites = 0; - count = pos; - pos += 2; - - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { - RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); - pos += WPA_SELECTOR_LEN; - num_suites++; - } - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { - RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); - pos += WPA_SELECTOR_LEN; - num_suites++; - } - - if (num_suites == 0) { - wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", - conf->wpa_key_mgmt); - return -1; - } - WPA_PUT_LE16(count, num_suites); - - /* WPA Capabilities; use defaults, so no need to include it */ - - hdr->len = (pos - buf) - 2; - - return pos - buf; -} - - -int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, - const u8 *pmkid) -{ - struct rsn_ie_hdr *hdr; - int num_suites, res; - u8 *pos, *count; - u16 capab; - u32 suite; - - hdr = (struct rsn_ie_hdr *) buf; - hdr->elem_id = WLAN_EID_RSN; - WPA_PUT_LE16(hdr->version, RSN_VERSION); - pos = (u8 *) (hdr + 1); - - suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group); - if (suite == 0) { - wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", - conf->wpa_group); - return -1; - } - RSN_SELECTOR_PUT(pos, suite); - pos += RSN_SELECTOR_LEN; - - num_suites = 0; - count = pos; - pos += 2; - -#ifdef CONFIG_RSN_TESTING - if (rsn_testing) { - RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1)); - pos += RSN_SELECTOR_LEN; - num_suites++; - } -#endif /* CONFIG_RSN_TESTING */ - - res = rsn_cipher_put_suites(pos, conf->rsn_pairwise); - num_suites += res; - pos += res * RSN_SELECTOR_LEN; - -#ifdef CONFIG_RSN_TESTING - if (rsn_testing) { - RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2)); - pos += RSN_SELECTOR_LEN; - num_suites++; - } -#endif /* CONFIG_RSN_TESTING */ - - if (num_suites == 0) { - wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", - conf->rsn_pairwise); - return -1; - } - WPA_PUT_LE16(count, num_suites); - - num_suites = 0; - count = pos; - pos += 2; - -#ifdef CONFIG_RSN_TESTING - if (rsn_testing) { - RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1)); - pos += RSN_SELECTOR_LEN; - num_suites++; - } -#endif /* CONFIG_RSN_TESTING */ - - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); - pos += RSN_SELECTOR_LEN; - num_suites++; - } - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); - pos += RSN_SELECTOR_LEN; - num_suites++; - } -#ifdef CONFIG_IEEE80211R - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); - pos += RSN_SELECTOR_LEN; - num_suites++; - } - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); - pos += RSN_SELECTOR_LEN; - num_suites++; - } -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); - pos += RSN_SELECTOR_LEN; - num_suites++; - } - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); - pos += RSN_SELECTOR_LEN; - num_suites++; - } -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_SAE - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); - pos += RSN_SELECTOR_LEN; - num_suites++; - } - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); - pos += RSN_SELECTOR_LEN; - num_suites++; - } -#endif /* CONFIG_SAE */ - -#ifdef CONFIG_RSN_TESTING - if (rsn_testing) { - RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2)); - pos += RSN_SELECTOR_LEN; - num_suites++; - } -#endif /* CONFIG_RSN_TESTING */ - - if (num_suites == 0) { - wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", - conf->wpa_key_mgmt); - return -1; - } - WPA_PUT_LE16(count, num_suites); - - /* RSN Capabilities */ - capab = 0; - if (conf->rsn_preauth) - capab |= WPA_CAPABILITY_PREAUTH; - if (conf->peerkey) - capab |= WPA_CAPABILITY_PEERKEY_ENABLED; - if (conf->wmm_enabled) { - /* 4 PTKSA replay counters when using WMM */ - capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); - } -#ifdef CONFIG_IEEE80211W - if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { - capab |= WPA_CAPABILITY_MFPC; - if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) - capab |= WPA_CAPABILITY_MFPR; - } -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_RSN_TESTING - if (rsn_testing) - capab |= BIT(8) | BIT(14) | BIT(15); -#endif /* CONFIG_RSN_TESTING */ - WPA_PUT_LE16(pos, capab); - pos += 2; - - if (pmkid) { - if (pos + 2 + PMKID_LEN > buf + len) - return -1; - /* PMKID Count */ - WPA_PUT_LE16(pos, 1); - pos += 2; - os_memcpy(pos, pmkid, PMKID_LEN); - pos += PMKID_LEN; - } - -#ifdef CONFIG_IEEE80211W - if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { - if (pos + 2 + 4 > buf + len) - return -1; - if (pmkid == NULL) { - /* PMKID Count */ - WPA_PUT_LE16(pos, 0); - pos += 2; - } - - /* Management Group Cipher Suite */ - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); - pos += RSN_SELECTOR_LEN; - } -#endif /* CONFIG_IEEE80211W */ - -#ifdef CONFIG_RSN_TESTING - if (rsn_testing) { - /* - * Fill in any defined fields and add extra data to the end of - * the element. - */ - int pmkid_count_set = pmkid != NULL; - if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) - pmkid_count_set = 1; - /* PMKID Count */ - WPA_PUT_LE16(pos, 0); - pos += 2; - if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) { - /* Management Group Cipher Suite */ - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); - pos += RSN_SELECTOR_LEN; - } - - os_memset(pos, 0x12, 17); - pos += 17; - } -#endif /* CONFIG_RSN_TESTING */ - - hdr->len = (pos - buf) - 2; - - return pos - buf; -} - - -int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) -{ - u8 *pos, buf[128]; - int res; - - pos = buf; - - if (wpa_auth->conf.wpa & WPA_PROTO_RSN) { - res = wpa_write_rsn_ie(&wpa_auth->conf, - pos, buf + sizeof(buf) - pos, NULL); - if (res < 0) - return res; - pos += res; - } -#ifdef CONFIG_IEEE80211R - 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) - return res; - pos += res; - } -#endif /* CONFIG_IEEE80211R */ - if (wpa_auth->conf.wpa & WPA_PROTO_WPA) { - res = wpa_write_wpa_ie(&wpa_auth->conf, - pos, buf + sizeof(buf) - pos); - if (res < 0) - return res; - pos += res; - } - - os_free(wpa_auth->wpa_ie); - wpa_auth->wpa_ie = os_malloc(pos - buf); - if (wpa_auth->wpa_ie == NULL) - return -1; - os_memcpy(wpa_auth->wpa_ie, buf, pos - buf); - wpa_auth->wpa_ie_len = pos - buf; - - return 0; -} - - -u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len, - const u8 *data2, size_t data2_len) -{ - *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = RSN_SELECTOR_LEN + data_len + data2_len; - RSN_SELECTOR_PUT(pos, kde); - pos += RSN_SELECTOR_LEN; - os_memcpy(pos, data, data_len); - pos += data_len; - if (data2) { - os_memcpy(pos, data2, data2_len); - pos += data2_len; - } - return pos; -} - - -struct wpa_auth_okc_iter_data { - struct rsn_pmksa_cache_entry *pmksa; - const u8 *aa; - const u8 *spa; - const u8 *pmkid; -}; - - -static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx) -{ - struct wpa_auth_okc_iter_data *data = ctx; - data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa, - data->pmkid); - if (data->pmksa) - return 1; - return 0; -} - - -int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, - const u8 *wpa_ie, size_t wpa_ie_len, - const u8 *mdie, size_t mdie_len) -{ - struct wpa_ie_data data; - int ciphers, key_mgmt, res, version; - u32 selector; - size_t i; - const u8 *pmkid = NULL; - - if (wpa_auth == NULL || sm == NULL) - return WPA_NOT_ENABLED; - - if (wpa_ie == NULL || wpa_ie_len < 1) - return WPA_INVALID_IE; - - if (wpa_ie[0] == WLAN_EID_RSN) - version = WPA_PROTO_RSN; - else - version = WPA_PROTO_WPA; - - if (!(wpa_auth->conf.wpa & version)) { - wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR, - version, MAC2STR(sm->addr)); - return WPA_INVALID_PROTO; - } - - if (version == WPA_PROTO_RSN) { - res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data); - - selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; - if (0) { - } -#ifdef CONFIG_IEEE80211R - else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) - selector = RSN_AUTH_KEY_MGMT_FT_802_1X; - else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) - selector = RSN_AUTH_KEY_MGMT_FT_PSK; -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) - selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256; - else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) - selector = RSN_AUTH_KEY_MGMT_PSK_SHA256; -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_SAE - else if (data.key_mgmt & WPA_KEY_MGMT_SAE) - selector = RSN_AUTH_KEY_MGMT_SAE; - else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) - selector = RSN_AUTH_KEY_MGMT_FT_SAE; -#endif /* CONFIG_SAE */ - else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) - selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; - else if (data.key_mgmt & WPA_KEY_MGMT_PSK) - selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; - wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; - - selector = wpa_cipher_to_suite(WPA_PROTO_RSN, - data.pairwise_cipher); - if (!selector) - selector = RSN_CIPHER_SUITE_CCMP; - wpa_auth->dot11RSNAPairwiseCipherSelected = selector; - - selector = wpa_cipher_to_suite(WPA_PROTO_RSN, - data.group_cipher); - if (!selector) - selector = RSN_CIPHER_SUITE_CCMP; - wpa_auth->dot11RSNAGroupCipherSelected = selector; - } else { - res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data); - - selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; - if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) - selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; - else if (data.key_mgmt & WPA_KEY_MGMT_PSK) - selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X; - wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; - - selector = wpa_cipher_to_suite(WPA_PROTO_WPA, - data.pairwise_cipher); - if (!selector) - selector = RSN_CIPHER_SUITE_TKIP; - wpa_auth->dot11RSNAPairwiseCipherSelected = selector; - - selector = wpa_cipher_to_suite(WPA_PROTO_WPA, - data.group_cipher); - if (!selector) - selector = WPA_CIPHER_SUITE_TKIP; - wpa_auth->dot11RSNAGroupCipherSelected = selector; - } - if (res) { - wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from " - MACSTR " (res=%d)", MAC2STR(sm->addr), res); - wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len); - return WPA_INVALID_IE; - } - - if (data.group_cipher != wpa_auth->conf.wpa_group) { - wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from " - MACSTR, data.group_cipher, MAC2STR(sm->addr)); - return WPA_INVALID_GROUP; - } - - key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt; - if (!key_mgmt) { - wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from " - MACSTR, data.key_mgmt, MAC2STR(sm->addr)); - return WPA_INVALID_AKMP; - } - if (0) { - } -#ifdef CONFIG_IEEE80211R - else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) - sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; - else if (key_mgmt & WPA_KEY_MGMT_FT_PSK) - sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK; -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) - sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; - else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256) - sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256; -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_SAE - else if (key_mgmt & WPA_KEY_MGMT_SAE) - sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE; - else if (key_mgmt & WPA_KEY_MGMT_FT_SAE) - sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE; -#endif /* CONFIG_SAE */ - else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X) - sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X; - else - sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK; - - if (version == WPA_PROTO_RSN) - ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise; - else - ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise; - if (!ciphers) { - wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) " - "from " MACSTR, - version == WPA_PROTO_RSN ? "RSN" : "WPA", - data.pairwise_cipher, MAC2STR(sm->addr)); - return WPA_INVALID_PAIRWISE; - } - -#ifdef CONFIG_IEEE80211W - if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) { - if (!(data.capabilities & WPA_CAPABILITY_MFPC)) { - wpa_printf(MSG_DEBUG, "Management frame protection " - "required, but client did not enable it"); - return WPA_MGMT_FRAME_PROTECTION_VIOLATION; - } - - if (ciphers & WPA_CIPHER_TKIP) { - wpa_printf(MSG_DEBUG, "Management frame protection " - "cannot use TKIP"); - return WPA_MGMT_FRAME_PROTECTION_VIOLATION; - } - - if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { - wpa_printf(MSG_DEBUG, "Unsupported management group " - "cipher %d", data.mgmt_group_cipher); - return WPA_INVALID_MGMT_GROUP_CIPHER; - } - } - - if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION || - !(data.capabilities & WPA_CAPABILITY_MFPC)) - sm->mgmt_frame_prot = 0; - else - sm->mgmt_frame_prot = 1; -#endif /* CONFIG_IEEE80211W */ - -#ifdef CONFIG_IEEE80211R - if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { - if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) { - wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but " - "MDIE not included"); - return WPA_INVALID_MDIE; - } - if (os_memcmp(mdie, wpa_auth->conf.mobility_domain, - MOBILITY_DOMAIN_ID_LEN) != 0) { - wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown " - "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN); - return WPA_INVALID_MDIE; - } - } -#endif /* CONFIG_IEEE80211R */ - - sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0); - if (sm->pairwise < 0) - return WPA_INVALID_PAIRWISE; - - /* TODO: clear WPA/WPA2 state if STA changes from one to another */ - if (wpa_ie[0] == WLAN_EID_RSN) - sm->wpa = WPA_VERSION_WPA2; - else - sm->wpa = WPA_VERSION_WPA; - - sm->pmksa = NULL; - for (i = 0; i < data.num_pmkid; i++) { - wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID", - &data.pmkid[i * PMKID_LEN], PMKID_LEN); - sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr, - &data.pmkid[i * PMKID_LEN]); - if (sm->pmksa) { - pmkid = sm->pmksa->pmkid; - break; - } - } - for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc && - i < data.num_pmkid; i++) { - struct wpa_auth_okc_iter_data idata; - idata.pmksa = NULL; - idata.aa = wpa_auth->addr; - idata.spa = sm->addr; - idata.pmkid = &data.pmkid[i * PMKID_LEN]; - wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata); - if (idata.pmksa) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "OKC match for PMKID"); - sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa, - idata.pmksa, - wpa_auth->addr, - idata.pmkid); - pmkid = idata.pmkid; - break; - } - } - if (sm->pmksa) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "PMKID found from PMKSA cache " - "eap_type=%d vlan_id=%d", - sm->pmksa->eap_type_authsrv, - sm->pmksa->vlan_id); - os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN); - } - - if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) { - os_free(sm->wpa_ie); - sm->wpa_ie = os_malloc(wpa_ie_len); - if (sm->wpa_ie == NULL) - return WPA_ALLOC_FAIL; - } - os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len); - sm->wpa_ie_len = wpa_ie_len; - - return WPA_IE_OK; -} - - -/** - * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs - * @pos: Pointer to the IE header - * @end: Pointer to the end of the Key Data buffer - * @ie: Pointer to parsed IE data - * Returns: 0 on success, 1 if end mark is found, -1 on failure - */ -static int wpa_parse_generic(const u8 *pos, const u8 *end, - struct wpa_eapol_ie_parse *ie) -{ - if (pos[1] == 0) - return 1; - - if (pos[1] >= 6 && - RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && - pos[2 + WPA_SELECTOR_LEN] == 1 && - pos[2 + WPA_SELECTOR_LEN + 1] == 0) { - ie->wpa_ie = pos; - ie->wpa_ie_len = pos[1] + 2; - return 0; - } - - if (pos + 1 + RSN_SELECTOR_LEN < end && - pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { - ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { - ie->gtk = pos + 2 + RSN_SELECTOR_LEN; - ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { - ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; - ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; - return 0; - } - -#ifdef CONFIG_PEERKEY - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { - ie->smk = pos + 2 + RSN_SELECTOR_LEN; - ie->smk_len = pos[1] - RSN_SELECTOR_LEN; - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { - ie->nonce = pos + 2 + RSN_SELECTOR_LEN; - ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { - ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; - ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { - ie->error = pos + 2 + RSN_SELECTOR_LEN; - ie->error_len = pos[1] - RSN_SELECTOR_LEN; - return 0; - } -#endif /* CONFIG_PEERKEY */ - -#ifdef CONFIG_IEEE80211W - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { - ie->igtk = pos + 2 + RSN_SELECTOR_LEN; - ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; - return 0; - } -#endif /* CONFIG_IEEE80211W */ - -#ifdef CONFIG_P2P - if (pos[1] >= RSN_SELECTOR_LEN + 1 && - RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) { - ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key", - ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN); - return 0; - } - - if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 && - RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) { - ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, - "WPA: IP Address Allocation in EAPOL-Key", - ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN); - return 0; - } -#endif /* CONFIG_P2P */ - - return 0; -} - - -/** - * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs - * @buf: Pointer to the Key Data buffer - * @len: Key Data Length - * @ie: Pointer to parsed IE data - * Returns: 0 on success, -1 on failure - */ -int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) -{ - const u8 *pos, *end; - int ret = 0; - - os_memset(ie, 0, sizeof(*ie)); - for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { - if (pos[0] == 0xdd && - ((pos == buf + len - 1) || pos[1] == 0)) { - /* Ignore padding */ - break; - } - if (pos + 2 + pos[1] > end) { - wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " - "underflow (ie=%d len=%d pos=%d)", - pos[0], pos[1], (int) (pos - buf)); - wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", - buf, len); - ret = -1; - break; - } - if (*pos == WLAN_EID_RSN) { - ie->rsn_ie = pos; - ie->rsn_ie_len = pos[1] + 2; -#ifdef CONFIG_IEEE80211R - } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { - ie->mdie = pos; - ie->mdie_len = pos[1] + 2; - } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { - ie->ftie = pos; - ie->ftie_len = pos[1] + 2; -#endif /* CONFIG_IEEE80211R */ - } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { - ret = wpa_parse_generic(pos, end, ie); - if (ret < 0) - break; - if (ret > 0) { - ret = 0; - break; - } - } else { - wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " - "Key Data IE", pos, 2 + pos[1]); - } - } - - return ret; -} - - -int wpa_auth_uses_mfp(struct wpa_state_machine *sm) -{ - return sm ? sm->mgmt_frame_prot : 0; -} diff --git a/contrib/hostapd/src/ap/wpa_auth_ie.h b/contrib/hostapd/src/ap/wpa_auth_ie.h deleted file mode 100644 index f945882522..0000000000 --- a/contrib/hostapd/src/ap/wpa_auth_ie.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * hostapd - WPA/RSN IE and KDE definitions - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_AUTH_IE_H -#define WPA_AUTH_IE_H - -struct wpa_eapol_ie_parse { - const u8 *wpa_ie; - size_t wpa_ie_len; - const u8 *rsn_ie; - size_t rsn_ie_len; - const u8 *pmkid; - const u8 *gtk; - size_t gtk_len; - const u8 *mac_addr; - size_t mac_addr_len; -#ifdef CONFIG_PEERKEY - const u8 *smk; - size_t smk_len; - const u8 *nonce; - size_t nonce_len; - const u8 *lifetime; - size_t lifetime_len; - const u8 *error; - size_t error_len; -#endif /* CONFIG_PEERKEY */ -#ifdef CONFIG_IEEE80211W - const u8 *igtk; - size_t igtk_len; -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_IEEE80211R - const u8 *mdie; - size_t mdie_len; - const u8 *ftie; - size_t ftie_len; -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_P2P - const u8 *ip_addr_req; - const u8 *ip_addr_alloc; -#endif /* CONFIG_P2P */ -}; - -int wpa_parse_kde_ies(const u8 *buf, size_t len, - struct wpa_eapol_ie_parse *ie); -u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len, - const u8 *data2, size_t data2_len); -int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth); - -#endif /* WPA_AUTH_IE_H */ diff --git a/contrib/hostapd/src/ap/wps_hostapd.c b/contrib/hostapd/src/ap/wps_hostapd.c deleted file mode 100644 index 1b1dce4c4a..0000000000 --- a/contrib/hostapd/src/ap/wps_hostapd.c +++ /dev/null @@ -1,2002 +0,0 @@ -/* - * hostapd / WPS integration - * Copyright (c) 2008-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "utils/uuid.h" -#include "common/wpa_ctrl.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "eapol_auth/eapol_auth_sm.h" -#include "eapol_auth/eapol_auth_sm_i.h" -#include "wps/wps.h" -#include "wps/wps_defs.h" -#include "wps/wps_dev_attr.h" -#include "wps/wps_attr_parse.h" -#include "hostapd.h" -#include "ap_config.h" -#include "ap_drv_ops.h" -#include "beacon.h" -#include "sta_info.h" -#include "wps_hostapd.h" - - -#ifdef CONFIG_WPS_UPNP -#include "wps/wps_upnp.h" -static int hostapd_wps_upnp_init(struct hostapd_data *hapd, - struct wps_context *wps); -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, const u8 *da, - const u8 *bssid, - const u8 *ie, size_t ie_len, - int ssi_signal); -static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx); - - -struct wps_for_each_data { - int (*func)(struct hostapd_data *h, void *ctx); - void *ctx; - struct hostapd_data *calling_hapd; -}; - - -static int wps_for_each(struct hostapd_iface *iface, void *ctx) -{ - struct wps_for_each_data *data = ctx; - size_t j; - - if (iface == NULL) - return 0; - for (j = 0; j < iface->num_bss; j++) { - struct hostapd_data *hapd = iface->bss[j]; - int ret; - - if (hapd != data->calling_hapd && - (hapd->conf->wps_independent || - data->calling_hapd->conf->wps_independent)) - continue; - - ret = data->func(hapd, data->ctx); - if (ret) - return ret; - } - - return 0; -} - - -static int hostapd_wps_for_each(struct hostapd_data *hapd, - int (*func)(struct hostapd_data *h, void *ctx), - void *ctx) -{ - struct hostapd_iface *iface = hapd->iface; - struct wps_for_each_data data; - data.func = func; - data.ctx = ctx; - data.calling_hapd = hapd; - if (iface->interfaces == NULL || - iface->interfaces->for_each_interface == NULL) - return wps_for_each(iface, &data); - return iface->interfaces->for_each_interface(iface->interfaces, - wps_for_each, &data); -} - - -static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, - const u8 *p2p_dev_addr, const u8 *psk, - size_t psk_len) -{ - struct hostapd_data *hapd = ctx; - struct hostapd_wpa_psk *p; - struct hostapd_ssid *ssid = &hapd->conf->ssid; - - if (is_zero_ether_addr(p2p_dev_addr)) { - wpa_printf(MSG_DEBUG, - "Received new WPA/WPA2-PSK from WPS for STA " MACSTR, - MAC2STR(mac_addr)); - } else { - wpa_printf(MSG_DEBUG, - "Received new WPA/WPA2-PSK from WPS for STA " MACSTR - " P2P Device Addr " MACSTR, - MAC2STR(mac_addr), MAC2STR(p2p_dev_addr)); - } - wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len); - - if (psk_len != PMK_LEN) { - wpa_printf(MSG_DEBUG, "Unexpected PSK length %lu", - (unsigned long) psk_len); - return -1; - } - - /* Add the new PSK to runtime PSK list */ - p = os_zalloc(sizeof(*p)); - if (p == NULL) - return -1; - os_memcpy(p->addr, mac_addr, ETH_ALEN); - os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN); - os_memcpy(p->psk, psk, PMK_LEN); - - if (hapd->new_psk_cb) { - hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr, - psk, psk_len); - } - - p->next = ssid->wpa_psk; - ssid->wpa_psk = p; - - if (ssid->wpa_psk_file) { - FILE *f; - char hex[PMK_LEN * 2 + 1]; - /* Add the new PSK to PSK list file */ - f = fopen(ssid->wpa_psk_file, "a"); - if (f == NULL) { - wpa_printf(MSG_DEBUG, "Failed to add the PSK to " - "'%s'", ssid->wpa_psk_file); - return -1; - } - - wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len); - fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex); - fclose(f); - } - - return 0; -} - - -static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie, - struct wpabuf *probe_resp_ie) -{ - struct hostapd_data *hapd = ctx; - wpabuf_free(hapd->wps_beacon_ie); - hapd->wps_beacon_ie = beacon_ie; - wpabuf_free(hapd->wps_probe_resp_ie); - hapd->wps_probe_resp_ie = probe_resp_ie; - if (hapd->beacon_set_done) - ieee802_11_set_beacon(hapd); - return hostapd_set_ap_wps_ie(hapd); -} - - -static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e, - const struct wps_device_data *dev) -{ - struct hostapd_data *hapd = ctx; - char uuid[40], txt[400]; - int len; - char devtype[WPS_DEV_TYPE_BUFSIZE]; - if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) - return; - wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid); - len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED - "%s " MACSTR " [%s|%s|%s|%s|%s|%s]", - uuid, MAC2STR(dev->mac_addr), dev->device_name, - dev->manufacturer, dev->model_name, - dev->model_number, dev->serial_number, - wps_dev_type_bin2str(dev->pri_dev_type, devtype, - sizeof(devtype))); - if (len > 0 && len < (int) sizeof(txt)) - wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt); - - if (hapd->conf->wps_pin_requests) { - FILE *f; - struct os_time t; - f = fopen(hapd->conf->wps_pin_requests, "a"); - if (f == NULL) - return; - os_get_time(&t); - fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s" - "\t%s\n", - t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name, - dev->manufacturer, dev->model_name, dev->model_number, - dev->serial_number, - wps_dev_type_bin2str(dev->pri_dev_type, devtype, - sizeof(devtype))); - fclose(f); - } -} - - -struct wps_stop_reg_data { - struct hostapd_data *current_hapd; - const u8 *uuid_e; - const u8 *dev_pw; - size_t dev_pw_len; -}; - -static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx) -{ - struct wps_stop_reg_data *data = ctx; - if (hapd != data->current_hapd && hapd->wps != NULL) - wps_registrar_complete(hapd->wps->registrar, data->uuid_e, - data->dev_pw, data->dev_pw_len); - return 0; -} - - -static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr, - const u8 *uuid_e, const u8 *dev_pw, - size_t dev_pw_len) -{ - 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", - MAC2STR(mac_addr), uuid); - 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; - data.dev_pw = dev_pw; - data.dev_pw_len = dev_pw_len; - hostapd_wps_for_each(hapd, wps_stop_registrar, &data); -} - - -static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr, - const u8 *uuid_e, - const u8 *pri_dev_type, - u16 config_methods, - u16 dev_password_id, u8 request_type, - const char *dev_name) -{ - struct hostapd_data *hapd = ctx; - char uuid[40]; - char devtype[WPS_DEV_TYPE_BUFSIZE]; - if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) - return; - if (dev_name == NULL) - dev_name = ""; - wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ENROLLEE_SEEN MACSTR - " %s %s 0x%x %u %u [%s]", - MAC2STR(addr), uuid, - wps_dev_type_bin2str(pri_dev_type, devtype, - sizeof(devtype)), - config_methods, dev_password_id, request_type, dev_name); -} - - -static int str_starts(const char *str, const char *start) -{ - return os_strncmp(str, start, os_strlen(start)) == 0; -} - - -static void wps_reload_config(void *eloop_data, void *user_ctx) -{ - struct hostapd_iface *iface = eloop_data; - - wpa_printf(MSG_DEBUG, "WPS: Reload configuration data"); - if (iface->interfaces == NULL || - iface->interfaces->reload_config(iface) < 0) { - wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated " - "configuration"); - } -} - - -void hostapd_wps_eap_completed(struct hostapd_data *hapd) -{ - /* - * Reduce race condition of the station trying to reconnect immediately - * after AP reconfiguration through WPS by rescheduling the reload - * timeout to happen after EAP completion rather than the originally - * scheduled 100 ms after new configuration became known. - */ - if (eloop_deplete_timeout(0, 0, wps_reload_config, hapd->iface, NULL) == - 1) - wpa_printf(MSG_DEBUG, "WPS: Reschedule immediate configuration reload"); -} - - -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_reconfig_in_memory(struct hostapd_data *hapd, - const struct wps_credential *cred) -{ - struct hostapd_bss_config *bss = hapd->conf; - - wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration"); - - bss->wps_state = 2; - if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) { - os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len); - bss->ssid.ssid_len = cred->ssid_len; - bss->ssid.ssid_set = 1; - } - - if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) && - (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))) - bss->wpa = 3; - else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) - bss->wpa = 2; - else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)) - bss->wpa = 1; - else - bss->wpa = 0; - - if (bss->wpa) { - if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) - bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X; - if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) - bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK; - - bss->wpa_pairwise = 0; - if (cred->encr_type & WPS_ENCR_AES) - bss->wpa_pairwise |= WPA_CIPHER_CCMP; - if (cred->encr_type & WPS_ENCR_TKIP) - bss->wpa_pairwise |= WPA_CIPHER_TKIP; - bss->rsn_pairwise = bss->wpa_pairwise; - bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, - bss->wpa_pairwise, - bss->rsn_pairwise); - - if (cred->key_len >= 8 && cred->key_len < 64) { - os_free(bss->ssid.wpa_passphrase); - bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1); - if (bss->ssid.wpa_passphrase) - os_memcpy(bss->ssid.wpa_passphrase, cred->key, - cred->key_len); - os_free(bss->ssid.wpa_psk); - bss->ssid.wpa_psk = NULL; - } else if (cred->key_len == 64) { - os_free(bss->ssid.wpa_psk); - bss->ssid.wpa_psk = - os_zalloc(sizeof(struct hostapd_wpa_psk)); - if (bss->ssid.wpa_psk && - hexstr2bin((const char *) cred->key, - bss->ssid.wpa_psk->psk, PMK_LEN) == 0) { - bss->ssid.wpa_psk->group = 1; - os_free(bss->ssid.wpa_passphrase); - bss->ssid.wpa_passphrase = NULL; - } - } - bss->auth_algs = 1; - } else { - if ((cred->auth_type & WPS_AUTH_OPEN) && - (cred->auth_type & WPS_AUTH_SHARED)) - bss->auth_algs = 3; - else if (cred->auth_type & WPS_AUTH_SHARED) - bss->auth_algs = 2; - else - bss->auth_algs = 1; - if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx > 0 && - cred->key_idx <= 4) { - struct hostapd_wep_keys *wep = &bss->ssid.wep; - int idx = cred->key_idx; - if (idx) - idx--; - wep->idx = idx; - if (cred->key_len == 10 || cred->key_len == 26) { - os_free(wep->key[idx]); - wep->key[idx] = os_malloc(cred->key_len / 2); - if (wep->key[idx] == NULL || - hexstr2bin((const char *) cred->key, - wep->key[idx], - cred->key_len / 2)) - return -1; - wep->len[idx] = cred->key_len / 2; - } else { - os_free(wep->key[idx]); - wep->key[idx] = os_malloc(cred->key_len); - if (wep->key[idx] == NULL) - return -1; - os_memcpy(wep->key[idx], cred->key, - cred->key_len); - wep->len[idx] = cred->key_len; - } - wep->keys_set = 1; - } - } - - /* Schedule configuration reload after short period of time to allow - * EAP-WSC to be finished. - */ - eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface, - NULL); - - return 0; -} - - -static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) -{ - const struct wps_credential *cred = ctx; - FILE *oconf, *nconf; - size_t len, i; - char *tmp_fname; - char buf[1024]; - int multi_bss; - int wpa; - - if (hapd->wps == NULL) - return 0; - - wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute", - cred->cred_attr, cred->cred_attr_len); - - wpa_printf(MSG_DEBUG, "WPS: Received new AP Settings"); - wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len); - wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x", - cred->auth_type); - wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type); - wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx); - wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", - cred->key, cred->key_len); - wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, - MAC2STR(cred->mac_addr)); - - if ((hapd->conf->wps_cred_processing == 1 || - hapd->conf->wps_cred_processing == 2) && cred->cred_attr) { - 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); - - if (hapd->conf->wps_cred_processing == 1) - return 0; - - os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len); - hapd->wps->ssid_len = cred->ssid_len; - hapd->wps->encr_types = cred->encr_type; - hapd->wps->auth_types = cred->auth_type; - if (cred->key_len == 0) { - os_free(hapd->wps->network_key); - hapd->wps->network_key = NULL; - hapd->wps->network_key_len = 0; - } else { - if (hapd->wps->network_key == NULL || - hapd->wps->network_key_len < cred->key_len) { - hapd->wps->network_key_len = 0; - os_free(hapd->wps->network_key); - hapd->wps->network_key = os_malloc(cred->key_len); - if (hapd->wps->network_key == NULL) - return -1; - } - hapd->wps->network_key_len = cred->key_len; - os_memcpy(hapd->wps->network_key, cred->key, cred->key_len); - } - hapd->wps->wps_state = WPS_STATE_CONFIGURED; - - if (hapd->iface->config_fname == NULL) - return hapd_wps_reconfig_in_memory(hapd, cred); - len = os_strlen(hapd->iface->config_fname) + 5; - tmp_fname = os_malloc(len); - if (tmp_fname == NULL) - return -1; - os_snprintf(tmp_fname, len, "%s-new", hapd->iface->config_fname); - - oconf = fopen(hapd->iface->config_fname, "r"); - if (oconf == NULL) { - wpa_printf(MSG_WARNING, "WPS: Could not open current " - "configuration file"); - os_free(tmp_fname); - return -1; - } - - nconf = fopen(tmp_fname, "w"); - if (nconf == NULL) { - wpa_printf(MSG_WARNING, "WPS: Could not write updated " - "configuration file"); - os_free(tmp_fname); - fclose(oconf); - return -1; - } - - fprintf(nconf, "# WPS configuration - START\n"); - - fprintf(nconf, "wps_state=2\n"); - - if (is_hex(cred->ssid, cred->ssid_len)) { - fprintf(nconf, "ssid2="); - for (i = 0; i < cred->ssid_len; i++) - fprintf(nconf, "%02x", cred->ssid[i]); - fprintf(nconf, "\n"); - } else { - fprintf(nconf, "ssid="); - for (i = 0; i < cred->ssid_len; i++) - fputc(cred->ssid[i], nconf); - fprintf(nconf, "\n"); - } - - if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) && - (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))) - wpa = 3; - else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) - wpa = 2; - else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)) - wpa = 1; - else - wpa = 0; - - if (wpa) { - char *prefix; - fprintf(nconf, "wpa=%d\n", wpa); - - fprintf(nconf, "wpa_key_mgmt="); - prefix = ""; - if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) { - fprintf(nconf, "WPA-EAP"); - prefix = " "; - } - if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) - fprintf(nconf, "%sWPA-PSK", prefix); - fprintf(nconf, "\n"); - - fprintf(nconf, "wpa_pairwise="); - prefix = ""; - if (cred->encr_type & WPS_ENCR_AES) { - fprintf(nconf, "CCMP"); - prefix = " "; - } - if (cred->encr_type & WPS_ENCR_TKIP) { - fprintf(nconf, "%sTKIP", prefix); - } - fprintf(nconf, "\n"); - - if (cred->key_len >= 8 && cred->key_len < 64) { - fprintf(nconf, "wpa_passphrase="); - for (i = 0; i < cred->key_len; i++) - fputc(cred->key[i], nconf); - fprintf(nconf, "\n"); - } else if (cred->key_len == 64) { - fprintf(nconf, "wpa_psk="); - for (i = 0; i < cred->key_len; i++) - fputc(cred->key[i], nconf); - fprintf(nconf, "\n"); - } else { - wpa_printf(MSG_WARNING, "WPS: Invalid key length %lu " - "for WPA/WPA2", - (unsigned long) cred->key_len); - } - - fprintf(nconf, "auth_algs=1\n"); - } else { - if ((cred->auth_type & WPS_AUTH_OPEN) && - (cred->auth_type & WPS_AUTH_SHARED)) - fprintf(nconf, "auth_algs=3\n"); - else if (cred->auth_type & WPS_AUTH_SHARED) - fprintf(nconf, "auth_algs=2\n"); - else - fprintf(nconf, "auth_algs=1\n"); - - if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx <= 4) { - int key_idx = cred->key_idx; - if (key_idx) - key_idx--; - fprintf(nconf, "wep_default_key=%d\n", key_idx); - fprintf(nconf, "wep_key%d=", key_idx); - if (cred->key_len == 10 || cred->key_len == 26) { - /* WEP key as a hex string */ - for (i = 0; i < cred->key_len; i++) - fputc(cred->key[i], nconf); - } else { - /* Raw WEP key; convert to hex */ - for (i = 0; i < cred->key_len; i++) - fprintf(nconf, "%02x", cred->key[i]); - } - fprintf(nconf, "\n"); - } - } - - fprintf(nconf, "# WPS configuration - END\n"); - - multi_bss = 0; - while (fgets(buf, sizeof(buf), oconf)) { - if (os_strncmp(buf, "bss=", 4) == 0) - multi_bss = 1; - if (!multi_bss && - (str_starts(buf, "ssid=") || - str_starts(buf, "ssid2=") || - str_starts(buf, "auth_algs=") || - str_starts(buf, "wep_default_key=") || - str_starts(buf, "wep_key") || - str_starts(buf, "wps_state=") || - str_starts(buf, "wpa=") || - str_starts(buf, "wpa_psk=") || - str_starts(buf, "wpa_pairwise=") || - str_starts(buf, "rsn_pairwise=") || - str_starts(buf, "wpa_key_mgmt=") || - str_starts(buf, "wpa_passphrase="))) { - fprintf(nconf, "#WPS# %s", buf); - } else - fprintf(nconf, "%s", buf); - } - - fclose(nconf); - fclose(oconf); - - if (rename(tmp_fname, hapd->iface->config_fname) < 0) { - wpa_printf(MSG_WARNING, "WPS: Failed to rename the updated " - "configuration file: %s", strerror(errno)); - os_free(tmp_fname); - return -1; - } - - os_free(tmp_fname); - - /* Schedule configuration reload after short period of time to allow - * EAP-WSC to be finished. - */ - eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface, - NULL); - - wpa_printf(MSG_DEBUG, "WPS: AP configuration updated"); - - return 0; -} - - -static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred) -{ - struct hostapd_data *hapd = ctx; - return hostapd_wps_for_each(hapd, hapd_wps_cred_cb, (void *) cred); -} - - -static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx) -{ - struct hostapd_data *hapd = eloop_data; - - if (hapd->conf->ap_setup_locked) - return; - if (hapd->ap_pin_failures_consecutive >= 10) - return; - - wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN"); - wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); - hapd->wps->ap_setup_locked = 0; - wps_registrar_update_ie(hapd->wps->registrar); -} - - -static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx) -{ - struct wps_event_pwd_auth_fail *data = ctx; - - if (!data->enrollee || hapd->conf->ap_pin == NULL || hapd->wps == NULL) - return 0; - - /* - * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup - * for some time if this happens multiple times to slow down brute - * force attacks. - */ - hapd->ap_pin_failures++; - hapd->ap_pin_failures_consecutive++; - wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u " - "(%u consecutive)", - hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive); - if (hapd->ap_pin_failures < 3) - return 0; - - wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED); - hapd->wps->ap_setup_locked = 1; - - wps_registrar_update_ie(hapd->wps->registrar); - - if (!hapd->conf->ap_setup_locked && - hapd->ap_pin_failures_consecutive >= 10) { - /* - * In indefinite lockdown - disable automatic AP PIN - * reenablement. - */ - eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); - wpa_printf(MSG_DEBUG, "WPS: AP PIN disabled indefinitely"); - } else if (!hapd->conf->ap_setup_locked) { - if (hapd->ap_pin_lockout_time == 0) - hapd->ap_pin_lockout_time = 60; - else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 && - (hapd->ap_pin_failures % 3) == 0) - hapd->ap_pin_lockout_time *= 2; - - wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds", - hapd->ap_pin_lockout_time); - eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); - eloop_register_timeout(hapd->ap_pin_lockout_time, 0, - hostapd_wps_reenable_ap_pin, hapd, - NULL); - } - - return 0; -} - - -static void hostapd_pwd_auth_fail(struct hostapd_data *hapd, - struct wps_event_pwd_auth_fail *data) -{ - /* Update WPS Status - Authentication Failure */ - wpa_printf(MSG_DEBUG, "WPS: Authentication failure update"); - hapd->wps_stats.status = WPS_STATUS_FAILURE; - hapd->wps_stats.failure_reason = WPS_EI_AUTH_FAILURE; - os_memcpy(hapd->wps_stats.peer_addr, data->peer_macaddr, ETH_ALEN); - - hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data); -} - - -static int wps_ap_pin_success(struct hostapd_data *hapd, void *ctx) -{ - if (hapd->conf->ap_pin == NULL || hapd->wps == NULL) - return 0; - - if (hapd->ap_pin_failures_consecutive == 0) - return 0; - - wpa_printf(MSG_DEBUG, "WPS: Clear consecutive AP PIN failure counter " - "- total validation failures %u (%u consecutive)", - hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive); - hapd->ap_pin_failures_consecutive = 0; - - return 0; -} - - -static void hostapd_wps_ap_pin_success(struct hostapd_data *hapd) -{ - hostapd_wps_for_each(hapd, wps_ap_pin_success, NULL); -} - - -static void hostapd_wps_event_pbc_overlap(struct hostapd_data *hapd) -{ - /* Update WPS Status - PBC Overlap */ - hapd->wps_stats.pbc_status = WPS_PBC_STATUS_OVERLAP; -} - - -static void hostapd_wps_event_pbc_timeout(struct hostapd_data *hapd) -{ - /* Update WPS PBC Status:PBC Timeout */ - hapd->wps_stats.pbc_status = WPS_PBC_STATUS_TIMEOUT; -} - - -static void hostapd_wps_event_pbc_active(struct hostapd_data *hapd) -{ - /* Update WPS PBC status - Active */ - hapd->wps_stats.pbc_status = WPS_PBC_STATUS_ACTIVE; -} - - -static void hostapd_wps_event_pbc_disable(struct hostapd_data *hapd) -{ - /* Update WPS PBC status - Active */ - hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE; -} - - -static void hostapd_wps_event_success(struct hostapd_data *hapd, - struct wps_event_success *success) -{ - /* Update WPS status - Success */ - hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE; - hapd->wps_stats.status = WPS_STATUS_SUCCESS; - os_memcpy(hapd->wps_stats.peer_addr, success->peer_macaddr, ETH_ALEN); -} - - -static void hostapd_wps_event_fail(struct hostapd_data *hapd, - struct wps_event_fail *fail) -{ - /* Update WPS status - Failure */ - hapd->wps_stats.status = WPS_STATUS_FAILURE; - os_memcpy(hapd->wps_stats.peer_addr, fail->peer_macaddr, ETH_ALEN); - - hapd->wps_stats.failure_reason = fail->error_indication; - - if (fail->error_indication > 0 && - fail->error_indication < NUM_WPS_EI_VALUES) { - wpa_msg(hapd->msg_ctx, MSG_INFO, - WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", - fail->msg, fail->config_error, fail->error_indication, - wps_ei_str(fail->error_indication)); - } else { - wpa_msg(hapd->msg_ctx, MSG_INFO, - WPS_EVENT_FAIL "msg=%d config_error=%d", - fail->msg, fail->config_error); - } -} - - -static void hostapd_wps_event_cb(void *ctx, enum wps_event event, - union wps_event_data *data) -{ - struct hostapd_data *hapd = ctx; - - 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: - hostapd_wps_event_success(hapd, &data->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: - hostapd_wps_event_pbc_overlap(hapd); - wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP); - break; - case WPS_EV_PBC_TIMEOUT: - hostapd_wps_event_pbc_timeout(hapd); - wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT); - break; - case WPS_EV_PBC_ACTIVE: - hostapd_wps_event_pbc_active(hapd); - wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ACTIVE); - break; - case WPS_EV_PBC_DISABLE: - hostapd_wps_event_pbc_disable(hapd); - wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_DISABLE); - break; - case WPS_EV_ER_AP_ADD: - break; - case WPS_EV_ER_AP_REMOVE: - break; - case WPS_EV_ER_ENROLLEE_ADD: - break; - case WPS_EV_ER_ENROLLEE_REMOVE: - break; - case WPS_EV_ER_AP_SETTINGS: - break; - case WPS_EV_ER_SET_SELECTED_REGISTRAR: - break; - case WPS_EV_AP_PIN_SUCCESS: - hostapd_wps_ap_pin_success(hapd); - break; - } - if (hapd->wps_event_cb) - hapd->wps_event_cb(hapd->wps_event_cb_ctx, event, data); -} - - -static int hostapd_wps_rf_band_cb(void *ctx) -{ - struct hostapd_data *hapd = ctx; - - return hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ? - WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ -} - - -static void hostapd_wps_clear_ies(struct hostapd_data *hapd) -{ - wpabuf_free(hapd->wps_beacon_ie); - hapd->wps_beacon_ie = NULL; - - wpabuf_free(hapd->wps_probe_resp_ie); - hapd->wps_probe_resp_ie = NULL; - - hostapd_set_ap_wps_ie(hapd); -} - - -static int get_uuid_cb(struct hostapd_iface *iface, void *ctx) -{ - const u8 **uuid = ctx; - size_t j; - - if (iface == NULL) - return 0; - for (j = 0; j < iface->num_bss; j++) { - struct hostapd_data *hapd = iface->bss[j]; - if (hapd->wps && !hapd->conf->wps_independent && - !is_nil_uuid(hapd->wps->uuid)) { - *uuid = hapd->wps->uuid; - return 1; - } - } - - return 0; -} - - -static const u8 * get_own_uuid(struct hostapd_iface *iface) -{ - const u8 *uuid; - if (iface->interfaces == NULL || - iface->interfaces->for_each_interface == NULL) - return NULL; - uuid = NULL; - iface->interfaces->for_each_interface(iface->interfaces, get_uuid_cb, - &uuid); - return uuid; -} - - -static int count_interface_cb(struct hostapd_iface *iface, void *ctx) -{ - int *count= ctx; - (*count)++; - return 0; -} - - -static int interface_count(struct hostapd_iface *iface) -{ - int count = 0; - if (iface->interfaces == NULL || - iface->interfaces->for_each_interface == NULL) - return 0; - iface->interfaces->for_each_interface(iface->interfaces, - count_interface_cb, &count); - return count; -} - - -static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd, - struct wps_context *wps) -{ - int i; - - for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { - wpabuf_free(wps->dev.vendor_ext[i]); - wps->dev.vendor_ext[i] = NULL; - - if (hapd->conf->wps_vendor_ext[i] == NULL) - continue; - - wps->dev.vendor_ext[i] = - wpabuf_dup(hapd->conf->wps_vendor_ext[i]); - if (wps->dev.vendor_ext[i] == NULL) { - while (--i >= 0) - wpabuf_free(wps->dev.vendor_ext[i]); - return -1; - } - } - - return 0; -} - - -int hostapd_init_wps(struct hostapd_data *hapd, - struct hostapd_bss_config *conf) -{ - struct wps_context *wps; - struct wps_registrar_config cfg; - - if (conf->wps_state == 0) { - hostapd_wps_clear_ies(hapd); - return 0; - } - - wps = os_zalloc(sizeof(*wps)); - if (wps == NULL) - return -1; - - wps->cred_cb = hostapd_wps_cred_cb; - wps->event_cb = hostapd_wps_event_cb; - wps->rf_band_cb = hostapd_wps_rf_band_cb; - wps->cb_ctx = hapd; - - os_memset(&cfg, 0, sizeof(cfg)); - wps->wps_state = hapd->conf->wps_state; - wps->ap_setup_locked = hapd->conf->ap_setup_locked; - if (is_nil_uuid(hapd->conf->uuid)) { - const u8 *uuid; - uuid = get_own_uuid(hapd->iface); - if (uuid && !conf->wps_independent) { - os_memcpy(wps->uuid, uuid, UUID_LEN); - wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another " - "interface", wps->uuid, UUID_LEN); - } else { - uuid_gen_mac_addr(hapd->own_addr, wps->uuid); - wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC " - "address", wps->uuid, UUID_LEN); - } - } else { - os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN); - wpa_hexdump(MSG_DEBUG, "WPS: Use configured UUID", - wps->uuid, UUID_LEN); - } - wps->ssid_len = hapd->conf->ssid.ssid_len; - os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len); - wps->ap = 1; - os_memcpy(wps->dev.mac_addr, hapd->own_addr, ETH_ALEN); - wps->dev.device_name = hapd->conf->device_name ? - os_strdup(hapd->conf->device_name) : NULL; - wps->dev.manufacturer = hapd->conf->manufacturer ? - os_strdup(hapd->conf->manufacturer) : NULL; - wps->dev.model_name = hapd->conf->model_name ? - os_strdup(hapd->conf->model_name) : NULL; - wps->dev.model_number = hapd->conf->model_number ? - os_strdup(hapd->conf->model_number) : NULL; - wps->dev.serial_number = hapd->conf->serial_number ? - os_strdup(hapd->conf->serial_number) : NULL; - wps->config_methods = - wps_config_methods_str2bin(hapd->conf->config_methods); -#ifdef CONFIG_WPS2 - if ((wps->config_methods & - (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY | - WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) { - wpa_printf(MSG_INFO, "WPS: Converting display to " - "virtual_display for WPS 2.0 compliance"); - wps->config_methods |= WPS_CONFIG_VIRT_DISPLAY; - } - if ((wps->config_methods & - (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON | - WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) { - wpa_printf(MSG_INFO, "WPS: Converting push_button to " - "virtual_push_button for WPS 2.0 compliance"); - wps->config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON; - } -#endif /* CONFIG_WPS2 */ - os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type, - WPS_DEV_TYPE_LEN); - - if (hostapd_wps_set_vendor_ext(hapd, wps) < 0) { - os_free(wps); - return -1; - } - - wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version); - - 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) - wps->auth_types |= WPS_AUTH_WPA2PSK; - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) - wps->auth_types |= WPS_AUTH_WPA2; - - if (conf->rsn_pairwise & WPA_CIPHER_CCMP) - wps->encr_types |= WPS_ENCR_AES; - if (conf->rsn_pairwise & WPA_CIPHER_TKIP) - wps->encr_types |= WPS_ENCR_TKIP; - } - - if (conf->wpa & WPA_PROTO_WPA) { - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) - wps->auth_types |= WPS_AUTH_WPAPSK; - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) - wps->auth_types |= WPS_AUTH_WPA; - - if (conf->wpa_pairwise & WPA_CIPHER_CCMP) - wps->encr_types |= WPS_ENCR_AES; - if (conf->wpa_pairwise & WPA_CIPHER_TKIP) - wps->encr_types |= WPS_ENCR_TKIP; - } - - if (conf->ssid.security_policy == SECURITY_PLAINTEXT) { - wps->encr_types |= WPS_ENCR_NONE; - wps->auth_types |= WPS_AUTH_OPEN; - } else if (conf->ssid.security_policy == SECURITY_STATIC_WEP) { - wps->encr_types |= WPS_ENCR_WEP; - if (conf->auth_algs & WPA_AUTH_ALG_OPEN) - wps->auth_types |= WPS_AUTH_OPEN; - if (conf->auth_algs & WPA_AUTH_ALG_SHARED) - wps->auth_types |= WPS_AUTH_SHARED; - } else if (conf->ssid.security_policy == SECURITY_IEEE_802_1X) { - wps->auth_types |= WPS_AUTH_OPEN; - if (conf->default_wep_key_len) - wps->encr_types |= WPS_ENCR_WEP; - else - wps->encr_types |= WPS_ENCR_NONE; - } - - if (conf->ssid.wpa_psk_file) { - /* Use per-device PSKs */ - } else if (conf->ssid.wpa_passphrase) { - wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase); - wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase); - } else if (conf->ssid.wpa_psk) { - wps->network_key = os_malloc(2 * PMK_LEN + 1); - if (wps->network_key == NULL) { - os_free(wps); - return -1; - } - wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1, - conf->ssid.wpa_psk->psk, PMK_LEN); - wps->network_key_len = 2 * PMK_LEN; - } else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) { - wps->network_key = os_malloc(conf->ssid.wep.len[0]); - if (wps->network_key == NULL) { - os_free(wps); - return -1; - } - os_memcpy(wps->network_key, conf->ssid.wep.key[0], - conf->ssid.wep.len[0]); - wps->network_key_len = conf->ssid.wep.len[0]; - } - - if (conf->ssid.wpa_psk) { - os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN); - wps->psk_set = 1; - } - - if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) { - /* Override parameters to enable security by default */ - wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK; - wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP; - } - - wps->ap_settings = conf->ap_settings; - wps->ap_settings_len = conf->ap_settings_len; - - cfg.new_psk_cb = hostapd_wps_new_psk_cb; - cfg.set_ie_cb = hostapd_wps_set_ie_cb; - cfg.pin_needed_cb = hostapd_wps_pin_needed_cb; - cfg.reg_success_cb = hostapd_wps_reg_success_cb; - cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb; - cfg.cb_ctx = hapd; - cfg.skip_cred_build = conf->skip_cred_build; - cfg.extra_cred = conf->extra_cred; - cfg.extra_cred_len = conf->extra_cred_len; - cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) && - conf->skip_cred_build; - if (conf->ssid.security_policy == SECURITY_STATIC_WEP) - cfg.static_wep_only = 1; - cfg.dualband = interface_count(hapd->iface) > 1; - if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) == - (WPS_RF_50GHZ | WPS_RF_24GHZ)) - cfg.dualband = 1; - if (cfg.dualband) - wpa_printf(MSG_DEBUG, "WPS: Dualband AP"); - cfg.force_per_enrollee_psk = conf->force_per_enrollee_psk; - - wps->registrar = wps_registrar_init(wps, &cfg); - if (wps->registrar == NULL) { - wpa_printf(MSG_ERROR, "Failed to initialize WPS Registrar"); - os_free(wps->network_key); - os_free(wps); - return -1; - } - -#ifdef CONFIG_WPS_UPNP - wps->friendly_name = hapd->conf->friendly_name; - wps->manufacturer_url = hapd->conf->manufacturer_url; - wps->model_description = hapd->conf->model_description; - wps->model_url = hapd->conf->model_url; - wps->upc = hapd->conf->upc; -#endif /* CONFIG_WPS_UPNP */ - - hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd); - - hapd->wps = wps; - - return 0; -} - - -int hostapd_init_wps_complete(struct hostapd_data *hapd) -{ - struct wps_context *wps = hapd->wps; - - if (wps == NULL) - return 0; - -#ifdef CONFIG_WPS_UPNP - if (hostapd_wps_upnp_init(hapd, wps) < 0) { - wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP"); - wps_registrar_deinit(wps->registrar); - os_free(wps->network_key); - os_free(wps); - hapd->wps = NULL; - return -1; - } -#endif /* CONFIG_WPS_UPNP */ - - return 0; -} - - -static void hostapd_wps_nfc_clear(struct wps_context *wps) -{ -#ifdef CONFIG_WPS_NFC - wpa_printf(MSG_DEBUG, "WPS: Clear NFC Tag context %p", wps); - wps->ap_nfc_dev_pw_id = 0; - wpabuf_free(wps->ap_nfc_dh_pubkey); - wps->ap_nfc_dh_pubkey = NULL; - wpabuf_free(wps->ap_nfc_dh_privkey); - wps->ap_nfc_dh_privkey = NULL; - wpabuf_free(wps->ap_nfc_dev_pw); - wps->ap_nfc_dev_pw = NULL; -#endif /* CONFIG_WPS_NFC */ -} - - -void hostapd_deinit_wps(struct hostapd_data *hapd) -{ - eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); - eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); - eloop_cancel_timeout(wps_reload_config, hapd->iface, NULL); - if (hapd->wps == NULL) - return; -#ifdef CONFIG_WPS_UPNP - hostapd_wps_upnp_deinit(hapd); -#endif /* CONFIG_WPS_UPNP */ - wps_registrar_deinit(hapd->wps->registrar); - os_free(hapd->wps->network_key); - wps_device_data_free(&hapd->wps->dev); - wpabuf_free(hapd->wps->dh_pubkey); - wpabuf_free(hapd->wps->dh_privkey); - wps_free_pending_msgs(hapd->wps->upnp_msgs); - hostapd_wps_nfc_clear(hapd->wps); - os_free(hapd->wps); - hapd->wps = NULL; - hostapd_wps_clear_ies(hapd); -} - - -void hostapd_update_wps(struct hostapd_data *hapd) -{ - if (hapd->wps == NULL) - return; - -#ifdef CONFIG_WPS_UPNP - hapd->wps->friendly_name = hapd->conf->friendly_name; - hapd->wps->manufacturer_url = hapd->conf->manufacturer_url; - hapd->wps->model_description = hapd->conf->model_description; - hapd->wps->model_url = hapd->conf->model_url; - hapd->wps->upc = hapd->conf->upc; -#endif /* CONFIG_WPS_UPNP */ - - hostapd_wps_set_vendor_ext(hapd, hapd->wps); - - if (hapd->conf->wps_state) - wps_registrar_update_ie(hapd->wps->registrar); - else - hostapd_deinit_wps(hapd); -} - - -struct wps_add_pin_data { - const u8 *addr; - const u8 *uuid; - const u8 *pin; - size_t pin_len; - int timeout; - int added; -}; - - -static int wps_add_pin(struct hostapd_data *hapd, void *ctx) -{ - struct wps_add_pin_data *data = ctx; - int ret; - - if (hapd->wps == NULL) - return 0; - ret = wps_registrar_add_pin(hapd->wps->registrar, data->addr, - data->uuid, data->pin, data->pin_len, - data->timeout); - if (ret == 0) - data->added++; - return ret; -} - - -int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr, - const char *uuid, const char *pin, int timeout) -{ - u8 u[UUID_LEN]; - struct wps_add_pin_data data; - - data.addr = addr; - data.uuid = u; - data.pin = (const u8 *) pin; - data.pin_len = os_strlen(pin); - data.timeout = timeout; - data.added = 0; - - if (os_strcmp(uuid, "any") == 0) - data.uuid = NULL; - else { - if (uuid_str2bin(uuid, u)) - return -1; - data.uuid = u; - } - if (hostapd_wps_for_each(hapd, wps_add_pin, &data) < 0) - return -1; - return data.added ? 0 : -1; -} - - -static int wps_button_pushed(struct hostapd_data *hapd, void *ctx) -{ - const u8 *p2p_dev_addr = ctx; - if (hapd->wps == NULL) - return 0; - return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr); -} - - -int hostapd_wps_button_pushed(struct hostapd_data *hapd, - const u8 *p2p_dev_addr) -{ - return hostapd_wps_for_each(hapd, wps_button_pushed, - (void *) p2p_dev_addr); -} - - -static int wps_cancel(struct hostapd_data *hapd, void *ctx) -{ - if (hapd->wps == NULL) - return 0; - - wps_registrar_wps_cancel(hapd->wps->registrar); - ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL); - - return 0; -} - - -int hostapd_wps_cancel(struct hostapd_data *hapd) -{ - return hostapd_wps_for_each(hapd, wps_cancel, NULL); -} - - -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, - int ssi_signal) -{ - struct hostapd_data *hapd = ctx; - struct wpabuf *wps_ie; - struct ieee802_11_elems elems; - - if (hapd->wps == NULL) - return 0; - - if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { - wpa_printf(MSG_DEBUG, "WPS: Could not parse ProbeReq from " - MACSTR, MAC2STR(addr)); - return 0; - } - - if (elems.ssid && elems.ssid_len > 0 && - (elems.ssid_len != hapd->conf->ssid.ssid_len || - os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) != - 0)) - return 0; /* Not for us */ - - wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); - if (wps_ie == NULL) - return 0; - if (wps_validate_probe_req(wps_ie, addr) < 0) { - wpabuf_free(wps_ie); - return 0; - } - - if (wpabuf_len(wps_ie) > 0) { - int p2p_wildcard = 0; -#ifdef CONFIG_P2P - if (elems.ssid && elems.ssid_len == P2P_WILDCARD_SSID_LEN && - os_memcmp(elems.ssid, P2P_WILDCARD_SSID, - P2P_WILDCARD_SSID_LEN) == 0) - p2p_wildcard = 1; -#endif /* CONFIG_P2P */ - wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie, - p2p_wildcard); -#ifdef CONFIG_WPS_UPNP - /* FIX: what exactly should be included in the WLANEvent? - * WPS attributes? Full ProbeReq frame? */ - if (!p2p_wildcard) - upnp_wps_device_send_wlan_event( - hapd->wps_upnp, addr, - UPNP_WPS_WLANEVENT_TYPE_PROBE, wps_ie); -#endif /* CONFIG_WPS_UPNP */ - } - - wpabuf_free(wps_ie); - - return 0; -} - - -#ifdef CONFIG_WPS_UPNP - -static int hostapd_rx_req_put_wlan_response( - void *priv, enum upnp_wps_wlanevent_type ev_type, - const u8 *mac_addr, const struct wpabuf *msg, - enum wps_msg_type msg_type) -{ - struct hostapd_data *hapd = priv; - struct sta_info *sta; - struct upnp_pending_message *p; - - wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr=" - MACSTR, ev_type, MAC2STR(mac_addr)); - wpa_hexdump(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage", - wpabuf_head(msg), wpabuf_len(msg)); - if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) { - wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected " - "PutWLANResponse WLANEventType %d", ev_type); - return -1; - } - - /* - * EAP response to ongoing to WPS Registration. Send it to EAP-WSC - * server implementation for delivery to the peer. - */ - - sta = ap_get_sta(hapd, mac_addr); -#ifndef CONFIG_WPS_STRICT - if (!sta) { - /* - * Workaround - Intel wsccmd uses bogus NewWLANEventMAC: - * Pick STA that is in an ongoing WPS registration without - * checking the MAC address. - */ - wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based " - "on NewWLANEventMAC; try wildcard match"); - for (sta = hapd->sta_list; sta; sta = sta->next) { - if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS)) - break; - } - } -#endif /* CONFIG_WPS_STRICT */ - - if (!sta || !(sta->flags & WLAN_STA_WPS)) { - wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found"); - return 0; - } - - p = os_zalloc(sizeof(*p)); - if (p == NULL) - return -1; - os_memcpy(p->addr, sta->addr, ETH_ALEN); - p->msg = wpabuf_dup(msg); - p->type = msg_type; - p->next = hapd->wps->upnp_msgs; - hapd->wps->upnp_msgs = p; - - return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap); -} - - -static int hostapd_wps_upnp_init(struct hostapd_data *hapd, - struct wps_context *wps) -{ - struct upnp_wps_device_ctx *ctx; - - if (!hapd->conf->upnp_iface) - return 0; - ctx = os_zalloc(sizeof(*ctx)); - if (ctx == NULL) - return -1; - - ctx->rx_req_put_wlan_response = hostapd_rx_req_put_wlan_response; - if (hapd->conf->ap_pin) - ctx->ap_pin = os_strdup(hapd->conf->ap_pin); - - hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd, - hapd->conf->upnp_iface); - if (hapd->wps_upnp == NULL) - return -1; - wps->wps_upnp = hapd->wps_upnp; - - return 0; -} - - -static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd) -{ - upnp_wps_device_deinit(hapd->wps_upnp, hapd); -} - -#endif /* CONFIG_WPS_UPNP */ - - -int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, - char *buf, size_t buflen) -{ - if (hapd->wps == NULL) - return 0; - return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen); -} - - -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); -} - - -static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout) -{ - wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout); - hapd->ap_pin_failures = 0; - hapd->ap_pin_failures_consecutive = 0; - hapd->conf->ap_setup_locked = 0; - if (hapd->wps->ap_setup_locked) { - wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); - hapd->wps->ap_setup_locked = 0; - wps_registrar_update_ie(hapd->wps->registrar); - } - eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); - if (timeout > 0) - eloop_register_timeout(timeout, 0, - hostapd_wps_ap_pin_timeout, hapd, NULL); -} - - -static int wps_ap_pin_disable(struct hostapd_data *hapd, void *ctx) -{ - os_free(hapd->conf->ap_pin); - hapd->conf->ap_pin = NULL; -#ifdef CONFIG_WPS_UPNP - upnp_wps_set_ap_pin(hapd->wps_upnp, NULL); -#endif /* CONFIG_WPS_UPNP */ - eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); - return 0; -} - - -void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd) -{ - wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN"); - hostapd_wps_for_each(hapd, wps_ap_pin_disable, NULL); -} - - -struct wps_ap_pin_data { - char pin_txt[9]; - int timeout; -}; - - -static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx) -{ - struct wps_ap_pin_data *data = ctx; - os_free(hapd->conf->ap_pin); - hapd->conf->ap_pin = os_strdup(data->pin_txt); -#ifdef CONFIG_WPS_UPNP - upnp_wps_set_ap_pin(hapd->wps_upnp, data->pin_txt); -#endif /* CONFIG_WPS_UPNP */ - hostapd_wps_ap_pin_enable(hapd, data->timeout); - return 0; -} - - -const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout) -{ - unsigned int pin; - struct wps_ap_pin_data data; - - pin = wps_generate_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; -} - - -const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd) -{ - return hapd->conf->ap_pin; -} - - -int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin, - int timeout) -{ - struct wps_ap_pin_data data; - int ret; - - ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin); - if (ret < 0 || ret >= (int) sizeof(data.pin_txt)) - return -1; - data.timeout = timeout; - return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data); -} - - -static int wps_update_ie(struct hostapd_data *hapd, void *ctx) -{ - if (hapd->wps) - wps_registrar_update_ie(hapd->wps->registrar); - return 0; -} - - -void hostapd_wps_update_ie(struct hostapd_data *hapd) -{ - hostapd_wps_for_each(hapd, wps_update_ie, NULL); -} - - -int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid, - const char *auth, const char *encr, const char *key) -{ - struct wps_credential cred; - size_t len; - - os_memset(&cred, 0, sizeof(cred)); - - len = os_strlen(ssid); - if ((len & 1) || len > 2 * sizeof(cred.ssid) || - hexstr2bin(ssid, cred.ssid, len / 2)) - return -1; - cred.ssid_len = len / 2; - - if (os_strncmp(auth, "OPEN", 4) == 0) - cred.auth_type = WPS_AUTH_OPEN; - else if (os_strncmp(auth, "WPAPSK", 6) == 0) - cred.auth_type = WPS_AUTH_WPAPSK; - else if (os_strncmp(auth, "WPA2PSK", 7) == 0) - cred.auth_type = WPS_AUTH_WPA2PSK; - else - return -1; - - if (encr) { - if (os_strncmp(encr, "NONE", 4) == 0) - cred.encr_type = WPS_ENCR_NONE; - else if (os_strncmp(encr, "WEP", 3) == 0) - cred.encr_type = WPS_ENCR_WEP; - else if (os_strncmp(encr, "TKIP", 4) == 0) - cred.encr_type = WPS_ENCR_TKIP; - else if (os_strncmp(encr, "CCMP", 4) == 0) - cred.encr_type = WPS_ENCR_AES; - else - return -1; - } else - cred.encr_type = WPS_ENCR_NONE; - - if (key) { - len = os_strlen(key); - if ((len & 1) || len > 2 * sizeof(cred.key) || - hexstr2bin(key, cred.key, len / 2)) - return -1; - cred.key_len = len / 2; - } - - return wps_registrar_config_ap(hapd->wps->registrar, &cred); -} - - -#ifdef CONFIG_WPS_NFC - -struct wps_nfc_password_token_data { - const u8 *oob_dev_pw; - size_t oob_dev_pw_len; - int added; -}; - - -static int wps_add_nfc_password_token(struct hostapd_data *hapd, void *ctx) -{ - struct wps_nfc_password_token_data *data = ctx; - int ret; - - if (hapd->wps == NULL) - return 0; - ret = wps_registrar_add_nfc_password_token(hapd->wps->registrar, - data->oob_dev_pw, - data->oob_dev_pw_len); - if (ret == 0) - data->added++; - return ret; -} - - -static int hostapd_wps_add_nfc_password_token(struct hostapd_data *hapd, - struct wps_parse_attr *attr) -{ - struct wps_nfc_password_token_data data; - - data.oob_dev_pw = attr->oob_dev_password; - data.oob_dev_pw_len = attr->oob_dev_password_len; - data.added = 0; - if (hostapd_wps_for_each(hapd, wps_add_nfc_password_token, &data) < 0) - return -1; - return data.added ? 0 : -1; -} - - -static int hostapd_wps_nfc_tag_process(struct hostapd_data *hapd, - const struct wpabuf *wps) -{ - struct wps_parse_attr attr; - - wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps); - - if (wps_parse_msg(wps, &attr)) { - wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag"); - return -1; - } - - if (attr.oob_dev_password) - return hostapd_wps_add_nfc_password_token(hapd, &attr); - - wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag"); - return -1; -} - - -int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd, - const struct wpabuf *data) -{ - const struct wpabuf *wps = data; - struct wpabuf *tmp = NULL; - int ret; - - if (wpabuf_len(data) < 4) - return -1; - - if (*wpabuf_head_u8(data) != 0x10) { - /* Assume this contains full NDEF record */ - tmp = ndef_parse_wifi(data); - if (tmp == NULL) { - wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF"); - return -1; - } - wps = tmp; - } - - ret = hostapd_wps_nfc_tag_process(hapd, wps); - wpabuf_free(tmp); - return ret; -} - - -struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd, - int ndef) -{ - struct wpabuf *ret; - - if (hapd->wps == NULL) - return NULL; - - ret = wps_get_oob_cred(hapd->wps, hostapd_wps_rf_band_cb(hapd), - hapd->iconf->channel); - if (ndef && ret) { - struct wpabuf *tmp; - tmp = ndef_build_wifi(ret); - wpabuf_free(ret); - if (tmp == NULL) - return NULL; - ret = tmp; - } - - return ret; -} - - -struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef) -{ - struct wpabuf *ret; - - if (hapd->wps == NULL) - return NULL; - - if (hapd->conf->wps_nfc_dh_pubkey == NULL) { - struct wps_context *wps = hapd->wps; - if (wps_nfc_gen_dh(&hapd->conf->wps_nfc_dh_pubkey, - &hapd->conf->wps_nfc_dh_privkey) < 0) - return NULL; - hostapd_wps_nfc_clear(wps); - wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER; - wps->ap_nfc_dh_pubkey = - wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey); - wps->ap_nfc_dh_privkey = - wpabuf_dup(hapd->conf->wps_nfc_dh_privkey); - if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) { - hostapd_wps_nfc_clear(wps); - return NULL; - } - } - - ret = wps_build_nfc_handover_sel(hapd->wps, - hapd->conf->wps_nfc_dh_pubkey, - hapd->own_addr, hapd->iface->freq); - - if (ndef && ret) { - struct wpabuf *tmp; - tmp = ndef_build_wifi(ret); - wpabuf_free(ret); - if (tmp == NULL) - return NULL; - ret = tmp; - } - - return ret; -} - - -int hostapd_wps_nfc_report_handover(struct hostapd_data *hapd, - const struct wpabuf *req, - const struct wpabuf *sel) -{ - struct wpabuf *wps; - int ret = -1; - u16 wsc_len; - const u8 *pos; - struct wpabuf msg; - struct wps_parse_attr attr; - u16 dev_pw_id; - - /* - * Enrollee/station is always initiator of the NFC connection handover, - * so use the request message here to find Enrollee public key hash. - */ - wps = ndef_parse_wifi(req); - if (wps == NULL) - return -1; - wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc " - "payload from NFC connection handover"); - wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps); - if (wpabuf_len(wps) < 2) { - wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request " - "Message"); - goto out; - } - pos = wpabuf_head(wps); - wsc_len = WPA_GET_BE16(pos); - if (wsc_len > wpabuf_len(wps) - 2) { - wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) " - "in rt Wi-Fi Handover Request Message", wsc_len); - goto out; - } - pos += 2; - - wpa_hexdump(MSG_DEBUG, - "WPS: WSC attributes in Wi-Fi Handover Request Message", - pos, wsc_len); - if (wsc_len < wpabuf_len(wps) - 2) { - wpa_hexdump(MSG_DEBUG, - "WPS: Ignore extra data after WSC attributes", - pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len); - } - - wpabuf_set(&msg, pos, wsc_len); - ret = wps_parse_msg(&msg, &attr); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in " - "Wi-Fi Handover Request Message"); - goto out; - } - - if (attr.oob_dev_password == NULL || - attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) { - wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password " - "included in Wi-Fi Handover Request Message"); - ret = -1; - goto out; - } - - if (attr.uuid_e == NULL) { - wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi " - "Handover Request Message"); - ret = -1; - goto out; - } - - wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN); - - wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password", - attr.oob_dev_password, attr.oob_dev_password_len); - dev_pw_id = WPA_GET_BE16(attr.oob_dev_password + - WPS_OOB_PUBKEY_HASH_LEN); - if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) { - wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID " - "%u in Wi-Fi Handover Request Message", dev_pw_id); - ret = -1; - goto out; - } - wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash", - attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN); - - ret = wps_registrar_add_nfc_pw_token(hapd->wps->registrar, - attr.oob_dev_password, - DEV_PW_NFC_CONNECTION_HANDOVER, - NULL, 0, 1); - -out: - wpabuf_free(wps); - return ret; -} - - -struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef) -{ - if (hapd->conf->wps_nfc_pw_from_config) { - return wps_nfc_token_build(ndef, - hapd->conf->wps_nfc_dev_pw_id, - hapd->conf->wps_nfc_dh_pubkey, - hapd->conf->wps_nfc_dev_pw); - } - - return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id, - &hapd->conf->wps_nfc_dh_pubkey, - &hapd->conf->wps_nfc_dh_privkey, - &hapd->conf->wps_nfc_dev_pw); -} - - -int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd) -{ - struct wps_context *wps = hapd->wps; - struct wpabuf *pw; - - if (wps == NULL) - return -1; - - if (!hapd->conf->wps_nfc_dh_pubkey || - !hapd->conf->wps_nfc_dh_privkey || - !hapd->conf->wps_nfc_dev_pw || - !hapd->conf->wps_nfc_dev_pw_id) - return -1; - - hostapd_wps_nfc_clear(wps); - wpa_printf(MSG_DEBUG, - "WPS: Enable NFC Tag (Dev Pw Id %u) for AP interface %s (context %p)", - hapd->conf->wps_nfc_dev_pw_id, hapd->conf->iface, wps); - wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id; - wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey); - wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey); - pw = hapd->conf->wps_nfc_dev_pw; - wps->ap_nfc_dev_pw = wpabuf_alloc( - wpabuf_len(pw) * 2 + 1); - if (wps->ap_nfc_dev_pw) { - wpa_snprintf_hex_uppercase( - (char *) wpabuf_put(wps->ap_nfc_dev_pw, - wpabuf_len(pw) * 2), - wpabuf_len(pw) * 2 + 1, - wpabuf_head(pw), wpabuf_len(pw)); - } - - if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey || - !wps->ap_nfc_dev_pw) { - hostapd_wps_nfc_clear(wps); - return -1; - } - - return 0; -} - - -void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd) -{ - wpa_printf(MSG_DEBUG, "WPS: Disable NFC token for AP interface %s", - hapd->conf->iface); - hostapd_wps_nfc_clear(hapd->wps); -} - -#endif /* CONFIG_WPS_NFC */ diff --git a/contrib/hostapd/src/ap/wps_hostapd.h b/contrib/hostapd/src/ap/wps_hostapd.h deleted file mode 100644 index 204bd820a5..0000000000 --- a/contrib/hostapd/src/ap/wps_hostapd.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * hostapd / WPS integration - * Copyright (c) 2008-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPS_HOSTAPD_H -#define WPS_HOSTAPD_H - -#ifdef CONFIG_WPS - -int hostapd_init_wps(struct hostapd_data *hapd, - struct hostapd_bss_config *conf); -int hostapd_init_wps_complete(struct hostapd_data *hapd); -void hostapd_deinit_wps(struct hostapd_data *hapd); -void hostapd_update_wps(struct hostapd_data *hapd); -void hostapd_wps_eap_completed(struct hostapd_data *hapd); -int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr, - const char *uuid, const char *pin, int timeout); -int hostapd_wps_button_pushed(struct hostapd_data *hapd, - const u8 *p2p_dev_addr); -int hostapd_wps_cancel(struct hostapd_data *hapd); -int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, - char *buf, size_t buflen); -void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd); -const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout); -const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd); -int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin, - int timeout); -void hostapd_wps_update_ie(struct hostapd_data *hapd); -int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid, - const char *auth, const char *encr, const char *key); -int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd, - const struct wpabuf *data); -struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd, - int ndef); -struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef); -int hostapd_wps_nfc_report_handover(struct hostapd_data *hapd, - const struct wpabuf *req, - const struct wpabuf *sel); -struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef); -int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd); -void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd); - -#else /* CONFIG_WPS */ - -static inline int hostapd_init_wps(struct hostapd_data *hapd, - struct hostapd_bss_config *conf) -{ - return 0; -} - -static inline void hostapd_deinit_wps(struct hostapd_data *hapd) -{ -} - -static inline int hostapd_init_wps_complete(struct hostapd_data *hapd) -{ - return 0; -} - -static inline void hostapd_update_wps(struct hostapd_data *hapd) -{ -} - -static inline void hostapd_wps_eap_completed(struct hostapd_data *hapd) -{ -} - -static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, - const u8 *addr, - char *buf, size_t buflen) -{ - return 0; -} - -static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd, - const u8 *p2p_dev_addr) -{ - return 0; -} - -static inline int hostapd_wps_cancel(struct hostapd_data *hapd) -{ - return 0; -} - -#endif /* CONFIG_WPS */ - -#endif /* WPS_HOSTAPD_H */ diff --git a/contrib/hostapd/src/common/defs.h b/contrib/hostapd/src/common/defs.h deleted file mode 100644 index 4811e8e909..0000000000 --- a/contrib/hostapd/src/common/defs.h +++ /dev/null @@ -1,299 +0,0 @@ -/* - * WPA Supplicant - Common definitions - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef DEFS_H -#define DEFS_H - -#ifdef FALSE -#undef FALSE -#endif -#ifdef TRUE -#undef TRUE -#endif -typedef enum { FALSE = 0, TRUE = 1 } Boolean; - - -#define WPA_CIPHER_NONE BIT(0) -#define WPA_CIPHER_WEP40 BIT(1) -#define WPA_CIPHER_WEP104 BIT(2) -#define WPA_CIPHER_TKIP BIT(3) -#define WPA_CIPHER_CCMP BIT(4) -#define WPA_CIPHER_AES_128_CMAC BIT(5) -#define WPA_CIPHER_GCMP BIT(6) -#define WPA_CIPHER_SMS4 BIT(7) -#define WPA_CIPHER_GCMP_256 BIT(8) -#define WPA_CIPHER_CCMP_256 BIT(9) -#define WPA_CIPHER_BIP_GMAC_128 BIT(11) -#define WPA_CIPHER_BIP_GMAC_256 BIT(12) -#define WPA_CIPHER_BIP_CMAC_256 BIT(13) -#define WPA_CIPHER_GTK_NOT_USED BIT(14) - -#define WPA_KEY_MGMT_IEEE8021X BIT(0) -#define WPA_KEY_MGMT_PSK BIT(1) -#define WPA_KEY_MGMT_NONE BIT(2) -#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3) -#define WPA_KEY_MGMT_WPA_NONE BIT(4) -#define WPA_KEY_MGMT_FT_IEEE8021X BIT(5) -#define WPA_KEY_MGMT_FT_PSK BIT(6) -#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7) -#define WPA_KEY_MGMT_PSK_SHA256 BIT(8) -#define WPA_KEY_MGMT_WPS BIT(9) -#define WPA_KEY_MGMT_SAE BIT(10) -#define WPA_KEY_MGMT_FT_SAE BIT(11) -#define WPA_KEY_MGMT_WAPI_PSK BIT(12) -#define WPA_KEY_MGMT_WAPI_CERT BIT(13) -#define WPA_KEY_MGMT_CCKM BIT(14) - -static inline int wpa_key_mgmt_wpa_ieee8021x(int akm) -{ - return !!(akm & (WPA_KEY_MGMT_IEEE8021X | - WPA_KEY_MGMT_FT_IEEE8021X | - WPA_KEY_MGMT_CCKM | - WPA_KEY_MGMT_IEEE8021X_SHA256)); -} - -static inline int wpa_key_mgmt_wpa_psk(int akm) -{ - return !!(akm & (WPA_KEY_MGMT_PSK | - WPA_KEY_MGMT_FT_PSK | - WPA_KEY_MGMT_PSK_SHA256 | - WPA_KEY_MGMT_SAE | - WPA_KEY_MGMT_FT_SAE)); -} - -static inline int wpa_key_mgmt_ft(int akm) -{ - return !!(akm & (WPA_KEY_MGMT_FT_PSK | - WPA_KEY_MGMT_FT_IEEE8021X | - WPA_KEY_MGMT_FT_SAE)); -} - -static inline int wpa_key_mgmt_sae(int akm) -{ - return !!(akm & (WPA_KEY_MGMT_SAE | - WPA_KEY_MGMT_FT_SAE)); -} - -static inline int wpa_key_mgmt_sha256(int akm) -{ - return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 | - WPA_KEY_MGMT_IEEE8021X_SHA256)); -} - -static inline int wpa_key_mgmt_wpa(int akm) -{ - return wpa_key_mgmt_wpa_ieee8021x(akm) || - wpa_key_mgmt_wpa_psk(akm) || - wpa_key_mgmt_sae(akm); -} - -static inline int wpa_key_mgmt_wpa_any(int akm) -{ - return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE); -} - -static inline int wpa_key_mgmt_cckm(int akm) -{ - return akm == WPA_KEY_MGMT_CCKM; -} - - -#define WPA_PROTO_WPA BIT(0) -#define WPA_PROTO_RSN BIT(1) -#define WPA_PROTO_WAPI BIT(2) - -#define WPA_AUTH_ALG_OPEN BIT(0) -#define WPA_AUTH_ALG_SHARED BIT(1) -#define WPA_AUTH_ALG_LEAP BIT(2) -#define WPA_AUTH_ALG_FT BIT(3) -#define WPA_AUTH_ALG_SAE BIT(4) - - -enum wpa_alg { - WPA_ALG_NONE, - WPA_ALG_WEP, - WPA_ALG_TKIP, - WPA_ALG_CCMP, - WPA_ALG_IGTK, - WPA_ALG_PMK, - WPA_ALG_GCMP, - WPA_ALG_SMS4, - WPA_ALG_KRK, - WPA_ALG_GCMP_256, - WPA_ALG_CCMP_256, - WPA_ALG_BIP_GMAC_128, - WPA_ALG_BIP_GMAC_256, - WPA_ALG_BIP_CMAC_256 -}; - -/** - * enum wpa_states - wpa_supplicant state - * - * These enumeration values are used to indicate the current wpa_supplicant - * state (wpa_s->wpa_state). The current state can be retrieved with - * wpa_supplicant_get_state() function and the state can be changed by calling - * wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the - * wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used - * to access the state variable. - */ -enum wpa_states { - /** - * WPA_DISCONNECTED - Disconnected state - * - * This state indicates that client is not associated, but is likely to - * start looking for an access point. This state is entered when a - * connection is lost. - */ - WPA_DISCONNECTED, - - /** - * WPA_INTERFACE_DISABLED - Interface disabled - * - * This stat eis entered if the network interface is disabled, e.g., - * due to rfkill. wpa_supplicant refuses any new operations that would - * use the radio until the interface has been enabled. - */ - WPA_INTERFACE_DISABLED, - - /** - * WPA_INACTIVE - Inactive state (wpa_supplicant disabled) - * - * This state is entered if there are no enabled networks in the - * configuration. wpa_supplicant is not trying to associate with a new - * network and external interaction (e.g., ctrl_iface call to add or - * enable a network) is needed to start association. - */ - WPA_INACTIVE, - - /** - * WPA_SCANNING - Scanning for a network - * - * This state is entered when wpa_supplicant starts scanning for a - * network. - */ - WPA_SCANNING, - - /** - * WPA_AUTHENTICATING - Trying to authenticate with a BSS/SSID - * - * This state is entered when wpa_supplicant has found a suitable BSS - * to authenticate with and the driver is configured to try to - * authenticate with this BSS. This state is used only with drivers - * that use wpa_supplicant as the SME. - */ - WPA_AUTHENTICATING, - - /** - * WPA_ASSOCIATING - Trying to associate with a BSS/SSID - * - * This state is entered when wpa_supplicant has found a suitable BSS - * to associate with and the driver is configured to try to associate - * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this - * state is entered when the driver is configured to try to associate - * with a network using the configured SSID and security policy. - */ - WPA_ASSOCIATING, - - /** - * WPA_ASSOCIATED - Association completed - * - * This state is entered when the driver reports that association has - * been successfully completed with an AP. If IEEE 802.1X is used - * (with or without WPA/WPA2), wpa_supplicant remains in this state - * until the IEEE 802.1X/EAPOL authentication has been completed. - */ - WPA_ASSOCIATED, - - /** - * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress - * - * This state is entered when WPA/WPA2 4-Way Handshake is started. In - * case of WPA-PSK, this happens when receiving the first EAPOL-Key - * frame after association. In case of WPA-EAP, this state is entered - * when the IEEE 802.1X/EAPOL authentication has been completed. - */ - WPA_4WAY_HANDSHAKE, - - /** - * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress - * - * This state is entered when 4-Way Key Handshake has been completed - * (i.e., when the supplicant sends out message 4/4) and when Group - * Key rekeying is started by the AP (i.e., when supplicant receives - * message 1/2). - */ - WPA_GROUP_HANDSHAKE, - - /** - * WPA_COMPLETED - All authentication completed - * - * This state is entered when the full authentication process is - * completed. In case of WPA2, this happens when the 4-Way Handshake is - * successfully completed. With WPA, this state is entered after the - * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is - * completed after dynamic keys are received (or if not used, after - * the EAP authentication has been completed). With static WEP keys and - * plaintext connections, this state is entered when an association - * has been completed. - * - * This state indicates that the supplicant has completed its - * processing for the association phase and that data connection is - * fully configured. - */ - WPA_COMPLETED -}; - -#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0 -#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1 -#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2 -#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3 - -#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0 -#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1 - - -/** - * enum mfp_options - Management frame protection (IEEE 802.11w) options - */ -enum mfp_options { - NO_MGMT_FRAME_PROTECTION = 0, - MGMT_FRAME_PROTECTION_OPTIONAL = 1, - MGMT_FRAME_PROTECTION_REQUIRED = 2, -}; -#define MGMT_FRAME_PROTECTION_DEFAULT 3 - -/** - * enum hostapd_hw_mode - Hardware mode - */ -enum hostapd_hw_mode { - HOSTAPD_MODE_IEEE80211B, - HOSTAPD_MODE_IEEE80211G, - HOSTAPD_MODE_IEEE80211A, - HOSTAPD_MODE_IEEE80211AD, - 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, - WPA_CTRL_REQ_SIM, - 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/contrib/hostapd/src/common/eapol_common.h b/contrib/hostapd/src/common/eapol_common.h deleted file mode 100644 index 4811f38aab..0000000000 --- a/contrib/hostapd/src/common/eapol_common.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * EAPOL definitions shared between hostapd and wpa_supplicant - * Copyright (c) 2002-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAPOL_COMMON_H -#define EAPOL_COMMON_H - -/* IEEE Std 802.1X-2004 */ - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct ieee802_1x_hdr { - u8 version; - u8 type; - be16 length; - /* followed by length octets of data */ -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - -#define EAPOL_VERSION 2 - -enum { IEEE802_1X_TYPE_EAP_PACKET = 0, - IEEE802_1X_TYPE_EAPOL_START = 1, - IEEE802_1X_TYPE_EAPOL_LOGOFF = 2, - IEEE802_1X_TYPE_EAPOL_KEY = 3, - IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4 -}; - -enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2, - EAPOL_KEY_TYPE_WPA = 254 }; - - -#define IEEE8021X_REPLAY_COUNTER_LEN 8 -#define IEEE8021X_KEY_SIGN_LEN 16 -#define IEEE8021X_KEY_IV_LEN 16 - -#define IEEE8021X_KEY_INDEX_FLAG 0x80 -#define IEEE8021X_KEY_INDEX_MASK 0x03 - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct ieee802_1x_eapol_key { - u8 type; - /* Note: key_length is unaligned */ - u8 key_length[2]; - /* does not repeat within the life of the keying material used to - * encrypt the Key field; 64-bit NTP timestamp MAY be used here */ - u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN]; - u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */ - u8 key_index; /* key flag in the most significant bit: - * 0 = broadcast (default key), - * 1 = unicast (key mapping key); key index is in the - * 7 least significant bits */ - /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as - * the key */ - u8 key_signature[IEEE8021X_KEY_SIGN_LEN]; - - /* followed by key: if packet body length = 44 + key length, then the - * key field (of key_length bytes) contains the key in encrypted form; - * if packet body length = 44, key field is absent and key_length - * represents the number of least significant octets from - * MS-MPPE-Send-Key attribute to be used as the keying material; - * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */ -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - -#endif /* EAPOL_COMMON_H */ diff --git a/contrib/hostapd/src/common/gas.c b/contrib/hostapd/src/common/gas.c deleted file mode 100644 index cff9254b74..0000000000 --- a/contrib/hostapd/src/common/gas.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Generic advertisement service (GAS) (IEEE 802.11u) - * Copyright (c) 2009, Atheros Communications - * Copyright (c) 2011-2012, Qualcomm Atheros - * - * This software may be distributed under the terms of the BSD license. - * See README 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; -} - - -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/contrib/hostapd/src/common/gas.h b/contrib/hostapd/src/common/gas.h deleted file mode 100644 index 306adc58c6..0000000000 --- a/contrib/hostapd/src/common/gas.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Generic advertisement service (GAS) (IEEE 802.11u) - * Copyright (c) 2009, Atheros Communications - * Copyright (c) 2011-2012, Qualcomm Atheros - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef GAS_H -#define GAS_H - -struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size); -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/contrib/hostapd/src/common/ieee802_11_common.c b/contrib/hostapd/src/common/ieee802_11_common.c deleted file mode 100644 index 809089faca..0000000000 --- a/contrib/hostapd/src/common/ieee802_11_common.c +++ /dev/null @@ -1,538 +0,0 @@ -/* - * IEEE 802.11 Common routines - * Copyright (c) 2002-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "defs.h" -#include "ieee802_11_defs.h" -#include "ieee802_11_common.h" - - -static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, - struct ieee802_11_elems *elems, - int show_errors) -{ - unsigned int oui; - - /* first 3 bytes in vendor specific information element are the IEEE - * OUI of the vendor. The following byte is used a vendor specific - * sub-type. */ - if (elen < 4) { - if (show_errors) { - wpa_printf(MSG_MSGDUMP, "short vendor specific " - "information element ignored (len=%lu)", - (unsigned long) elen); - } - return -1; - } - - oui = WPA_GET_BE24(pos); - switch (oui) { - case OUI_MICROSOFT: - /* Microsoft/Wi-Fi information elements are further typed and - * subtyped */ - switch (pos[3]) { - case 1: - /* Microsoft OUI (00:50:F2) with OUI Type 1: - * real WPA information element */ - elems->wpa_ie = pos; - elems->wpa_ie_len = elen; - break; - case WMM_OUI_TYPE: - /* WMM information element */ - if (elen < 5) { - wpa_printf(MSG_MSGDUMP, "short WMM " - "information element ignored " - "(len=%lu)", - (unsigned long) elen); - return -1; - } - switch (pos[4]) { - case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT: - case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT: - /* - * Share same pointer since only one of these - * is used and they start with same data. - * Length field can be used to distinguish the - * IEs. - */ - elems->wmm = pos; - elems->wmm_len = elen; - break; - case WMM_OUI_SUBTYPE_TSPEC_ELEMENT: - elems->wmm_tspec = pos; - elems->wmm_tspec_len = elen; - break; - default: - wpa_printf(MSG_EXCESSIVE, "unknown WMM " - "information element ignored " - "(subtype=%d len=%lu)", - pos[4], (unsigned long) elen); - return -1; - } - break; - case 4: - /* Wi-Fi Protected Setup (WPS) IE */ - elems->wps_ie = pos; - elems->wps_ie_len = elen; - break; - default: - wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft " - "information element ignored " - "(type=%d len=%lu)", - pos[3], (unsigned long) elen); - return -1; - } - break; - - case OUI_WFA: - switch (pos[3]) { - case P2P_OUI_TYPE: - /* Wi-Fi Alliance - P2P IE */ - elems->p2p = pos; - elems->p2p_len = elen; - break; - case WFD_OUI_TYPE: - /* Wi-Fi Alliance - WFD IE */ - elems->wfd = pos; - elems->wfd_len = elen; - break; - case HS20_INDICATION_OUI_TYPE: - /* Hotspot 2.0 */ - elems->hs20 = pos; - elems->hs20_len = elen; - break; - default: - wpa_printf(MSG_MSGDUMP, "Unknown WFA " - "information element ignored " - "(type=%d len=%lu)\n", - pos[3], (unsigned long) elen); - return -1; - } - break; - - case OUI_BROADCOM: - switch (pos[3]) { - case VENDOR_HT_CAPAB_OUI_TYPE: - elems->vendor_ht_cap = pos; - elems->vendor_ht_cap_len = elen; - break; - default: - wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom " - "information element ignored " - "(type=%d len=%lu)", - pos[3], (unsigned long) elen); - return -1; - } - break; - - default: - wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " - "information element ignored (vendor OUI " - "%02x:%02x:%02x len=%lu)", - pos[0], pos[1], pos[2], (unsigned long) elen); - return -1; - } - - return 0; -} - - -/** - * ieee802_11_parse_elems - Parse information elements in management frames - * @start: Pointer to the start of IEs - * @len: Length of IE buffer in octets - * @elems: Data structure for parsed elements - * @show_errors: Whether to show parsing errors in debug log - * Returns: Parsing result - */ -ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, - struct ieee802_11_elems *elems, - int show_errors) -{ - size_t left = len; - const u8 *pos = start; - int unknown = 0; - - os_memset(elems, 0, sizeof(*elems)); - - while (left >= 2) { - u8 id, elen; - - id = *pos++; - elen = *pos++; - left -= 2; - - if (elen > left) { - if (show_errors) { - wpa_printf(MSG_DEBUG, "IEEE 802.11 element " - "parse failed (id=%d elen=%d " - "left=%lu)", - id, elen, (unsigned long) left); - wpa_hexdump(MSG_MSGDUMP, "IEs", start, len); - } - return ParseFailed; - } - - switch (id) { - case WLAN_EID_SSID: - elems->ssid = pos; - elems->ssid_len = elen; - break; - case WLAN_EID_SUPP_RATES: - elems->supp_rates = pos; - elems->supp_rates_len = elen; - break; - case WLAN_EID_DS_PARAMS: - elems->ds_params = pos; - elems->ds_params_len = elen; - break; - case WLAN_EID_CF_PARAMS: - case WLAN_EID_TIM: - break; - case WLAN_EID_CHALLENGE: - elems->challenge = pos; - elems->challenge_len = elen; - break; - case WLAN_EID_ERP_INFO: - elems->erp_info = pos; - elems->erp_info_len = elen; - break; - case WLAN_EID_EXT_SUPP_RATES: - elems->ext_supp_rates = pos; - elems->ext_supp_rates_len = elen; - break; - case WLAN_EID_VENDOR_SPECIFIC: - if (ieee802_11_parse_vendor_specific(pos, elen, - elems, - show_errors)) - unknown++; - break; - case WLAN_EID_RSN: - elems->rsn_ie = pos; - elems->rsn_ie_len = elen; - break; - case WLAN_EID_PWR_CAPABILITY: - break; - case WLAN_EID_SUPPORTED_CHANNELS: - elems->supp_channels = pos; - elems->supp_channels_len = elen; - break; - case WLAN_EID_MOBILITY_DOMAIN: - elems->mdie = pos; - elems->mdie_len = elen; - break; - case WLAN_EID_FAST_BSS_TRANSITION: - elems->ftie = pos; - elems->ftie_len = elen; - break; - case WLAN_EID_TIMEOUT_INTERVAL: - elems->timeout_int = pos; - elems->timeout_int_len = elen; - break; - case WLAN_EID_HT_CAP: - elems->ht_capabilities = pos; - elems->ht_capabilities_len = elen; - break; - case WLAN_EID_HT_OPERATION: - elems->ht_operation = pos; - elems->ht_operation_len = elen; - break; - case WLAN_EID_VHT_CAP: - elems->vht_capabilities = pos; - elems->vht_capabilities_len = elen; - break; - case WLAN_EID_VHT_OPERATION: - elems->vht_operation = pos; - elems->vht_operation_len = elen; - break; - case WLAN_EID_LINK_ID: - if (elen < 18) - break; - elems->link_id = pos; - break; - case WLAN_EID_INTERWORKING: - elems->interworking = pos; - elems->interworking_len = elen; - break; - case WLAN_EID_QOS_MAP_SET: - if (elen < 16) - break; - elems->qos_map_set = pos; - elems->qos_map_set_len = elen; - break; - case WLAN_EID_EXT_CAPAB: - elems->ext_capab = pos; - elems->ext_capab_len = elen; - break; - case WLAN_EID_BSS_MAX_IDLE_PERIOD: - if (elen < 3) - break; - elems->bss_max_idle_period = pos; - break; - case WLAN_EID_SSID_LIST: - elems->ssid_list = pos; - elems->ssid_list_len = elen; - break; - default: - unknown++; - if (!show_errors) - break; - wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse " - "ignored unknown element (id=%d elen=%d)", - id, elen); - break; - } - - left -= elen; - pos += elen; - } - - if (left) - return ParseFailed; - - return unknown ? ParseUnknown : ParseOK; -} - - -int ieee802_11_ie_count(const u8 *ies, size_t ies_len) -{ - int count = 0; - const u8 *pos, *end; - - if (ies == NULL) - return 0; - - pos = ies; - end = ies + ies_len; - - while (pos + 2 <= end) { - if (pos + 2 + pos[1] > end) - break; - count++; - pos += 2 + pos[1]; - } - - return count; -} - - -struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, - u32 oui_type) -{ - struct wpabuf *buf; - const u8 *end, *pos, *ie; - - pos = ies; - end = ies + ies_len; - ie = NULL; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - return NULL; - if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && - WPA_GET_BE32(&pos[2]) == oui_type) { - ie = pos; - break; - } - pos += 2 + pos[1]; - } - - if (ie == NULL) - return NULL; /* No specified vendor IE found */ - - buf = wpabuf_alloc(ies_len); - if (buf == NULL) - return NULL; - - /* - * There may be multiple vendor IEs in the message, so need to - * concatenate their data fields. - */ - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && - WPA_GET_BE32(&pos[2]) == oui_type) - wpabuf_put_data(buf, pos + 6, pos[1] - 4); - pos += 2 + pos[1]; - } - - 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; - } -} - - -int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[], - const char *name, const char *val) -{ - int num, v; - const char *pos; - struct hostapd_wmm_ac_params *ac; - - /* skip 'wme_ac_' or 'wmm_ac_' prefix */ - pos = name + 7; - if (os_strncmp(pos, "be_", 3) == 0) { - num = 0; - pos += 3; - } else if (os_strncmp(pos, "bk_", 3) == 0) { - num = 1; - pos += 3; - } else if (os_strncmp(pos, "vi_", 3) == 0) { - num = 2; - pos += 3; - } else if (os_strncmp(pos, "vo_", 3) == 0) { - num = 3; - pos += 3; - } else { - wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos); - return -1; - } - - ac = &wmm_ac_params[num]; - - if (os_strcmp(pos, "aifs") == 0) { - v = atoi(val); - if (v < 1 || v > 255) { - wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v); - return -1; - } - ac->aifs = v; - } else if (os_strcmp(pos, "cwmin") == 0) { - v = atoi(val); - if (v < 0 || v > 12) { - wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v); - return -1; - } - ac->cwmin = v; - } else if (os_strcmp(pos, "cwmax") == 0) { - v = atoi(val); - if (v < 0 || v > 12) { - wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v); - return -1; - } - ac->cwmax = v; - } else if (os_strcmp(pos, "txop_limit") == 0) { - v = atoi(val); - if (v < 0 || v > 0xffff) { - wpa_printf(MSG_ERROR, "Invalid txop value %d", v); - return -1; - } - ac->txop_limit = v; - } else if (os_strcmp(pos, "acm") == 0) { - v = atoi(val); - if (v < 0 || v > 1) { - wpa_printf(MSG_ERROR, "Invalid acm value %d", v); - return -1; - } - ac->admission_control_mandatory = v; - } else { - wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos); - return -1; - } - - return 0; -} - - -enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel) -{ - enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES; - - if (freq >= 2412 && freq <= 2472) { - mode = HOSTAPD_MODE_IEEE80211G; - *channel = (freq - 2407) / 5; - } else if (freq == 2484) { - mode = HOSTAPD_MODE_IEEE80211B; - *channel = 14; - } else if (freq >= 4900 && freq < 5000) { - mode = HOSTAPD_MODE_IEEE80211A; - *channel = (freq - 4000) / 5; - } else if (freq >= 5000 && freq < 5900) { - mode = HOSTAPD_MODE_IEEE80211A; - *channel = (freq - 5000) / 5; - } else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) { - mode = HOSTAPD_MODE_IEEE80211AD; - *channel = (freq - 56160) / 2160; - } - - return mode; -} - - -static int is_11b(u8 rate) -{ - return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16; -} - - -int supp_rates_11b_only(struct ieee802_11_elems *elems) -{ - int num_11b = 0, num_others = 0; - int i; - - if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL) - return 0; - - for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) { - if (is_11b(elems->supp_rates[i])) - num_11b++; - else - num_others++; - } - - for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len; - i++) { - if (is_11b(elems->ext_supp_rates[i])) - num_11b++; - else - num_others++; - } - - return num_11b > 0 && num_others == 0; -} diff --git a/contrib/hostapd/src/common/ieee802_11_common.h b/contrib/hostapd/src/common/ieee802_11_common.h deleted file mode 100644 index b84dd9e757..0000000000 --- a/contrib/hostapd/src/common/ieee802_11_common.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * IEEE 802.11 Common routines - * Copyright (c) 2002-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef IEEE802_11_COMMON_H -#define IEEE802_11_COMMON_H - -/* Parsed Information Elements */ -struct ieee802_11_elems { - const u8 *ssid; - const u8 *supp_rates; - const u8 *ds_params; - const u8 *challenge; - const u8 *erp_info; - const u8 *ext_supp_rates; - const u8 *wpa_ie; - const u8 *rsn_ie; - const u8 *wmm; /* WMM Information or Parameter Element */ - const u8 *wmm_tspec; - const u8 *wps_ie; - const u8 *supp_channels; - const u8 *mdie; - const u8 *ftie; - const u8 *timeout_int; - const u8 *ht_capabilities; - const u8 *ht_operation; - const u8 *vht_capabilities; - const u8 *vht_operation; - const u8 *vendor_ht_cap; - const u8 *p2p; - const u8 *wfd; - const u8 *link_id; - const u8 *interworking; - const u8 *qos_map_set; - const u8 *hs20; - const u8 *ext_capab; - const u8 *bss_max_idle_period; - const u8 *ssid_list; - - u8 ssid_len; - u8 supp_rates_len; - u8 ds_params_len; - u8 challenge_len; - u8 erp_info_len; - u8 ext_supp_rates_len; - u8 wpa_ie_len; - u8 rsn_ie_len; - u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */ - u8 wmm_tspec_len; - u8 wps_ie_len; - u8 supp_channels_len; - u8 mdie_len; - u8 ftie_len; - u8 timeout_int_len; - u8 ht_capabilities_len; - u8 ht_operation_len; - u8 vht_capabilities_len; - u8 vht_operation_len; - u8 vendor_ht_cap_len; - u8 p2p_len; - u8 wfd_len; - u8 interworking_len; - u8 qos_map_set_len; - u8 hs20_len; - u8 ext_capab_len; - u8 ssid_list_len; -}; - -typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; - -ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, - struct ieee802_11_elems *elems, - int show_errors); -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); - -struct hostapd_wmm_ac_params { - int cwmin; - int cwmax; - int aifs; - int txop_limit; /* in units of 32us */ - int admission_control_mandatory; -}; - -int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[], - const char *name, const char *val); -enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel); - -int supp_rates_11b_only(struct ieee802_11_elems *elems); - -#endif /* IEEE802_11_COMMON_H */ diff --git a/contrib/hostapd/src/common/ieee802_11_defs.h b/contrib/hostapd/src/common/ieee802_11_defs.h deleted file mode 100644 index 6f7f7779da..0000000000 --- a/contrib/hostapd/src/common/ieee802_11_defs.h +++ /dev/null @@ -1,1193 +0,0 @@ -/* - * IEEE 802.11 Frame type definitions - * Copyright (c) 2002-2009, Jouni Malinen - * Copyright (c) 2007-2008 Intel Corporation - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef IEEE802_11_DEFS_H -#define IEEE802_11_DEFS_H - -/* IEEE 802.11 defines */ - -#define WLAN_FC_PVER 0x0003 -#define WLAN_FC_TODS 0x0100 -#define WLAN_FC_FROMDS 0x0200 -#define WLAN_FC_MOREFRAG 0x0400 -#define WLAN_FC_RETRY 0x0800 -#define WLAN_FC_PWRMGT 0x1000 -#define WLAN_FC_MOREDATA 0x2000 -#define WLAN_FC_ISWEP 0x4000 -#define WLAN_FC_ORDER 0x8000 - -#define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2) -#define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4) - -#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0))) -#define WLAN_GET_SEQ_SEQ(seq) \ - (((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4) - -#define WLAN_FC_TYPE_MGMT 0 -#define WLAN_FC_TYPE_CTRL 1 -#define WLAN_FC_TYPE_DATA 2 - -/* management */ -#define WLAN_FC_STYPE_ASSOC_REQ 0 -#define WLAN_FC_STYPE_ASSOC_RESP 1 -#define WLAN_FC_STYPE_REASSOC_REQ 2 -#define WLAN_FC_STYPE_REASSOC_RESP 3 -#define WLAN_FC_STYPE_PROBE_REQ 4 -#define WLAN_FC_STYPE_PROBE_RESP 5 -#define WLAN_FC_STYPE_BEACON 8 -#define WLAN_FC_STYPE_ATIM 9 -#define WLAN_FC_STYPE_DISASSOC 10 -#define WLAN_FC_STYPE_AUTH 11 -#define WLAN_FC_STYPE_DEAUTH 12 -#define WLAN_FC_STYPE_ACTION 13 - -/* control */ -#define WLAN_FC_STYPE_PSPOLL 10 -#define WLAN_FC_STYPE_RTS 11 -#define WLAN_FC_STYPE_CTS 12 -#define WLAN_FC_STYPE_ACK 13 -#define WLAN_FC_STYPE_CFEND 14 -#define WLAN_FC_STYPE_CFENDACK 15 - -/* data */ -#define WLAN_FC_STYPE_DATA 0 -#define WLAN_FC_STYPE_DATA_CFACK 1 -#define WLAN_FC_STYPE_DATA_CFPOLL 2 -#define WLAN_FC_STYPE_DATA_CFACKPOLL 3 -#define WLAN_FC_STYPE_NULLFUNC 4 -#define WLAN_FC_STYPE_CFACK 5 -#define WLAN_FC_STYPE_CFPOLL 6 -#define WLAN_FC_STYPE_CFACKPOLL 7 -#define WLAN_FC_STYPE_QOS_DATA 8 -#define WLAN_FC_STYPE_QOS_DATA_CFACK 9 -#define WLAN_FC_STYPE_QOS_DATA_CFPOLL 10 -#define WLAN_FC_STYPE_QOS_DATA_CFACKPOLL 11 -#define WLAN_FC_STYPE_QOS_NULL 12 -#define WLAN_FC_STYPE_QOS_CFPOLL 14 -#define WLAN_FC_STYPE_QOS_CFACKPOLL 15 - -/* Authentication algorithms */ -#define WLAN_AUTH_OPEN 0 -#define WLAN_AUTH_SHARED_KEY 1 -#define WLAN_AUTH_FT 2 -#define WLAN_AUTH_SAE 3 -#define WLAN_AUTH_LEAP 128 - -#define WLAN_AUTH_CHALLENGE_LEN 128 - -#define WLAN_CAPABILITY_ESS BIT(0) -#define WLAN_CAPABILITY_IBSS BIT(1) -#define WLAN_CAPABILITY_CF_POLLABLE BIT(2) -#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3) -#define WLAN_CAPABILITY_PRIVACY BIT(4) -#define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5) -#define WLAN_CAPABILITY_PBCC BIT(6) -#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7) -#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8) -#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10) -#define WLAN_CAPABILITY_DSSS_OFDM BIT(13) - -/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */ -#define WLAN_STATUS_SUCCESS 0 -#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 -#define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2 -#define WLAN_STATUS_TDLS_WAKEUP_REJECT 3 -#define WLAN_STATUS_SECURITY_DISABLED 5 -#define WLAN_STATUS_UNACCEPTABLE_LIFETIME 6 -#define WLAN_STATUS_NOT_IN_SAME_BSS 7 -#define WLAN_STATUS_CAPS_UNSUPPORTED 10 -#define WLAN_STATUS_REASSOC_NO_ASSOC 11 -#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 -#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 -#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 -#define WLAN_STATUS_CHALLENGE_FAIL 15 -#define WLAN_STATUS_AUTH_TIMEOUT 16 -#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 -#define WLAN_STATUS_ASSOC_DENIED_RATES 18 -/* IEEE 802.11b */ -#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 -#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 -#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 -/* IEEE 802.11h */ -#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22 -#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23 -#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24 -/* IEEE 802.11g */ -#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 -#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 26 -#define WLAN_STATUS_ASSOC_DENIED_NO_HT 27 -#define WLAN_STATUS_R0KH_UNREACHABLE 28 -#define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29 -/* IEEE 802.11w */ -#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30 -#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 -#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32 -#define WLAN_STATUS_REQUEST_DECLINED 37 -#define WLAN_STATUS_INVALID_PARAMETERS 38 -/* IEEE 802.11i */ -#define WLAN_STATUS_INVALID_IE 40 -#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41 -#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42 -#define WLAN_STATUS_AKMP_NOT_VALID 43 -#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44 -#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45 -#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46 -#define WLAN_STATUS_TS_NOT_CREATED 47 -#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48 -#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49 -#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50 -#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51 -/* IEEE 802.11r */ -#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52 -#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_ANTI_CLOGGING_TOKEN_REQ 76 -#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77 -#define WLAN_STATUS_TRANSMISSION_FAILURE 79 -#define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104 - -/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */ -#define WLAN_REASON_UNSPECIFIED 1 -#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 -#define WLAN_REASON_DEAUTH_LEAVING 3 -#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 -#define WLAN_REASON_DISASSOC_AP_BUSY 5 -#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 -#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 -#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 -#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 -/* IEEE 802.11h */ -#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10 -#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11 -/* IEEE 802.11i */ -#define WLAN_REASON_INVALID_IE 13 -#define WLAN_REASON_MICHAEL_MIC_FAILURE 14 -#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15 -#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16 -#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17 -#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18 -#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19 -#define WLAN_REASON_AKMP_NOT_VALID 20 -#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21 -#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22 -#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23 -#define WLAN_REASON_CIPHER_SUITE_REJECTED 24 -#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25 -#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26 -/* IEEE 802.11e */ -#define WLAN_REASON_DISASSOC_LOW_ACK 34 - - -/* Information Element IDs */ -#define WLAN_EID_SSID 0 -#define WLAN_EID_SUPP_RATES 1 -#define WLAN_EID_FH_PARAMS 2 -#define WLAN_EID_DS_PARAMS 3 -#define WLAN_EID_CF_PARAMS 4 -#define WLAN_EID_TIM 5 -#define WLAN_EID_IBSS_PARAMS 6 -#define WLAN_EID_COUNTRY 7 -#define WLAN_EID_BSS_LOAD 11 -#define WLAN_EID_CHALLENGE 16 -/* EIDs defined by IEEE 802.11h - START */ -#define WLAN_EID_PWR_CONSTRAINT 32 -#define WLAN_EID_PWR_CAPABILITY 33 -#define WLAN_EID_TPC_REQUEST 34 -#define WLAN_EID_TPC_REPORT 35 -#define WLAN_EID_SUPPORTED_CHANNELS 36 -#define WLAN_EID_CHANNEL_SWITCH 37 -#define WLAN_EID_MEASURE_REQUEST 38 -#define WLAN_EID_MEASURE_REPORT 39 -#define WLAN_EID_QUITE 40 -#define WLAN_EID_IBSS_DFS 41 -/* EIDs defined by IEEE 802.11h - END */ -#define WLAN_EID_ERP_INFO 42 -#define WLAN_EID_HT_CAP 45 -#define WLAN_EID_QOS 46 -#define WLAN_EID_RSN 48 -#define WLAN_EID_EXT_SUPP_RATES 50 -#define WLAN_EID_MOBILITY_DOMAIN 54 -#define WLAN_EID_FAST_BSS_TRANSITION 55 -#define WLAN_EID_TIMEOUT_INTERVAL 56 -#define WLAN_EID_RIC_DATA 57 -#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59 -#define WLAN_EID_HT_OPERATION 61 -#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 -#define WLAN_EID_WAPI 68 -#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_SSID_LIST 84 -#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90 -#define WLAN_EID_TFS_REQ 91 -#define WLAN_EID_TFS_RESP 92 -#define WLAN_EID_WNMSLEEP 93 -#define WLAN_EID_TIME_ZONE 98 -#define WLAN_EID_LINK_ID 101 -#define WLAN_EID_INTERWORKING 107 -#define WLAN_EID_ADV_PROTO 108 -#define WLAN_EID_QOS_MAP_SET 110 -#define WLAN_EID_ROAMING_CONSORTIUM 111 -#define WLAN_EID_EXT_CAPAB 127 -#define WLAN_EID_CCKM 156 -#define WLAN_EID_VHT_CAP 191 -#define WLAN_EID_VHT_OPERATION 192 -#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193 -#define WLAN_EID_VHT_WIDE_BW_CHSWITCH 194 -#define WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE 195 -#define WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER 196 -#define WLAN_EID_VHT_AID 197 -#define WLAN_EID_VHT_QUIET_CHANNEL 198 -#define WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION 199 -#define WLAN_EID_VENDOR_SPECIFIC 221 - - -/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */ -#define WLAN_ACTION_SPECTRUM_MGMT 0 -#define WLAN_ACTION_QOS 1 -#define WLAN_ACTION_DLS 2 -#define WLAN_ACTION_BLOCK_ACK 3 -#define WLAN_ACTION_PUBLIC 4 -#define WLAN_ACTION_RADIO_MEASUREMENT 5 -#define WLAN_ACTION_FT 6 -#define WLAN_ACTION_HT 7 -#define WLAN_ACTION_SA_QUERY 8 -#define WLAN_ACTION_PROTECTED_DUAL 9 -#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 - -/* Public action codes */ -#define WLAN_PA_20_40_BSS_COEX 0 -#define WLAN_PA_VENDOR_SPECIFIC 9 -#define WLAN_PA_GAS_INITIAL_REQ 10 -#define WLAN_PA_GAS_INITIAL_RESP 11 -#define WLAN_PA_GAS_COMEBACK_REQ 12 -#define WLAN_PA_GAS_COMEBACK_RESP 13 -#define WLAN_TDLS_DISCOVERY_RESPONSE 14 - -/* Protected Dual of Public Action frames */ -#define WLAN_PROT_DSE_ENABLEMENT 1 -#define WLAN_PROT_DSE_DEENABLEMENT 2 -#define WLAN_PROT_EXT_CSA 4 -#define WLAN_PROT_MEASUREMENT_REQ 5 -#define WLAN_PROT_MEASUREMENT_REPORT 6 -#define WLAN_PROT_DSE_POWER_CONSTRAINT 8 -#define WLAN_PROT_VENDOR_SPECIFIC 9 -#define WLAN_PROT_GAS_INITIAL_REQ 10 -#define WLAN_PROT_GAS_INITIAL_RESP 11 -#define WLAN_PROT_GAS_COMEBACK_REQ 12 -#define WLAN_PROT_GAS_COMEBACK_RESP 13 - -/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ -#define WLAN_SA_QUERY_REQUEST 0 -#define WLAN_SA_QUERY_RESPONSE 1 - -#define WLAN_SA_QUERY_TR_ID_LEN 2 - -/* TDLS action codes */ -#define WLAN_TDLS_SETUP_REQUEST 0 -#define WLAN_TDLS_SETUP_RESPONSE 1 -#define WLAN_TDLS_SETUP_CONFIRM 2 -#define WLAN_TDLS_TEARDOWN 3 -#define WLAN_TDLS_PEER_TRAFFIC_INDICATION 4 -#define WLAN_TDLS_CHANNEL_SWITCH_REQUEST 5 -#define WLAN_TDLS_CHANNEL_SWITCH_RESPONSE 6 -#define WLAN_TDLS_PEER_PSM_REQUEST 7 -#define WLAN_TDLS_PEER_PSM_RESPONSE 8 -#define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9 -#define WLAN_TDLS_DISCOVERY_REQUEST 10 - -/* Timeout Interval Type */ -#define WLAN_TIMEOUT_REASSOC_DEADLINE 1 -#define WLAN_TIMEOUT_KEY_LIFETIME 2 -#define WLAN_TIMEOUT_ASSOC_COMEBACK 3 - -/* 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 { - ACCESS_NETWORK_QUERY_PROTOCOL = 0, - MIH_INFO_SERVICE = 1, - MIH_CMD_AND_EVENT_DISCOVERY = 2, - EMERGENCY_ALERT_SYSTEM = 3, - ADV_PROTO_VENDOR_SPECIFIC = 221 -}; - -/* 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) -#endif /* _MSC_VER */ - -struct ieee80211_hdr { - le16 frame_control; - le16 duration_id; - u8 addr1[6]; - u8 addr2[6]; - u8 addr3[6]; - le16 seq_ctrl; - /* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame - */ -} STRUCT_PACKED; - -#define IEEE80211_DA_FROMDS addr1 -#define IEEE80211_BSSID_FROMDS addr2 -#define IEEE80211_SA_FROMDS addr3 - -#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr)) - -#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4)) - -struct ieee80211_mgmt { - le16 frame_control; - le16 duration; - u8 da[6]; - u8 sa[6]; - u8 bssid[6]; - le16 seq_ctrl; - union { - struct { - le16 auth_alg; - le16 auth_transaction; - le16 status_code; - /* possibly followed by Challenge text */ - u8 variable[0]; - } STRUCT_PACKED auth; - struct { - le16 reason_code; - u8 variable[0]; - } STRUCT_PACKED deauth; - struct { - le16 capab_info; - le16 listen_interval; - /* followed by SSID and Supported rates */ - u8 variable[0]; - } STRUCT_PACKED assoc_req; - struct { - le16 capab_info; - le16 status_code; - le16 aid; - /* followed by Supported rates */ - u8 variable[0]; - } STRUCT_PACKED assoc_resp, reassoc_resp; - struct { - le16 capab_info; - le16 listen_interval; - u8 current_ap[6]; - /* followed by SSID and Supported rates */ - u8 variable[0]; - } STRUCT_PACKED reassoc_req; - struct { - le16 reason_code; - u8 variable[0]; - } STRUCT_PACKED disassoc; - struct { - u8 timestamp[8]; - le16 beacon_int; - le16 capab_info; - /* followed by some of SSID, Supported rates, - * FH Params, DS Params, CF Params, IBSS Params, TIM */ - u8 variable[0]; - } STRUCT_PACKED beacon; - struct { - /* only variable items: SSID, Supported rates */ - u8 variable[0]; - } STRUCT_PACKED probe_req; - struct { - u8 timestamp[8]; - le16 beacon_int; - le16 capab_info; - /* followed by some of SSID, Supported rates, - * FH Params, DS Params, CF Params, IBSS Params */ - u8 variable[0]; - } STRUCT_PACKED probe_resp; - struct { - u8 category; - union { - struct { - u8 action_code; - u8 dialog_token; - u8 status_code; - u8 variable[0]; - } STRUCT_PACKED wmm_action; - struct{ - u8 action_code; - u8 element_id; - u8 length; - u8 switch_mode; - u8 new_chan; - u8 switch_count; - } STRUCT_PACKED chan_switch; - struct { - u8 action; - u8 sta_addr[ETH_ALEN]; - u8 target_ap_addr[ETH_ALEN]; - u8 variable[0]; /* FT Request */ - } STRUCT_PACKED ft_action_req; - struct { - u8 action; - u8 sta_addr[ETH_ALEN]; - u8 target_ap_addr[ETH_ALEN]; - le16 status_code; - u8 variable[0]; /* FT Request */ - } STRUCT_PACKED ft_action_resp; - struct { - u8 action; - u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; - } STRUCT_PACKED sa_query_req; - struct { - u8 action; /* */ - u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; - } STRUCT_PACKED sa_query_resp; - struct { - u8 action; - u8 dialogtoken; - u8 variable[0]; - } STRUCT_PACKED wnm_sleep_req; - struct { - u8 action; - u8 dialogtoken; - le16 keydata_len; - u8 variable[0]; - } STRUCT_PACKED wnm_sleep_resp; - struct { - u8 action; - u8 variable[0]; - } STRUCT_PACKED public_action; - struct { - u8 action; /* 9 */ - u8 oui[3]; - /* 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; - struct { - u8 action; /* 8 */ - u8 dialog_token; - u8 status_code; - u8 bss_termination_delay; - /* Target BSSID (optional), - * BSS Transition Candidate List - * Entries (optional) */ - u8 variable[0]; - } STRUCT_PACKED bss_tm_resp; - struct { - u8 action; /* 6 */ - u8 dialog_token; - u8 query_reason; - /* BSS Transition Candidate List - * Entries (optional) */ - u8 variable[0]; - } STRUCT_PACKED bss_tm_query; - } u; - } STRUCT_PACKED action; - } u; -} STRUCT_PACKED; - - -/* Rx MCS bitmask is in the first 77 bits of supported_mcs_set */ -#define IEEE80211_HT_MCS_MASK_LEN 10 - -struct ieee80211_ht_capabilities { - le16 ht_capabilities_info; - u8 a_mpdu_params; - u8 supported_mcs_set[16]; - le16 ht_extended_capabilities; - le32 tx_bf_capability_info; - u8 asel_capabilities; -} STRUCT_PACKED; - - -struct ieee80211_ht_operation { - u8 control_chan; - u8 ht_param; - le16 operation_mode; - le16 stbc_param; - u8 basic_set[16]; -} STRUCT_PACKED; - - -struct ieee80211_obss_scan_parameters { - le16 scan_passive_dwell; - le16 scan_active_dwell; - le16 width_trigger_scan_interval; - le16 scan_passive_total_per_channel; - le16 scan_active_total_per_channel; - le16 channel_transition_delay_factor; - le16 scan_activity_threshold; -} STRUCT_PACKED; - - -struct ieee80211_vht_capabilities { - le32 vht_capabilities_info; - struct { - le16 rx_map; - le16 rx_highest; - le16 tx_map; - le16 tx_highest; - } vht_supported_mcs_set; -} STRUCT_PACKED; - -struct ieee80211_vht_operation { - u8 vht_op_info_chwidth; - u8 vht_op_info_chan_center_freq_seg0_idx; - u8 vht_op_info_chan_center_freq_seg1_idx; - le16 vht_basic_mcs_set; -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - -#define ERP_INFO_NON_ERP_PRESENT BIT(0) -#define ERP_INFO_USE_PROTECTION BIT(1) -#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) - - -#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0)) -#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1)) -#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3))) -#define HT_CAP_INFO_SMPS_STATIC ((u16) 0) -#define HT_CAP_INFO_SMPS_DYNAMIC ((u16) BIT(2)) -#define HT_CAP_INFO_SMPS_DISABLED ((u16) (BIT(2) | BIT(3))) -#define HT_CAP_INFO_GREEN_FIELD ((u16) BIT(4)) -#define HT_CAP_INFO_SHORT_GI20MHZ ((u16) BIT(5)) -#define HT_CAP_INFO_SHORT_GI40MHZ ((u16) BIT(6)) -#define HT_CAP_INFO_TX_STBC ((u16) BIT(7)) -#define HT_CAP_INFO_RX_STBC_MASK ((u16) (BIT(8) | BIT(9))) -#define HT_CAP_INFO_RX_STBC_1 ((u16) BIT(8)) -#define HT_CAP_INFO_RX_STBC_12 ((u16) BIT(9)) -#define HT_CAP_INFO_RX_STBC_123 ((u16) (BIT(8) | BIT(9))) -#define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10)) -#define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11)) -#define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12)) -#define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13)) -#define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14)) -#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15)) - - -#define EXT_HT_CAP_INFO_PCO ((u16) BIT(0)) -#define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET 1 -#define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET 8 -#define EXT_HT_CAP_INFO_HTC_SUPPORTED ((u16) BIT(10)) -#define EXT_HT_CAP_INFO_RD_RESPONDER ((u16) BIT(11)) - - -#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0)) -#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1)) -#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2)) -#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3)) -#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4)) -#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5)) -#define TX_BEAMFORM_CAP_CALIB_OFFSET 6 -#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8)) -#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9)) -#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10)) -#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11 -#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13 -#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15 -#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17 -#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19 -#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21 -#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23 -#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25 - - -#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0)) -#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1)) -#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2)) -#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3)) -#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4)) -#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5)) -#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6)) - -#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1)) -#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0)) -#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1)) -#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2)) -#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3)) -#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4)) -#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5)) - - -#define OP_MODE_PURE 0 -#define OP_MODE_MAY_BE_LEGACY_STAS 1 -#define OP_MODE_20MHZ_HT_STA_ASSOCED 2 -#define OP_MODE_MIXED 3 - -#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \ - (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)) -#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4)) - -#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6)) -#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7)) -#define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8)) -#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9)) -#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10)) -#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11)) - -#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126 -#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 - -/* VHT Defines */ -#define VHT_CAP_MAX_MPDU_LENGTH_7991 ((u32) BIT(0)) -#define VHT_CAP_MAX_MPDU_LENGTH_11454 ((u32) BIT(1)) -#define VHT_CAP_MAX_MPDU_LENGTH_MASK ((u32) BIT(0) | BIT(1)) -#define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ((u32) BIT(2)) -#define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ ((u32) BIT(3)) -#define VHT_CAP_SUPP_CHAN_WIDTH_MASK ((u32) BIT(2) | BIT(3)) -#define VHT_CAP_RXLDPC ((u32) BIT(4)) -#define VHT_CAP_SHORT_GI_80 ((u32) BIT(5)) -#define VHT_CAP_SHORT_GI_160 ((u32) BIT(6)) -#define VHT_CAP_TXSTBC ((u32) BIT(7)) -#define VHT_CAP_RXSTBC_1 ((u32) BIT(8)) -#define VHT_CAP_RXSTBC_2 ((u32) BIT(9)) -#define VHT_CAP_RXSTBC_3 ((u32) BIT(8) | BIT(9)) -#define VHT_CAP_RXSTBC_4 ((u32) BIT(10)) -#define VHT_CAP_RXSTBC_MASK ((u32) BIT(8) | BIT(9) | \ - BIT(10)) -#define VHT_CAP_SU_BEAMFORMER_CAPABLE ((u32) BIT(11)) -#define VHT_CAP_SU_BEAMFORMEE_CAPABLE ((u32) BIT(12)) -#define VHT_CAP_BEAMFORMEE_STS_MAX ((u32) BIT(13) | \ - BIT(14) | BIT(15)) -#define VHT_CAP_BEAMFORMEE_STS_OFFSET 13 -#define VHT_CAP_SOUNDING_DIMENSION_MAX ((u32) BIT(16) | \ - BIT(17) | BIT(18)) -#define VHT_CAP_SOUNDING_DIMENSION_OFFSET 16 -#define VHT_CAP_MU_BEAMFORMER_CAPABLE ((u32) BIT(19)) -#define VHT_CAP_MU_BEAMFORMEE_CAPABLE ((u32) BIT(20)) -#define VHT_CAP_VHT_TXOP_PS ((u32) BIT(21)) -#define VHT_CAP_HTC_VHT ((u32) BIT(22)) -#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT ((u32) BIT(23) | \ - BIT(24) | BIT(25)) -#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB ((u32) BIT(27)) -#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB ((u32) BIT(26) | BIT(27)) -#define VHT_CAP_RX_ANTENNA_PATTERN ((u32) BIT(28)) -#define VHT_CAP_TX_ANTENNA_PATTERN ((u32) BIT(29)) - -/* VHT channel widths */ -#define VHT_CHANWIDTH_USE_HT 0 -#define VHT_CHANWIDTH_80MHZ 1 -#define VHT_CHANWIDTH_160MHZ 2 -#define VHT_CHANWIDTH_80P80MHZ 3 - -#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) - * 00:50:F2 */ -#define WPA_IE_VENDOR_TYPE 0x0050f201 -#define WPS_IE_VENDOR_TYPE 0x0050f204 -#define OUI_WFA 0x506f9a -#define P2P_IE_VENDOR_TYPE 0x506f9a09 -#define WFD_IE_VENDOR_TYPE 0x506f9a0a -#define WFD_OUI_TYPE 10 -#define HS20_IE_VENDOR_TYPE 0x506f9a10 - -#define WMM_OUI_TYPE 2 -#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0 -#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1 -#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2 -#define WMM_VERSION 1 - -#define WMM_ACTION_CODE_ADDTS_REQ 0 -#define WMM_ACTION_CODE_ADDTS_RESP 1 -#define WMM_ACTION_CODE_DELTS 2 - -#define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0 -#define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1 -/* 2 - Reserved */ -#define WMM_ADDTS_STATUS_REFUSED 3 -/* 4-255 - Reserved */ - -/* WMM TSPEC Direction Field Values */ -#define WMM_TSPEC_DIRECTION_UPLINK 0 -#define WMM_TSPEC_DIRECTION_DOWNLINK 1 -/* 2 - Reserved */ -#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3 - -/* - * WMM Information Element (used in (Re)Association Request frames; may also be - * used in Beacon frames) - */ -struct wmm_information_element { - /* Element ID: 221 (0xdd); Length: 7 */ - /* required fields for WMM version 1 */ - u8 oui[3]; /* 00:50:f2 */ - u8 oui_type; /* 2 */ - u8 oui_subtype; /* 0 */ - u8 version; /* 1 for WMM version 1.0 */ - u8 qos_info; /* AP/STA specific QoS info */ - -} 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 -#define WMM_AC_ACI_MASK 0x60 -#define WMM_AC_ACI_SHIFT 5 - -#define WMM_AC_ECWMIN_MASK 0x0f -#define WMM_AC_ECWMIN_SHIFT 0 -#define WMM_AC_ECWMAX_MASK 0xf0 -#define WMM_AC_ECWMAX_SHIFT 4 - -struct wmm_ac_parameter { - u8 aci_aifsn; /* AIFSN, ACM, ACI */ - u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */ - le16 txop_limit; -} STRUCT_PACKED; - -/* - * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association - * Response frmaes) - */ -struct wmm_parameter_element { - /* Element ID: 221 (0xdd); Length: 24 */ - /* required fields for WMM version 1 */ - u8 oui[3]; /* 00:50:f2 */ - u8 oui_type; /* 2 */ - u8 oui_subtype; /* 1 */ - u8 version; /* 1 for WMM version 1.0 */ - 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 */ - -} STRUCT_PACKED; - -/* WMM TSPEC Element */ -struct wmm_tspec_element { - u8 eid; /* 221 = 0xdd */ - u8 length; /* 6 + 55 = 61 */ - u8 oui[3]; /* 00:50:f2 */ - u8 oui_type; /* 2 */ - u8 oui_subtype; /* 2 */ - u8 version; /* 1 */ - /* WMM TSPEC body (55 octets): */ - u8 ts_info[3]; - le16 nominal_msdu_size; - le16 maximum_msdu_size; - le32 minimum_service_interval; - le32 maximum_service_interval; - le32 inactivity_interval; - le32 suspension_interval; - le32 service_start_time; - le32 minimum_data_rate; - le32 mean_data_rate; - le32 peak_data_rate; - le32 maximum_burst_size; - le32 delay_bound; - le32 minimum_phy_rate; - le16 surplus_bandwidth_allowance; - le16 medium_time; -} STRUCT_PACKED; - - -/* Access Categories / ACI to AC coding */ -enum { - WMM_AC_BE = 0 /* Best Effort */, - WMM_AC_BK = 1 /* Background */, - WMM_AC_VI = 2 /* Video */, - WMM_AC_VO = 3 /* Voice */ -}; - - -#define HS20_INDICATION_OUI_TYPE 16 -#define HS20_ANQP_OUI_TYPE 17 -#define HS20_STYPE_QUERY_LIST 1 -#define HS20_STYPE_CAPABILITY_LIST 2 -#define HS20_STYPE_OPERATOR_FRIENDLY_NAME 3 -#define HS20_STYPE_WAN_METRICS 4 -#define HS20_STYPE_CONNECTION_CAPABILITY 5 -#define HS20_STYPE_NAI_HOME_REALM_QUERY 6 -#define HS20_STYPE_OPERATING_CLASS 7 - -/* Wi-Fi Direct (P2P) */ - -#define P2P_OUI_TYPE 9 - -enum p2p_attr_id { - P2P_ATTR_STATUS = 0, - P2P_ATTR_MINOR_REASON_CODE = 1, - P2P_ATTR_CAPABILITY = 2, - P2P_ATTR_DEVICE_ID = 3, - P2P_ATTR_GROUP_OWNER_INTENT = 4, - P2P_ATTR_CONFIGURATION_TIMEOUT = 5, - P2P_ATTR_LISTEN_CHANNEL = 6, - P2P_ATTR_GROUP_BSSID = 7, - P2P_ATTR_EXT_LISTEN_TIMING = 8, - P2P_ATTR_INTENDED_INTERFACE_ADDR = 9, - P2P_ATTR_MANAGEABILITY = 10, - P2P_ATTR_CHANNEL_LIST = 11, - P2P_ATTR_NOTICE_OF_ABSENCE = 12, - P2P_ATTR_DEVICE_INFO = 13, - P2P_ATTR_GROUP_INFO = 14, - P2P_ATTR_GROUP_ID = 15, - P2P_ATTR_INTERFACE = 16, - P2P_ATTR_OPERATING_CHANNEL = 17, - P2P_ATTR_INVITATION_FLAGS = 18, - P2P_ATTR_OOB_GO_NEG_CHANNEL = 19, - P2P_ATTR_VENDOR_SPECIFIC = 221 -}; - -#define P2P_MAX_GO_INTENT 15 - -/* P2P Capability - Device Capability bitmap */ -#define P2P_DEV_CAPAB_SERVICE_DISCOVERY BIT(0) -#define P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY BIT(1) -#define P2P_DEV_CAPAB_CONCURRENT_OPER BIT(2) -#define P2P_DEV_CAPAB_INFRA_MANAGED BIT(3) -#define P2P_DEV_CAPAB_DEVICE_LIMIT BIT(4) -#define P2P_DEV_CAPAB_INVITATION_PROCEDURE BIT(5) - -/* P2P Capability - Group Capability bitmap */ -#define P2P_GROUP_CAPAB_GROUP_OWNER BIT(0) -#define P2P_GROUP_CAPAB_PERSISTENT_GROUP BIT(1) -#define P2P_GROUP_CAPAB_GROUP_LIMIT BIT(2) -#define P2P_GROUP_CAPAB_INTRA_BSS_DIST BIT(3) -#define P2P_GROUP_CAPAB_CROSS_CONN BIT(4) -#define P2P_GROUP_CAPAB_PERSISTENT_RECONN BIT(5) -#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6) -#define P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION BIT(7) - -/* Invitation Flags */ -#define P2P_INVITATION_FLAGS_TYPE BIT(0) - -/* P2P Manageability */ -#define P2P_MAN_DEVICE_MANAGEMENT BIT(0) -#define P2P_MAN_CROSS_CONNECTION_PERMITTED BIT(1) -#define P2P_MAN_COEXISTENCE_OPTIONAL BIT(2) - -enum p2p_status_code { - P2P_SC_SUCCESS = 0, - P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE = 1, - P2P_SC_FAIL_INCOMPATIBLE_PARAMS = 2, - P2P_SC_FAIL_LIMIT_REACHED = 3, - P2P_SC_FAIL_INVALID_PARAMS = 4, - P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE = 5, - P2P_SC_FAIL_PREV_PROTOCOL_ERROR = 6, - P2P_SC_FAIL_NO_COMMON_CHANNELS = 7, - P2P_SC_FAIL_UNKNOWN_GROUP = 8, - P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9, - P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10, - P2P_SC_FAIL_REJECTED_BY_USER = 11, -}; - -enum p2p_role_indication { - P2P_DEVICE_NOT_IN_GROUP = 0x00, - P2P_CLIENT_IN_A_GROUP = 0x01, - P2P_GO_IN_A_GROUP = 0x02, -}; - -#define P2P_WILDCARD_SSID "DIRECT-" -#define P2P_WILDCARD_SSID_LEN 7 - -/* P2P action frames */ -enum p2p_act_frame_type { - P2P_NOA = 0, - P2P_PRESENCE_REQ = 1, - P2P_PRESENCE_RESP = 2, - P2P_GO_DISC_REQ = 3 -}; - -/* P2P public action frames */ -enum p2p_action_frame_type { - P2P_GO_NEG_REQ = 0, - P2P_GO_NEG_RESP = 1, - P2P_GO_NEG_CONF = 2, - P2P_INVITATION_REQ = 3, - P2P_INVITATION_RESP = 4, - P2P_DEV_DISC_REQ = 5, - P2P_DEV_DISC_RESP = 6, - P2P_PROV_DISC_REQ = 7, - P2P_PROV_DISC_RESP = 8 -}; - -enum p2p_service_protocol_type { - P2P_SERV_ALL_SERVICES = 0, - P2P_SERV_BONJOUR = 1, - P2P_SERV_UPNP = 2, - P2P_SERV_WS_DISCOVERY = 3, - P2P_SERV_WIFI_DISPLAY = 4, - P2P_SERV_VENDOR_SPECIFIC = 255 -}; - -enum p2p_sd_status { - P2P_SD_SUCCESS = 0, - P2P_SD_PROTO_NOT_AVAILABLE = 1, - P2P_SD_REQUESTED_INFO_NOT_AVAILABLE = 2, - P2P_SD_BAD_REQUEST = 3 -}; - - -enum wifi_display_subelem { - WFD_SUBELEM_DEVICE_INFO = 0, - WFD_SUBELEM_ASSOCIATED_BSSID = 1, - WFD_SUBELEM_AUDIO_FORMATS = 2, - WFD_SUBELEM_VIDEO_FORMATS = 3, - WFD_SUBELEM_3D_VIDEO_FORMATS = 4, - WFD_SUBELEM_CONTENT_PROTECTION = 5, - WFD_SUBELEM_COUPLED_SINK = 6, - WFD_SUBELEM_EXT_CAPAB = 7, - WFD_SUBELEM_LOCAL_IP_ADDRESS = 8, - WFD_SUBELEM_SESSION_INFO = 9 -}; - - -#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */ - -#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */ - -/* cipher suite selectors */ -#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 -#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 -#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02 -/* reserved: 0x000FAC03 */ -#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 -#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 -#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 -#define WLAN_CIPHER_SUITE_NO_GROUP_ADDR 0x000FAC07 -#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08 -#define WLAN_CIPHER_SUITE_GCMP_256 0x000FAC09 -#define WLAN_CIPHER_SUITE_CCMP_256 0x000FAC0A -#define WLAN_CIPHER_SUITE_BIP_GMAC_128 0x000FAC0B -#define WLAN_CIPHER_SUITE_BIP_GMAC_256 0x000FAC0C -#define WLAN_CIPHER_SUITE_BIP_CMAC_256 0x000FAC0D - -#define WLAN_CIPHER_SUITE_SMS4 0x00147201 - -#define WLAN_CIPHER_SUITE_CKIP 0x00409600 -#define WLAN_CIPHER_SUITE_CKIP_CMIC 0x00409601 -#define WLAN_CIPHER_SUITE_CMIC 0x00409602 -#define WLAN_CIPHER_SUITE_KRK 0x004096FF /* for nl80211 use only */ - -/* AKM suite selectors */ -#define WLAN_AKM_SUITE_8021X 0x000FAC01 -#define WLAN_AKM_SUITE_PSK 0x000FAC02 -#define WLAN_AKM_SUITE_FT_8021X 0x000FAC03 -#define WLAN_AKM_SUITE_FT_PSK 0x000FAC04 -#define WLAN_AKM_SUITE_CCKM 0x00409600 - - -/* 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) - -/* IEEE Std 802.11-2012 - Table 8-253 */ -enum bss_trans_mgmt_status_code { - WNM_BSS_TM_ACCEPT = 0, - WNM_BSS_TM_REJECT_UNSPECIFIED = 1, - WNM_BSS_TM_REJECT_INSUFFICIENT_BEACON = 2, - WNM_BSS_TM_REJECT_INSUFFICIENT_CAPABITY = 3, - WNM_BSS_TM_REJECT_UNDESIRED = 4, - WNM_BSS_TM_REJECT_DELAY_REQUEST = 5, - WNM_BSS_TM_REJECT_STA_CANDIDATE_LIST_PROVIDED = 6, - WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES = 7, - WNM_BSS_TM_REJECT_LEAVING_ESS = 8 -}; - -#define WNM_NEIGHBOR_TSF 1 -#define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING 2 -#define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE 3 -#define WNM_NEIGHBOR_BSS_TERMINATION_DURATION 4 -#define WNM_NEIGHBOR_BEARING 5 -#define WNM_NEIGHBOR_MEASUREMENT_PILOT 66 -#define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES 70 -#define WNM_NEIGHBOR_MULTIPLE_BSSID 71 - -/* QoS action */ -enum qos_action { - QOS_ADDTS_REQ = 0, - QOS_ADDTS_RESP = 1, - QOS_DELTS = 2, - QOS_SCHEDULE = 3, - QOS_QOS_MAP_CONFIG = 4, -}; - -/* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */ -#define WLAN_20_40_BSS_COEX_INFO_REQ BIT(0) -#define WLAN_20_40_BSS_COEX_40MHZ_INTOL BIT(1) -#define WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ BIT(2) -#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_REQ BIT(3) -#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_GRNT BIT(4) - -struct ieee80211_2040_bss_coex_ie { - u8 element_id; - u8 length; - u8 coex_param; -} STRUCT_PACKED; - -struct ieee80211_2040_intol_chan_report { - u8 element_id; - u8 length; - u8 op_class; - u8 variable[0]; /* Channel List */ -} STRUCT_PACKED; - -/* IEEE 802.11v - WNM-Sleep Mode element */ -struct wnm_sleep_element { - u8 eid; /* WLAN_EID_WNMSLEEP */ - u8 len; - u8 action_type; /* WNM_SLEEP_ENTER/WNM_SLEEP_MODE_EXIT */ - u8 status; - le16 intval; -} STRUCT_PACKED; - -#define WNM_SLEEP_MODE_ENTER 0 -#define WNM_SLEEP_MODE_EXIT 1 - -enum wnm_sleep_mode_response_status { - WNM_STATUS_SLEEP_ACCEPT = 0, - WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE = 1, - WNM_STATUS_DENIED_ACTION = 2, - WNM_STATUS_DENIED_TMP = 3, - WNM_STATUS_DENIED_KEY = 4, - WNM_STATUS_DENIED_OTHER_WNM_SERVICE = 5 -}; - -/* WNM-Sleep Mode subelement IDs */ -enum wnm_sleep_mode_subelement_id { - WNM_SLEEP_SUBELEM_GTK = 0, - WNM_SLEEP_SUBELEM_IGTK = 1 -}; - -/* Channel Switch modes (802.11h) */ -#define CHAN_SWITCH_MODE_ALLOW_TX 0 -#define CHAN_SWITCH_MODE_BLOCK_TX 1 - -#endif /* IEEE802_11_DEFS_H */ diff --git a/contrib/hostapd/src/common/privsep_commands.h b/contrib/hostapd/src/common/privsep_commands.h deleted file mode 100644 index 858b51d388..0000000000 --- a/contrib/hostapd/src/common/privsep_commands.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * WPA Supplicant - privilege separation commands - * Copyright (c) 2007-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef PRIVSEP_COMMANDS_H -#define PRIVSEP_COMMANDS_H - -enum privsep_cmd { - PRIVSEP_CMD_REGISTER, - PRIVSEP_CMD_UNREGISTER, - PRIVSEP_CMD_SCAN, - PRIVSEP_CMD_GET_SCAN_RESULTS, - PRIVSEP_CMD_ASSOCIATE, - PRIVSEP_CMD_GET_BSSID, - PRIVSEP_CMD_GET_SSID, - PRIVSEP_CMD_SET_KEY, - PRIVSEP_CMD_GET_CAPA, - PRIVSEP_CMD_L2_REGISTER, - PRIVSEP_CMD_L2_UNREGISTER, - PRIVSEP_CMD_L2_NOTIFY_AUTH_START, - PRIVSEP_CMD_L2_SEND, - PRIVSEP_CMD_SET_COUNTRY, -}; - -struct privsep_cmd_associate -{ - u8 bssid[ETH_ALEN]; - u8 ssid[32]; - size_t ssid_len; - int freq; - int pairwise_suite; - int group_suite; - int key_mgmt_suite; - int auth_alg; - int mode; - size_t wpa_ie_len; - /* followed by wpa_ie_len bytes of wpa_ie */ -}; - -struct privsep_cmd_set_key -{ - int alg; - u8 addr[ETH_ALEN]; - int key_idx; - int set_tx; - u8 seq[8]; - size_t seq_len; - u8 key[32]; - size_t key_len; -}; - -enum privsep_event { - PRIVSEP_EVENT_SCAN_RESULTS, - PRIVSEP_EVENT_ASSOC, - PRIVSEP_EVENT_DISASSOC, - PRIVSEP_EVENT_ASSOCINFO, - PRIVSEP_EVENT_MICHAEL_MIC_FAILURE, - PRIVSEP_EVENT_INTERFACE_STATUS, - PRIVSEP_EVENT_PMKID_CANDIDATE, - PRIVSEP_EVENT_STKSTART, - PRIVSEP_EVENT_FT_RESPONSE, - PRIVSEP_EVENT_RX_EAPOL, -}; - -#endif /* PRIVSEP_COMMANDS_H */ diff --git a/contrib/hostapd/src/common/qca-vendor.h b/contrib/hostapd/src/common/qca-vendor.h deleted file mode 100644 index 0d83920a60..0000000000 --- a/contrib/hostapd/src/common/qca-vendor.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Qualcomm Atheros OUI and vendor specific assignments - * Copyright (c) 2014, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef QCA_VENDOR_H -#define QCA_VENDOR_H - -/* - * This file is a registry of identifier assignments from the Qualcomm Atheros - * OUI 00:13:74 for purposes other than MAC address assignment. New identifiers - * can be assigned through normal review process for changes to the upstream - * hostap.git repository. - */ - -#define OUI_QCA 0x001374 - -/** - * enum qca_nl80211_vendor_subcmds - QCA nl80211 vendor command identifiers - * - * @QCA_NL80211_VENDOR_SUBCMD_UNSPEC: Reserved value 0 - * - * @QCA_NL80211_VENDOR_SUBCMD_TEST: Test command/event - * - * @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: Recommendation of frequency - * ranges to avoid to reduce issues due to interference or internal - * co-existence information in the driver. The event data structure is - * defined in struct qca_avoid_freq_list. - */ -enum qca_nl80211_vendor_subcmds { - QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0, - QCA_NL80211_VENDOR_SUBCMD_TEST = 1, - /* subcmds 2..9 not yet allocated */ - QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10, -}; - - -struct qca_avoid_freq_range { - u32 start_freq; - u32 end_freq; -} STRUCT_PACKED; - -struct qca_avoid_freq_list { - u32 count; - struct qca_avoid_freq_range range[0]; -} STRUCT_PACKED; - -#endif /* QCA_VENDOR_H */ diff --git a/contrib/hostapd/src/common/sae.c b/contrib/hostapd/src/common/sae.c deleted file mode 100644 index 08bf054cbd..0000000000 --- a/contrib/hostapd/src/common/sae.c +++ /dev/null @@ -1,1047 +0,0 @@ -/* - * Simultaneous authentication of equals - * Copyright (c) 2012-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/crypto.h" -#include "crypto/sha256.h" -#include "crypto/random.h" -#include "crypto/dh_groups.h" -#include "ieee802_11_defs.h" -#include "sae.h" - - -int sae_set_group(struct sae_data *sae, int group) -{ - struct sae_temporary_data *tmp; - - sae_clear_data(sae); - tmp = sae->tmp = os_zalloc(sizeof(*tmp)); - if (tmp == NULL) - return -1; - - /* First, check if this is an ECC group */ - tmp->ec = crypto_ec_init(group); - if (tmp->ec) { - sae->group = group; - tmp->prime_len = crypto_ec_prime_len(tmp->ec); - tmp->prime = crypto_ec_get_prime(tmp->ec); - tmp->order = crypto_ec_get_order(tmp->ec); - return 0; - } - - /* Not an ECC group, check FFC */ - tmp->dh = dh_groups_get(group); - if (tmp->dh) { - sae->group = group; - tmp->prime_len = tmp->dh->prime_len; - if (tmp->prime_len > SAE_MAX_PRIME_LEN) { - sae_clear_data(sae); - return -1; - } - - tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime, - tmp->prime_len); - if (tmp->prime_buf == NULL) { - sae_clear_data(sae); - return -1; - } - tmp->prime = tmp->prime_buf; - - tmp->order_buf = crypto_bignum_init_set(tmp->dh->order, - tmp->dh->order_len); - if (tmp->order_buf == NULL) { - sae_clear_data(sae); - return -1; - } - tmp->order = tmp->order_buf; - - return 0; - } - - /* Unsupported group */ - return -1; -} - - -void sae_clear_temp_data(struct sae_data *sae) -{ - struct sae_temporary_data *tmp; - if (sae == NULL || sae->tmp == NULL) - return; - tmp = sae->tmp; - crypto_ec_deinit(tmp->ec); - crypto_bignum_deinit(tmp->prime_buf, 0); - crypto_bignum_deinit(tmp->order_buf, 0); - crypto_bignum_deinit(tmp->sae_rand, 1); - crypto_bignum_deinit(tmp->pwe_ffc, 1); - crypto_bignum_deinit(tmp->own_commit_scalar, 0); - crypto_bignum_deinit(tmp->own_commit_element_ffc, 0); - crypto_bignum_deinit(tmp->peer_commit_element_ffc, 0); - crypto_ec_point_deinit(tmp->pwe_ecc, 1); - crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0); - crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0); - os_free(sae->tmp); - sae->tmp = NULL; -} - - -void sae_clear_data(struct sae_data *sae) -{ - if (sae == NULL) - return; - sae_clear_temp_data(sae); - crypto_bignum_deinit(sae->peer_commit_scalar, 0); - os_memset(sae, 0, sizeof(*sae)); -} - - -static void buf_shift_right(u8 *buf, size_t len, size_t bits) -{ - size_t i; - for (i = len - 1; i > 0; i--) - buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits); - buf[0] >>= bits; -} - - -static struct crypto_bignum * sae_get_rand(struct sae_data *sae) -{ - u8 val[SAE_MAX_PRIME_LEN]; - int iter = 0; - struct crypto_bignum *bn = NULL; - int order_len_bits = crypto_bignum_bits(sae->tmp->order); - size_t order_len = (order_len_bits + 7) / 8; - - if (order_len > sizeof(val)) - return NULL; - - for (;;) { - if (iter++ > 100) - return NULL; - if (random_get_bytes(val, order_len) < 0) - return NULL; - if (order_len_bits % 8) - buf_shift_right(val, order_len, 8 - order_len_bits % 8); - bn = crypto_bignum_init_set(val, order_len); - if (bn == NULL) - return NULL; - if (crypto_bignum_is_zero(bn) || - crypto_bignum_is_one(bn) || - crypto_bignum_cmp(bn, sae->tmp->order) >= 0) - continue; - break; - } - - os_memset(val, 0, order_len); - return bn; -} - - -static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae) -{ - crypto_bignum_deinit(sae->tmp->sae_rand, 1); - sae->tmp->sae_rand = sae_get_rand(sae); - if (sae->tmp->sae_rand == NULL) - return NULL; - return sae_get_rand(sae); -} - - -static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key) -{ - wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR - " addr2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2)); - if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) { - os_memcpy(key, addr1, ETH_ALEN); - os_memcpy(key + ETH_ALEN, addr2, ETH_ALEN); - } else { - os_memcpy(key, addr2, ETH_ALEN); - os_memcpy(key + ETH_ALEN, addr1, ETH_ALEN); - } -} - - -static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, - struct crypto_ec_point *pwe) -{ - u8 pwd_value[SAE_MAX_ECC_PRIME_LEN], prime[SAE_MAX_ECC_PRIME_LEN]; - struct crypto_bignum *x; - int y_bit; - size_t bits; - - if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime), - sae->tmp->prime_len) < 0) - return -1; - - wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN); - - /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */ - bits = crypto_ec_prime_len_bits(sae->tmp->ec); - sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking", - prime, sae->tmp->prime_len, pwd_value, bits); - if (bits % 8) - buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8); - wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", - pwd_value, sae->tmp->prime_len); - - if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0) - return 0; - - y_bit = pwd_seed[SHA256_MAC_LEN - 1] & 0x01; - - x = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len); - if (x == NULL) - return -1; - if (crypto_ec_point_solve_y_coord(sae->tmp->ec, pwe, x, y_bit) < 0) { - crypto_bignum_deinit(x, 0); - wpa_printf(MSG_DEBUG, "SAE: No solution found"); - return 0; - } - crypto_bignum_deinit(x, 0); - - wpa_printf(MSG_DEBUG, "SAE: PWE found"); - - return 1; -} - - -static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed, - struct crypto_bignum *pwe) -{ - u8 pwd_value[SAE_MAX_PRIME_LEN]; - size_t bits = sae->tmp->prime_len * 8; - u8 exp[1]; - struct crypto_bignum *a, *b; - int res; - - wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN); - - /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */ - sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking", - sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value, - bits); - if (bits % 8) - buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8); - wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value, - sae->tmp->prime_len); - - if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0) - { - wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p"); - return 0; - } - - /* PWE = pwd-value^((p-1)/r) modulo p */ - - a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len); - - if (sae->tmp->dh->safe_prime) { - /* - * r = (p-1)/2 for the group used here, so this becomes: - * PWE = pwd-value^2 modulo p - */ - exp[0] = 2; - b = crypto_bignum_init_set(exp, sizeof(exp)); - } else { - /* Calculate exponent: (p-1)/r */ - exp[0] = 1; - b = crypto_bignum_init_set(exp, sizeof(exp)); - if (b == NULL || - crypto_bignum_sub(sae->tmp->prime, b, b) < 0 || - crypto_bignum_div(b, sae->tmp->order, b) < 0) { - crypto_bignum_deinit(b, 0); - b = NULL; - } - } - - if (a == NULL || b == NULL) - res = -1; - else - res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe); - - crypto_bignum_deinit(a, 0); - crypto_bignum_deinit(b, 0); - - if (res < 0) { - wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE"); - return -1; - } - - /* if (PWE > 1) --> found */ - if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) { - wpa_printf(MSG_DEBUG, "SAE: PWE <= 1"); - return 0; - } - - wpa_printf(MSG_DEBUG, "SAE: PWE found"); - return 1; -} - - -static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, - const u8 *addr2, const u8 *password, - size_t password_len) -{ - u8 counter, k = 4; - u8 addrs[2 * ETH_ALEN]; - const u8 *addr[2]; - size_t len[2]; - int found = 0; - struct crypto_ec_point *pwe_tmp; - - if (sae->tmp->pwe_ecc == NULL) { - sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec); - if (sae->tmp->pwe_ecc == NULL) - return -1; - } - pwe_tmp = crypto_ec_point_init(sae->tmp->ec); - if (pwe_tmp == NULL) - return -1; - - wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", - password, password_len); - - /* - * H(salt, ikm) = HMAC-SHA256(salt, ikm) - * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC), - * password || counter) - */ - sae_pwd_seed_key(addr1, addr2, addrs); - - addr[0] = password; - len[0] = password_len; - addr[1] = &counter; - len[1] = sizeof(counter); - - /* - * Continue for at least k iterations to protect against side-channel - * attacks that attempt to determine the number of iterations required - * in the loop. - */ - for (counter = 1; counter < k || !found; counter++) { - u8 pwd_seed[SHA256_MAC_LEN]; - int res; - - if (counter > 200) { - /* This should not happen in practice */ - wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE"); - break; - } - - wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter); - if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len, - pwd_seed) < 0) - break; - res = sae_test_pwd_seed_ecc(sae, pwd_seed, - found ? pwe_tmp : - sae->tmp->pwe_ecc); - if (res < 0) - break; - if (res == 0) - continue; - if (found) { - wpa_printf(MSG_DEBUG, "SAE: Ignore this PWE (one was " - "already selected)"); - } else { - wpa_printf(MSG_DEBUG, "SAE: Use this PWE"); - found = 1; - } - } - - crypto_ec_point_deinit(pwe_tmp, 1); - - return found ? 0 : -1; -} - - -static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, - const u8 *addr2, const u8 *password, - size_t password_len) -{ - u8 counter; - u8 addrs[2 * ETH_ALEN]; - const u8 *addr[2]; - size_t len[2]; - int found = 0; - - if (sae->tmp->pwe_ffc == NULL) { - sae->tmp->pwe_ffc = crypto_bignum_init(); - if (sae->tmp->pwe_ffc == NULL) - return -1; - } - - wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", - password, password_len); - - /* - * H(salt, ikm) = HMAC-SHA256(salt, ikm) - * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC), - * password || counter) - */ - sae_pwd_seed_key(addr1, addr2, addrs); - - addr[0] = password; - len[0] = password_len; - addr[1] = &counter; - len[1] = sizeof(counter); - - for (counter = 1; !found; counter++) { - u8 pwd_seed[SHA256_MAC_LEN]; - int res; - - if (counter > 200) { - /* This should not happen in practice */ - wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE"); - break; - } - - wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter); - if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len, - pwd_seed) < 0) - break; - res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc); - if (res < 0) - break; - if (res > 0) { - wpa_printf(MSG_DEBUG, "SAE: Use this PWE"); - found = 1; - } - } - - return found ? 0 : -1; -} - - -static int sae_derive_commit_element_ecc(struct sae_data *sae, - struct crypto_bignum *mask) -{ - /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */ - if (!sae->tmp->own_commit_element_ecc) { - sae->tmp->own_commit_element_ecc = - crypto_ec_point_init(sae->tmp->ec); - if (!sae->tmp->own_commit_element_ecc) - return -1; - } - - if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask, - sae->tmp->own_commit_element_ecc) < 0 || - crypto_ec_point_invert(sae->tmp->ec, - sae->tmp->own_commit_element_ecc) < 0) { - wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element"); - return -1; - } - - return 0; -} - - -static int sae_derive_commit_element_ffc(struct sae_data *sae, - struct crypto_bignum *mask) -{ - /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */ - if (!sae->tmp->own_commit_element_ffc) { - sae->tmp->own_commit_element_ffc = crypto_bignum_init(); - if (!sae->tmp->own_commit_element_ffc) - return -1; - } - - if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime, - sae->tmp->own_commit_element_ffc) < 0 || - crypto_bignum_inverse(sae->tmp->own_commit_element_ffc, - sae->tmp->prime, - sae->tmp->own_commit_element_ffc) < 0) { - wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element"); - return -1; - } - - return 0; -} - - -static int sae_derive_commit(struct sae_data *sae) -{ - struct crypto_bignum *mask; - int ret = -1; - - mask = sae_get_rand_and_mask(sae); - if (mask == NULL) { - wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask"); - return -1; - } - - /* commit-scalar = (rand + mask) modulo r */ - if (!sae->tmp->own_commit_scalar) { - sae->tmp->own_commit_scalar = crypto_bignum_init(); - if (!sae->tmp->own_commit_scalar) - goto fail; - } - crypto_bignum_add(sae->tmp->sae_rand, mask, - sae->tmp->own_commit_scalar); - crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order, - sae->tmp->own_commit_scalar); - - if (sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) - goto fail; - if (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0) - goto fail; - - ret = 0; -fail: - crypto_bignum_deinit(mask, 1); - return ret; -} - - -int sae_prepare_commit(const u8 *addr1, const u8 *addr2, - const u8 *password, size_t password_len, - struct sae_data *sae) -{ - if (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password, - password_len) < 0) - return -1; - if (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password, - password_len) < 0) - return -1; - if (sae_derive_commit(sae) < 0) - return -1; - return 0; -} - - -static int sae_derive_k_ecc(struct sae_data *sae, u8 *k) -{ - struct crypto_ec_point *K; - int ret = -1; - - K = crypto_ec_point_init(sae->tmp->ec); - if (K == NULL) - goto fail; - - /* - * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE), - * PEER-COMMIT-ELEMENT))) - * If K is identity element (point-at-infinity), reject - * k = F(K) (= x coordinate) - */ - - if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, - sae->peer_commit_scalar, K) < 0 || - crypto_ec_point_add(sae->tmp->ec, K, - sae->tmp->peer_commit_element_ecc, K) < 0 || - crypto_ec_point_mul(sae->tmp->ec, K, sae->tmp->sae_rand, K) < 0 || - crypto_ec_point_is_at_infinity(sae->tmp->ec, K) || - crypto_ec_point_to_bin(sae->tmp->ec, K, k, NULL) < 0) { - wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k"); - goto fail; - } - - wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len); - - ret = 0; -fail: - crypto_ec_point_deinit(K, 1); - return ret; -} - - -static int sae_derive_k_ffc(struct sae_data *sae, u8 *k) -{ - struct crypto_bignum *K; - int ret = -1; - - K = crypto_bignum_init(); - if (K == NULL) - goto fail; - - /* - * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE), - * PEER-COMMIT-ELEMENT))) - * If K is identity element (one), reject. - * k = F(K) (= x coordinate) - */ - - if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, sae->peer_commit_scalar, - sae->tmp->prime, K) < 0 || - crypto_bignum_mulmod(K, sae->tmp->peer_commit_element_ffc, - sae->tmp->prime, K) < 0 || - crypto_bignum_exptmod(K, sae->tmp->sae_rand, sae->tmp->prime, K) < 0 - || - crypto_bignum_is_one(K) || - crypto_bignum_to_bin(K, k, SAE_MAX_PRIME_LEN, sae->tmp->prime_len) < - 0) { - wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k"); - goto fail; - } - - wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len); - - ret = 0; -fail: - crypto_bignum_deinit(K, 1); - return ret; -} - - -static int sae_derive_keys(struct sae_data *sae, const u8 *k) -{ - u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN]; - u8 keyseed[SHA256_MAC_LEN]; - u8 keys[SAE_KCK_LEN + SAE_PMK_LEN]; - struct crypto_bignum *tmp; - int ret = -1; - - tmp = crypto_bignum_init(); - if (tmp == NULL) - goto fail; - - /* keyseed = H(<0>32, k) - * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK", - * (commit-scalar + peer-commit-scalar) modulo r) - * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128) - */ - - os_memset(null_key, 0, sizeof(null_key)); - hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len, - keyseed); - wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed)); - - crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar, - tmp); - crypto_bignum_mod(tmp, sae->tmp->order, tmp); - crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len); - wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN); - sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK", - val, sae->tmp->prime_len, keys, sizeof(keys)); - os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN); - os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN); - wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN); - wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN); - - ret = 0; -fail: - crypto_bignum_deinit(tmp, 0); - return ret; -} - - -int sae_process_commit(struct sae_data *sae) -{ - u8 k[SAE_MAX_PRIME_LEN]; - if ((sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) || - (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) || - sae_derive_keys(sae, k) < 0) - return -1; - return 0; -} - - -void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, - const struct wpabuf *token) -{ - u8 *pos; - wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */ - if (token) - wpabuf_put_buf(buf, token); - pos = wpabuf_put(buf, sae->tmp->prime_len); - crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos, - sae->tmp->prime_len, sae->tmp->prime_len); - wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar", - pos, sae->tmp->prime_len); - if (sae->tmp->ec) { - pos = wpabuf_put(buf, 2 * sae->tmp->prime_len); - crypto_ec_point_to_bin(sae->tmp->ec, - sae->tmp->own_commit_element_ecc, - pos, pos + sae->tmp->prime_len); - wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)", - pos, sae->tmp->prime_len); - wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)", - pos + sae->tmp->prime_len, sae->tmp->prime_len); - } else { - pos = wpabuf_put(buf, sae->tmp->prime_len); - crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos, - sae->tmp->prime_len, sae->tmp->prime_len); - wpa_hexdump(MSG_DEBUG, "SAE: own commit-element", - pos, sae->tmp->prime_len); - } -} - - -static u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, - u16 group) -{ - if (allowed_groups) { - int i; - for (i = 0; allowed_groups[i] > 0; i++) { - if (allowed_groups[i] == group) - break; - } - if (allowed_groups[i] != group) { - wpa_printf(MSG_DEBUG, "SAE: Proposed group %u not " - "enabled in the current configuration", - group); - return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; - } - } - - if (sae->state == SAE_COMMITTED && group != sae->group) { - wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed"); - return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; - } - - if (group != sae->group && sae_set_group(sae, group) < 0) { - wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u", - group); - return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; - } - - if (sae->tmp == NULL) { - wpa_printf(MSG_DEBUG, "SAE: Group information not yet initialized"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - if (sae->tmp->dh && !allowed_groups) { - wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without " - "explicit configuration enabling it", group); - return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; - } - - return WLAN_STATUS_SUCCESS; -} - - -static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos, - const u8 *end, const u8 **token, - size_t *token_len) -{ - if (*pos + (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end) { - size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) * - sae->tmp->prime_len); - wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen); - if (token) - *token = *pos; - if (token_len) - *token_len = tlen; - *pos += tlen; - } else { - if (token) - *token = NULL; - if (token_len) - *token_len = 0; - } -} - - -static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos, - const u8 *end) -{ - struct crypto_bignum *peer_scalar; - - if (*pos + sae->tmp->prime_len > end) { - wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - peer_scalar = crypto_bignum_init_set(*pos, sae->tmp->prime_len); - if (peer_scalar == NULL) - return WLAN_STATUS_UNSPECIFIED_FAILURE; - - /* - * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for - * the peer and it is in Authenticated state, the new Commit Message - * shall be dropped if the peer-scalar is identical to the one used in - * the existing protocol instance. - */ - if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar && - crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) { - wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous " - "peer-commit-scalar"); - crypto_bignum_deinit(peer_scalar, 0); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - /* 0 < scalar < r */ - if (crypto_bignum_is_zero(peer_scalar) || - crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) { - wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar"); - crypto_bignum_deinit(peer_scalar, 0); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - - crypto_bignum_deinit(sae->peer_commit_scalar, 0); - sae->peer_commit_scalar = peer_scalar; - wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar", - *pos, sae->tmp->prime_len); - *pos += sae->tmp->prime_len; - - return WLAN_STATUS_SUCCESS; -} - - -static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos, - const u8 *end) -{ - u8 prime[SAE_MAX_ECC_PRIME_LEN]; - - if (pos + 2 * sae->tmp->prime_len > end) { - wpa_printf(MSG_DEBUG, "SAE: Not enough data for " - "commit-element"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime), - sae->tmp->prime_len) < 0) - return WLAN_STATUS_UNSPECIFIED_FAILURE; - - /* element x and y coordinates < p */ - if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 || - os_memcmp(pos + sae->tmp->prime_len, prime, - sae->tmp->prime_len) >= 0) { - wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer " - "element"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)", - pos, sae->tmp->prime_len); - wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)", - pos + sae->tmp->prime_len, sae->tmp->prime_len); - - crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0); - sae->tmp->peer_commit_element_ecc = - crypto_ec_point_from_bin(sae->tmp->ec, pos); - if (sae->tmp->peer_commit_element_ecc == NULL) - return WLAN_STATUS_UNSPECIFIED_FAILURE; - - if (!crypto_ec_point_is_on_curve(sae->tmp->ec, - sae->tmp->peer_commit_element_ecc)) { - wpa_printf(MSG_DEBUG, "SAE: Peer element is not on curve"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - return WLAN_STATUS_SUCCESS; -} - - -static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos, - const u8 *end) -{ - struct crypto_bignum *res; - - if (pos + sae->tmp->prime_len > end) { - wpa_printf(MSG_DEBUG, "SAE: Not enough data for " - "commit-element"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", pos, - sae->tmp->prime_len); - - crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0); - sae->tmp->peer_commit_element_ffc = - crypto_bignum_init_set(pos, sae->tmp->prime_len); - if (sae->tmp->peer_commit_element_ffc == NULL) - return WLAN_STATUS_UNSPECIFIED_FAILURE; - if (crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) || - crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) || - crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc, - sae->tmp->prime) >= 0) { - wpa_printf(MSG_DEBUG, "SAE: Invalid peer element"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - /* scalar-op(r, ELEMENT) = 1 modulo p */ - res = crypto_bignum_init(); - if (res == NULL || - crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc, - sae->tmp->order, sae->tmp->prime, res) < 0 || - !crypto_bignum_is_one(res)) { - wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)"); - crypto_bignum_deinit(res, 0); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - crypto_bignum_deinit(res, 0); - - return WLAN_STATUS_SUCCESS; -} - - -static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos, - const u8 *end) -{ - if (sae->tmp->dh) - return sae_parse_commit_element_ffc(sae, pos, end); - return sae_parse_commit_element_ecc(sae, pos, end); -} - - -u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, - const u8 **token, size_t *token_len, int *allowed_groups) -{ - const u8 *pos = data, *end = data + len; - u16 res; - - /* Check Finite Cyclic Group */ - if (pos + 2 > end) - return WLAN_STATUS_UNSPECIFIED_FAILURE; - res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos)); - if (res != WLAN_STATUS_SUCCESS) - return res; - pos += 2; - - /* Optional Anti-Clogging Token */ - sae_parse_commit_token(sae, &pos, end, token, token_len); - - /* commit-scalar */ - res = sae_parse_commit_scalar(sae, &pos, end); - if (res != WLAN_STATUS_SUCCESS) - return res; - - /* commit-element */ - return sae_parse_commit_element(sae, pos, end); -} - - -static void sae_cn_confirm(struct sae_data *sae, const u8 *sc, - const struct crypto_bignum *scalar1, - const u8 *element1, size_t element1_len, - const struct crypto_bignum *scalar2, - const u8 *element2, size_t element2_len, - u8 *confirm) -{ - const u8 *addr[5]; - size_t len[5]; - u8 scalar_b1[SAE_MAX_PRIME_LEN], scalar_b2[SAE_MAX_PRIME_LEN]; - - /* Confirm - * CN(key, X, Y, Z, ...) = - * HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...) - * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT, - * peer-commit-scalar, PEER-COMMIT-ELEMENT) - * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar, - * PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT) - */ - addr[0] = sc; - len[0] = 2; - crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1), - sae->tmp->prime_len); - addr[1] = scalar_b1; - len[1] = sae->tmp->prime_len; - addr[2] = element1; - len[2] = element1_len; - crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2), - sae->tmp->prime_len); - addr[3] = scalar_b2; - len[3] = sae->tmp->prime_len; - addr[4] = element2; - len[4] = element2_len; - hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len, - confirm); -} - - -static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc, - const struct crypto_bignum *scalar1, - const struct crypto_ec_point *element1, - const struct crypto_bignum *scalar2, - const struct crypto_ec_point *element2, - u8 *confirm) -{ - u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN]; - u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN]; - - crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1, - element_b1 + sae->tmp->prime_len); - crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2, - element_b2 + sae->tmp->prime_len); - - sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len, - scalar2, element_b2, 2 * sae->tmp->prime_len, confirm); -} - - -static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc, - const struct crypto_bignum *scalar1, - const struct crypto_bignum *element1, - const struct crypto_bignum *scalar2, - const struct crypto_bignum *element2, - u8 *confirm) -{ - u8 element_b1[SAE_MAX_PRIME_LEN]; - u8 element_b2[SAE_MAX_PRIME_LEN]; - - crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1), - sae->tmp->prime_len); - crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2), - sae->tmp->prime_len); - - sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len, - scalar2, element_b2, sae->tmp->prime_len, confirm); -} - - -void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf) -{ - const u8 *sc; - - /* Send-Confirm */ - sc = wpabuf_put(buf, 0); - wpabuf_put_le16(buf, sae->send_confirm); - sae->send_confirm++; - - if (sae->tmp->ec) - sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ecc, - sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ecc, - wpabuf_put(buf, SHA256_MAC_LEN)); - else - sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ffc, - sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ffc, - wpabuf_put(buf, SHA256_MAC_LEN)); -} - - -int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) -{ - u8 verifier[SHA256_MAC_LEN]; - - if (len < 2 + SHA256_MAC_LEN) { - wpa_printf(MSG_DEBUG, "SAE: Too short confirm message"); - return -1; - } - - wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data)); - - if (sae->tmp->ec) - sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ecc, - sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ecc, - verifier); - else - sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ffc, - sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ffc, - verifier); - - if (os_memcmp(verifier, data + 2, SHA256_MAC_LEN) != 0) { - wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch"); - wpa_hexdump(MSG_DEBUG, "SAE: Received confirm", - data + 2, SHA256_MAC_LEN); - wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier", - verifier, SHA256_MAC_LEN); - return -1; - } - - return 0; -} diff --git a/contrib/hostapd/src/common/sae.h b/contrib/hostapd/src/common/sae.h deleted file mode 100644 index d82a98e888..0000000000 --- a/contrib/hostapd/src/common/sae.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Simultaneous authentication of equals - * Copyright (c) 2012-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef SAE_H -#define SAE_H - -#define SAE_KCK_LEN 32 -#define SAE_PMK_LEN 32 -#define SAE_PMKID_LEN 16 -#define SAE_KEYSEED_KEY_LEN 32 -#define SAE_MAX_PRIME_LEN 512 -#define SAE_MAX_ECC_PRIME_LEN 66 -#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN) -#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN) - -struct sae_temporary_data { - u8 kck[SAE_KCK_LEN]; - struct crypto_bignum *own_commit_scalar; - struct crypto_bignum *own_commit_element_ffc; - struct crypto_ec_point *own_commit_element_ecc; - struct crypto_bignum *peer_commit_element_ffc; - struct crypto_ec_point *peer_commit_element_ecc; - struct crypto_ec_point *pwe_ecc; - struct crypto_bignum *pwe_ffc; - struct crypto_bignum *sae_rand; - struct crypto_ec *ec; - int prime_len; - const struct dh_group *dh; - const struct crypto_bignum *prime; - const struct crypto_bignum *order; - struct crypto_bignum *prime_buf; - struct crypto_bignum *order_buf; -}; - -struct sae_data { - enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state; - u16 send_confirm; - u8 pmk[SAE_PMK_LEN]; - struct crypto_bignum *peer_commit_scalar; - int group; - struct sae_temporary_data *tmp; -}; - -int sae_set_group(struct sae_data *sae, int group); -void sae_clear_temp_data(struct sae_data *sae); -void sae_clear_data(struct sae_data *sae); - -int sae_prepare_commit(const u8 *addr1, const u8 *addr2, - const u8 *password, size_t password_len, - struct sae_data *sae); -int sae_process_commit(struct sae_data *sae); -void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, - const struct wpabuf *token); -u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, - const u8 **token, size_t *token_len, int *allowed_groups); -void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf); -int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len); - -#endif /* SAE_H */ diff --git a/contrib/hostapd/src/common/version.h b/contrib/hostapd/src/common/version.h deleted file mode 100644 index 0edf11cc9d..0000000000 --- a/contrib/hostapd/src/common/version.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef VERSION_H -#define VERSION_H - -#ifndef VERSION_STR_POSTFIX -#define VERSION_STR_POSTFIX "" -#endif /* VERSION_STR_POSTFIX */ - -#define VERSION_STR "2.1" VERSION_STR_POSTFIX - -#endif /* VERSION_H */ diff --git a/contrib/hostapd/src/common/wpa_common.c b/contrib/hostapd/src/common/wpa_common.c deleted file mode 100644 index 37b265d05f..0000000000 --- a/contrib/hostapd/src/common/wpa_common.c +++ /dev/null @@ -1,1436 +0,0 @@ -/* - * WPA/RSN - Shared functions for supplicant and authenticator - * Copyright (c) 2002-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/md5.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "crypto/aes_wrap.h" -#include "crypto/crypto.h" -#include "ieee802_11_defs.h" -#include "defs.h" -#include "wpa_common.h" - - -/** - * wpa_eapol_key_mic - Calculate EAPOL-Key MIC - * @key: EAPOL-Key Key Confirmation Key (KCK) - * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) - * @buf: Pointer to the beginning of the EAPOL header (version field) - * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) - * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written - * Returns: 0 on success, -1 on failure - * - * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has - * to be cleared (all zeroes) when calling this function. - * - * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the - * description of the Key MIC calculation. It includes packet data from the - * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change - * happened during final editing of the standard and the correct behavior is - * defined in the last draft (IEEE 802.11i/D10). - */ -int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, - u8 *mic) -{ - u8 hash[SHA1_MAC_LEN]; - - switch (ver) { -#ifndef CONFIG_FIPS - case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: - return hmac_md5(key, 16, buf, len, mic); -#endif /* CONFIG_FIPS */ - case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: - if (hmac_sha1(key, 16, buf, len, hash)) - return -1; - os_memcpy(mic, hash, MD5_MAC_LEN); - break; -#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) - case WPA_KEY_INFO_TYPE_AES_128_CMAC: - return omac1_aes_128(key, buf, len, mic); -#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ - default: - return -1; - } - - return 0; -} - - -/** - * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces - * @pmk: Pairwise master key - * @pmk_len: Length of PMK - * @label: Label to use in derivation - * @addr1: AA or SA - * @addr2: SA or AA - * @nonce1: ANonce or SNonce - * @nonce2: SNonce or ANonce - * @ptk: Buffer for pairwise transient key - * @ptk_len: Length of PTK - * @use_sha256: Whether to use SHA256-based KDF - * - * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy - * PTK = PRF-X(PMK, "Pairwise key expansion", - * Min(AA, SA) || Max(AA, SA) || - * Min(ANonce, SNonce) || Max(ANonce, SNonce)) - * - * STK = PRF-X(SMK, "Peer key expansion", - * Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) || - * Min(INonce, PNonce) || Max(INonce, PNonce)) - */ -void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, - const u8 *addr1, const u8 *addr2, - const u8 *nonce1, const u8 *nonce2, - u8 *ptk, size_t ptk_len, int use_sha256) -{ - u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN]; - - if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) { - os_memcpy(data, addr1, ETH_ALEN); - os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN); - } else { - os_memcpy(data, addr2, ETH_ALEN); - os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN); - } - - if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) { - os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN); - os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2, - WPA_NONCE_LEN); - } else { - os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN); - os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1, - WPA_NONCE_LEN); - } - -#ifdef CONFIG_IEEE80211W - if (use_sha256) - sha256_prf(pmk, pmk_len, label, data, sizeof(data), - ptk, ptk_len); - else -#endif /* CONFIG_IEEE80211W */ - sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, - ptk_len); - - wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR, - MAC2STR(addr1), MAC2STR(addr2)); - wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN); - wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len); - wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len); -} - - -#ifdef CONFIG_IEEE80211R -int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, - u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, - const u8 *ftie, size_t ftie_len, - const u8 *rsnie, size_t rsnie_len, - const u8 *ric, size_t ric_len, u8 *mic) -{ - u8 *buf, *pos; - size_t buf_len; - - buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len; - buf = os_malloc(buf_len); - if (buf == NULL) - return -1; - - pos = buf; - os_memcpy(pos, sta_addr, ETH_ALEN); - pos += ETH_ALEN; - os_memcpy(pos, ap_addr, ETH_ALEN); - pos += ETH_ALEN; - *pos++ = transaction_seqnum; - if (rsnie) { - os_memcpy(pos, rsnie, rsnie_len); - pos += rsnie_len; - } - if (mdie) { - os_memcpy(pos, mdie, mdie_len); - pos += mdie_len; - } - if (ftie) { - struct rsn_ftie *_ftie; - os_memcpy(pos, ftie, ftie_len); - if (ftie_len < 2 + sizeof(*_ftie)) { - os_free(buf); - return -1; - } - _ftie = (struct rsn_ftie *) (pos + 2); - os_memset(_ftie->mic, 0, sizeof(_ftie->mic)); - pos += ftie_len; - } - if (ric) { - os_memcpy(pos, ric, ric_len); - pos += ric_len; - } - - wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf); - if (omac1_aes_128(kck, buf, pos - buf, mic)) { - os_free(buf); - return -1; - } - - os_free(buf); - - 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 */ - - -static int rsn_selector_to_bitfield(const u8 *s) -{ - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE) - return WPA_CIPHER_NONE; - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40) - return WPA_CIPHER_WEP40; - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP) - return WPA_CIPHER_TKIP; - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP) - return WPA_CIPHER_CCMP; - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104) - return WPA_CIPHER_WEP104; -#ifdef CONFIG_IEEE80211W - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC) - return WPA_CIPHER_AES_128_CMAC; -#endif /* CONFIG_IEEE80211W */ - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP) - return WPA_CIPHER_GCMP; - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256) - return WPA_CIPHER_CCMP_256; - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256) - return WPA_CIPHER_GCMP_256; - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128) - return WPA_CIPHER_BIP_GMAC_128; - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256) - return WPA_CIPHER_BIP_GMAC_256; - if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256) - return WPA_CIPHER_BIP_CMAC_256; - return 0; -} - - -static int rsn_key_mgmt_to_bitfield(const u8 *s) -{ - if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X) - return WPA_KEY_MGMT_IEEE8021X; - if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X) - return WPA_KEY_MGMT_PSK; -#ifdef CONFIG_IEEE80211R - if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X) - return WPA_KEY_MGMT_FT_IEEE8021X; - if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK) - return WPA_KEY_MGMT_FT_PSK; -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256) - return WPA_KEY_MGMT_IEEE8021X_SHA256; - if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256) - return WPA_KEY_MGMT_PSK_SHA256; -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_SAE - if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE) - return WPA_KEY_MGMT_SAE; - if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE) - return WPA_KEY_MGMT_FT_SAE; -#endif /* CONFIG_SAE */ - return 0; -} - - -/** - * wpa_parse_wpa_ie_rsn - Parse RSN IE - * @rsn_ie: Buffer containing RSN IE - * @rsn_ie_len: RSN IE buffer length (including IE number and length octets) - * @data: Pointer to structure that will be filled in with parsed data - * Returns: 0 on success, <0 on failure - */ -int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, - struct wpa_ie_data *data) -{ - const struct rsn_ie_hdr *hdr; - const u8 *pos; - int left; - int i, count; - - os_memset(data, 0, sizeof(*data)); - data->proto = WPA_PROTO_RSN; - data->pairwise_cipher = WPA_CIPHER_CCMP; - data->group_cipher = WPA_CIPHER_CCMP; - data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; - data->capabilities = 0; - data->pmkid = NULL; - data->num_pmkid = 0; -#ifdef CONFIG_IEEE80211W - data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; -#else /* CONFIG_IEEE80211W */ - data->mgmt_group_cipher = 0; -#endif /* CONFIG_IEEE80211W */ - - if (rsn_ie_len == 0) { - /* No RSN IE - fail silently */ - return -1; - } - - if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { - wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", - __func__, (unsigned long) rsn_ie_len); - return -1; - } - - hdr = (const struct rsn_ie_hdr *) rsn_ie; - - if (hdr->elem_id != WLAN_EID_RSN || - hdr->len != rsn_ie_len - 2 || - WPA_GET_LE16(hdr->version) != RSN_VERSION) { - wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", - __func__); - return -2; - } - - pos = (const u8 *) (hdr + 1); - left = rsn_ie_len - sizeof(*hdr); - - if (left >= RSN_SELECTOR_LEN) { - data->group_cipher = rsn_selector_to_bitfield(pos); -#ifdef CONFIG_IEEE80211W - if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) { - wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group " - "cipher", __func__); - return -1; - } -#endif /* CONFIG_IEEE80211W */ - pos += RSN_SELECTOR_LEN; - left -= RSN_SELECTOR_LEN; - } else if (left > 0) { - wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", - __func__, left); - return -3; - } - - if (left >= 2) { - data->pairwise_cipher = 0; - count = WPA_GET_LE16(pos); - pos += 2; - left -= 2; - if (count == 0 || left < count * RSN_SELECTOR_LEN) { - wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " - "count %u left %u", __func__, count, left); - return -4; - } - for (i = 0; i < count; i++) { - data->pairwise_cipher |= rsn_selector_to_bitfield(pos); - pos += RSN_SELECTOR_LEN; - left -= RSN_SELECTOR_LEN; - } -#ifdef CONFIG_IEEE80211W - if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) { - wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as " - "pairwise cipher", __func__); - return -1; - } -#endif /* CONFIG_IEEE80211W */ - } else if (left == 1) { - wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", - __func__); - return -5; - } - - if (left >= 2) { - data->key_mgmt = 0; - count = WPA_GET_LE16(pos); - pos += 2; - left -= 2; - if (count == 0 || left < count * RSN_SELECTOR_LEN) { - wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " - "count %u left %u", __func__, count, left); - return -6; - } - for (i = 0; i < count; i++) { - data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); - pos += RSN_SELECTOR_LEN; - left -= RSN_SELECTOR_LEN; - } - } else if (left == 1) { - wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", - __func__); - return -7; - } - - if (left >= 2) { - data->capabilities = WPA_GET_LE16(pos); - pos += 2; - left -= 2; - } - - if (left >= 2) { - data->num_pmkid = WPA_GET_LE16(pos); - pos += 2; - left -= 2; - if (left < (int) data->num_pmkid * PMKID_LEN) { - wpa_printf(MSG_DEBUG, "%s: PMKID underflow " - "(num_pmkid=%lu left=%d)", - __func__, (unsigned long) data->num_pmkid, - left); - data->num_pmkid = 0; - return -9; - } else { - data->pmkid = pos; - pos += data->num_pmkid * PMKID_LEN; - left -= data->num_pmkid * PMKID_LEN; - } - } - -#ifdef CONFIG_IEEE80211W - if (left >= 4) { - data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); - if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { - wpa_printf(MSG_DEBUG, "%s: Unsupported management " - "group cipher 0x%x", __func__, - data->mgmt_group_cipher); - return -10; - } - pos += RSN_SELECTOR_LEN; - left -= RSN_SELECTOR_LEN; - } -#endif /* CONFIG_IEEE80211W */ - - if (left > 0) { - wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", - __func__, left); - } - - return 0; -} - - -static int wpa_selector_to_bitfield(const u8 *s) -{ - if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE) - return WPA_CIPHER_NONE; - if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40) - return WPA_CIPHER_WEP40; - if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP) - return WPA_CIPHER_TKIP; - if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP) - return WPA_CIPHER_CCMP; - if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104) - return WPA_CIPHER_WEP104; - return 0; -} - - -static int wpa_key_mgmt_to_bitfield(const u8 *s) -{ - if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X) - return WPA_KEY_MGMT_IEEE8021X; - if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X) - return WPA_KEY_MGMT_PSK; - if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE) - return WPA_KEY_MGMT_WPA_NONE; - return 0; -} - - -int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, - struct wpa_ie_data *data) -{ - const struct wpa_ie_hdr *hdr; - const u8 *pos; - int left; - int i, count; - - os_memset(data, 0, sizeof(*data)); - data->proto = WPA_PROTO_WPA; - data->pairwise_cipher = WPA_CIPHER_TKIP; - data->group_cipher = WPA_CIPHER_TKIP; - data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; - data->capabilities = 0; - data->pmkid = NULL; - data->num_pmkid = 0; - data->mgmt_group_cipher = 0; - - if (wpa_ie_len == 0) { - /* No WPA IE - fail silently */ - return -1; - } - - if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { - wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", - __func__, (unsigned long) wpa_ie_len); - return -1; - } - - hdr = (const struct wpa_ie_hdr *) wpa_ie; - - if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC || - hdr->len != wpa_ie_len - 2 || - RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE || - WPA_GET_LE16(hdr->version) != WPA_VERSION) { - wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", - __func__); - return -2; - } - - pos = (const u8 *) (hdr + 1); - left = wpa_ie_len - sizeof(*hdr); - - if (left >= WPA_SELECTOR_LEN) { - data->group_cipher = wpa_selector_to_bitfield(pos); - pos += WPA_SELECTOR_LEN; - left -= WPA_SELECTOR_LEN; - } else if (left > 0) { - wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", - __func__, left); - return -3; - } - - if (left >= 2) { - data->pairwise_cipher = 0; - count = WPA_GET_LE16(pos); - pos += 2; - left -= 2; - if (count == 0 || left < count * WPA_SELECTOR_LEN) { - wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " - "count %u left %u", __func__, count, left); - return -4; - } - for (i = 0; i < count; i++) { - data->pairwise_cipher |= wpa_selector_to_bitfield(pos); - pos += WPA_SELECTOR_LEN; - left -= WPA_SELECTOR_LEN; - } - } else if (left == 1) { - wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", - __func__); - return -5; - } - - if (left >= 2) { - data->key_mgmt = 0; - count = WPA_GET_LE16(pos); - pos += 2; - left -= 2; - if (count == 0 || left < count * WPA_SELECTOR_LEN) { - wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " - "count %u left %u", __func__, count, left); - return -6; - } - for (i = 0; i < count; i++) { - data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); - pos += WPA_SELECTOR_LEN; - left -= WPA_SELECTOR_LEN; - } - } else if (left == 1) { - wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", - __func__); - return -7; - } - - if (left >= 2) { - data->capabilities = WPA_GET_LE16(pos); - pos += 2; - left -= 2; - } - - if (left > 0) { - wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", - __func__, left); - } - - return 0; -} - - -#ifdef CONFIG_IEEE80211R - -/** - * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name - * - * IEEE Std 802.11r-2008 - 8.5.1.5.3 - */ -void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, - const u8 *ssid, size_t ssid_len, - const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, - const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name) -{ - u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 + - FT_R0KH_ID_MAX_LEN + ETH_ALEN]; - u8 *pos, r0_key_data[48], hash[32]; - const u8 *addr[2]; - size_t len[2]; - - /* - * R0-Key-Data = KDF-384(XXKey, "FT-R0", - * SSIDlength || SSID || MDID || R0KHlength || - * R0KH-ID || S0KH-ID) - * XXKey is either the second 256 bits of MSK or PSK. - * PMK-R0 = L(R0-Key-Data, 0, 256) - * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128) - */ - if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN) - return; - pos = buf; - *pos++ = ssid_len; - os_memcpy(pos, ssid, ssid_len); - pos += ssid_len; - os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN); - pos += MOBILITY_DOMAIN_ID_LEN; - *pos++ = r0kh_id_len; - os_memcpy(pos, r0kh_id, r0kh_id_len); - pos += r0kh_id_len; - os_memcpy(pos, s0kh_id, ETH_ALEN); - pos += ETH_ALEN; - - sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, - r0_key_data, sizeof(r0_key_data)); - os_memcpy(pmk_r0, r0_key_data, PMK_LEN); - - /* - * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt) - */ - addr[0] = (const u8 *) "FT-R0N"; - len[0] = 6; - addr[1] = r0_key_data + PMK_LEN; - len[1] = 16; - - sha256_vector(2, addr, len, hash); - os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN); -} - - -/** - * wpa_derive_pmk_r1_name - Derive PMKR1Name - * - * IEEE Std 802.11r-2008 - 8.5.1.5.4 - */ -void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, - const u8 *s1kh_id, u8 *pmk_r1_name) -{ - u8 hash[32]; - const u8 *addr[4]; - size_t len[4]; - - /* - * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name || - * R1KH-ID || S1KH-ID)) - */ - addr[0] = (const u8 *) "FT-R1N"; - len[0] = 6; - addr[1] = pmk_r0_name; - len[1] = WPA_PMK_NAME_LEN; - addr[2] = r1kh_id; - len[2] = FT_R1KH_ID_LEN; - addr[3] = s1kh_id; - len[3] = ETH_ALEN; - - sha256_vector(4, addr, len, hash); - os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN); -} - - -/** - * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0 - * - * IEEE Std 802.11r-2008 - 8.5.1.5.4 - */ -void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, - const u8 *r1kh_id, const u8 *s1kh_id, - u8 *pmk_r1, u8 *pmk_r1_name) -{ - u8 buf[FT_R1KH_ID_LEN + ETH_ALEN]; - u8 *pos; - - /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */ - pos = buf; - os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN); - pos += FT_R1KH_ID_LEN; - os_memcpy(pos, s1kh_id, ETH_ALEN); - pos += ETH_ALEN; - - sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN); - - wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name); -} - - -/** - * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1 - * - * IEEE Std 802.11r-2008 - 8.5.1.5.5 - */ -void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, - const u8 *sta_addr, const u8 *bssid, - const u8 *pmk_r1_name, - u8 *ptk, size_t ptk_len, u8 *ptk_name) -{ - u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN]; - u8 *pos, hash[32]; - const u8 *addr[6]; - size_t len[6]; - - /* - * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || - * BSSID || STA-ADDR) - */ - pos = buf; - os_memcpy(pos, snonce, WPA_NONCE_LEN); - pos += WPA_NONCE_LEN; - os_memcpy(pos, anonce, WPA_NONCE_LEN); - pos += WPA_NONCE_LEN; - os_memcpy(pos, bssid, ETH_ALEN); - pos += ETH_ALEN; - os_memcpy(pos, sta_addr, ETH_ALEN); - pos += ETH_ALEN; - - sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len); - - /* - * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce || - * ANonce || BSSID || STA-ADDR)) - */ - addr[0] = pmk_r1_name; - len[0] = WPA_PMK_NAME_LEN; - addr[1] = (const u8 *) "FT-PTKN"; - len[1] = 7; - addr[2] = snonce; - len[2] = WPA_NONCE_LEN; - addr[3] = anonce; - len[3] = WPA_NONCE_LEN; - addr[4] = bssid; - len[4] = ETH_ALEN; - addr[5] = sta_addr; - len[5] = ETH_ALEN; - - sha256_vector(6, addr, len, hash); - os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN); -} - -#endif /* CONFIG_IEEE80211R */ - - -/** - * rsn_pmkid - Calculate PMK identifier - * @pmk: Pairwise master key - * @pmk_len: Length of pmk in bytes - * @aa: Authenticator address - * @spa: Supplicant address - * @pmkid: Buffer for PMKID - * @use_sha256: Whether to use SHA256-based KDF - * - * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy - * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA) - */ -void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, - u8 *pmkid, int use_sha256) -{ - char *title = "PMK Name"; - const u8 *addr[3]; - const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; - unsigned char hash[SHA256_MAC_LEN]; - - addr[0] = (u8 *) title; - addr[1] = aa; - addr[2] = spa; - -#ifdef CONFIG_IEEE80211W - if (use_sha256) - hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); - else -#endif /* CONFIG_IEEE80211W */ - hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash); - os_memcpy(pmkid, hash, PMKID_LEN); -} - - -/** - * wpa_cipher_txt - Convert cipher suite to a text string - * @cipher: Cipher suite (WPA_CIPHER_* enum) - * Returns: Pointer to a text string of the cipher suite name - */ -const char * wpa_cipher_txt(int cipher) -{ - switch (cipher) { - case WPA_CIPHER_NONE: - return "NONE"; - case WPA_CIPHER_WEP40: - return "WEP-40"; - case WPA_CIPHER_WEP104: - return "WEP-104"; - case WPA_CIPHER_TKIP: - return "TKIP"; - case WPA_CIPHER_CCMP: - return "CCMP"; - case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP: - return "CCMP+TKIP"; - case WPA_CIPHER_GCMP: - return "GCMP"; - case WPA_CIPHER_GCMP_256: - return "GCMP-256"; - case WPA_CIPHER_CCMP_256: - return "CCMP-256"; - case WPA_CIPHER_GTK_NOT_USED: - return "GTK_NOT_USED"; - default: - return "UNKNOWN"; - } -} - - -/** - * wpa_key_mgmt_txt - Convert key management suite to a text string - * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum) - * @proto: WPA/WPA2 version (WPA_PROTO_*) - * Returns: Pointer to a text string of the key management suite name - */ -const char * wpa_key_mgmt_txt(int key_mgmt, int proto) -{ - switch (key_mgmt) { - case WPA_KEY_MGMT_IEEE8021X: - if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) - return "WPA2+WPA/IEEE 802.1X/EAP"; - return proto == WPA_PROTO_RSN ? - "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP"; - case WPA_KEY_MGMT_PSK: - if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) - return "WPA2-PSK+WPA-PSK"; - return proto == WPA_PROTO_RSN ? - "WPA2-PSK" : "WPA-PSK"; - case WPA_KEY_MGMT_NONE: - return "NONE"; - case WPA_KEY_MGMT_IEEE8021X_NO_WPA: - return "IEEE 802.1X (no WPA)"; -#ifdef CONFIG_IEEE80211R - case WPA_KEY_MGMT_FT_IEEE8021X: - return "FT-EAP"; - case WPA_KEY_MGMT_FT_PSK: - return "FT-PSK"; -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - case WPA_KEY_MGMT_IEEE8021X_SHA256: - return "WPA2-EAP-SHA256"; - case WPA_KEY_MGMT_PSK_SHA256: - return "WPA2-PSK-SHA256"; -#endif /* CONFIG_IEEE80211W */ - default: - return "UNKNOWN"; - } -} - - -int wpa_compare_rsn_ie(int ft_initial_assoc, - const u8 *ie1, size_t ie1len, - const u8 *ie2, size_t ie2len) -{ - if (ie1 == NULL || ie2 == NULL) - return -1; - - if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0) - return 0; /* identical IEs */ - -#ifdef CONFIG_IEEE80211R - if (ft_initial_assoc) { - struct wpa_ie_data ie1d, ie2d; - /* - * The PMKID-List in RSN IE is different between Beacon/Probe - * Response/(Re)Association Request frames and EAPOL-Key - * messages in FT initial mobility domain association. Allow - * for this, but verify that other parts of the RSN IEs are - * identical. - */ - if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 || - wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0) - return -1; - if (ie1d.proto == ie2d.proto && - ie1d.pairwise_cipher == ie2d.pairwise_cipher && - ie1d.group_cipher == ie2d.group_cipher && - ie1d.key_mgmt == ie2d.key_mgmt && - ie1d.capabilities == ie2d.capabilities && - ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher) - return 0; - } -#endif /* CONFIG_IEEE80211R */ - - return -1; -} - - -#ifdef CONFIG_IEEE80211R -int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) -{ - u8 *start, *end, *rpos, *rend; - int added = 0; - - start = ies; - end = ies + ies_len; - - while (start < end) { - if (*start == WLAN_EID_RSN) - break; - start += 2 + start[1]; - } - if (start >= end) { - wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in " - "IEs data"); - return -1; - } - wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification", - start, 2 + start[1]); - - /* Find start of PMKID-Count */ - rpos = start + 2; - rend = rpos + start[1]; - - /* Skip Version and Group Data Cipher Suite */ - rpos += 2 + 4; - /* Skip Pairwise Cipher Suite Count and List */ - rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; - /* Skip AKM Suite Count and List */ - rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; - - if (rpos == rend) { - /* Add RSN Capabilities */ - os_memmove(rpos + 2, rpos, end - rpos); - *rpos++ = 0; - *rpos++ = 0; - } else { - /* Skip RSN Capabilities */ - rpos += 2; - if (rpos > rend) { - wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in " - "IEs data"); - return -1; - } - } - - if (rpos == rend) { - /* No PMKID-Count field included; add it */ - os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos); - WPA_PUT_LE16(rpos, 1); - rpos += 2; - os_memcpy(rpos, pmkid, PMKID_LEN); - added += 2 + PMKID_LEN; - start[1] += 2 + PMKID_LEN; - } else { - /* PMKID-Count was included; use it */ - if (WPA_GET_LE16(rpos) != 0) { - wpa_printf(MSG_ERROR, "FT: Unexpected PMKID " - "in RSN IE in EAPOL-Key data"); - return -1; - } - WPA_PUT_LE16(rpos, 1); - rpos += 2; - os_memmove(rpos + PMKID_LEN, rpos, end - rpos); - os_memcpy(rpos, pmkid, PMKID_LEN); - added += PMKID_LEN; - start[1] += PMKID_LEN; - } - - wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification " - "(PMKID inserted)", start, 2 + start[1]); - - return added; -} -#endif /* CONFIG_IEEE80211R */ - - -int wpa_cipher_key_len(int cipher) -{ - switch (cipher) { - case WPA_CIPHER_CCMP_256: - case WPA_CIPHER_GCMP_256: - return 32; - case WPA_CIPHER_CCMP: - case WPA_CIPHER_GCMP: - return 16; - case WPA_CIPHER_TKIP: - return 32; - case WPA_CIPHER_WEP104: - return 13; - case WPA_CIPHER_WEP40: - return 5; - } - - return 0; -} - - -int wpa_cipher_rsc_len(int cipher) -{ - switch (cipher) { - case WPA_CIPHER_CCMP_256: - case WPA_CIPHER_GCMP_256: - case WPA_CIPHER_CCMP: - case WPA_CIPHER_GCMP: - case WPA_CIPHER_TKIP: - return 6; - case WPA_CIPHER_WEP104: - case WPA_CIPHER_WEP40: - return 0; - } - - return 0; -} - - -int wpa_cipher_to_alg(int cipher) -{ - switch (cipher) { - case WPA_CIPHER_CCMP_256: - return WPA_ALG_CCMP_256; - case WPA_CIPHER_GCMP_256: - return WPA_ALG_GCMP_256; - case WPA_CIPHER_CCMP: - return WPA_ALG_CCMP; - case WPA_CIPHER_GCMP: - return WPA_ALG_GCMP; - case WPA_CIPHER_TKIP: - return WPA_ALG_TKIP; - case WPA_CIPHER_WEP104: - case WPA_CIPHER_WEP40: - return WPA_ALG_WEP; - } - return WPA_ALG_NONE; -} - - -int wpa_cipher_valid_pairwise(int cipher) -{ - return cipher == WPA_CIPHER_CCMP_256 || - cipher == WPA_CIPHER_GCMP_256 || - cipher == WPA_CIPHER_CCMP || - cipher == WPA_CIPHER_GCMP || - cipher == WPA_CIPHER_TKIP; -} - - -u32 wpa_cipher_to_suite(int proto, int cipher) -{ - if (cipher & WPA_CIPHER_CCMP_256) - return RSN_CIPHER_SUITE_CCMP_256; - if (cipher & WPA_CIPHER_GCMP_256) - return RSN_CIPHER_SUITE_GCMP_256; - if (cipher & WPA_CIPHER_CCMP) - return (proto == WPA_PROTO_RSN ? - RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP); - if (cipher & WPA_CIPHER_GCMP) - return RSN_CIPHER_SUITE_GCMP; - if (cipher & WPA_CIPHER_TKIP) - return (proto == WPA_PROTO_RSN ? - RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP); - if (cipher & WPA_CIPHER_WEP104) - return (proto == WPA_PROTO_RSN ? - RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104); - if (cipher & WPA_CIPHER_WEP40) - return (proto == WPA_PROTO_RSN ? - RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40); - if (cipher & WPA_CIPHER_NONE) - return (proto == WPA_PROTO_RSN ? - RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); - if (cipher & WPA_CIPHER_GTK_NOT_USED) - return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED; - return 0; -} - - -int rsn_cipher_put_suites(u8 *pos, int ciphers) -{ - int num_suites = 0; - - if (ciphers & WPA_CIPHER_CCMP_256) { - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256); - pos += RSN_SELECTOR_LEN; - num_suites++; - } - if (ciphers & WPA_CIPHER_GCMP_256) { - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256); - pos += RSN_SELECTOR_LEN; - num_suites++; - } - if (ciphers & WPA_CIPHER_CCMP) { - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); - pos += RSN_SELECTOR_LEN; - num_suites++; - } - if (ciphers & WPA_CIPHER_GCMP) { - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP); - pos += RSN_SELECTOR_LEN; - num_suites++; - } - if (ciphers & WPA_CIPHER_TKIP) { - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); - pos += RSN_SELECTOR_LEN; - num_suites++; - } - if (ciphers & WPA_CIPHER_NONE) { - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); - pos += RSN_SELECTOR_LEN; - num_suites++; - } - - return num_suites; -} - - -int wpa_cipher_put_suites(u8 *pos, int ciphers) -{ - int num_suites = 0; - - if (ciphers & WPA_CIPHER_CCMP) { - RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); - pos += WPA_SELECTOR_LEN; - num_suites++; - } - if (ciphers & WPA_CIPHER_TKIP) { - RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); - pos += WPA_SELECTOR_LEN; - num_suites++; - } - if (ciphers & WPA_CIPHER_NONE) { - RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); - pos += WPA_SELECTOR_LEN; - num_suites++; - } - - return num_suites; -} - - -int wpa_pick_pairwise_cipher(int ciphers, int none_allowed) -{ - if (ciphers & WPA_CIPHER_CCMP_256) - return WPA_CIPHER_CCMP_256; - if (ciphers & WPA_CIPHER_GCMP_256) - return WPA_CIPHER_GCMP_256; - if (ciphers & WPA_CIPHER_CCMP) - return WPA_CIPHER_CCMP; - if (ciphers & WPA_CIPHER_GCMP) - return WPA_CIPHER_GCMP; - if (ciphers & WPA_CIPHER_TKIP) - return WPA_CIPHER_TKIP; - if (none_allowed && (ciphers & WPA_CIPHER_NONE)) - return WPA_CIPHER_NONE; - return -1; -} - - -int wpa_pick_group_cipher(int ciphers) -{ - if (ciphers & WPA_CIPHER_CCMP_256) - return WPA_CIPHER_CCMP_256; - if (ciphers & WPA_CIPHER_GCMP_256) - return WPA_CIPHER_GCMP_256; - if (ciphers & WPA_CIPHER_CCMP) - return WPA_CIPHER_CCMP; - if (ciphers & WPA_CIPHER_GCMP) - return WPA_CIPHER_GCMP; - if (ciphers & WPA_CIPHER_GTK_NOT_USED) - return WPA_CIPHER_GTK_NOT_USED; - if (ciphers & WPA_CIPHER_TKIP) - return WPA_CIPHER_TKIP; - if (ciphers & WPA_CIPHER_WEP104) - return WPA_CIPHER_WEP104; - if (ciphers & WPA_CIPHER_WEP40) - return WPA_CIPHER_WEP40; - return -1; -} - - -int wpa_parse_cipher(const char *value) -{ - int val = 0, last; - char *start, *end, *buf; - - buf = os_strdup(value); - if (buf == NULL) - return -1; - start = buf; - - while (*start != '\0') { - while (*start == ' ' || *start == '\t') - start++; - if (*start == '\0') - break; - end = start; - while (*end != ' ' && *end != '\t' && *end != '\0') - end++; - last = *end == '\0'; - *end = '\0'; - if (os_strcmp(start, "CCMP-256") == 0) - val |= WPA_CIPHER_CCMP_256; - else if (os_strcmp(start, "GCMP-256") == 0) - val |= WPA_CIPHER_GCMP_256; - else if (os_strcmp(start, "CCMP") == 0) - val |= WPA_CIPHER_CCMP; - else if (os_strcmp(start, "GCMP") == 0) - val |= WPA_CIPHER_GCMP; - else if (os_strcmp(start, "TKIP") == 0) - val |= WPA_CIPHER_TKIP; - else if (os_strcmp(start, "WEP104") == 0) - val |= WPA_CIPHER_WEP104; - else if (os_strcmp(start, "WEP40") == 0) - val |= WPA_CIPHER_WEP40; - else if (os_strcmp(start, "NONE") == 0) - val |= WPA_CIPHER_NONE; - else if (os_strcmp(start, "GTK_NOT_USED") == 0) - val |= WPA_CIPHER_GTK_NOT_USED; - else { - os_free(buf); - return -1; - } - - if (last) - break; - start = end + 1; - } - os_free(buf); - - return val; -} - - -int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim) -{ - char *pos = start; - int ret; - - if (ciphers & WPA_CIPHER_CCMP_256) { - ret = os_snprintf(pos, end - pos, "%sCCMP-256", - pos == start ? "" : delim); - if (ret < 0 || ret >= end - pos) - return -1; - pos += ret; - } - if (ciphers & WPA_CIPHER_GCMP_256) { - ret = os_snprintf(pos, end - pos, "%sGCMP-256", - pos == start ? "" : delim); - if (ret < 0 || ret >= end - pos) - return -1; - pos += ret; - } - if (ciphers & WPA_CIPHER_CCMP) { - ret = os_snprintf(pos, end - pos, "%sCCMP", - pos == start ? "" : delim); - if (ret < 0 || ret >= end - pos) - return -1; - pos += ret; - } - if (ciphers & WPA_CIPHER_GCMP) { - ret = os_snprintf(pos, end - pos, "%sGCMP", - pos == start ? "" : delim); - if (ret < 0 || ret >= end - pos) - return -1; - pos += ret; - } - if (ciphers & WPA_CIPHER_TKIP) { - ret = os_snprintf(pos, end - pos, "%sTKIP", - pos == start ? "" : delim); - if (ret < 0 || ret >= end - pos) - return -1; - pos += ret; - } - if (ciphers & WPA_CIPHER_WEP104) { - ret = os_snprintf(pos, end - pos, "%sWEP104", - pos == start ? "" : delim); - if (ret < 0 || ret >= end - pos) - return -1; - pos += ret; - } - if (ciphers & WPA_CIPHER_WEP40) { - ret = os_snprintf(pos, end - pos, "%sWEP40", - pos == start ? "" : delim); - if (ret < 0 || ret >= end - pos) - return -1; - pos += ret; - } - if (ciphers & WPA_CIPHER_NONE) { - ret = os_snprintf(pos, end - pos, "%sNONE", - pos == start ? "" : delim); - if (ret < 0 || ret >= end - pos) - return -1; - pos += ret; - } - - return pos - start; -} - - -int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise) -{ - int pairwise = 0; - - /* Select group cipher based on the enabled pairwise cipher suites */ - if (wpa & 1) - pairwise |= wpa_pairwise; - if (wpa & 2) - pairwise |= rsn_pairwise; - - if (pairwise & WPA_CIPHER_TKIP) - return WPA_CIPHER_TKIP; - if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP) - return WPA_CIPHER_GCMP; - if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP | - WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256) - return WPA_CIPHER_GCMP_256; - if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP | - WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256) - return WPA_CIPHER_CCMP_256; - return WPA_CIPHER_CCMP; -} diff --git a/contrib/hostapd/src/common/wpa_common.h b/contrib/hostapd/src/common/wpa_common.h deleted file mode 100644 index dcc035c7d8..0000000000 --- a/contrib/hostapd/src/common/wpa_common.h +++ /dev/null @@ -1,419 +0,0 @@ -/* - * WPA definitions shared between hostapd and wpa_supplicant - * Copyright (c) 2002-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_COMMON_H -#define WPA_COMMON_H - -#define WPA_MAX_SSID_LEN 32 - -/* IEEE 802.11i */ -#define PMKID_LEN 16 -#define PMK_LEN 32 -#define WPA_REPLAY_COUNTER_LEN 8 -#define WPA_NONCE_LEN 32 -#define WPA_KEY_RSC_LEN 8 -#define WPA_GMK_LEN 32 -#define WPA_GTK_MAX_LEN 32 - -#define WPA_ALLOWED_PAIRWISE_CIPHERS \ -(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE | \ -WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256) -#define WPA_ALLOWED_GROUP_CIPHERS \ -(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | \ -WPA_CIPHER_WEP40 | WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \ -WPA_CIPHER_GTK_NOT_USED) - -#define WPA_SELECTOR_LEN 4 -#define WPA_VERSION 1 -#define RSN_SELECTOR_LEN 4 -#define RSN_VERSION 1 - -#define RSN_SELECTOR(a, b, c, d) \ - ((((u32) (a)) << 24) | (((u32) (b)) << 16) | (((u32) (c)) << 8) | \ - (u32) (d)) - -#define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0) -#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1) -#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2) -#define WPA_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0) -#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0) -#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1) -#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2) -#if 0 -#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3) -#endif -#define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4) -#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5) - - -#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1) -#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2) -#ifdef CONFIG_IEEE80211R -#define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3) -#define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4) -#endif /* CONFIG_IEEE80211R */ -#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) -#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6) -#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7) -#define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8) -#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9) -#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B RSN_SELECTOR(0x00, 0x0f, 0xac, 11) -#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_384 RSN_SELECTOR(0x00, 0x0f, 0xac, 12) -#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_384 \ -RSN_SELECTOR(0x00, 0x0f, 0xac, 13) -#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00) - -#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0) -#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1) -#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2) -#if 0 -#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3) -#endif -#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4) -#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) -#ifdef CONFIG_IEEE80211W -#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6) -#endif /* CONFIG_IEEE80211W */ -#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7) -#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8) -#define RSN_CIPHER_SUITE_GCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 9) -#define RSN_CIPHER_SUITE_CCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 10) -#define RSN_CIPHER_SUITE_BIP_GMAC_128 RSN_SELECTOR(0x00, 0x0f, 0xac, 11) -#define RSN_CIPHER_SUITE_BIP_GMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 12) -#define RSN_CIPHER_SUITE_BIP_CMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 13) - -/* EAPOL-Key Key Data Encapsulation - * GroupKey and PeerKey require encryption, otherwise, encryption is optional. - */ -#define RSN_KEY_DATA_GROUPKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 1) -#if 0 -#define RSN_KEY_DATA_STAKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 2) -#endif -#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3) -#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4) -#ifdef CONFIG_PEERKEY -#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5) -#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6) -#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7) -#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8) -#endif /* CONFIG_PEERKEY */ -#ifdef CONFIG_IEEE80211W -#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9) -#endif /* CONFIG_IEEE80211W */ -#define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10) -#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11) -#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12) - -#define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4) -#define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5) - -#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1) - -#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val)) -#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a)) - -#define RSN_NUM_REPLAY_COUNTERS_1 0 -#define RSN_NUM_REPLAY_COUNTERS_2 1 -#define RSN_NUM_REPLAY_COUNTERS_4 2 -#define RSN_NUM_REPLAY_COUNTERS_16 3 - - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -#ifdef CONFIG_IEEE80211W -#define WPA_IGTK_LEN 16 -#endif /* CONFIG_IEEE80211W */ - - -/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */ -#define WPA_CAPABILITY_PREAUTH BIT(0) -#define WPA_CAPABILITY_NO_PAIRWISE BIT(1) -/* B2-B3: PTKSA Replay Counter */ -/* B4-B5: GTKSA Replay Counter */ -#define WPA_CAPABILITY_MFPR BIT(6) -#define WPA_CAPABILITY_MFPC BIT(7) -/* B8: Reserved */ -#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9) -#define WPA_CAPABILITY_SPP_A_MSDU_CAPABLE BIT(10) -#define WPA_CAPABILITY_SPP_A_MSDU_REQUIRED BIT(11) -#define WPA_CAPABILITY_PBAC BIT(12) -#define WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST BIT(13) -/* B14-B15: Reserved */ - - -/* IEEE 802.11r */ -#define MOBILITY_DOMAIN_ID_LEN 2 -#define FT_R0KH_ID_MAX_LEN 48 -#define FT_R1KH_ID_LEN 6 -#define WPA_PMK_NAME_LEN 16 - - -/* IEEE 802.11, 8.5.2 EAPOL-Key frames */ -#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2))) -#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0) -#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1) -#define WPA_KEY_INFO_TYPE_AES_128_CMAC 3 -#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */ -/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */ -#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5)) -#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4 -#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */ -#define WPA_KEY_INFO_TXRX BIT(6) /* group */ -#define WPA_KEY_INFO_ACK BIT(7) -#define WPA_KEY_INFO_MIC BIT(8) -#define WPA_KEY_INFO_SECURE BIT(9) -#define WPA_KEY_INFO_ERROR BIT(10) -#define WPA_KEY_INFO_REQUEST BIT(11) -#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */ -#define WPA_KEY_INFO_SMK_MESSAGE BIT(13) - - -struct wpa_eapol_key { - u8 type; - /* Note: key_info, key_length, and key_data_length are unaligned */ - u8 key_info[2]; /* big endian */ - u8 key_length[2]; /* big endian */ - u8 replay_counter[WPA_REPLAY_COUNTER_LEN]; - u8 key_nonce[WPA_NONCE_LEN]; - u8 key_iv[16]; - u8 key_rsc[WPA_KEY_RSC_LEN]; - u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */ - u8 key_mic[16]; - u8 key_data_length[2]; /* big endian */ - /* followed by key_data_length bytes of key_data */ -} STRUCT_PACKED; - -/** - * struct wpa_ptk - WPA Pairwise Transient Key - * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy - */ -struct wpa_ptk { - u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */ - u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */ - u8 tk1[16]; /* Temporal Key 1 (TK1) */ - union { - u8 tk2[16]; /* Temporal Key 2 (TK2) */ - struct { - u8 tx_mic_key[8]; - u8 rx_mic_key[8]; - } auth; - } u; -} STRUCT_PACKED; - - -/* WPA IE version 1 - * 00-50-f2:1 (OUI:OUI type) - * 0x01 0x00 (version; little endian) - * (all following fields are optional:) - * Group Suite Selector (4 octets) (default: TKIP) - * Pairwise Suite Count (2 octets, little endian) (default: 1) - * Pairwise Suite List (4 * n octets) (default: TKIP) - * Authenticated Key Management Suite Count (2 octets, little endian) - * (default: 1) - * Authenticated Key Management Suite List (4 * n octets) - * (default: unspec 802.1X) - * WPA Capabilities (2 octets, little endian) (default: 0) - */ - -struct wpa_ie_hdr { - u8 elem_id; - u8 len; - u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */ - u8 version[2]; /* little endian */ -} STRUCT_PACKED; - - -/* 1/4: PMKID - * 2/4: RSN IE - * 3/4: one or two RSN IEs + GTK IE (encrypted) - * 4/4: empty - * 1/2: GTK IE (encrypted) - * 2/2: empty - */ - -/* RSN IE version 1 - * 0x01 0x00 (version; little endian) - * (all following fields are optional:) - * Group Suite Selector (4 octets) (default: CCMP) - * Pairwise Suite Count (2 octets, little endian) (default: 1) - * Pairwise Suite List (4 * n octets) (default: CCMP) - * Authenticated Key Management Suite Count (2 octets, little endian) - * (default: 1) - * Authenticated Key Management Suite List (4 * n octets) - * (default: unspec 802.1X) - * RSN Capabilities (2 octets, little endian) (default: 0) - * PMKID Count (2 octets) (default: 0) - * PMKID List (16 * n octets) - * Management Group Cipher Suite (4 octets) (default: AES-128-CMAC) - */ - -struct rsn_ie_hdr { - u8 elem_id; /* WLAN_EID_RSN */ - u8 len; - u8 version[2]; /* little endian */ -} STRUCT_PACKED; - - -#ifdef CONFIG_PEERKEY -enum { - STK_MUI_4WAY_STA_AP = 1, - STK_MUI_4WAY_STAT_STA = 2, - STK_MUI_GTK = 3, - STK_MUI_SMK = 4 -}; - -enum { - STK_ERR_STA_NR = 1, - STK_ERR_STA_NRSN = 2, - STK_ERR_CPHR_NS = 3, - STK_ERR_NO_STSL = 4 -}; -#endif /* CONFIG_PEERKEY */ - -struct rsn_error_kde { - be16 mui; - be16 error_type; -} STRUCT_PACKED; - -#ifdef CONFIG_IEEE80211W -struct wpa_igtk_kde { - u8 keyid[2]; - u8 pn[6]; - u8 igtk[WPA_IGTK_LEN]; -} STRUCT_PACKED; -#endif /* CONFIG_IEEE80211W */ - -#ifdef CONFIG_IEEE80211R -struct rsn_mdie { - u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; - u8 ft_capab; -} STRUCT_PACKED; - -#define RSN_FT_CAPAB_FT_OVER_DS BIT(0) -#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1) - -struct rsn_ftie { - u8 mic_control[2]; - u8 mic[16]; - u8 anonce[WPA_NONCE_LEN]; - u8 snonce[WPA_NONCE_LEN]; - /* followed by optional parameters */ -} STRUCT_PACKED; - -#define FTIE_SUBELEM_R1KH_ID 1 -#define FTIE_SUBELEM_GTK 2 -#define FTIE_SUBELEM_R0KH_ID 3 -#define FTIE_SUBELEM_IGTK 4 - -struct rsn_rdie { - u8 id; - u8 descr_count; - le16 status_code; -} STRUCT_PACKED; - -#endif /* CONFIG_IEEE80211R */ - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - - -int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, - u8 *mic); -void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, - const u8 *addr1, const u8 *addr2, - const u8 *nonce1, const u8 *nonce2, - u8 *ptk, size_t ptk_len, int use_sha256); - -#ifdef CONFIG_IEEE80211R -int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, - u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, - const u8 *ftie, size_t ftie_len, - const u8 *rsnie, size_t rsnie_len, - const u8 *ric, size_t ric_len, u8 *mic); -void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, - const u8 *ssid, size_t ssid_len, - const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, - const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name); -void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, - const u8 *s1kh_id, u8 *pmk_r1_name); -void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, - const u8 *r1kh_id, const u8 *s1kh_id, - u8 *pmk_r1, u8 *pmk_r1_name); -void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, - const u8 *sta_addr, const u8 *bssid, - const u8 *pmk_r1_name, - u8 *ptk, size_t ptk_len, u8 *ptk_name); -#endif /* CONFIG_IEEE80211R */ - -struct wpa_ie_data { - int proto; - int pairwise_cipher; - int group_cipher; - int key_mgmt; - int capabilities; - size_t num_pmkid; - const u8 *pmkid; - int mgmt_group_cipher; -}; - - -int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, - struct wpa_ie_data *data); -int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, - struct wpa_ie_data *data); - -void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, - u8 *pmkid, int use_sha256); - -const char * wpa_cipher_txt(int cipher); -const char * wpa_key_mgmt_txt(int key_mgmt, int proto); -int wpa_compare_rsn_ie(int ft_initial_assoc, - const u8 *ie1, size_t ie1len, - 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); - -int wpa_cipher_key_len(int cipher); -int wpa_cipher_rsc_len(int cipher); -int wpa_cipher_to_alg(int cipher); -int wpa_cipher_valid_pairwise(int cipher); -u32 wpa_cipher_to_suite(int proto, int cipher); -int rsn_cipher_put_suites(u8 *pos, int ciphers); -int wpa_cipher_put_suites(u8 *pos, int ciphers); -int wpa_pick_pairwise_cipher(int ciphers, int none_allowed); -int wpa_pick_group_cipher(int ciphers); -int wpa_parse_cipher(const char *value); -int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim); -int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise); - -#endif /* WPA_COMMON_H */ diff --git a/contrib/hostapd/src/common/wpa_ctrl.c b/contrib/hostapd/src/common/wpa_ctrl.c deleted file mode 100644 index f4af94aa1c..0000000000 --- a/contrib/hostapd/src/common/wpa_ctrl.c +++ /dev/null @@ -1,671 +0,0 @@ -/* - * wpa_supplicant/hostapd control interface library - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#ifdef CONFIG_CTRL_IFACE - -#ifdef CONFIG_CTRL_IFACE_UNIX -#include -#include -#include -#endif /* CONFIG_CTRL_IFACE_UNIX */ -#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE -#include -#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ - -#ifdef ANDROID -#include -#include -#include "private/android_filesystem_config.h" -#endif /* ANDROID */ - -#include "wpa_ctrl.h" -#include "common.h" - - -#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) -#define CTRL_IFACE_SOCKET -#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */ - - -/** - * struct wpa_ctrl - Internal structure for control interface library - * - * This structure is used by the wpa_supplicant/hostapd control interface - * library to store internal data. Programs using the library should not touch - * this data directly. They can only use the pointer to the data structure as - * an identifier for the control interface connection and use this as one of - * the arguments for most of the control interface library functions. - */ -struct wpa_ctrl { -#ifdef CONFIG_CTRL_IFACE_UDP - int s; - struct sockaddr_in local; - struct sockaddr_in dest; - char *cookie; - char *remote_ifname; - char *remote_ip; -#endif /* CONFIG_CTRL_IFACE_UDP */ -#ifdef CONFIG_CTRL_IFACE_UNIX - int s; - struct sockaddr_un local; - struct sockaddr_un dest; -#endif /* CONFIG_CTRL_IFACE_UNIX */ -#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE - HANDLE pipe; -#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ -}; - - -#ifdef CONFIG_CTRL_IFACE_UNIX - -#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR -#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp" -#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */ -#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX -#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_" -#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */ - - -struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) -{ - struct wpa_ctrl *ctrl; - static int counter = 0; - int ret; - size_t res; - int tries = 0; - int flags; - - if (ctrl_path == NULL) - return NULL; - - ctrl = os_malloc(sizeof(*ctrl)); - if (ctrl == NULL) - return NULL; - os_memset(ctrl, 0, sizeof(*ctrl)); - - ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); - if (ctrl->s < 0) { - os_free(ctrl); - return NULL; - } - - ctrl->local.sun_family = AF_UNIX; - counter++; -try_again: - ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), - CONFIG_CTRL_IFACE_CLIENT_DIR "/" - CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d", - (int) getpid(), counter); - if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) { - close(ctrl->s); - os_free(ctrl); - return NULL; - } - tries++; - if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, - sizeof(ctrl->local)) < 0) { - if (errno == EADDRINUSE && tries < 2) { - /* - * getpid() returns unique identifier for this instance - * of wpa_ctrl, so the existing socket file must have - * been left by unclean termination of an earlier run. - * Remove the file and try again. - */ - unlink(ctrl->local.sun_path); - goto try_again; - } - close(ctrl->s); - os_free(ctrl); - return NULL; - } - -#ifdef ANDROID - chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI); - - if (os_strncmp(ctrl_path, "@android:", 9) == 0) { - if (socket_local_client_connect( - ctrl->s, ctrl_path + 9, - ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_DGRAM) < 0) { - close(ctrl->s); - unlink(ctrl->local.sun_path); - os_free(ctrl); - return NULL; - } - return ctrl; - } - - /* - * If the ctrl_path isn't an absolute pathname, assume that - * it's the name of a socket in the Android reserved namespace. - * Otherwise, it's a normal UNIX domain socket appearing in the - * filesystem. - */ - if (*ctrl_path != '/') { - char buf[21]; - os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path); - if (socket_local_client_connect( - ctrl->s, buf, - ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_DGRAM) < 0) { - close(ctrl->s); - unlink(ctrl->local.sun_path); - os_free(ctrl); - return NULL; - } - return ctrl; - } -#endif /* ANDROID */ - - ctrl->dest.sun_family = AF_UNIX; - if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) { - ctrl->dest.sun_path[0] = '\0'; - os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10, - sizeof(ctrl->dest.sun_path) - 1); - } else { - res = os_strlcpy(ctrl->dest.sun_path, ctrl_path, - sizeof(ctrl->dest.sun_path)); - if (res >= sizeof(ctrl->dest.sun_path)) { - close(ctrl->s); - os_free(ctrl); - return NULL; - } - } - if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, - sizeof(ctrl->dest)) < 0) { - close(ctrl->s); - unlink(ctrl->local.sun_path); - os_free(ctrl); - return NULL; - } - - /* - * Make socket non-blocking so that we don't hang forever if - * target dies unexpectedly. - */ - flags = fcntl(ctrl->s, F_GETFL); - if (flags >= 0) { - flags |= O_NONBLOCK; - if (fcntl(ctrl->s, F_SETFL, flags) < 0) { - perror("fcntl(ctrl->s, O_NONBLOCK)"); - /* Not fatal, continue on.*/ - } - } - - return ctrl; -} - - -void wpa_ctrl_close(struct wpa_ctrl *ctrl) -{ - if (ctrl == NULL) - return; - unlink(ctrl->local.sun_path); - if (ctrl->s >= 0) - close(ctrl->s); - 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; - 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_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 */ - - -#ifdef CONFIG_CTRL_IFACE_UDP - -struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) -{ - struct wpa_ctrl *ctrl; - char buf[128]; - size_t len; -#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE - struct hostent *h; -#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ - - ctrl = os_malloc(sizeof(*ctrl)); - if (ctrl == NULL) - return NULL; - os_memset(ctrl, 0, sizeof(*ctrl)); - - ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); - if (ctrl->s < 0) { - perror("socket"); - os_free(ctrl); - return NULL; - } - - ctrl->local.sin_family = AF_INET; -#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE - ctrl->local.sin_addr.s_addr = INADDR_ANY; -#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ - ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); -#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ - if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, - sizeof(ctrl->local)) < 0) { - close(ctrl->s); - os_free(ctrl); - return NULL; - } - - ctrl->dest.sin_family = AF_INET; - ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); - ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT); - -#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE - if (ctrl_path) { - char *port, *name; - int port_id; - - name = os_strdup(ctrl_path); - if (name == NULL) { - close(ctrl->s); - os_free(ctrl); - return NULL; - } - port = os_strchr(name, ':'); - - if (port) { - port_id = atoi(&port[1]); - port[0] = '\0'; - } else - port_id = WPA_CTRL_IFACE_PORT; - - h = gethostbyname(name); - ctrl->remote_ip = os_strdup(name); - os_free(name); - if (h == NULL) { - perror("gethostbyname"); - close(ctrl->s); - os_free(ctrl->remote_ip); - os_free(ctrl); - return NULL; - } - ctrl->dest.sin_port = htons(port_id); - os_memcpy(h->h_addr, (char *) &ctrl->dest.sin_addr.s_addr, - h->h_length); - } else - ctrl->remote_ip = os_strdup("localhost"); -#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ - - if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, - sizeof(ctrl->dest)) < 0) { - perror("connect"); - close(ctrl->s); - os_free(ctrl->remote_ip); - os_free(ctrl); - return NULL; - } - - len = sizeof(buf) - 1; - if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) { - buf[len] = '\0'; - ctrl->cookie = os_strdup(buf); - } - - if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) { - buf[len] = '\0'; - ctrl->remote_ifname = os_strdup(buf); - } - - return ctrl; -} - - -char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl) -{ -#define WPA_CTRL_MAX_PS_NAME 100 - static char ps[WPA_CTRL_MAX_PS_NAME] = {}; - os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s", - ctrl->remote_ip, ctrl->remote_ifname); - return ps; -} - - -void wpa_ctrl_close(struct wpa_ctrl *ctrl) -{ - close(ctrl->s); - os_free(ctrl->cookie); - os_free(ctrl->remote_ifname); - os_free(ctrl->remote_ip); - os_free(ctrl); -} - -#endif /* CONFIG_CTRL_IFACE_UDP */ - - -#ifdef CTRL_IFACE_SOCKET -int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, - char *reply, size_t *reply_len, - void (*msg_cb)(char *msg, size_t len)) -{ - struct timeval tv; - struct os_reltime started_at; - int res; - fd_set rfds; - const char *_cmd; - char *cmd_buf = NULL; - size_t _cmd_len; - -#ifdef CONFIG_CTRL_IFACE_UDP - if (ctrl->cookie) { - char *pos; - _cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len; - cmd_buf = os_malloc(_cmd_len); - if (cmd_buf == NULL) - return -1; - _cmd = cmd_buf; - pos = cmd_buf; - os_strlcpy(pos, ctrl->cookie, _cmd_len); - pos += os_strlen(ctrl->cookie); - *pos++ = ' '; - os_memcpy(pos, cmd, cmd_len); - } else -#endif /* CONFIG_CTRL_IFACE_UDP */ - { - _cmd = cmd; - _cmd_len = cmd_len; - } - - errno = 0; - started_at.sec = 0; - started_at.usec = 0; -retry_send: - if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) { - if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK) - { - /* - * Must be a non-blocking socket... Try for a bit - * longer before giving up. - */ - if (started_at.sec == 0) - os_get_reltime(&started_at); - else { - struct os_reltime n; - os_get_reltime(&n); - /* Try for a few seconds. */ - if (os_reltime_expired(&n, &started_at, 5)) - goto send_err; - } - os_sleep(1, 0); - goto retry_send; - } - send_err: - os_free(cmd_buf); - return -1; - } - os_free(cmd_buf); - - for (;;) { - tv.tv_sec = 10; - tv.tv_usec = 0; - FD_ZERO(&rfds); - FD_SET(ctrl->s, &rfds); - res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); - if (res < 0) - return res; - if (FD_ISSET(ctrl->s, &rfds)) { - res = recv(ctrl->s, reply, *reply_len, 0); - if (res < 0) - return res; - if (res > 0 && reply[0] == '<') { - /* This is an unsolicited message from - * wpa_supplicant, not the reply to the - * request. Use msg_cb to report this to the - * caller. */ - if (msg_cb) { - /* Make sure the message is nul - * terminated. */ - if ((size_t) res == *reply_len) - res = (*reply_len) - 1; - reply[res] = '\0'; - msg_cb(reply, res); - } - continue; - } - *reply_len = res; - break; - } else { - return -2; - } - } - return 0; -} -#endif /* CTRL_IFACE_SOCKET */ - - -static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) -{ - char buf[10]; - int ret; - size_t len = 10; - - ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6, - buf, &len, NULL); - if (ret < 0) - return ret; - if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0) - return 0; - return -1; -} - - -int wpa_ctrl_attach(struct wpa_ctrl *ctrl) -{ - return wpa_ctrl_attach_helper(ctrl, 1); -} - - -int wpa_ctrl_detach(struct wpa_ctrl *ctrl) -{ - return wpa_ctrl_attach_helper(ctrl, 0); -} - - -#ifdef CTRL_IFACE_SOCKET - -int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) -{ - int res; - - res = recv(ctrl->s, reply, *reply_len, 0); - if (res < 0) - return res; - *reply_len = res; - return 0; -} - - -int wpa_ctrl_pending(struct wpa_ctrl *ctrl) -{ - struct timeval tv; - fd_set rfds; - tv.tv_sec = 0; - tv.tv_usec = 0; - FD_ZERO(&rfds); - FD_SET(ctrl->s, &rfds); - select(ctrl->s + 1, &rfds, NULL, NULL, &tv); - return FD_ISSET(ctrl->s, &rfds); -} - - -int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) -{ - return ctrl->s; -} - -#endif /* CTRL_IFACE_SOCKET */ - - -#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE - -#ifndef WPA_SUPPLICANT_NAMED_PIPE -#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" -#endif -#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) - -struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) -{ - struct wpa_ctrl *ctrl; - DWORD mode; - TCHAR name[256]; - int i, ret; - - ctrl = os_malloc(sizeof(*ctrl)); - if (ctrl == NULL) - return NULL; - os_memset(ctrl, 0, sizeof(*ctrl)); - -#ifdef UNICODE - if (ctrl_path == NULL) - ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX); - else - ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), - ctrl_path); -#else /* UNICODE */ - if (ctrl_path == NULL) - ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX); - else - ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", - ctrl_path); -#endif /* UNICODE */ - if (ret < 0 || ret >= 256) { - os_free(ctrl); - return NULL; - } - - for (i = 0; i < 10; i++) { - ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, - NULL, OPEN_EXISTING, 0, NULL); - /* - * Current named pipe server side in wpa_supplicant is - * re-opening the pipe for new clients only after the previous - * one is taken into use. This leaves a small window for race - * conditions when two connections are being opened at almost - * the same time. Retry if that was the case. - */ - if (ctrl->pipe != INVALID_HANDLE_VALUE || - GetLastError() != ERROR_PIPE_BUSY) - break; - WaitNamedPipe(name, 1000); - } - if (ctrl->pipe == INVALID_HANDLE_VALUE) { - os_free(ctrl); - return NULL; - } - - mode = PIPE_READMODE_MESSAGE; - if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) { - CloseHandle(ctrl->pipe); - os_free(ctrl); - return NULL; - } - - return ctrl; -} - - -void wpa_ctrl_close(struct wpa_ctrl *ctrl) -{ - CloseHandle(ctrl->pipe); - os_free(ctrl); -} - - -int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, - char *reply, size_t *reply_len, - void (*msg_cb)(char *msg, size_t len)) -{ - DWORD written; - DWORD readlen = *reply_len; - - if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL)) - return -1; - - if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL)) - return -1; - *reply_len = readlen; - - return 0; -} - - -int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) -{ - DWORD len = *reply_len; - if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL)) - return -1; - *reply_len = len; - return 0; -} - - -int wpa_ctrl_pending(struct wpa_ctrl *ctrl) -{ - DWORD left; - - if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL)) - return -1; - return left ? 1 : 0; -} - - -int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) -{ - return -1; -} - -#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ - -#endif /* CONFIG_CTRL_IFACE */ diff --git a/contrib/hostapd/src/common/wpa_ctrl.h b/contrib/hostapd/src/common/wpa_ctrl.h deleted file mode 100644 index 759cee47dd..0000000000 --- a/contrib/hostapd/src/common/wpa_ctrl.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - * wpa_supplicant/hostapd control interface library - * Copyright (c) 2004-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_CTRL_H -#define WPA_CTRL_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* wpa_supplicant control interface - fixed message prefixes */ - -/** Interactive request for identity/password/pin */ -#define WPA_CTRL_REQ "CTRL-REQ-" - -/** Response to identity/password/pin request */ -#define WPA_CTRL_RSP "CTRL-RSP-" - -/* Event messages with fixed prefix */ -/** Authentication completed successfully and data connection enabled */ -#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED " -/** Disconnected, data connection is not available */ -#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED " -/** Association rejected during connection attempt */ -#define WPA_EVENT_ASSOC_REJECT "CTRL-EVENT-ASSOC-REJECT " -/** wpa_supplicant is exiting */ -#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING " -/** Password change was completed successfully */ -#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED " -/** EAP-Request/Notification received */ -#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION " -/** EAP authentication started (EAP-Request/Identity received) */ -#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED " -/** EAP method proposed by the server */ -#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD " -/** EAP method selected */ -#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD " -/** EAP peer certificate from TLS */ -#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT " -/** EAP TLS certificate chain validation error */ -#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR " -/** EAP status */ -#define WPA_EVENT_EAP_STATUS "CTRL-EVENT-EAP-STATUS " -/** EAP authentication completed successfully */ -#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS " -/** EAP authentication failed (EAP-Failure received) */ -#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE " -/** Network block temporarily disabled (e.g., due to authentication failure) */ -#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED " -/** Temporarily disabled network block re-enabled */ -#define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED " -/** New scan started */ -#define WPA_EVENT_SCAN_STARTED "CTRL-EVENT-SCAN-STARTED " -/** New scan results available */ -#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS " -/** wpa_supplicant state change */ -#define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE " -/** A new BSS entry was added (followed by BSS entry id and BSSID) */ -#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED " -/** A BSS entry was removed (followed by BSS entry id and BSSID) */ -#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED " - -/** RSN IBSS 4-way handshakes completed with specified peer */ -#define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED " - -/** Notification of frequency conflict due to a concurrent operation. - * - * The indicated network is disabled and needs to be re-enabled before it can - * be used again. - */ -#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT " -/** Frequency ranges that the driver recommends to avoid */ -#define WPA_EVENT_AVOID_FREQ "CTRL-EVENT-AVOID-FREQ " -/** WPS overlap detected in PBC mode */ -#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED " -/** Available WPS AP with active PBC found in scan results */ -#define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC " -/** Available WPS AP with our address as authorized in scan results */ -#define WPS_EVENT_AP_AVAILABLE_AUTH "WPS-AP-AVAILABLE-AUTH " -/** Available WPS AP with recently selected PIN registrar found in scan results - */ -#define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN " -/** Available WPS AP found in scan results */ -#define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE " -/** A new credential received */ -#define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED " -/** M2D received */ -#define WPS_EVENT_M2D "WPS-M2D " -/** WPS registration failed after M2/M2D */ -#define WPS_EVENT_FAIL "WPS-FAIL " -/** WPS registration completed successfully */ -#define WPS_EVENT_SUCCESS "WPS-SUCCESS " -/** WPS enrollment attempt timed out and was terminated */ -#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT " -/* PBC mode was activated */ -#define WPS_EVENT_ACTIVE "WPS-PBC-ACTIVE " -/* PBC mode was disabled */ -#define WPS_EVENT_DISABLE "WPS-PBC-DISABLE " - -#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN " - -#define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK " - -/* WPS ER events */ -#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD " -#define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE " -#define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD " -#define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE " -#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS " -#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG " - -/** P2P device found */ -#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND " - -/** P2P device lost */ -#define P2P_EVENT_DEVICE_LOST "P2P-DEVICE-LOST " - -/** A P2P device requested GO negotiation, but we were not ready to start the - * negotiation */ -#define P2P_EVENT_GO_NEG_REQUEST "P2P-GO-NEG-REQUEST " -#define P2P_EVENT_GO_NEG_SUCCESS "P2P-GO-NEG-SUCCESS " -#define P2P_EVENT_GO_NEG_FAILURE "P2P-GO-NEG-FAILURE " -#define P2P_EVENT_GROUP_FORMATION_SUCCESS "P2P-GROUP-FORMATION-SUCCESS " -#define P2P_EVENT_GROUP_FORMATION_FAILURE "P2P-GROUP-FORMATION-FAILURE " -#define P2P_EVENT_GROUP_STARTED "P2P-GROUP-STARTED " -#define P2P_EVENT_GROUP_REMOVED "P2P-GROUP-REMOVED " -#define P2P_EVENT_CROSS_CONNECT_ENABLE "P2P-CROSS-CONNECT-ENABLE " -#define P2P_EVENT_CROSS_CONNECT_DISABLE "P2P-CROSS-CONNECT-DISABLE " -/* parameters: */ -#define P2P_EVENT_PROV_DISC_SHOW_PIN "P2P-PROV-DISC-SHOW-PIN " -/* parameters: */ -#define P2P_EVENT_PROV_DISC_ENTER_PIN "P2P-PROV-DISC-ENTER-PIN " -/* parameters: */ -#define P2P_EVENT_PROV_DISC_PBC_REQ "P2P-PROV-DISC-PBC-REQ " -/* parameters: */ -#define P2P_EVENT_PROV_DISC_PBC_RESP "P2P-PROV-DISC-PBC-RESP " -/* parameters: */ -#define P2P_EVENT_PROV_DISC_FAILURE "P2P-PROV-DISC-FAILURE" -/* parameters: */ -#define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ " -/* parameters: */ -#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 P2P_EVENT_PERSISTENT_PSK_FAIL "P2P-PERSISTENT-PSK-FAIL id=" -#define P2P_EVENT_PRESENCE_RESPONSE "P2P-PRESENCE-RESPONSE " -#define P2P_EVENT_NFC_BOTH_GO "P2P-NFC-BOTH-GO " -#define P2P_EVENT_NFC_PEER_CLIENT "P2P-NFC-PEER-CLIENT " -#define P2P_EVENT_NFC_WHILE_CLIENT "P2P-NFC-WHILE-CLIENT " - -/* parameters: */ -#define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT " -#define P2P_EVENT_REMOVE_AND_REFORM_GROUP "P2P-REMOVE-AND-REFORM-GROUP " - -#define INTERWORKING_AP "INTERWORKING-AP " -#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH " -#define INTERWORKING_ALREADY_CONNECTED "INTERWORKING-ALREADY-CONNECTED " - -#define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO " -/* parameters: */ -#define GAS_QUERY_START "GAS-QUERY-START " -/* parameters: */ -#define GAS_QUERY_DONE "GAS-QUERY-DONE " - -#define EXT_RADIO_WORK_START "EXT-RADIO-WORK-START " -#define EXT_RADIO_WORK_TIMEOUT "EXT-RADIO-WORK-TIMEOUT " - -/* hostapd control interface - fixed message prefixes */ -#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED " -#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS " -#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS " -#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED " -#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED " -#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED " -#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED " -#define AP_STA_CONNECTED "AP-STA-CONNECTED " -#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED " - -#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA " -#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA " - -#define AP_EVENT_ENABLED "AP-ENABLED " -#define AP_EVENT_DISABLED "AP-DISABLED " - -#define ACS_EVENT_STARTED "ACS-STARTED " -#define ACS_EVENT_COMPLETED "ACS-COMPLETED " -#define ACS_EVENT_FAILED "ACS-FAILED " - -#define DFS_EVENT_RADAR_DETECTED "DFS-RADAR-DETECTED " -#define DFS_EVENT_NEW_CHANNEL "DFS-NEW-CHANNEL " -#define DFS_EVENT_CAC_START "DFS-CAC-START " -#define DFS_EVENT_CAC_COMPLETED "DFS-CAC-COMPLETED " -#define DFS_EVENT_NOP_FINISHED "DFS-NOP-FINISHED " - -#define AP_CSA_FINISHED "AP-CSA-FINISHED " - -/* BSS command information masks */ - -#define WPA_BSS_MASK_ALL 0xFFFDFFFF -#define WPA_BSS_MASK_ID BIT(0) -#define WPA_BSS_MASK_BSSID BIT(1) -#define WPA_BSS_MASK_FREQ BIT(2) -#define WPA_BSS_MASK_BEACON_INT BIT(3) -#define WPA_BSS_MASK_CAPABILITIES BIT(4) -#define WPA_BSS_MASK_QUAL BIT(5) -#define WPA_BSS_MASK_NOISE BIT(6) -#define WPA_BSS_MASK_LEVEL BIT(7) -#define WPA_BSS_MASK_TSF BIT(8) -#define WPA_BSS_MASK_AGE BIT(9) -#define WPA_BSS_MASK_IE BIT(10) -#define WPA_BSS_MASK_FLAGS BIT(11) -#define WPA_BSS_MASK_SSID BIT(12) -#define WPA_BSS_MASK_WPS_SCAN BIT(13) -#define WPA_BSS_MASK_P2P_SCAN BIT(14) -#define WPA_BSS_MASK_INTERNETW BIT(15) -#define WPA_BSS_MASK_WIFI_DISPLAY BIT(16) -#define WPA_BSS_MASK_DELIM BIT(17) - - -/* wpa_supplicant/hostapd control interface access */ - -/** - * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd - * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used. - * Returns: Pointer to abstract control interface data or %NULL on failure - * - * This function is used to open a control interface to wpa_supplicant/hostapd. - * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path - * is configured in wpa_supplicant/hostapd and other programs using the control - * interface need to use matching path configuration. - */ -struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path); - - -/** - * wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd - * @ctrl: Control interface data from wpa_ctrl_open() - * - * This function is used to close a control interface. - */ -void wpa_ctrl_close(struct wpa_ctrl *ctrl); - - -/** - * wpa_ctrl_request - Send a command to wpa_supplicant/hostapd - * @ctrl: Control interface data from wpa_ctrl_open() - * @cmd: Command; usually, ASCII text, e.g., "PING" - * @cmd_len: Length of the cmd in bytes - * @reply: Buffer for the response - * @reply_len: Reply buffer length - * @msg_cb: Callback function for unsolicited messages or %NULL if not used - * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout - * - * This function is used to send commands to wpa_supplicant/hostapd. Received - * response will be written to reply and reply_len is set to the actual length - * of the reply. This function will block for up to two seconds while waiting - * for the reply. If unsolicited messages are received, the blocking time may - * be longer. - * - * msg_cb can be used to register a callback function that will be called for - * unsolicited messages received while waiting for the command response. These - * messages may be received if wpa_ctrl_request() is called at the same time as - * wpa_supplicant/hostapd is sending such a message. This can happen only if - * the program has used wpa_ctrl_attach() to register itself as a monitor for - * event messages. Alternatively to msg_cb, programs can register two control - * interface connections and use one of them for commands and the other one for - * receiving event messages, in other words, call wpa_ctrl_attach() only for - * the control interface connection that will be used for event messages. - */ -int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, - char *reply, size_t *reply_len, - void (*msg_cb)(char *msg, size_t len)); - - -/** - * wpa_ctrl_attach - Register as an event monitor for the control interface - * @ctrl: Control interface data from wpa_ctrl_open() - * Returns: 0 on success, -1 on failure, -2 on timeout - * - * This function registers the control interface connection as a monitor for - * wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the - * control interface connection starts receiving event messages that can be - * read with wpa_ctrl_recv(). - */ -int wpa_ctrl_attach(struct wpa_ctrl *ctrl); - - -/** - * wpa_ctrl_detach - Unregister event monitor from the control interface - * @ctrl: Control interface data from wpa_ctrl_open() - * Returns: 0 on success, -1 on failure, -2 on timeout - * - * This function unregisters the control interface connection as a monitor for - * wpa_supplicant/hostapd events, i.e., cancels the registration done with - * wpa_ctrl_attach(). - */ -int wpa_ctrl_detach(struct wpa_ctrl *ctrl); - - -/** - * wpa_ctrl_recv - Receive a pending control interface message - * @ctrl: Control interface data from wpa_ctrl_open() - * @reply: Buffer for the message data - * @reply_len: Length of the reply buffer - * Returns: 0 on success, -1 on failure - * - * This function will receive a pending control interface message. This - * function will block if no messages are available. The received response will - * be written to reply and reply_len is set to the actual length of the reply. - * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach() - * must have been used to register the control interface as an event monitor. - */ -int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len); - - -/** - * wpa_ctrl_pending - Check whether there are pending event messages - * @ctrl: Control interface data from wpa_ctrl_open() - * Returns: 1 if there are pending messages, 0 if no, or -1 on error - * - * This function will check whether there are any pending control interface - * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is - * only used for event messages, i.e., wpa_ctrl_attach() must have been used to - * register the control interface as an event monitor. - */ -int wpa_ctrl_pending(struct wpa_ctrl *ctrl); - - -/** - * wpa_ctrl_get_fd - Get file descriptor used by the control interface - * @ctrl: Control interface data from wpa_ctrl_open() - * Returns: File descriptor used for the connection - * - * This function can be used to get the file descriptor that is used for the - * control interface connection. The returned value can be used, e.g., with - * select() while waiting for multiple events. - * - * The returned file descriptor must not be used directly for sending or - * receiving packets; instead, the library functions wpa_ctrl_request() and - * wpa_ctrl_recv() must be used for this. - */ -int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl); - -char * wpa_ctrl_get_remote_ifname(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 -/* Port range for multiple wpa_supplicant instances and multiple VIFs */ -#define WPA_CTRL_IFACE_PORT 9877 -#define WPA_CTRL_IFACE_PORT_LIMIT 50 /* decremented from start */ -#define WPA_GLOBAL_CTRL_IFACE_PORT 9878 -#define WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT 20 /* incremented from start */ -#endif /* CONFIG_CTRL_IFACE_UDP */ - - -#ifdef __cplusplus -} -#endif - -#endif /* WPA_CTRL_H */ diff --git a/contrib/hostapd/src/crypto/aes-cbc.c b/contrib/hostapd/src/crypto/aes-cbc.c deleted file mode 100644 index 2833cfcc84..0000000000 --- a/contrib/hostapd/src/crypto/aes-cbc.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * AES-128 CBC - * - * Copyright (c) 2003-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "aes.h" -#include "aes_wrap.h" - -/** - * aes_128_cbc_encrypt - AES-128 CBC encryption - * @key: Encryption key - * @iv: Encryption IV for CBC mode (16 bytes) - * @data: Data to encrypt in-place - * @data_len: Length of data in bytes (must be divisible by 16) - * Returns: 0 on success, -1 on failure - */ -int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) -{ - void *ctx; - u8 cbc[AES_BLOCK_SIZE]; - u8 *pos = data; - int i, j, blocks; - - ctx = aes_encrypt_init(key, 16); - if (ctx == NULL) - return -1; - os_memcpy(cbc, iv, AES_BLOCK_SIZE); - - blocks = data_len / AES_BLOCK_SIZE; - for (i = 0; i < blocks; i++) { - for (j = 0; j < AES_BLOCK_SIZE; j++) - cbc[j] ^= pos[j]; - aes_encrypt(ctx, cbc, cbc); - os_memcpy(pos, cbc, AES_BLOCK_SIZE); - pos += AES_BLOCK_SIZE; - } - aes_encrypt_deinit(ctx); - return 0; -} - - -/** - * aes_128_cbc_decrypt - AES-128 CBC decryption - * @key: Decryption key - * @iv: Decryption IV for CBC mode (16 bytes) - * @data: Data to decrypt in-place - * @data_len: Length of data in bytes (must be divisible by 16) - * Returns: 0 on success, -1 on failure - */ -int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) -{ - void *ctx; - u8 cbc[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE]; - u8 *pos = data; - int i, j, blocks; - - ctx = aes_decrypt_init(key, 16); - if (ctx == NULL) - return -1; - os_memcpy(cbc, iv, AES_BLOCK_SIZE); - - blocks = data_len / AES_BLOCK_SIZE; - for (i = 0; i < blocks; i++) { - os_memcpy(tmp, pos, AES_BLOCK_SIZE); - aes_decrypt(ctx, pos, pos); - for (j = 0; j < AES_BLOCK_SIZE; j++) - pos[j] ^= cbc[j]; - os_memcpy(cbc, tmp, AES_BLOCK_SIZE); - pos += AES_BLOCK_SIZE; - } - aes_decrypt_deinit(ctx); - return 0; -} diff --git a/contrib/hostapd/src/crypto/aes-ccm.c b/contrib/hostapd/src/crypto/aes-ccm.c deleted file mode 100644 index d14670db8d..0000000000 --- a/contrib/hostapd/src/crypto/aes-ccm.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Counter with CBC-MAC (CCM) with AES - * - * Copyright (c) 2010-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "aes.h" -#include "aes_wrap.h" - - -static void xor_aes_block(u8 *dst, const u8 *src) -{ - u32 *d = (u32 *) dst; - u32 *s = (u32 *) src; - *d++ ^= *s++; - *d++ ^= *s++; - *d++ ^= *s++; - *d++ ^= *s++; -} - - -static void aes_ccm_auth_start(void *aes, size_t M, size_t L, const u8 *nonce, - const u8 *aad, size_t aad_len, size_t plain_len, - u8 *x) -{ - u8 aad_buf[2 * AES_BLOCK_SIZE]; - u8 b[AES_BLOCK_SIZE]; - - /* Authentication */ - /* B_0: Flags | Nonce N | l(m) */ - b[0] = aad_len ? 0x40 : 0 /* Adata */; - b[0] |= (((M - 2) / 2) /* M' */ << 3); - b[0] |= (L - 1) /* L' */; - os_memcpy(&b[1], nonce, 15 - L); - WPA_PUT_BE16(&b[AES_BLOCK_SIZE - L], plain_len); - - wpa_hexdump_key(MSG_EXCESSIVE, "CCM B_0", b, AES_BLOCK_SIZE); - aes_encrypt(aes, b, x); /* X_1 = E(K, B_0) */ - - if (!aad_len) - return; - - WPA_PUT_BE16(aad_buf, aad_len); - os_memcpy(aad_buf + 2, aad, aad_len); - os_memset(aad_buf + 2 + aad_len, 0, sizeof(aad_buf) - 2 - aad_len); - - xor_aes_block(aad_buf, x); - aes_encrypt(aes, aad_buf, x); /* X_2 = E(K, X_1 XOR B_1) */ - - if (aad_len > AES_BLOCK_SIZE - 2) { - xor_aes_block(&aad_buf[AES_BLOCK_SIZE], x); - /* X_3 = E(K, X_2 XOR B_2) */ - aes_encrypt(aes, &aad_buf[AES_BLOCK_SIZE], x); - } -} - - -static void aes_ccm_auth(void *aes, const u8 *data, size_t len, u8 *x) -{ - size_t last = len % AES_BLOCK_SIZE; - size_t i; - - for (i = 0; i < len / AES_BLOCK_SIZE; i++) { - /* X_i+1 = E(K, X_i XOR B_i) */ - xor_aes_block(x, data); - data += AES_BLOCK_SIZE; - aes_encrypt(aes, x, x); - } - if (last) { - /* XOR zero-padded last block */ - for (i = 0; i < last; i++) - x[i] ^= *data++; - aes_encrypt(aes, x, x); - } -} - - -static void aes_ccm_encr_start(size_t L, const u8 *nonce, u8 *a) -{ - /* A_i = Flags | Nonce N | Counter i */ - a[0] = L - 1; /* Flags = L' */ - os_memcpy(&a[1], nonce, 15 - L); -} - - -static void aes_ccm_encr(void *aes, size_t L, const u8 *in, size_t len, u8 *out, - u8 *a) -{ - size_t last = len % AES_BLOCK_SIZE; - size_t i; - - /* crypt = msg XOR (S_1 | S_2 | ... | S_n) */ - for (i = 1; i <= len / AES_BLOCK_SIZE; i++) { - WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], i); - /* S_i = E(K, A_i) */ - aes_encrypt(aes, a, out); - xor_aes_block(out, in); - out += AES_BLOCK_SIZE; - in += AES_BLOCK_SIZE; - } - if (last) { - WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], i); - aes_encrypt(aes, a, out); - /* XOR zero-padded last block */ - for (i = 0; i < last; i++) - *out++ ^= *in++; - } -} - - -static void aes_ccm_encr_auth(void *aes, size_t M, u8 *x, u8 *a, u8 *auth) -{ - size_t i; - u8 tmp[AES_BLOCK_SIZE]; - - wpa_hexdump_key(MSG_EXCESSIVE, "CCM T", x, M); - /* U = T XOR S_0; S_0 = E(K, A_0) */ - WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0); - aes_encrypt(aes, a, tmp); - for (i = 0; i < M; i++) - auth[i] = x[i] ^ tmp[i]; - wpa_hexdump_key(MSG_EXCESSIVE, "CCM U", auth, M); -} - - -static void aes_ccm_decr_auth(void *aes, size_t M, u8 *a, const u8 *auth, u8 *t) -{ - size_t i; - u8 tmp[AES_BLOCK_SIZE]; - - wpa_hexdump_key(MSG_EXCESSIVE, "CCM U", auth, M); - /* U = T XOR S_0; S_0 = E(K, A_0) */ - WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0); - aes_encrypt(aes, a, tmp); - for (i = 0; i < M; i++) - t[i] = auth[i] ^ tmp[i]; - wpa_hexdump_key(MSG_EXCESSIVE, "CCM T", t, M); -} - - -/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */ -int aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce, - size_t M, const u8 *plain, size_t plain_len, - const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth) -{ - const size_t L = 2; - void *aes; - u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE]; - - if (aad_len > 30 || M > AES_BLOCK_SIZE) - return -1; - - aes = aes_encrypt_init(key, key_len); - if (aes == NULL) - return -1; - - aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, plain_len, x); - aes_ccm_auth(aes, plain, plain_len, x); - - /* Encryption */ - aes_ccm_encr_start(L, nonce, a); - aes_ccm_encr(aes, L, plain, plain_len, crypt, a); - aes_ccm_encr_auth(aes, M, x, a, auth); - - aes_encrypt_deinit(aes); - - return 0; -} - - -/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */ -int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce, - size_t M, const u8 *crypt, size_t crypt_len, - const u8 *aad, size_t aad_len, const u8 *auth, u8 *plain) -{ - const size_t L = 2; - void *aes; - u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE]; - u8 t[AES_BLOCK_SIZE]; - - if (aad_len > 30 || M > AES_BLOCK_SIZE) - return -1; - - aes = aes_encrypt_init(key, key_len); - if (aes == NULL) - return -1; - - /* Decryption */ - aes_ccm_encr_start(L, nonce, a); - aes_ccm_decr_auth(aes, M, a, auth, t); - - /* plaintext = msg XOR (S_1 | S_2 | ... | S_n) */ - aes_ccm_encr(aes, L, crypt, crypt_len, plain, a); - - aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, crypt_len, x); - aes_ccm_auth(aes, plain, crypt_len, x); - - aes_encrypt_deinit(aes); - - if (os_memcmp(x, t, M) != 0) { - wpa_printf(MSG_EXCESSIVE, "CCM: Auth mismatch"); - return -1; - } - - return 0; -} diff --git a/contrib/hostapd/src/crypto/aes-ctr.c b/contrib/hostapd/src/crypto/aes-ctr.c deleted file mode 100644 index d4d874daac..0000000000 --- a/contrib/hostapd/src/crypto/aes-ctr.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * AES-128 CTR - * - * Copyright (c) 2003-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "aes.h" -#include "aes_wrap.h" - -/** - * aes_128_ctr_encrypt - AES-128 CTR mode encryption - * @key: Key for encryption (16 bytes) - * @nonce: Nonce for counter mode (16 bytes) - * @data: Data to encrypt in-place - * @data_len: Length of data in bytes - * Returns: 0 on success, -1 on failure - */ -int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, - u8 *data, size_t data_len) -{ - void *ctx; - size_t j, len, left = data_len; - int i; - u8 *pos = data; - u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE]; - - ctx = aes_encrypt_init(key, 16); - if (ctx == NULL) - return -1; - os_memcpy(counter, nonce, AES_BLOCK_SIZE); - - while (left > 0) { - aes_encrypt(ctx, counter, buf); - - len = (left < AES_BLOCK_SIZE) ? left : AES_BLOCK_SIZE; - for (j = 0; j < len; j++) - pos[j] ^= buf[j]; - pos += len; - left -= len; - - for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) { - counter[i]++; - if (counter[i]) - break; - } - } - aes_encrypt_deinit(ctx); - return 0; -} diff --git a/contrib/hostapd/src/crypto/aes-eax.c b/contrib/hostapd/src/crypto/aes-eax.c deleted file mode 100644 index 21941c66de..0000000000 --- a/contrib/hostapd/src/crypto/aes-eax.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * AES-128 EAX - * - * Copyright (c) 2003-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "aes.h" -#include "aes_wrap.h" - -/** - * aes_128_eax_encrypt - AES-128 EAX mode encryption - * @key: Key for encryption (16 bytes) - * @nonce: Nonce for counter mode - * @nonce_len: Nonce length in bytes - * @hdr: Header data to be authenticity protected - * @hdr_len: Length of the header data bytes - * @data: Data to encrypt in-place - * @data_len: Length of data in bytes - * @tag: 16-byte tag value - * Returns: 0 on success, -1 on failure - */ -int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len, - const u8 *hdr, size_t hdr_len, - u8 *data, size_t data_len, u8 *tag) -{ - u8 *buf; - size_t buf_len; - u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE], - data_mac[AES_BLOCK_SIZE]; - int i, ret = -1; - - if (nonce_len > data_len) - buf_len = nonce_len; - else - buf_len = data_len; - if (hdr_len > buf_len) - buf_len = hdr_len; - buf_len += 16; - - buf = os_malloc(buf_len); - if (buf == NULL) - return -1; - - os_memset(buf, 0, 15); - - buf[15] = 0; - os_memcpy(buf + 16, nonce, nonce_len); - if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) - goto fail; - - buf[15] = 1; - os_memcpy(buf + 16, hdr, hdr_len); - if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) - goto fail; - - if (aes_128_ctr_encrypt(key, nonce_mac, data, data_len)) - goto fail; - buf[15] = 2; - os_memcpy(buf + 16, data, data_len); - if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) - goto fail; - - for (i = 0; i < AES_BLOCK_SIZE; i++) - tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]; - - ret = 0; -fail: - os_free(buf); - - return ret; -} - - -/** - * aes_128_eax_decrypt - AES-128 EAX mode decryption - * @key: Key for decryption (16 bytes) - * @nonce: Nonce for counter mode - * @nonce_len: Nonce length in bytes - * @hdr: Header data to be authenticity protected - * @hdr_len: Length of the header data bytes - * @data: Data to encrypt in-place - * @data_len: Length of data in bytes - * @tag: 16-byte tag value - * Returns: 0 on success, -1 on failure, -2 if tag does not match - */ -int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len, - const u8 *hdr, size_t hdr_len, - u8 *data, size_t data_len, const u8 *tag) -{ - u8 *buf; - size_t buf_len; - u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE], - data_mac[AES_BLOCK_SIZE]; - int i; - - if (nonce_len > data_len) - buf_len = nonce_len; - else - buf_len = data_len; - if (hdr_len > buf_len) - buf_len = hdr_len; - buf_len += 16; - - buf = os_malloc(buf_len); - if (buf == NULL) - return -1; - - os_memset(buf, 0, 15); - - buf[15] = 0; - os_memcpy(buf + 16, nonce, nonce_len); - if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) { - os_free(buf); - return -1; - } - - buf[15] = 1; - os_memcpy(buf + 16, hdr, hdr_len); - if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) { - os_free(buf); - return -1; - } - - buf[15] = 2; - os_memcpy(buf + 16, data, data_len); - if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) { - os_free(buf); - return -1; - } - - os_free(buf); - - for (i = 0; i < AES_BLOCK_SIZE; i++) { - if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i])) - return -2; - } - - return aes_128_ctr_encrypt(key, nonce_mac, data, data_len); -} diff --git a/contrib/hostapd/src/crypto/aes-encblock.c b/contrib/hostapd/src/crypto/aes-encblock.c deleted file mode 100644 index a5216211dd..0000000000 --- a/contrib/hostapd/src/crypto/aes-encblock.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * AES encrypt_block - * - * Copyright (c) 2003-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "aes.h" -#include "aes_wrap.h" - -/** - * aes_128_encrypt_block - Perform one AES 128-bit block operation - * @key: Key for AES - * @in: Input data (16 bytes) - * @out: Output of the AES block operation (16 bytes) - * Returns: 0 on success, -1 on failure - */ -int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out) -{ - void *ctx; - ctx = aes_encrypt_init(key, 16); - if (ctx == NULL) - return -1; - aes_encrypt(ctx, in, out); - aes_encrypt_deinit(ctx); - return 0; -} diff --git a/contrib/hostapd/src/crypto/aes-gcm.c b/contrib/hostapd/src/crypto/aes-gcm.c deleted file mode 100644 index 3d91c71de2..0000000000 --- a/contrib/hostapd/src/crypto/aes-gcm.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Galois/Counter Mode (GCM) and GMAC with AES - * - * Copyright (c) 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "aes.h" -#include "aes_wrap.h" - -static void inc32(u8 *block) -{ - u32 val; - val = WPA_GET_BE32(block + AES_BLOCK_SIZE - 4); - val++; - WPA_PUT_BE32(block + AES_BLOCK_SIZE - 4, val); -} - - -static void xor_block(u8 *dst, const u8 *src) -{ - u32 *d = (u32 *) dst; - u32 *s = (u32 *) src; - *d++ ^= *s++; - *d++ ^= *s++; - *d++ ^= *s++; - *d++ ^= *s++; -} - - -static void shift_right_block(u8 *v) -{ - u32 val; - - val = WPA_GET_BE32(v + 12); - val >>= 1; - if (v[11] & 0x01) - val |= 0x80000000; - WPA_PUT_BE32(v + 12, val); - - val = WPA_GET_BE32(v + 8); - val >>= 1; - if (v[7] & 0x01) - val |= 0x80000000; - WPA_PUT_BE32(v + 8, val); - - val = WPA_GET_BE32(v + 4); - val >>= 1; - if (v[3] & 0x01) - val |= 0x80000000; - WPA_PUT_BE32(v + 4, val); - - val = WPA_GET_BE32(v); - val >>= 1; - WPA_PUT_BE32(v, val); -} - - -/* Multiplication in GF(2^128) */ -static void gf_mult(const u8 *x, const u8 *y, u8 *z) -{ - u8 v[16]; - int i, j; - - os_memset(z, 0, 16); /* Z_0 = 0^128 */ - os_memcpy(v, y, 16); /* V_0 = Y */ - - for (i = 0; i < 16; i++) { - for (j = 0; j < 8; j++) { - if (x[i] & BIT(7 - j)) { - /* Z_(i + 1) = Z_i XOR V_i */ - xor_block(z, v); - } else { - /* Z_(i + 1) = Z_i */ - } - - if (v[15] & 0x01) { - /* V_(i + 1) = (V_i >> 1) XOR R */ - shift_right_block(v); - /* R = 11100001 || 0^120 */ - v[0] ^= 0xe1; - } else { - /* V_(i + 1) = V_i >> 1 */ - shift_right_block(v); - } - } - } -} - - -static void ghash_start(u8 *y) -{ - /* Y_0 = 0^128 */ - os_memset(y, 0, 16); -} - - -static void ghash(const u8 *h, const u8 *x, size_t xlen, u8 *y) -{ - size_t m, i; - const u8 *xpos = x; - u8 tmp[16]; - - m = xlen / 16; - - for (i = 0; i < m; i++) { - /* Y_i = (Y^(i-1) XOR X_i) dot H */ - xor_block(y, xpos); - xpos += 16; - - /* dot operation: - * multiplication operation for binary Galois (finite) field of - * 2^128 elements */ - gf_mult(y, h, tmp); - os_memcpy(y, tmp, 16); - } - - if (x + xlen > xpos) { - /* Add zero padded last block */ - size_t last = x + xlen - xpos; - os_memcpy(tmp, xpos, last); - os_memset(tmp + last, 0, sizeof(tmp) - last); - - /* Y_i = (Y^(i-1) XOR X_i) dot H */ - xor_block(y, tmp); - - /* dot operation: - * multiplication operation for binary Galois (finite) field of - * 2^128 elements */ - gf_mult(y, h, tmp); - os_memcpy(y, tmp, 16); - } - - /* Return Y_m */ -} - - -static void aes_gctr(void *aes, const u8 *icb, const u8 *x, size_t xlen, u8 *y) -{ - size_t i, n, last; - u8 cb[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE]; - const u8 *xpos = x; - u8 *ypos = y; - - if (xlen == 0) - return; - - n = xlen / 16; - - os_memcpy(cb, icb, AES_BLOCK_SIZE); - /* Full blocks */ - for (i = 0; i < n; i++) { - aes_encrypt(aes, cb, ypos); - xor_block(ypos, xpos); - xpos += AES_BLOCK_SIZE; - ypos += AES_BLOCK_SIZE; - inc32(cb); - } - - last = x + xlen - xpos; - if (last) { - /* Last, partial block */ - aes_encrypt(aes, cb, tmp); - for (i = 0; i < last; i++) - *ypos++ = *xpos++ ^ tmp[i]; - } -} - - -static void * aes_gcm_init_hash_subkey(const u8 *key, size_t key_len, u8 *H) -{ - void *aes; - - aes = aes_encrypt_init(key, key_len); - if (aes == NULL) - return NULL; - - /* Generate hash subkey H = AES_K(0^128) */ - os_memset(H, 0, AES_BLOCK_SIZE); - aes_encrypt(aes, H, H); - wpa_hexdump_key(MSG_EXCESSIVE, "Hash subkey H for GHASH", - H, AES_BLOCK_SIZE); - return aes; -} - - -static void aes_gcm_prepare_j0(const u8 *iv, size_t iv_len, const u8 *H, u8 *J0) -{ - u8 len_buf[16]; - - if (iv_len == 12) { - /* Prepare block J_0 = IV || 0^31 || 1 [len(IV) = 96] */ - os_memcpy(J0, iv, iv_len); - os_memset(J0 + iv_len, 0, AES_BLOCK_SIZE - iv_len); - J0[AES_BLOCK_SIZE - 1] = 0x01; - } else { - /* - * s = 128 * ceil(len(IV)/128) - len(IV) - * J_0 = GHASH_H(IV || 0^(s+64) || [len(IV)]_64) - */ - ghash_start(J0); - ghash(H, iv, iv_len, J0); - WPA_PUT_BE64(len_buf, 0); - WPA_PUT_BE64(len_buf + 8, iv_len * 8); - ghash(H, len_buf, sizeof(len_buf), J0); - } -} - - -static void aes_gcm_gctr(void *aes, const u8 *J0, const u8 *in, size_t len, - u8 *out) -{ - u8 J0inc[AES_BLOCK_SIZE]; - - if (len == 0) - return; - - os_memcpy(J0inc, J0, AES_BLOCK_SIZE); - inc32(J0inc); - aes_gctr(aes, J0inc, in, len, out); -} - - -static void aes_gcm_ghash(const u8 *H, const u8 *aad, size_t aad_len, - const u8 *crypt, size_t crypt_len, u8 *S) -{ - u8 len_buf[16]; - - /* - * u = 128 * ceil[len(C)/128] - len(C) - * v = 128 * ceil[len(A)/128] - len(A) - * S = GHASH_H(A || 0^v || C || 0^u || [len(A)]64 || [len(C)]64) - * (i.e., zero padded to block size A || C and lengths of each in bits) - */ - ghash_start(S); - ghash(H, aad, aad_len, S); - ghash(H, crypt, crypt_len, S); - WPA_PUT_BE64(len_buf, aad_len * 8); - WPA_PUT_BE64(len_buf + 8, crypt_len * 8); - ghash(H, len_buf, sizeof(len_buf), S); - - wpa_hexdump_key(MSG_EXCESSIVE, "S = GHASH_H(...)", S, 16); -} - - -/** - * aes_gcm_ae - GCM-AE_K(IV, P, A) - */ -int aes_gcm_ae(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len, - const u8 *plain, size_t plain_len, - const u8 *aad, size_t aad_len, u8 *crypt, u8 *tag) -{ - u8 H[AES_BLOCK_SIZE]; - u8 J0[AES_BLOCK_SIZE]; - u8 S[16]; - void *aes; - - aes = aes_gcm_init_hash_subkey(key, key_len, H); - if (aes == NULL) - return -1; - - aes_gcm_prepare_j0(iv, iv_len, H, J0); - - /* C = GCTR_K(inc_32(J_0), P) */ - aes_gcm_gctr(aes, J0, plain, plain_len, crypt); - - aes_gcm_ghash(H, aad, aad_len, crypt, plain_len, S); - - /* T = MSB_t(GCTR_K(J_0, S)) */ - aes_gctr(aes, J0, S, sizeof(S), tag); - - /* Return (C, T) */ - - aes_encrypt_deinit(aes); - - return 0; -} - - -/** - * aes_gcm_ad - GCM-AD_K(IV, C, A, T) - */ -int aes_gcm_ad(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len, - const u8 *crypt, size_t crypt_len, - const u8 *aad, size_t aad_len, const u8 *tag, u8 *plain) -{ - u8 H[AES_BLOCK_SIZE]; - u8 J0[AES_BLOCK_SIZE]; - u8 S[16], T[16]; - void *aes; - - aes = aes_gcm_init_hash_subkey(key, key_len, H); - if (aes == NULL) - return -1; - - aes_gcm_prepare_j0(iv, iv_len, H, J0); - - /* P = GCTR_K(inc_32(J_0), C) */ - aes_gcm_gctr(aes, J0, crypt, crypt_len, plain); - - aes_gcm_ghash(H, aad, aad_len, crypt, crypt_len, S); - - /* T' = MSB_t(GCTR_K(J_0, S)) */ - aes_gctr(aes, J0, S, sizeof(S), T); - - aes_encrypt_deinit(aes); - - if (os_memcmp(tag, T, 16) != 0) { - wpa_printf(MSG_EXCESSIVE, "GCM: Tag mismatch"); - return -1; - } - - return 0; -} - - -int aes_gmac(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len, - const u8 *aad, size_t aad_len, u8 *tag) -{ - return aes_gcm_ae(key, key_len, iv, iv_len, NULL, 0, aad, aad_len, NULL, - tag); -} diff --git a/contrib/hostapd/src/crypto/aes-internal-dec.c b/contrib/hostapd/src/crypto/aes-internal-dec.c deleted file mode 100644 index 720c7036e4..0000000000 --- a/contrib/hostapd/src/crypto/aes-internal-dec.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * AES (Rijndael) cipher - decrypt - * - * Modifications to public domain implementation: - * - cleanup - * - use C pre-processor to make it easier to change S table access - * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at - * cost of reduced throughput (quite small difference on Pentium 4, - * 10-25% when using -O1 or -O2 optimization) - * - * Copyright (c) 2003-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" -#include "aes_i.h" - -/** - * Expand the cipher key into the decryption key schedule. - * - * @return the number of rounds for the given cipher key size. - */ -static int rijndaelKeySetupDec(u32 rk[], const u8 cipherKey[], int keyBits) -{ - int Nr, i, j; - u32 temp; - - /* expand the cipher key: */ - Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits); - if (Nr < 0) - return Nr; - /* invert the order of the round keys: */ - for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { - temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; - temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; - temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; - temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; - } - /* apply the inverse MixColumn transform to all round keys but the - * first and the last: */ - for (i = 1; i < Nr; i++) { - rk += 4; - for (j = 0; j < 4; j++) { - rk[j] = TD0_(TE4((rk[j] >> 24) )) ^ - TD1_(TE4((rk[j] >> 16) & 0xff)) ^ - TD2_(TE4((rk[j] >> 8) & 0xff)) ^ - TD3_(TE4((rk[j] ) & 0xff)); - } - } - - return Nr; -} - -void * aes_decrypt_init(const u8 *key, size_t len) -{ - u32 *rk; - int res; - rk = os_malloc(AES_PRIV_SIZE); - if (rk == NULL) - return NULL; - res = rijndaelKeySetupDec(rk, key, len * 8); - if (res < 0) { - os_free(rk); - return NULL; - } - rk[AES_PRIV_NR_POS] = res; - return rk; -} - -static void rijndaelDecrypt(const u32 rk[/*44*/], int Nr, const u8 ct[16], - u8 pt[16]) -{ - u32 s0, s1, s2, s3, t0, t1, t2, t3; -#ifndef FULL_UNROLL - int r; -#endif /* ?FULL_UNROLL */ - - /* - * map byte array block to cipher state - * and add initial round key: - */ - s0 = GETU32(ct ) ^ rk[0]; - s1 = GETU32(ct + 4) ^ rk[1]; - s2 = GETU32(ct + 8) ^ rk[2]; - s3 = GETU32(ct + 12) ^ rk[3]; - -#define ROUND(i,d,s) \ -d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \ -d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \ -d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \ -d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3] - -#ifdef FULL_UNROLL - - ROUND(1,t,s); - ROUND(2,s,t); - ROUND(3,t,s); - ROUND(4,s,t); - ROUND(5,t,s); - ROUND(6,s,t); - ROUND(7,t,s); - ROUND(8,s,t); - ROUND(9,t,s); - if (Nr > 10) { - ROUND(10,s,t); - ROUND(11,t,s); - if (Nr > 12) { - ROUND(12,s,t); - ROUND(13,t,s); - } - } - - rk += Nr << 2; - -#else /* !FULL_UNROLL */ - - /* Nr - 1 full rounds: */ - r = Nr >> 1; - for (;;) { - ROUND(1,t,s); - rk += 8; - if (--r == 0) - break; - ROUND(0,s,t); - } - -#endif /* ?FULL_UNROLL */ - -#undef ROUND - - /* - * apply last round and - * map cipher state to byte array block: - */ - s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0]; - PUTU32(pt , s0); - s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1]; - PUTU32(pt + 4, s1); - s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2]; - PUTU32(pt + 8, s2); - s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3]; - PUTU32(pt + 12, s3); -} - -void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) -{ - u32 *rk = ctx; - rijndaelDecrypt(ctx, rk[AES_PRIV_NR_POS], crypt, plain); -} - - -void aes_decrypt_deinit(void *ctx) -{ - os_memset(ctx, 0, AES_PRIV_SIZE); - os_free(ctx); -} diff --git a/contrib/hostapd/src/crypto/aes-internal-enc.c b/contrib/hostapd/src/crypto/aes-internal-enc.c deleted file mode 100644 index f3c61b8508..0000000000 --- a/contrib/hostapd/src/crypto/aes-internal-enc.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * AES (Rijndael) cipher - encrypt - * - * Modifications to public domain implementation: - * - cleanup - * - use C pre-processor to make it easier to change S table access - * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at - * cost of reduced throughput (quite small difference on Pentium 4, - * 10-25% when using -O1 or -O2 optimization) - * - * Copyright (c) 2003-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" -#include "aes_i.h" - -static void rijndaelEncrypt(const u32 rk[], int Nr, const u8 pt[16], u8 ct[16]) -{ - u32 s0, s1, s2, s3, t0, t1, t2, t3; -#ifndef FULL_UNROLL - int r; -#endif /* ?FULL_UNROLL */ - - /* - * map byte array block to cipher state - * and add initial round key: - */ - s0 = GETU32(pt ) ^ rk[0]; - s1 = GETU32(pt + 4) ^ rk[1]; - s2 = GETU32(pt + 8) ^ rk[2]; - s3 = GETU32(pt + 12) ^ rk[3]; - -#define ROUND(i,d,s) \ -d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ -d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ -d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ -d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3] - -#ifdef FULL_UNROLL - - ROUND(1,t,s); - ROUND(2,s,t); - ROUND(3,t,s); - ROUND(4,s,t); - ROUND(5,t,s); - ROUND(6,s,t); - ROUND(7,t,s); - ROUND(8,s,t); - ROUND(9,t,s); - if (Nr > 10) { - ROUND(10,s,t); - ROUND(11,t,s); - if (Nr > 12) { - ROUND(12,s,t); - ROUND(13,t,s); - } - } - - rk += Nr << 2; - -#else /* !FULL_UNROLL */ - - /* Nr - 1 full rounds: */ - r = Nr >> 1; - for (;;) { - ROUND(1,t,s); - rk += 8; - if (--r == 0) - break; - ROUND(0,s,t); - } - -#endif /* ?FULL_UNROLL */ - -#undef ROUND - - /* - * apply last round and - * map cipher state to byte array block: - */ - s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0]; - PUTU32(ct , s0); - s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1]; - PUTU32(ct + 4, s1); - s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2]; - PUTU32(ct + 8, s2); - s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3]; - PUTU32(ct + 12, s3); -} - - -void * aes_encrypt_init(const u8 *key, size_t len) -{ - u32 *rk; - int res; - rk = os_malloc(AES_PRIV_SIZE); - if (rk == NULL) - return NULL; - res = rijndaelKeySetupEnc(rk, key, len * 8); - if (res < 0) { - os_free(rk); - return NULL; - } - rk[AES_PRIV_NR_POS] = res; - return rk; -} - - -void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -{ - u32 *rk = ctx; - rijndaelEncrypt(ctx, rk[AES_PRIV_NR_POS], plain, crypt); -} - - -void aes_encrypt_deinit(void *ctx) -{ - os_memset(ctx, 0, AES_PRIV_SIZE); - os_free(ctx); -} diff --git a/contrib/hostapd/src/crypto/aes-internal.c b/contrib/hostapd/src/crypto/aes-internal.c deleted file mode 100644 index bd4535d209..0000000000 --- a/contrib/hostapd/src/crypto/aes-internal.c +++ /dev/null @@ -1,845 +0,0 @@ -/* - * AES (Rijndael) cipher - * - * Modifications to public domain implementation: - * - cleanup - * - use C pre-processor to make it easier to change S table access - * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at - * cost of reduced throughput (quite small difference on Pentium 4, - * 10-25% when using -O1 or -O2 optimization) - * - * Copyright (c) 2003-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" -#include "aes_i.h" - -/* - * rijndael-alg-fst.c - * - * @version 3.0 (December 2000) - * - * Optimised ANSI C code for the Rijndael cipher (now AES) - * - * @author Vincent Rijmen - * @author Antoon Bosselaers - * @author Paulo Barreto - * - * This code is hereby placed in the public domain. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -/* -Te0[x] = S [x].[02, 01, 01, 03]; -Te1[x] = S [x].[03, 02, 01, 01]; -Te2[x] = S [x].[01, 03, 02, 01]; -Te3[x] = S [x].[01, 01, 03, 02]; -Te4[x] = S [x].[01, 01, 01, 01]; - -Td0[x] = Si[x].[0e, 09, 0d, 0b]; -Td1[x] = Si[x].[0b, 0e, 09, 0d]; -Td2[x] = Si[x].[0d, 0b, 0e, 09]; -Td3[x] = Si[x].[09, 0d, 0b, 0e]; -Td4[x] = Si[x].[01, 01, 01, 01]; -*/ - -const u32 Te0[256] = { - 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, - 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, - 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, - 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, - 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, - 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, - 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, - 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, - 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, - 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, - 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, - 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, - 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, - 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, - 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, - 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, - 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, - 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, - 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, - 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, - 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, - 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, - 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, - 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, - 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, - 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, - 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, - 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, - 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, - 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, - 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, - 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, - 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, - 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, - 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, - 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, - 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, - 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, - 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, - 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, - 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, - 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, - 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, - 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, - 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, - 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, - 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, - 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, - 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, - 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, - 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, - 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, - 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, - 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, - 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, - 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, - 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, - 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, - 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, - 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, - 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, - 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, - 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, - 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, -}; -#ifndef AES_SMALL_TABLES -const u32 Te1[256] = { - 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, - 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, - 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, - 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, - 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, - 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, - 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, - 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, - 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, - 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, - 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, - 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, - 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, - 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, - 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, - 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, - 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, - 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, - 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, - 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, - 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, - 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, - 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, - 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, - 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, - 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, - 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, - 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, - 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, - 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, - 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, - 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, - 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, - 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, - 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, - 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, - 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, - 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, - 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, - 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, - 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, - 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, - 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, - 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, - 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, - 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, - 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, - 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, - 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, - 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, - 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, - 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, - 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, - 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, - 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, - 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, - 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, - 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, - 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, - 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, - 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, - 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, - 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, - 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, -}; -const u32 Te2[256] = { - 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, - 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, - 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, - 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, - 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, - 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, - 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, - 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, - 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, - 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, - 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, - 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, - 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, - 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, - 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, - 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, - 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, - 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, - 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, - 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, - 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, - 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, - 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, - 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, - 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, - 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, - 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, - 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, - 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, - 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, - 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, - 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, - 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, - 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, - 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, - 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, - 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, - 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, - 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, - 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, - 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, - 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, - 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, - 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, - 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, - 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, - 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, - 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, - 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, - 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, - 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, - 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, - 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, - 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, - 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, - 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, - 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, - 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, - 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, - 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, - 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, - 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, - 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, - 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, -}; -const u32 Te3[256] = { - - 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, - 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, - 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, - 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, - 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, - 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, - 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, - 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, - 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, - 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, - 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, - 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, - 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, - 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, - 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, - 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, - 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, - 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, - 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, - 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, - 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, - 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, - 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, - 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, - 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, - 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, - 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, - 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, - 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, - 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, - 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, - 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, - 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, - 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, - 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, - 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, - 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, - 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, - 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, - 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, - 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, - 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, - 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, - 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, - 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, - 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, - 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, - 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, - 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, - 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, - 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, - 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, - 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, - 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, - 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, - 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, - 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, - 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, - 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, - 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, - 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, - 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, - 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, - 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, -}; -const u32 Te4[256] = { - 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, - 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, - 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, - 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, - 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, - 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, - 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, - 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, - 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, - 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, - 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, - 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, - 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, - 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, - 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, - 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, - 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, - 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, - 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, - 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, - 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, - 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, - 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, - 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, - 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, - 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, - 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, - 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, - 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, - 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, - 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, - 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, - 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, - 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, - 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, - 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, - 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, - 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, - 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, - 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, - 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, - 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, - 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, - 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, - 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, - 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, - 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, - 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, - 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, - 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, - 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, - 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, - 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, - 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, - 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, - 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, - 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, - 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, - 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, - 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, - 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, - 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, - 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, - 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, -}; -#endif /* AES_SMALL_TABLES */ -const u32 Td0[256] = { - 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, - 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, - 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, - 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, - 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, - 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, - 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, - 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, - 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, - 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, - 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, - 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, - 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, - 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, - 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, - 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, - 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, - 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, - 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, - 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, - 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, - 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, - 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, - 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, - 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, - 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, - 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, - 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, - 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, - 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, - 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, - 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, - 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, - 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, - 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, - 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, - 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, - 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, - 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, - 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, - 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, - 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, - 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, - 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, - 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, - 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, - 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, - 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, - 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, - 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, - 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, - 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, - 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, - 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, - 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, - 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, - 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, - 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, - 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, - 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, - 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, - 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, - 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, - 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, -}; -#ifndef AES_SMALL_TABLES -const u32 Td1[256] = { - 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, - 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, - 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, - 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, - 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, - 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, - 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, - 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, - 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, - 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, - 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, - 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, - 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, - 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, - 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, - 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, - 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, - 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, - 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, - 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, - 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, - 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, - 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, - 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, - 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, - 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, - 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, - 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, - 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, - 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, - 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, - 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, - 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, - 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, - 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, - 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, - 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, - 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, - 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, - 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, - 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, - 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, - 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, - 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, - 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, - 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, - 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, - 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, - 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, - 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, - 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, - 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, - 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, - 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, - 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, - 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, - 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, - 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, - 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, - 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, - 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, - 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, - 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, - 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, -}; -const u32 Td2[256] = { - 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, - 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, - 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, - 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, - 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, - 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, - 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, - 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, - 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, - 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, - 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, - 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, - 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, - 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, - 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, - 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, - 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, - 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, - 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, - 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, - - 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, - 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, - 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, - 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, - 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, - 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, - 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, - 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, - 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, - 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, - 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, - 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, - 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, - 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, - 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, - 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, - 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, - 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, - 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, - 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, - 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, - 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, - 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, - 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, - 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, - 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, - 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, - 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, - 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, - 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, - 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, - 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, - 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, - 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, - 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, - 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, - 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, - 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, - 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, - 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, - 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, - 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, - 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, - 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, -}; -const u32 Td3[256] = { - 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, - 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, - 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, - 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, - 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, - 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, - 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, - 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, - 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, - 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, - 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, - 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, - 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, - 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, - 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, - 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, - 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, - 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, - 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, - 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, - 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, - 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, - 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, - 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, - 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, - 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, - 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, - 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, - 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, - 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, - 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, - 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, - 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, - 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, - 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, - 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, - 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, - 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, - 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, - 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, - 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, - 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, - 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, - 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, - 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, - 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, - 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, - 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, - 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, - 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, - 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, - 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, - 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, - 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, - 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, - 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, - 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, - 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, - 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, - 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, - 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, - 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, - 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, - 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, -}; -const u32 Td4[256] = { - 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, - 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, - 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, - 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, - 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, - 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, - 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, - 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, - 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, - 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, - 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, - 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, - 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, - 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, - 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, - 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, - 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, - 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, - 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, - 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, - 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, - 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, - 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, - 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, - 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, - 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, - 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, - 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, - 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, - 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, - 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, - 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, - 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, - 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, - 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, - 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, - 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, - 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, - 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, - 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, - 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, - 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, - 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, - 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, - 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, - 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, - 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, - 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, - 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, - 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, - 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, - 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, - 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, - 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, - 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, - 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, - 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, - 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, - 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, - 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, - 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, - 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, - 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, - 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, -}; -const u32 rcon[] = { - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ -}; -#else /* AES_SMALL_TABLES */ -const u8 Td4s[256] = { - 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, - 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, - 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, - 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, - 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, - 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, - 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, - 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, - 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, - 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, - 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, - 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, - 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, - 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, - 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, - 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, - 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, - 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, - 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, - 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, - 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, - 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, - 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, - 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, - 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, - 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, - 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, - 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, - 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, - 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, - 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, - 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, -}; -const u8 rcons[] = { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 - /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ -}; -#endif /* AES_SMALL_TABLES */ -/** - * Expand the cipher key into the encryption key schedule. - * - * @return the number of rounds for the given cipher key size. - */ -int rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits) -{ - int i; - u32 temp; - - rk[0] = GETU32(cipherKey ); - rk[1] = GETU32(cipherKey + 4); - rk[2] = GETU32(cipherKey + 8); - rk[3] = GETU32(cipherKey + 12); - - if (keyBits == 128) { - for (i = 0; i < 10; i++) { - temp = rk[3]; - rk[4] = rk[0] ^ TE421(temp) ^ TE432(temp) ^ - TE443(temp) ^ TE414(temp) ^ RCON(i); - rk[5] = rk[1] ^ rk[4]; - rk[6] = rk[2] ^ rk[5]; - rk[7] = rk[3] ^ rk[6]; - rk += 4; - } - return 10; - } - - rk[4] = GETU32(cipherKey + 16); - rk[5] = GETU32(cipherKey + 20); - - if (keyBits == 192) { - for (i = 0; i < 8; i++) { - temp = rk[5]; - rk[6] = rk[0] ^ TE421(temp) ^ TE432(temp) ^ - TE443(temp) ^ TE414(temp) ^ RCON(i); - rk[7] = rk[1] ^ rk[6]; - rk[8] = rk[2] ^ rk[7]; - rk[9] = rk[3] ^ rk[8]; - if (i == 7) - return 12; - rk[10] = rk[4] ^ rk[9]; - rk[11] = rk[5] ^ rk[10]; - rk += 6; - } - } - - rk[6] = GETU32(cipherKey + 24); - rk[7] = GETU32(cipherKey + 28); - - if (keyBits == 256) { - for (i = 0; i < 7; i++) { - temp = rk[7]; - rk[8] = rk[0] ^ TE421(temp) ^ TE432(temp) ^ - TE443(temp) ^ TE414(temp) ^ RCON(i); - rk[9] = rk[1] ^ rk[8]; - rk[10] = rk[2] ^ rk[9]; - rk[11] = rk[3] ^ rk[10]; - if (i == 6) - return 14; - temp = rk[11]; - rk[12] = rk[4] ^ TE411(temp) ^ TE422(temp) ^ - TE433(temp) ^ TE444(temp); - rk[13] = rk[5] ^ rk[12]; - rk[14] = rk[6] ^ rk[13]; - rk[15] = rk[7] ^ rk[14]; - rk += 8; - } - } - - return -1; -} diff --git a/contrib/hostapd/src/crypto/aes-omac1.c b/contrib/hostapd/src/crypto/aes-omac1.c deleted file mode 100644 index 27895eb007..0000000000 --- a/contrib/hostapd/src/crypto/aes-omac1.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * One-key CBC MAC (OMAC1) hash with AES-128 - * - * Copyright (c) 2003-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "aes.h" -#include "aes_wrap.h" - -static void gf_mulx(u8 *pad) -{ - int i, carry; - - carry = pad[0] & 0x80; - for (i = 0; i < AES_BLOCK_SIZE - 1; i++) - pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); - pad[AES_BLOCK_SIZE - 1] <<= 1; - if (carry) - pad[AES_BLOCK_SIZE - 1] ^= 0x87; -} - - -/** - * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128 - * @key: 128-bit key for the hash operation - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) - * Returns: 0 on success, -1 on failure - * - * This is a mode for using block cipher (AES in this case) for authentication. - * OMAC1 was standardized with the name CMAC by NIST in a Special Publication - * (SP) 800-38B. - */ -int omac1_aes_128_vector(const u8 *key, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac) -{ - void *ctx; - u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; - const u8 *pos, *end; - size_t i, e, left, total_len; - - ctx = aes_encrypt_init(key, 16); - if (ctx == NULL) - return -1; - os_memset(cbc, 0, AES_BLOCK_SIZE); - - total_len = 0; - for (e = 0; e < num_elem; e++) - total_len += len[e]; - left = total_len; - - e = 0; - pos = addr[0]; - end = pos + len[0]; - - while (left >= AES_BLOCK_SIZE) { - for (i = 0; i < AES_BLOCK_SIZE; i++) { - cbc[i] ^= *pos++; - if (pos >= end) { - e++; - pos = addr[e]; - end = pos + len[e]; - } - } - if (left > AES_BLOCK_SIZE) - aes_encrypt(ctx, cbc, cbc); - left -= AES_BLOCK_SIZE; - } - - os_memset(pad, 0, AES_BLOCK_SIZE); - aes_encrypt(ctx, pad, pad); - gf_mulx(pad); - - if (left || total_len == 0) { - for (i = 0; i < left; i++) { - cbc[i] ^= *pos++; - if (pos >= end) { - e++; - pos = addr[e]; - end = pos + len[e]; - } - } - cbc[left] ^= 0x80; - gf_mulx(pad); - } - - for (i = 0; i < AES_BLOCK_SIZE; i++) - pad[i] ^= cbc[i]; - aes_encrypt(ctx, pad, mac); - aes_encrypt_deinit(ctx); - return 0; -} - - -/** - * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) - * @key: 128-bit key for the hash operation - * @data: Data buffer for which a MAC is determined - * @data_len: Length of data buffer in bytes - * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) - * Returns: 0 on success, -1 on failure - * - * This is a mode for using block cipher (AES in this case) for authentication. - * OMAC1 was standardized with the name CMAC by NIST in a Special Publication - * (SP) 800-38B. - */ -int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) -{ - return omac1_aes_128_vector(key, 1, &data, &data_len, mac); -} diff --git a/contrib/hostapd/src/crypto/aes-unwrap.c b/contrib/hostapd/src/crypto/aes-unwrap.c deleted file mode 100644 index 9dd51602f3..0000000000 --- a/contrib/hostapd/src/crypto/aes-unwrap.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * AES key unwrap (128-bit KEK, RFC3394) - * - * Copyright (c) 2003-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "aes.h" -#include "aes_wrap.h" - -/** - * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) - * @kek: Key encryption key (KEK) - * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 - * bytes - * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits - * @plain: Plaintext key, n * 64 bits - * Returns: 0 on success, -1 on failure (e.g., integrity verification failed) - */ -int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) -{ - u8 a[8], *r, b[16]; - int i, j; - void *ctx; - - /* 1) Initialize variables. */ - os_memcpy(a, cipher, 8); - r = plain; - os_memcpy(r, cipher + 8, 8 * n); - - ctx = aes_decrypt_init(kek, 16); - if (ctx == NULL) - return -1; - - /* 2) Compute intermediate values. - * For j = 5 to 0 - * For i = n to 1 - * B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i - * A = MSB(64, B) - * R[i] = LSB(64, B) - */ - for (j = 5; j >= 0; j--) { - r = plain + (n - 1) * 8; - for (i = n; i >= 1; i--) { - os_memcpy(b, a, 8); - b[7] ^= n * j + i; - - os_memcpy(b + 8, r, 8); - aes_decrypt(ctx, b, b); - os_memcpy(a, b, 8); - os_memcpy(r, b + 8, 8); - r -= 8; - } - } - aes_decrypt_deinit(ctx); - - /* 3) Output results. - * - * These are already in @plain due to the location of temporary - * variables. Just verify that the IV matches with the expected value. - */ - for (i = 0; i < 8; i++) { - if (a[i] != 0xa6) - return -1; - } - - return 0; -} diff --git a/contrib/hostapd/src/crypto/aes-wrap.c b/contrib/hostapd/src/crypto/aes-wrap.c deleted file mode 100644 index 89d6f94bf7..0000000000 --- a/contrib/hostapd/src/crypto/aes-wrap.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * AES Key Wrap Algorithm (128-bit KEK) (RFC3394) - * - * Copyright (c) 2003-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "aes.h" -#include "aes_wrap.h" - -/** - * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) - * @kek: 16-octet Key encryption key (KEK) - * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 - * bytes - * @plain: Plaintext key to be wrapped, n * 64 bits - * @cipher: Wrapped key, (n + 1) * 64 bits - * Returns: 0 on success, -1 on failure - */ -int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) -{ - u8 *a, *r, b[16]; - int i, j; - void *ctx; - - a = cipher; - r = cipher + 8; - - /* 1) Initialize variables. */ - os_memset(a, 0xa6, 8); - os_memcpy(r, plain, 8 * n); - - ctx = aes_encrypt_init(kek, 16); - if (ctx == NULL) - return -1; - - /* 2) Calculate intermediate values. - * For j = 0 to 5 - * For i=1 to n - * B = AES(K, A | R[i]) - * A = MSB(64, B) ^ t where t = (n*j)+i - * R[i] = LSB(64, B) - */ - for (j = 0; j <= 5; j++) { - r = cipher + 8; - for (i = 1; i <= n; i++) { - os_memcpy(b, a, 8); - os_memcpy(b + 8, r, 8); - aes_encrypt(ctx, b, b); - os_memcpy(a, b, 8); - a[7] ^= n * j + i; - os_memcpy(r, b + 8, 8); - r += 8; - } - } - aes_encrypt_deinit(ctx); - - /* 3) Output the results. - * - * These are already in @cipher due to the location of temporary - * variables. - */ - - return 0; -} diff --git a/contrib/hostapd/src/crypto/aes.h b/contrib/hostapd/src/crypto/aes.h deleted file mode 100644 index 2de59e04ef..0000000000 --- a/contrib/hostapd/src/crypto/aes.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * AES functions - * Copyright (c) 2003-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef AES_H -#define AES_H - -#define AES_BLOCK_SIZE 16 - -void * aes_encrypt_init(const u8 *key, size_t len); -void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt); -void aes_encrypt_deinit(void *ctx); -void * aes_decrypt_init(const u8 *key, size_t len); -void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); -void aes_decrypt_deinit(void *ctx); - -#endif /* AES_H */ diff --git a/contrib/hostapd/src/crypto/aes_i.h b/contrib/hostapd/src/crypto/aes_i.h deleted file mode 100644 index 54375cf355..0000000000 --- a/contrib/hostapd/src/crypto/aes_i.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * AES (Rijndael) cipher - * Copyright (c) 2003-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef AES_I_H -#define AES_I_H - -#include "aes.h" - -/* #define FULL_UNROLL */ -#define AES_SMALL_TABLES - -extern const u32 Te0[256]; -extern const u32 Te1[256]; -extern const u32 Te2[256]; -extern const u32 Te3[256]; -extern const u32 Te4[256]; -extern const u32 Td0[256]; -extern const u32 Td1[256]; -extern const u32 Td2[256]; -extern const u32 Td3[256]; -extern const u32 Td4[256]; -extern const u32 rcon[10]; -extern const u8 Td4s[256]; -extern const u8 rcons[10]; - -#ifndef AES_SMALL_TABLES - -#define RCON(i) rcon[(i)] - -#define TE0(i) Te0[((i) >> 24) & 0xff] -#define TE1(i) Te1[((i) >> 16) & 0xff] -#define TE2(i) Te2[((i) >> 8) & 0xff] -#define TE3(i) Te3[(i) & 0xff] -#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000) -#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000) -#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00) -#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff) -#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000) -#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000) -#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00) -#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff) -#define TE411(i) (Te4[((i) >> 24) & 0xff] & 0xff000000) -#define TE422(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000) -#define TE433(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00) -#define TE444(i) (Te4[(i) & 0xff] & 0x000000ff) -#define TE4(i) (Te4[(i)] & 0x000000ff) - -#define TD0(i) Td0[((i) >> 24) & 0xff] -#define TD1(i) Td1[((i) >> 16) & 0xff] -#define TD2(i) Td2[((i) >> 8) & 0xff] -#define TD3(i) Td3[(i) & 0xff] -#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000) -#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000) -#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00) -#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff) -#define TD0_(i) Td0[(i) & 0xff] -#define TD1_(i) Td1[(i) & 0xff] -#define TD2_(i) Td2[(i) & 0xff] -#define TD3_(i) Td3[(i) & 0xff] - -#else /* AES_SMALL_TABLES */ - -#define RCON(i) (rcons[(i)] << 24) - -static inline u32 rotr(u32 val, int bits) -{ - return (val >> bits) | (val << (32 - bits)); -} - -#define TE0(i) Te0[((i) >> 24) & 0xff] -#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8) -#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16) -#define TE3(i) rotr(Te0[(i) & 0xff], 24) -#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) -#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) -#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) -#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) -#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000) -#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000) -#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00) -#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff) -#define TE411(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) -#define TE422(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) -#define TE433(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) -#define TE444(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) -#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff) - -#define TD0(i) Td0[((i) >> 24) & 0xff] -#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8) -#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16) -#define TD3(i) rotr(Td0[(i) & 0xff], 24) -#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24) -#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16) -#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8) -#define TD44(i) (Td4s[(i) & 0xff]) -#define TD0_(i) Td0[(i) & 0xff] -#define TD1_(i) rotr(Td0[(i) & 0xff], 8) -#define TD2_(i) rotr(Td0[(i) & 0xff], 16) -#define TD3_(i) rotr(Td0[(i) & 0xff], 24) - -#endif /* AES_SMALL_TABLES */ - -#ifdef _MSC_VER -#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) -#define GETU32(p) SWAP(*((u32 *)(p))) -#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); } -#else -#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \ -((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) -#define PUTU32(ct, st) { \ -(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \ -(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } -#endif - -#define AES_PRIV_SIZE (4 * 4 * 15 + 4) -#define AES_PRIV_NR_POS (4 * 15) - -int rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits); - -#endif /* AES_I_H */ diff --git a/contrib/hostapd/src/crypto/aes_wrap.h b/contrib/hostapd/src/crypto/aes_wrap.h deleted file mode 100644 index 0433c0434e..0000000000 --- a/contrib/hostapd/src/crypto/aes_wrap.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * AES-based functions - * - * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394) - * - One-Key CBC MAC (OMAC1) hash with AES-128 - * - AES-128 CTR mode encryption - * - AES-128 EAX mode encryption/decryption - * - AES-128 CBC - * - AES-GCM - * - AES-CCM - * - * Copyright (c) 2003-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef AES_WRAP_H -#define AES_WRAP_H - -int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher); -int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain); -int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem, - const u8 *addr[], const size_t *len, - u8 *mac); -int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, - u8 *mac); -int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out); -int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, - u8 *data, size_t data_len); -int __must_check aes_128_eax_encrypt(const u8 *key, - const u8 *nonce, size_t nonce_len, - const u8 *hdr, size_t hdr_len, - u8 *data, size_t data_len, u8 *tag); -int __must_check aes_128_eax_decrypt(const u8 *key, - const u8 *nonce, size_t nonce_len, - const u8 *hdr, size_t hdr_len, - u8 *data, size_t data_len, const u8 *tag); -int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, - size_t data_len); -int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, - size_t data_len); -int __must_check aes_gcm_ae(const u8 *key, size_t key_len, - const u8 *iv, size_t iv_len, - const u8 *plain, size_t plain_len, - const u8 *aad, size_t aad_len, - u8 *crypt, u8 *tag); -int __must_check aes_gcm_ad(const u8 *key, size_t key_len, - const u8 *iv, size_t iv_len, - const u8 *crypt, size_t crypt_len, - const u8 *aad, size_t aad_len, const u8 *tag, - u8 *plain); -int __must_check aes_gmac(const u8 *key, size_t key_len, - const u8 *iv, size_t iv_len, - const u8 *aad, size_t aad_len, u8 *tag); -int __must_check aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce, - size_t M, const u8 *plain, size_t plain_len, - const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth); -int __must_check aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce, - size_t M, const u8 *crypt, size_t crypt_len, - const u8 *aad, size_t aad_len, const u8 *auth, - u8 *plain); - -#endif /* AES_WRAP_H */ diff --git a/contrib/hostapd/src/crypto/crypto.h b/contrib/hostapd/src/crypto/crypto.h deleted file mode 100644 index 9bccaaa8f8..0000000000 --- a/contrib/hostapd/src/crypto/crypto.h +++ /dev/null @@ -1,785 +0,0 @@ -/* - * Wrapper functions for crypto libraries - * Copyright (c) 2004-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file defines the cryptographic functions that need to be implemented - * for wpa_supplicant and hostapd. When TLS is not used, internal - * implementation of MD5, SHA1, and AES is used and no external libraries are - * required. When TLS is enabled (e.g., by enabling EAP-TLS or EAP-PEAP), the - * crypto library used by the TLS implementation is expected to be used for - * non-TLS needs, too, in order to save space by not implementing these - * functions twice. - * - * Wrapper code for using each crypto library is in its own file (crypto*.c) - * and one of these files is build and linked in to provide the functions - * defined here. - */ - -#ifndef CRYPTO_H -#define CRYPTO_H - -/** - * md4_vector - MD4 hash for data vector - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash - * Returns: 0 on success, -1 on failure - */ -int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); - -/** - * md5_vector - MD5 hash for data vector - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash - * Returns: 0 on success, -1 on failure - */ -int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); - - -/** - * sha1_vector - SHA-1 hash for data vector - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash - * Returns: 0 on success, -1 on failure - */ -int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, - u8 *mac); - -/** - * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF - * @seed: Seed/key for the PRF - * @seed_len: Seed length in bytes - * @x: Buffer for PRF output - * @xlen: Output length in bytes - * Returns: 0 on success, -1 on failure - * - * This function implements random number generation specified in NIST FIPS - * Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to - * SHA-1, but has different message padding. - */ -int __must_check fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, - size_t xlen); - -/** - * sha256_vector - SHA256 hash for data vector - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash - * Returns: 0 on success, -1 on failure - */ -int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, - u8 *mac); - -/** - * des_encrypt - Encrypt one block with DES - * @clear: 8 octets (in) - * @key: 7 octets (in) (no parity bits included) - * @cypher: 8 octets (out) - */ -void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher); - -/** - * aes_encrypt_init - Initialize AES for encryption - * @key: Encryption key - * @len: Key length in bytes (usually 16, i.e., 128 bits) - * Returns: Pointer to context data or %NULL on failure - */ -void * aes_encrypt_init(const u8 *key, size_t len); - -/** - * aes_encrypt - Encrypt one AES block - * @ctx: Context pointer from aes_encrypt_init() - * @plain: Plaintext data to be encrypted (16 bytes) - * @crypt: Buffer for the encrypted data (16 bytes) - */ -void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt); - -/** - * aes_encrypt_deinit - Deinitialize AES encryption - * @ctx: Context pointer from aes_encrypt_init() - */ -void aes_encrypt_deinit(void *ctx); - -/** - * aes_decrypt_init - Initialize AES for decryption - * @key: Decryption key - * @len: Key length in bytes (usually 16, i.e., 128 bits) - * Returns: Pointer to context data or %NULL on failure - */ -void * aes_decrypt_init(const u8 *key, size_t len); - -/** - * aes_decrypt - Decrypt one AES block - * @ctx: Context pointer from aes_encrypt_init() - * @crypt: Encrypted data (16 bytes) - * @plain: Buffer for the decrypted data (16 bytes) - */ -void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); - -/** - * aes_decrypt_deinit - Deinitialize AES decryption - * @ctx: Context pointer from aes_encrypt_init() - */ -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_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256 -}; - -struct crypto_hash; - -/** - * crypto_hash_init - Initialize hash/HMAC function - * @alg: Hash algorithm - * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed - * @key_len: Length of the key in bytes - * Returns: Pointer to hash context to use with other hash functions or %NULL - * on failure - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, - size_t key_len); - -/** - * crypto_hash_update - Add data to hash calculation - * @ctx: Context pointer from crypto_hash_init() - * @data: Data buffer to add - * @len: Length of the buffer - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len); - -/** - * crypto_hash_finish - Complete hash calculation - * @ctx: Context pointer from crypto_hash_init() - * @hash: Buffer for hash value or %NULL if caller is just freeing the hash - * context - * @len: Pointer to length of the buffer or %NULL if caller is just freeing the - * hash context; on return, this is set to the actual length of the hash value - * Returns: 0 on success, -1 if buffer is too small (len set to needed length), - * or -2 on other failures (including failed crypto_hash_update() operations) - * - * This function calculates the hash value and frees the context buffer that - * was used for hash calculation. - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len); - - -enum crypto_cipher_alg { - CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES, - CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4 -}; - -struct crypto_cipher; - -/** - * crypto_cipher_init - Initialize block/stream cipher function - * @alg: Cipher algorithm - * @iv: Initialization vector for block ciphers or %NULL for stream ciphers - * @key: Cipher key - * @key_len: Length of key in bytes - * Returns: Pointer to cipher context to use with other cipher functions or - * %NULL on failure - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, - const u8 *iv, const u8 *key, - size_t key_len); - -/** - * crypto_cipher_encrypt - Cipher encrypt - * @ctx: Context pointer from crypto_cipher_init() - * @plain: Plaintext to cipher - * @crypt: Resulting ciphertext - * @len: Length of the plaintext - * Returns: 0 on success, -1 on failure - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -int __must_check crypto_cipher_encrypt(struct crypto_cipher *ctx, - const u8 *plain, u8 *crypt, size_t len); - -/** - * crypto_cipher_decrypt - Cipher decrypt - * @ctx: Context pointer from crypto_cipher_init() - * @crypt: Ciphertext to decrypt - * @plain: Resulting plaintext - * @len: Length of the cipher text - * Returns: 0 on success, -1 on failure - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -int __must_check crypto_cipher_decrypt(struct crypto_cipher *ctx, - const u8 *crypt, u8 *plain, size_t len); - -/** - * crypto_cipher_decrypt - Free cipher context - * @ctx: Context pointer from crypto_cipher_init() - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -void crypto_cipher_deinit(struct crypto_cipher *ctx); - - -struct crypto_public_key; -struct crypto_private_key; - -/** - * crypto_public_key_import - Import an RSA public key - * @key: Key buffer (DER encoded RSA public key) - * @len: Key buffer length in bytes - * Returns: Pointer to the public key or %NULL on failure - * - * This function can just return %NULL if the crypto library supports X.509 - * parsing. In that case, crypto_public_key_from_cert() is used to import the - * public key from a certificate. - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len); - -/** - * crypto_private_key_import - Import an RSA private key - * @key: Key buffer (DER encoded RSA private key) - * @len: Key buffer length in bytes - * @passwd: Key encryption password or %NULL if key is not encrypted - * Returns: Pointer to the private key or %NULL on failure - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -struct crypto_private_key * crypto_private_key_import(const u8 *key, - size_t len, - const char *passwd); - -/** - * crypto_public_key_from_cert - Import an RSA public key from a certificate - * @buf: DER encoded X.509 certificate - * @len: Certificate buffer length in bytes - * Returns: Pointer to public key or %NULL on failure - * - * This function can just return %NULL if the crypto library does not support - * X.509 parsing. In that case, internal code will be used to parse the - * certificate and public key is imported using crypto_public_key_import(). - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, - size_t len); - -/** - * crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5) - * @key: Public key - * @in: Plaintext buffer - * @inlen: Length of plaintext buffer in bytes - * @out: Output buffer for encrypted data - * @outlen: Length of output buffer in bytes; set to used length on success - * Returns: 0 on success, -1 on failure - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -int __must_check crypto_public_key_encrypt_pkcs1_v15( - struct crypto_public_key *key, const u8 *in, size_t inlen, - u8 *out, size_t *outlen); - -/** - * crypto_private_key_decrypt_pkcs1_v15 - Private key decryption (PKCS #1 v1.5) - * @key: Private key - * @in: Encrypted buffer - * @inlen: Length of encrypted buffer in bytes - * @out: Output buffer for encrypted data - * @outlen: Length of output buffer in bytes; set to used length on success - * Returns: 0 on success, -1 on failure - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -int __must_check crypto_private_key_decrypt_pkcs1_v15( - struct crypto_private_key *key, const u8 *in, size_t inlen, - u8 *out, size_t *outlen); - -/** - * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1) - * @key: Private key from crypto_private_key_import() - * @in: Plaintext buffer - * @inlen: Length of plaintext buffer in bytes - * @out: Output buffer for encrypted (signed) data - * @outlen: Length of output buffer in bytes; set to used length on success - * Returns: 0 on success, -1 on failure - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -int __must_check crypto_private_key_sign_pkcs1(struct crypto_private_key *key, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen); - -/** - * crypto_public_key_free - Free public key - * @key: Public key - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -void crypto_public_key_free(struct crypto_public_key *key); - -/** - * crypto_private_key_free - Free private key - * @key: Private key from crypto_private_key_import() - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -void crypto_private_key_free(struct crypto_private_key *key); - -/** - * crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature - * @key: Public key - * @crypt: Encrypted signature data (using the private key) - * @crypt_len: Encrypted signature data length - * @plain: Buffer for plaintext (at least crypt_len bytes) - * @plain_len: Plaintext length (max buffer size on input, real len on output); - * Returns: 0 on success, -1 on failure - */ -int __must_check crypto_public_key_decrypt_pkcs1( - struct crypto_public_key *key, const u8 *crypt, size_t crypt_len, - u8 *plain, size_t *plain_len); - -/** - * crypto_global_init - Initialize crypto wrapper - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -int __must_check crypto_global_init(void); - -/** - * crypto_global_deinit - Deinitialize crypto wrapper - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -void crypto_global_deinit(void); - -/** - * crypto_mod_exp - Modular exponentiation of large integers - * @base: Base integer (big endian byte array) - * @base_len: Length of base integer in bytes - * @power: Power integer (big endian byte array) - * @power_len: Length of power integer in bytes - * @modulus: Modulus integer (big endian byte array) - * @modulus_len: Length of modulus integer in bytes - * @result: Buffer for the result - * @result_len: Result length (max buffer size on input, real len on output) - * Returns: 0 on success, -1 on failure - * - * This function calculates result = base ^ power mod modulus. modules_len is - * used as the maximum size of modulus buffer. It is set to the used size on - * success. - * - * This function is only used with internal TLSv1 implementation - * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need - * to implement this. - */ -int __must_check crypto_mod_exp(const u8 *base, size_t base_len, - const u8 *power, size_t power_len, - const u8 *modulus, size_t modulus_len, - u8 *result, size_t *result_len); - -/** - * rc4_skip - XOR RC4 stream to given data with skip-stream-start - * @key: RC4 key - * @keylen: RC4 key length - * @skip: number of bytes to skip from the beginning of the RC4 stream - * @data: data to be XOR'ed with RC4 stream - * @data_len: buf length - * Returns: 0 on success, -1 on failure - * - * Generate RC4 pseudo random stream for the given key, skip beginning of the - * stream, and XOR the end result with the data buffer to perform RC4 - * encryption/decryption. - */ -int rc4_skip(const u8 *key, size_t keylen, size_t skip, - u8 *data, size_t data_len); - -/** - * crypto_get_random - Generate cryptographically strong pseudy-random bytes - * @buf: Buffer for data - * @len: Number of bytes to generate - * Returns: 0 on success, -1 on failure - * - * If the PRNG does not have enough entropy to ensure unpredictable byte - * sequence, this functions must return -1. - */ -int crypto_get_random(void *buf, size_t len); - - -/** - * struct crypto_bignum - bignum - * - * Internal data structure for bignum implementation. The contents is specific - * to the used crypto library. - */ -struct crypto_bignum; - -/** - * crypto_bignum_init - Allocate memory for bignum - * Returns: Pointer to allocated bignum or %NULL on failure - */ -struct crypto_bignum * crypto_bignum_init(void); - -/** - * crypto_bignum_init_set - Allocate memory for bignum and set the value - * @buf: Buffer with unsigned binary value - * @len: Length of buf in octets - * Returns: Pointer to allocated bignum or %NULL on failure - */ -struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len); - -/** - * crypto_bignum_deinit - Free bignum - * @n: Bignum from crypto_bignum_init() or crypto_bignum_init_set() - * @clear: Whether to clear the value from memory - */ -void crypto_bignum_deinit(struct crypto_bignum *n, int clear); - -/** - * crypto_bignum_to_bin - Set binary buffer to unsigned bignum - * @a: Bignum - * @buf: Buffer for the binary number - * @len: Length of @buf in octets - * @padlen: Length in octets to pad the result to or 0 to indicate no padding - * Returns: Number of octets written on success, -1 on failure - */ -int crypto_bignum_to_bin(const struct crypto_bignum *a, - u8 *buf, size_t buflen, size_t padlen); - -/** - * crypto_bignum_add - c = a + b - * @a: Bignum - * @b: Bignum - * @c: Bignum; used to store the result of a + b - * Returns: 0 on success, -1 on failure - */ -int crypto_bignum_add(const struct crypto_bignum *a, - const struct crypto_bignum *b, - struct crypto_bignum *c); - -/** - * crypto_bignum_mod - c = a % b - * @a: Bignum - * @b: Bignum - * @c: Bignum; used to store the result of a % b - * Returns: 0 on success, -1 on failure - */ -int crypto_bignum_mod(const struct crypto_bignum *a, - const struct crypto_bignum *b, - struct crypto_bignum *c); - -/** - * crypto_bignum_exptmod - Modular exponentiation: d = a^b (mod c) - * @a: Bignum; base - * @b: Bignum; exponent - * @c: Bignum; modulus - * @d: Bignum; used to store the result of a^b (mod c) - * Returns: 0 on success, -1 on failure - */ -int crypto_bignum_exptmod(const struct crypto_bignum *a, - const struct crypto_bignum *b, - const struct crypto_bignum *c, - struct crypto_bignum *d); - -/** - * crypto_bignum_rshift - b = a >> n - * @a: Bignum - * @n: Number of bits to shift - * @b: Bignum; used to store the result of a >> n - * Returns: 0 on success, -1 on failure - */ -int crypto_bignum_rshift(const struct crypto_bignum *a, int n, - struct crypto_bignum *b); - -/** - * crypto_bignum_inverse - Inverse a bignum so that a * c = 1 (mod b) - * @a: Bignum - * @b: Bignum - * @c: Bignum; used to store the result - * Returns: 0 on success, -1 on failure - */ -int crypto_bignum_inverse(const struct crypto_bignum *a, - const struct crypto_bignum *b, - struct crypto_bignum *c); - -/** - * crypto_bignum_sub - c = a - b - * @a: Bignum - * @b: Bignum - * @c: Bignum; used to store the result of a - b - * Returns: 0 on success, -1 on failure - */ -int crypto_bignum_sub(const struct crypto_bignum *a, - const struct crypto_bignum *b, - struct crypto_bignum *c); - -/** - * crypto_bignum_div - c = a / b - * @a: Bignum - * @b: Bignum - * @c: Bignum; used to store the result of a / b - * Returns: 0 on success, -1 on failure - */ -int crypto_bignum_div(const struct crypto_bignum *a, - const struct crypto_bignum *b, - struct crypto_bignum *c); - -/** - * crypto_bignum_mulmod - d = a * b (mod c) - * @a: Bignum - * @b: Bignum - * @c: Bignum - * @d: Bignum; used to store the result of (a * b) % c - * Returns: 0 on success, -1 on failure - */ -int crypto_bignum_mulmod(const struct crypto_bignum *a, - const struct crypto_bignum *b, - const struct crypto_bignum *c, - struct crypto_bignum *d); - -/** - * crypto_bignum_cmp - Compare two bignums - * @a: Bignum - * @b: Bignum - * Returns: -1 if a < b, 0 if a == b, or 1 if a > b - */ -int crypto_bignum_cmp(const struct crypto_bignum *a, - const struct crypto_bignum *b); - -/** - * crypto_bignum_bits - Get size of a bignum in bits - * @a: Bignum - * Returns: Number of bits in the bignum - */ -int crypto_bignum_bits(const struct crypto_bignum *a); - -/** - * crypto_bignum_is_zero - Is the given bignum zero - * @a: Bignum - * Returns: 1 if @a is zero or 0 if not - */ -int crypto_bignum_is_zero(const struct crypto_bignum *a); - -/** - * crypto_bignum_is_one - Is the given bignum one - * @a: Bignum - * Returns: 1 if @a is one or 0 if not - */ -int crypto_bignum_is_one(const struct crypto_bignum *a); - -/** - * struct crypto_ec - Elliptic curve context - * - * Internal data structure for EC implementation. The contents is specific - * to the used crypto library. - */ -struct crypto_ec; - -/** - * crypto_ec_init - Initialize elliptic curve context - * @group: Identifying number for the ECC group (IANA "Group Description" - * attribute registrty for RFC 2409) - * Returns: Pointer to EC context or %NULL on failure - */ -struct crypto_ec * crypto_ec_init(int group); - -/** - * crypto_ec_deinit - Deinitialize elliptic curve context - * @e: EC context from crypto_ec_init() - */ -void crypto_ec_deinit(struct crypto_ec *e); - -/** - * crypto_ec_prime_len - Get length of the prime in octets - * @e: EC context from crypto_ec_init() - * Returns: Length of the prime defining the group - */ -size_t crypto_ec_prime_len(struct crypto_ec *e); - -/** - * crypto_ec_prime_len_bits - Get length of the prime in bits - * @e: EC context from crypto_ec_init() - * Returns: Length of the prime defining the group in bits - */ -size_t crypto_ec_prime_len_bits(struct crypto_ec *e); - -/** - * crypto_ec_get_prime - Get prime defining an EC group - * @e: EC context from crypto_ec_init() - * Returns: Prime (bignum) defining the group - */ -const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e); - -/** - * crypto_ec_get_order - Get order of an EC group - * @e: EC context from crypto_ec_init() - * Returns: Order (bignum) of the group - */ -const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e); - -/** - * struct crypto_ec_point - Elliptic curve point - * - * Internal data structure for EC implementation to represent a point. The - * contents is specific to the used crypto library. - */ -struct crypto_ec_point; - -/** - * crypto_ec_point_init - Initialize data for an EC point - * @e: EC context from crypto_ec_init() - * Returns: Pointer to EC point data or %NULL on failure - */ -struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e); - -/** - * crypto_ec_point_deinit - Deinitialize EC point data - * @p: EC point data from crypto_ec_point_init() - * @clear: Whether to clear the EC point value from memory - */ -void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear); - -/** - * crypto_ec_point_to_bin - Write EC point value as binary data - * @e: EC context from crypto_ec_init() - * @p: EC point data from crypto_ec_point_init() - * @x: Buffer for writing the binary data for x coordinate or %NULL if not used - * @y: Buffer for writing the binary data for y coordinate or %NULL if not used - * Returns: 0 on success, -1 on failure - * - * This function can be used to write an EC point as binary data in a format - * that has the x and y coordinates in big endian byte order fields padded to - * the length of the prime defining the group. - */ -int crypto_ec_point_to_bin(struct crypto_ec *e, - const struct crypto_ec_point *point, u8 *x, u8 *y); - -/** - * crypto_ec_point_from_bin - Create EC point from binary data - * @e: EC context from crypto_ec_init() - * @val: Binary data to read the EC point from - * Returns: Pointer to EC point data or %NULL on failure - * - * This function readers x and y coordinates of the EC point from the provided - * buffer assuming the values are in big endian byte order with fields padded to - * the length of the prime defining the group. - */ -struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e, - const u8 *val); - -/** - * crypto_bignum_add - c = a + b - * @e: EC context from crypto_ec_init() - * @a: Bignum - * @b: Bignum - * @c: Bignum; used to store the result of a + b - * Returns: 0 on success, -1 on failure - */ -int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a, - const struct crypto_ec_point *b, - struct crypto_ec_point *c); - -/** - * crypto_bignum_mul - res = b * p - * @e: EC context from crypto_ec_init() - * @p: EC point - * @b: Bignum - * @res: EC point; used to store the result of b * p - * Returns: 0 on success, -1 on failure - */ -int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p, - const struct crypto_bignum *b, - struct crypto_ec_point *res); - -/** - * crypto_ec_point_invert - Compute inverse of an EC point - * @e: EC context from crypto_ec_init() - * @p: EC point to invert (and result of the operation) - * Returns: 0 on success, -1 on failure - */ -int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p); - -/** - * crypto_ec_point_solve_y_coord - Solve y coordinate for an x coordinate - * @e: EC context from crypto_ec_init() - * @p: EC point to use for the returning the result - * @x: x coordinate - * @y_bit: y-bit (0 or 1) for selecting the y value to use - * Returns: 0 on success, -1 on failure - */ -int crypto_ec_point_solve_y_coord(struct crypto_ec *e, - struct crypto_ec_point *p, - const struct crypto_bignum *x, int y_bit); - -/** - * crypto_ec_point_is_at_infinity - Check whether EC point is neutral element - * @e: EC context from crypto_ec_init() - * @p: EC point - * Returns: 1 if the specified EC point is the neutral element of the group or - * 0 if not - */ -int crypto_ec_point_is_at_infinity(struct crypto_ec *e, - const struct crypto_ec_point *p); - -/** - * crypto_ec_point_is_on_curve - Check whether EC point is on curve - * @e: EC context from crypto_ec_init() - * @p: EC point - * Returns: 1 if the specified EC point is on the curve or 0 if not - */ -int crypto_ec_point_is_on_curve(struct crypto_ec *e, - const struct crypto_ec_point *p); - -#endif /* CRYPTO_H */ diff --git a/contrib/hostapd/src/crypto/crypto_cryptoapi.c b/contrib/hostapd/src/crypto/crypto_cryptoapi.c deleted file mode 100644 index 55a069b0d0..0000000000 --- a/contrib/hostapd/src/crypto/crypto_cryptoapi.c +++ /dev/null @@ -1,783 +0,0 @@ -/* - * Crypto wrapper for Microsoft CryptoAPI - * Copyright (c) 2005-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include -#include - -#include "common.h" -#include "crypto.h" - -#ifndef MS_ENH_RSA_AES_PROV -#ifdef UNICODE -#define MS_ENH_RSA_AES_PROV \ -L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" -#else -#define MS_ENH_RSA_AES_PROV \ -"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" -#endif -#endif /* MS_ENH_RSA_AES_PROV */ - -#ifndef CALG_HMAC -#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC) -#endif - -#ifdef __MINGW32_VERSION -/* - * MinGW does not yet include all the needed definitions for CryptoAPI, so - * define here whatever extra is needed. - */ - -static BOOL WINAPI -(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType, - PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey) -= NULL; /* to be loaded from crypt32.dll */ - - -static int mingw_load_crypto_func(void) -{ - HINSTANCE dll; - - /* MinGW does not yet have full CryptoAPI support, so load the needed - * function here. */ - - if (CryptImportPublicKeyInfo) - return 0; - - dll = LoadLibrary("crypt32"); - if (dll == NULL) { - wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 " - "library"); - return -1; - } - - CryptImportPublicKeyInfo = GetProcAddress( - dll, "CryptImportPublicKeyInfo"); - if (CryptImportPublicKeyInfo == NULL) { - wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get " - "CryptImportPublicKeyInfo() address from " - "crypt32 library"); - return -1; - } - - return 0; -} - -#else /* __MINGW32_VERSION */ - -static int mingw_load_crypto_func(void) -{ - return 0; -} - -#endif /* __MINGW32_VERSION */ - - -static void cryptoapi_report_error(const char *msg) -{ - char *s, *pos; - DWORD err = GetLastError(); - - if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) { - wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err); - } - - pos = s; - while (*pos) { - if (*pos == '\n' || *pos == '\r') { - *pos = '\0'; - break; - } - pos++; - } - - wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s); - LocalFree(s); -} - - -int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac) -{ - HCRYPTPROV prov; - HCRYPTHASH hash; - size_t i; - DWORD hlen; - int ret = 0; - - if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) { - cryptoapi_report_error("CryptAcquireContext"); - return -1; - } - - if (!CryptCreateHash(prov, alg, 0, 0, &hash)) { - cryptoapi_report_error("CryptCreateHash"); - CryptReleaseContext(prov, 0); - return -1; - } - - for (i = 0; i < num_elem; i++) { - if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) { - cryptoapi_report_error("CryptHashData"); - CryptDestroyHash(hash); - CryptReleaseContext(prov, 0); - } - } - - hlen = hash_len; - if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) { - cryptoapi_report_error("CryptGetHashParam"); - ret = -1; - } - - CryptDestroyHash(hash); - CryptReleaseContext(prov, 0); - - return ret; -} - - -int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac); -} - - -void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -{ - u8 next, tmp; - int i; - HCRYPTPROV prov; - HCRYPTKEY ckey; - DWORD dlen; - struct { - BLOBHEADER hdr; - DWORD len; - BYTE key[8]; - } key_blob; - DWORD mode = CRYPT_MODE_ECB; - - key_blob.hdr.bType = PLAINTEXTKEYBLOB; - key_blob.hdr.bVersion = CUR_BLOB_VERSION; - key_blob.hdr.reserved = 0; - key_blob.hdr.aiKeyAlg = CALG_DES; - key_blob.len = 8; - - /* Add parity bits to the key */ - next = 0; - for (i = 0; i < 7; i++) { - tmp = key[i]; - key_blob.key[i] = (tmp >> i) | next | 1; - next = tmp << (7 - i); - } - key_blob.key[i] = next | 1; - - if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) { - wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " - "%d", (int) GetLastError()); - return; - } - - if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0, - &ckey)) { - wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", - (int) GetLastError()); - CryptReleaseContext(prov, 0); - return; - } - - if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) { - wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " - "failed: %d", (int) GetLastError()); - CryptDestroyKey(ckey); - CryptReleaseContext(prov, 0); - return; - } - - os_memcpy(cypher, clear, 8); - dlen = 8; - if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) { - wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", - (int) GetLastError()); - os_memset(cypher, 0, 8); - } - - CryptDestroyKey(ckey); - CryptReleaseContext(prov, 0); -} - - -int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac); -} - - -int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac); -} - - -struct aes_context { - HCRYPTPROV prov; - HCRYPTKEY ckey; -}; - - -void * aes_encrypt_init(const u8 *key, size_t len) -{ - struct aes_context *akey; - struct { - BLOBHEADER hdr; - DWORD len; - BYTE key[16]; - } key_blob; - DWORD mode = CRYPT_MODE_ECB; - - if (len != 16) - return NULL; - - key_blob.hdr.bType = PLAINTEXTKEYBLOB; - key_blob.hdr.bVersion = CUR_BLOB_VERSION; - key_blob.hdr.reserved = 0; - key_blob.hdr.aiKeyAlg = CALG_AES_128; - key_blob.len = len; - os_memcpy(key_blob.key, key, len); - - akey = os_zalloc(sizeof(*akey)); - if (akey == NULL) - return NULL; - - if (!CryptAcquireContext(&akey->prov, NULL, - MS_ENH_RSA_AES_PROV, PROV_RSA_AES, - CRYPT_VERIFYCONTEXT)) { - wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " - "%d", (int) GetLastError()); - os_free(akey); - return NULL; - } - - if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob), - 0, 0, &akey->ckey)) { - wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", - (int) GetLastError()); - CryptReleaseContext(akey->prov, 0); - os_free(akey); - return NULL; - } - - if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) { - wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " - "failed: %d", (int) GetLastError()); - CryptDestroyKey(akey->ckey); - CryptReleaseContext(akey->prov, 0); - os_free(akey); - return NULL; - } - - return akey; -} - - -void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -{ - struct aes_context *akey = ctx; - DWORD dlen; - - os_memcpy(crypt, plain, 16); - dlen = 16; - if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) { - wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", - (int) GetLastError()); - os_memset(crypt, 0, 16); - } -} - - -void aes_encrypt_deinit(void *ctx) -{ - struct aes_context *akey = ctx; - if (akey) { - CryptDestroyKey(akey->ckey); - CryptReleaseContext(akey->prov, 0); - os_free(akey); - } -} - - -void * aes_decrypt_init(const u8 *key, size_t len) -{ - return aes_encrypt_init(key, len); -} - - -void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) -{ - struct aes_context *akey = ctx; - DWORD dlen; - - os_memcpy(plain, crypt, 16); - dlen = 16; - - if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) { - wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d", - (int) GetLastError()); - } -} - - -void aes_decrypt_deinit(void *ctx) -{ - aes_encrypt_deinit(ctx); -} - - -struct crypto_hash { - enum crypto_hash_alg alg; - int error; - HCRYPTPROV prov; - HCRYPTHASH hash; - HCRYPTKEY key; -}; - -struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, - size_t key_len) -{ - struct crypto_hash *ctx; - ALG_ID calg; - struct { - BLOBHEADER hdr; - DWORD len; - BYTE key[32]; - } key_blob; - - os_memset(&key_blob, 0, sizeof(key_blob)); - switch (alg) { - case CRYPTO_HASH_ALG_MD5: - calg = CALG_MD5; - break; - case CRYPTO_HASH_ALG_SHA1: - calg = CALG_SHA; - break; - case CRYPTO_HASH_ALG_HMAC_MD5: - case CRYPTO_HASH_ALG_HMAC_SHA1: - calg = CALG_HMAC; - key_blob.hdr.bType = PLAINTEXTKEYBLOB; - key_blob.hdr.bVersion = CUR_BLOB_VERSION; - key_blob.hdr.reserved = 0; - /* - * Note: RC2 is not really used, but that can be used to - * import HMAC keys of up to 16 byte long. - * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to - * be able to import longer keys (HMAC-SHA1 uses 20-byte key). - */ - key_blob.hdr.aiKeyAlg = CALG_RC2; - key_blob.len = key_len; - if (key_len > sizeof(key_blob.key)) - return NULL; - os_memcpy(key_blob.key, key, key_len); - break; - default: - return NULL; - } - - ctx = os_zalloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - - ctx->alg = alg; - - if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) { - cryptoapi_report_error("CryptAcquireContext"); - os_free(ctx); - return NULL; - } - - if (calg == CALG_HMAC) { -#ifndef CRYPT_IPSEC_HMAC_KEY -#define CRYPT_IPSEC_HMAC_KEY 0x00000100 -#endif - if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, - sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY, - &ctx->key)) { - cryptoapi_report_error("CryptImportKey"); - CryptReleaseContext(ctx->prov, 0); - os_free(ctx); - return NULL; - } - } - - if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) { - cryptoapi_report_error("CryptCreateHash"); - CryptReleaseContext(ctx->prov, 0); - os_free(ctx); - return NULL; - } - - if (calg == CALG_HMAC) { - HMAC_INFO info; - os_memset(&info, 0, sizeof(info)); - switch (alg) { - case CRYPTO_HASH_ALG_HMAC_MD5: - info.HashAlgid = CALG_MD5; - break; - case CRYPTO_HASH_ALG_HMAC_SHA1: - info.HashAlgid = CALG_SHA; - break; - default: - /* unreachable */ - break; - } - - if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info, - 0)) { - cryptoapi_report_error("CryptSetHashParam"); - CryptDestroyHash(ctx->hash); - CryptReleaseContext(ctx->prov, 0); - os_free(ctx); - return NULL; - } - } - - return ctx; -} - - -void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) -{ - if (ctx == NULL || ctx->error) - return; - - if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) { - cryptoapi_report_error("CryptHashData"); - ctx->error = 1; - } -} - - -int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) -{ - int ret = 0; - DWORD hlen; - - if (ctx == NULL) - return -2; - - if (mac == NULL || len == NULL) - goto done; - - if (ctx->error) { - ret = -2; - goto done; - } - - hlen = *len; - if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) { - cryptoapi_report_error("CryptGetHashParam"); - ret = -2; - } - *len = hlen; - -done: - if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 || - ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5) - CryptDestroyKey(ctx->key); - - os_free(ctx); - - return ret; -} - - -struct crypto_cipher { - HCRYPTPROV prov; - HCRYPTKEY key; -}; - - -struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, - const u8 *iv, const u8 *key, - size_t key_len) -{ - struct crypto_cipher *ctx; - struct { - BLOBHEADER hdr; - DWORD len; - BYTE key[32]; - } key_blob; - DWORD mode = CRYPT_MODE_CBC; - - key_blob.hdr.bType = PLAINTEXTKEYBLOB; - key_blob.hdr.bVersion = CUR_BLOB_VERSION; - key_blob.hdr.reserved = 0; - key_blob.len = key_len; - if (key_len > sizeof(key_blob.key)) - return NULL; - os_memcpy(key_blob.key, key, key_len); - - switch (alg) { - case CRYPTO_CIPHER_ALG_AES: - if (key_len == 32) - key_blob.hdr.aiKeyAlg = CALG_AES_256; - else if (key_len == 24) - key_blob.hdr.aiKeyAlg = CALG_AES_192; - else - key_blob.hdr.aiKeyAlg = CALG_AES_128; - break; - case CRYPTO_CIPHER_ALG_3DES: - key_blob.hdr.aiKeyAlg = CALG_3DES; - break; - case CRYPTO_CIPHER_ALG_DES: - key_blob.hdr.aiKeyAlg = CALG_DES; - break; - case CRYPTO_CIPHER_ALG_RC2: - key_blob.hdr.aiKeyAlg = CALG_RC2; - break; - case CRYPTO_CIPHER_ALG_RC4: - key_blob.hdr.aiKeyAlg = CALG_RC4; - break; - default: - return NULL; - } - - ctx = os_zalloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - - if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV, - PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { - cryptoapi_report_error("CryptAcquireContext"); - goto fail1; - } - - if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, - sizeof(key_blob), 0, 0, &ctx->key)) { - cryptoapi_report_error("CryptImportKey"); - goto fail2; - } - - if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) { - cryptoapi_report_error("CryptSetKeyParam(KP_MODE)"); - goto fail3; - } - - if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) { - cryptoapi_report_error("CryptSetKeyParam(KP_IV)"); - goto fail3; - } - - return ctx; - -fail3: - CryptDestroyKey(ctx->key); -fail2: - CryptReleaseContext(ctx->prov, 0); -fail1: - os_free(ctx); - return NULL; -} - - -int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, - u8 *crypt, size_t len) -{ - DWORD dlen; - - os_memcpy(crypt, plain, len); - dlen = len; - if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) { - cryptoapi_report_error("CryptEncrypt"); - os_memset(crypt, 0, len); - return -1; - } - - return 0; -} - - -int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, - u8 *plain, size_t len) -{ - DWORD dlen; - - os_memcpy(plain, crypt, len); - dlen = len; - if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) { - cryptoapi_report_error("CryptDecrypt"); - return -1; - } - - return 0; -} - - -void crypto_cipher_deinit(struct crypto_cipher *ctx) -{ - CryptDestroyKey(ctx->key); - CryptReleaseContext(ctx->prov, 0); - os_free(ctx); -} - - -struct crypto_public_key { - HCRYPTPROV prov; - HCRYPTKEY rsa; -}; - -struct crypto_private_key { - HCRYPTPROV prov; - HCRYPTKEY rsa; -}; - - -struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) -{ - /* Use crypto_public_key_from_cert() instead. */ - return NULL; -} - - -struct crypto_private_key * crypto_private_key_import(const u8 *key, - size_t len, - const char *passwd) -{ - /* TODO */ - return NULL; -} - - -struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, - size_t len) -{ - struct crypto_public_key *pk; - PCCERT_CONTEXT cc; - - pk = os_zalloc(sizeof(*pk)); - if (pk == NULL) - return NULL; - - cc = CertCreateCertificateContext(X509_ASN_ENCODING | - PKCS_7_ASN_ENCODING, buf, len); - if (!cc) { - cryptoapi_report_error("CryptCreateCertificateContext"); - os_free(pk); - return NULL; - } - - if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, - 0)) { - cryptoapi_report_error("CryptAcquireContext"); - os_free(pk); - CertFreeCertificateContext(cc); - return NULL; - } - - if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING | - PKCS_7_ASN_ENCODING, - &cc->pCertInfo->SubjectPublicKeyInfo, - &pk->rsa)) { - cryptoapi_report_error("CryptImportPublicKeyInfo"); - CryptReleaseContext(pk->prov, 0); - os_free(pk); - CertFreeCertificateContext(cc); - return NULL; - } - - CertFreeCertificateContext(cc); - - return pk; -} - - -int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - DWORD clen; - u8 *tmp; - size_t i; - - if (*outlen < inlen) - return -1; - tmp = malloc(*outlen); - if (tmp == NULL) - return -1; - - os_memcpy(tmp, in, inlen); - clen = inlen; - if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) { - wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using " - "public key: %d", (int) GetLastError()); - os_free(tmp); - return -1; - } - - *outlen = clen; - - /* Reverse the output */ - for (i = 0; i < *outlen; i++) - out[i] = tmp[*outlen - 1 - i]; - - os_free(tmp); - - return 0; -} - - -int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - /* TODO */ - return -1; -} - - -void crypto_public_key_free(struct crypto_public_key *key) -{ - if (key) { - CryptDestroyKey(key->rsa); - CryptReleaseContext(key->prov, 0); - os_free(key); - } -} - - -void crypto_private_key_free(struct crypto_private_key *key) -{ - if (key) { - CryptDestroyKey(key->rsa); - CryptReleaseContext(key->prov, 0); - os_free(key); - } -} - - -int crypto_global_init(void) -{ - return mingw_load_crypto_func(); -} - - -void crypto_global_deinit(void) -{ -} - - -int crypto_mod_exp(const u8 *base, size_t base_len, - const u8 *power, size_t power_len, - const u8 *modulus, size_t modulus_len, - u8 *result, size_t *result_len) -{ - /* TODO */ - return -1; -} diff --git a/contrib/hostapd/src/crypto/crypto_gnutls.c b/contrib/hostapd/src/crypto/crypto_gnutls.c deleted file mode 100644 index 0dfd54d22d..0000000000 --- a/contrib/hostapd/src/crypto/crypto_gnutls.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * WPA Supplicant / wrapper functions for libgcrypt - * Copyright (c) 2004-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "crypto.h" - -int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - gcry_md_hd_t hd; - unsigned char *p; - size_t i; - - if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR) - return -1; - for (i = 0; i < num_elem; i++) - gcry_md_write(hd, addr[i], len[i]); - p = gcry_md_read(hd, GCRY_MD_MD4); - if (p) - memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4)); - gcry_md_close(hd); - return 0; -} - - -void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -{ - gcry_cipher_hd_t hd; - u8 pkey[8], next, tmp; - int i; - - /* Add parity bits to the key */ - next = 0; - for (i = 0; i < 7; i++) { - tmp = key[i]; - pkey[i] = (tmp >> i) | next | 1; - next = tmp << (7 - i); - } - pkey[i] = next | 1; - - gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - gcry_err_code(gcry_cipher_setkey(hd, pkey, 8)); - gcry_cipher_encrypt(hd, cypher, 8, clear, 8); - gcry_cipher_close(hd); -} - - -int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - gcry_md_hd_t hd; - unsigned char *p; - size_t i; - - if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR) - return -1; - for (i = 0; i < num_elem; i++) - gcry_md_write(hd, addr[i], len[i]); - p = gcry_md_read(hd, GCRY_MD_MD5); - if (p) - memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5)); - gcry_md_close(hd); - return 0; -} - - -int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - gcry_md_hd_t hd; - unsigned char *p; - size_t i; - - if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR) - return -1; - for (i = 0; i < num_elem; i++) - gcry_md_write(hd, addr[i], len[i]); - p = gcry_md_read(hd, GCRY_MD_SHA1); - if (p) - memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1)); - gcry_md_close(hd); - return 0; -} - - -void * aes_encrypt_init(const u8 *key, size_t len) -{ - gcry_cipher_hd_t hd; - - if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) != - GPG_ERR_NO_ERROR) { - printf("cipher open failed\n"); - return NULL; - } - if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) { - printf("setkey failed\n"); - gcry_cipher_close(hd); - return NULL; - } - - return hd; -} - - -void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -{ - gcry_cipher_hd_t hd = ctx; - gcry_cipher_encrypt(hd, crypt, 16, plain, 16); -} - - -void aes_encrypt_deinit(void *ctx) -{ - gcry_cipher_hd_t hd = ctx; - gcry_cipher_close(hd); -} - - -void * aes_decrypt_init(const u8 *key, size_t len) -{ - gcry_cipher_hd_t hd; - - if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) != - GPG_ERR_NO_ERROR) - return NULL; - if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) { - gcry_cipher_close(hd); - return NULL; - } - - return hd; -} - - -void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) -{ - gcry_cipher_hd_t hd = ctx; - gcry_cipher_decrypt(hd, plain, 16, crypt, 16); -} - - -void aes_decrypt_deinit(void *ctx) -{ - gcry_cipher_hd_t hd = ctx; - gcry_cipher_close(hd); -} - - -int crypto_mod_exp(const u8 *base, size_t base_len, - const u8 *power, size_t power_len, - const u8 *modulus, size_t modulus_len, - u8 *result, size_t *result_len) -{ - gcry_mpi_t bn_base = NULL, bn_exp = NULL, bn_modulus = NULL, - bn_result = NULL; - int ret = -1; - - if (gcry_mpi_scan(&bn_base, GCRYMPI_FMT_USG, base, base_len, NULL) != - GPG_ERR_NO_ERROR || - gcry_mpi_scan(&bn_exp, GCRYMPI_FMT_USG, power, power_len, NULL) != - GPG_ERR_NO_ERROR || - gcry_mpi_scan(&bn_modulus, GCRYMPI_FMT_USG, modulus, modulus_len, - NULL) != GPG_ERR_NO_ERROR) - goto error; - bn_result = gcry_mpi_new(modulus_len * 8); - - gcry_mpi_powm(bn_result, bn_base, bn_exp, bn_modulus); - - if (gcry_mpi_print(GCRYMPI_FMT_USG, result, *result_len, result_len, - bn_result) != GPG_ERR_NO_ERROR) - goto error; - - ret = 0; - -error: - gcry_mpi_release(bn_base); - gcry_mpi_release(bn_exp); - gcry_mpi_release(bn_modulus); - gcry_mpi_release(bn_result); - return ret; -} - - -struct crypto_cipher { - gcry_cipher_hd_t enc; - gcry_cipher_hd_t dec; -}; - - -struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, - const u8 *iv, const u8 *key, - size_t key_len) -{ - struct crypto_cipher *ctx; - gcry_error_t res; - enum gcry_cipher_algos a; - int ivlen; - - ctx = os_zalloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - - switch (alg) { - case CRYPTO_CIPHER_ALG_RC4: - a = GCRY_CIPHER_ARCFOUR; - res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_STREAM, - 0); - gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_STREAM, 0); - break; - case CRYPTO_CIPHER_ALG_AES: - if (key_len == 24) - a = GCRY_CIPHER_AES192; - else if (key_len == 32) - a = GCRY_CIPHER_AES256; - else - a = GCRY_CIPHER_AES; - res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0); - gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0); - break; - case CRYPTO_CIPHER_ALG_3DES: - a = GCRY_CIPHER_3DES; - res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0); - gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0); - break; - case CRYPTO_CIPHER_ALG_DES: - a = GCRY_CIPHER_DES; - res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0); - gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0); - break; - case CRYPTO_CIPHER_ALG_RC2: - if (key_len == 5) - a = GCRY_CIPHER_RFC2268_40; - else - a = GCRY_CIPHER_RFC2268_128; - res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0); - gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0); - break; - default: - os_free(ctx); - return NULL; - } - - if (res != GPG_ERR_NO_ERROR) { - os_free(ctx); - return NULL; - } - - if (gcry_cipher_setkey(ctx->enc, key, key_len) != GPG_ERR_NO_ERROR || - gcry_cipher_setkey(ctx->dec, key, key_len) != GPG_ERR_NO_ERROR) { - gcry_cipher_close(ctx->enc); - gcry_cipher_close(ctx->dec); - os_free(ctx); - return NULL; - } - - ivlen = gcry_cipher_get_algo_blklen(a); - if (gcry_cipher_setiv(ctx->enc, iv, ivlen) != GPG_ERR_NO_ERROR || - gcry_cipher_setiv(ctx->dec, iv, ivlen) != GPG_ERR_NO_ERROR) { - gcry_cipher_close(ctx->enc); - gcry_cipher_close(ctx->dec); - os_free(ctx); - return NULL; - } - - return ctx; -} - - -int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, - u8 *crypt, size_t len) -{ - if (gcry_cipher_encrypt(ctx->enc, crypt, len, plain, len) != - GPG_ERR_NO_ERROR) - return -1; - return 0; -} - - -int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, - u8 *plain, size_t len) -{ - if (gcry_cipher_decrypt(ctx->dec, plain, len, crypt, len) != - GPG_ERR_NO_ERROR) - return -1; - return 0; -} - - -void crypto_cipher_deinit(struct crypto_cipher *ctx) -{ - gcry_cipher_close(ctx->enc); - gcry_cipher_close(ctx->dec); - os_free(ctx); -} diff --git a/contrib/hostapd/src/crypto/crypto_internal-cipher.c b/contrib/hostapd/src/crypto/crypto_internal-cipher.c deleted file mode 100644 index ad0930a5a9..0000000000 --- a/contrib/hostapd/src/crypto/crypto_internal-cipher.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Crypto wrapper for internal crypto implementation - Cipher wrappers - * Copyright (c) 2006-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" -#include "aes.h" -#include "des_i.h" - - -struct crypto_cipher { - enum crypto_cipher_alg alg; - union { - struct { - size_t used_bytes; - u8 key[16]; - size_t keylen; - } rc4; - struct { - u8 cbc[32]; - void *ctx_enc; - void *ctx_dec; - } aes; - struct { - struct des3_key_s key; - u8 cbc[8]; - } des3; - struct { - u32 ek[32]; - u32 dk[32]; - u8 cbc[8]; - } des; - } u; -}; - - -struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, - const u8 *iv, const u8 *key, - size_t key_len) -{ - struct crypto_cipher *ctx; - - ctx = os_zalloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - - ctx->alg = alg; - - switch (alg) { - case CRYPTO_CIPHER_ALG_RC4: - if (key_len > sizeof(ctx->u.rc4.key)) { - os_free(ctx); - return NULL; - } - ctx->u.rc4.keylen = key_len; - os_memcpy(ctx->u.rc4.key, key, key_len); - break; - case CRYPTO_CIPHER_ALG_AES: - ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len); - if (ctx->u.aes.ctx_enc == NULL) { - os_free(ctx); - return NULL; - } - ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len); - if (ctx->u.aes.ctx_dec == NULL) { - aes_encrypt_deinit(ctx->u.aes.ctx_enc); - os_free(ctx); - return NULL; - } - os_memcpy(ctx->u.aes.cbc, iv, AES_BLOCK_SIZE); - break; - case CRYPTO_CIPHER_ALG_3DES: - if (key_len != 24) { - os_free(ctx); - return NULL; - } - des3_key_setup(key, &ctx->u.des3.key); - os_memcpy(ctx->u.des3.cbc, iv, 8); - break; - case CRYPTO_CIPHER_ALG_DES: - if (key_len != 8) { - os_free(ctx); - return NULL; - } - des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk); - os_memcpy(ctx->u.des.cbc, iv, 8); - break; - default: - os_free(ctx); - return NULL; - } - - return ctx; -} - - -int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, - u8 *crypt, size_t len) -{ - size_t i, j, blocks; - - switch (ctx->alg) { - case CRYPTO_CIPHER_ALG_RC4: - if (plain != crypt) - os_memcpy(crypt, plain, len); - rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, - ctx->u.rc4.used_bytes, crypt, len); - ctx->u.rc4.used_bytes += len; - break; - case CRYPTO_CIPHER_ALG_AES: - if (len % AES_BLOCK_SIZE) - return -1; - blocks = len / AES_BLOCK_SIZE; - for (i = 0; i < blocks; i++) { - for (j = 0; j < AES_BLOCK_SIZE; j++) - ctx->u.aes.cbc[j] ^= plain[j]; - aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc, - ctx->u.aes.cbc); - os_memcpy(crypt, ctx->u.aes.cbc, AES_BLOCK_SIZE); - plain += AES_BLOCK_SIZE; - crypt += AES_BLOCK_SIZE; - } - break; - case CRYPTO_CIPHER_ALG_3DES: - if (len % 8) - return -1; - blocks = len / 8; - for (i = 0; i < blocks; i++) { - for (j = 0; j < 8; j++) - ctx->u.des3.cbc[j] ^= plain[j]; - des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key, - ctx->u.des3.cbc); - os_memcpy(crypt, ctx->u.des3.cbc, 8); - plain += 8; - crypt += 8; - } - break; - case CRYPTO_CIPHER_ALG_DES: - if (len % 8) - return -1; - blocks = len / 8; - for (i = 0; i < blocks; i++) { - for (j = 0; j < 8; j++) - ctx->u.des3.cbc[j] ^= plain[j]; - des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek, - ctx->u.des.cbc); - os_memcpy(crypt, ctx->u.des.cbc, 8); - plain += 8; - crypt += 8; - } - break; - default: - return -1; - } - - return 0; -} - - -int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, - u8 *plain, size_t len) -{ - size_t i, j, blocks; - u8 tmp[32]; - - switch (ctx->alg) { - case CRYPTO_CIPHER_ALG_RC4: - if (plain != crypt) - os_memcpy(plain, crypt, len); - rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, - ctx->u.rc4.used_bytes, plain, len); - ctx->u.rc4.used_bytes += len; - break; - case CRYPTO_CIPHER_ALG_AES: - if (len % AES_BLOCK_SIZE) - return -1; - blocks = len / AES_BLOCK_SIZE; - for (i = 0; i < blocks; i++) { - os_memcpy(tmp, crypt, AES_BLOCK_SIZE); - aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain); - for (j = 0; j < AES_BLOCK_SIZE; j++) - plain[j] ^= ctx->u.aes.cbc[j]; - os_memcpy(ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE); - plain += AES_BLOCK_SIZE; - crypt += AES_BLOCK_SIZE; - } - break; - case CRYPTO_CIPHER_ALG_3DES: - if (len % 8) - return -1; - blocks = len / 8; - for (i = 0; i < blocks; i++) { - os_memcpy(tmp, crypt, 8); - des3_decrypt(crypt, &ctx->u.des3.key, plain); - for (j = 0; j < 8; j++) - plain[j] ^= ctx->u.des3.cbc[j]; - os_memcpy(ctx->u.des3.cbc, tmp, 8); - plain += 8; - crypt += 8; - } - break; - case CRYPTO_CIPHER_ALG_DES: - if (len % 8) - return -1; - blocks = len / 8; - for (i = 0; i < blocks; i++) { - os_memcpy(tmp, crypt, 8); - des_block_decrypt(crypt, ctx->u.des.dk, plain); - for (j = 0; j < 8; j++) - plain[j] ^= ctx->u.des.cbc[j]; - os_memcpy(ctx->u.des.cbc, tmp, 8); - plain += 8; - crypt += 8; - } - break; - default: - return -1; - } - - return 0; -} - - -void crypto_cipher_deinit(struct crypto_cipher *ctx) -{ - switch (ctx->alg) { - case CRYPTO_CIPHER_ALG_AES: - aes_encrypt_deinit(ctx->u.aes.ctx_enc); - aes_decrypt_deinit(ctx->u.aes.ctx_dec); - break; - case CRYPTO_CIPHER_ALG_3DES: - break; - default: - break; - } - os_free(ctx); -} diff --git a/contrib/hostapd/src/crypto/crypto_internal-modexp.c b/contrib/hostapd/src/crypto/crypto_internal-modexp.c deleted file mode 100644 index 9dcabb95bd..0000000000 --- a/contrib/hostapd/src/crypto/crypto_internal-modexp.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Crypto wrapper for internal crypto implementation - modexp - * Copyright (c) 2006-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "tls/bignum.h" -#include "crypto.h" - - -int crypto_mod_exp(const u8 *base, size_t base_len, - const u8 *power, size_t power_len, - const u8 *modulus, size_t modulus_len, - u8 *result, size_t *result_len) -{ - struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result; - int ret = -1; - - bn_base = bignum_init(); - bn_exp = bignum_init(); - bn_modulus = bignum_init(); - bn_result = bignum_init(); - - if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL || - bn_result == NULL) - goto error; - - if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 || - bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 || - bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0) - goto error; - - if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0) - goto error; - - ret = bignum_get_unsigned_bin(bn_result, result, result_len); - -error: - bignum_deinit(bn_base); - bignum_deinit(bn_exp); - bignum_deinit(bn_modulus); - bignum_deinit(bn_result); - return ret; -} diff --git a/contrib/hostapd/src/crypto/crypto_internal-rsa.c b/contrib/hostapd/src/crypto/crypto_internal-rsa.c deleted file mode 100644 index 54209fad3c..0000000000 --- a/contrib/hostapd/src/crypto/crypto_internal-rsa.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Crypto wrapper for internal crypto implementation - RSA parts - * Copyright (c) 2006-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" -#include "tls/rsa.h" -#include "tls/pkcs1.h" -#include "tls/pkcs8.h" - -/* Dummy structures; these are just typecast to struct crypto_rsa_key */ -struct crypto_public_key; -struct crypto_private_key; - - -struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) -{ - return (struct crypto_public_key *) - crypto_rsa_import_public_key(key, len); -} - - -struct crypto_private_key * crypto_private_key_import(const u8 *key, - size_t len, - const char *passwd) -{ - struct crypto_private_key *res; - - /* First, check for possible PKCS #8 encoding */ - res = pkcs8_key_import(key, len); - if (res) - return res; - - if (passwd) { - /* Try to parse as encrypted PKCS #8 */ - res = pkcs8_enc_key_import(key, len, passwd); - if (res) - return res; - } - - /* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */ - wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private " - "key"); - return (struct crypto_private_key *) - crypto_rsa_import_private_key(key, len); -} - - -struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, - size_t len) -{ - /* No X.509 support in crypto_internal.c */ - return NULL; -} - - -int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - return pkcs1_encrypt(2, (struct crypto_rsa_key *) key, - 0, in, inlen, out, outlen); -} - - -int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - return pkcs1_v15_private_key_decrypt((struct crypto_rsa_key *) key, - in, inlen, out, outlen); -} - - -int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - return pkcs1_encrypt(1, (struct crypto_rsa_key *) key, - 1, in, inlen, out, outlen); -} - - -void crypto_public_key_free(struct crypto_public_key *key) -{ - crypto_rsa_free((struct crypto_rsa_key *) key); -} - - -void crypto_private_key_free(struct crypto_private_key *key) -{ - crypto_rsa_free((struct crypto_rsa_key *) key); -} - - -int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key, - const u8 *crypt, size_t crypt_len, - u8 *plain, size_t *plain_len) -{ - return pkcs1_decrypt_public_key((struct crypto_rsa_key *) key, - crypt, crypt_len, plain, plain_len); -} diff --git a/contrib/hostapd/src/crypto/crypto_internal.c b/contrib/hostapd/src/crypto/crypto_internal.c deleted file mode 100644 index f3602dac34..0000000000 --- a/contrib/hostapd/src/crypto/crypto_internal.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Crypto wrapper for internal crypto implementation - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" -#include "sha256_i.h" -#include "sha1_i.h" -#include "md5_i.h" - -struct crypto_hash { - enum crypto_hash_alg alg; - 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; -}; - - -struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, - size_t key_len) -{ - struct crypto_hash *ctx; - u8 k_pad[64]; - u8 tk[32]; - size_t i; - - ctx = os_zalloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - - ctx->alg = alg; - - switch (alg) { - case CRYPTO_HASH_ALG_MD5: - MD5Init(&ctx->u.md5); - break; - 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); - MD5Update(&ctx->u.md5, key, key_len); - MD5Final(tk, &ctx->u.md5); - key = tk; - key_len = 16; - } - 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; - MD5Init(&ctx->u.md5); - MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); - break; - case CRYPTO_HASH_ALG_HMAC_SHA1: - if (key_len > sizeof(k_pad)) { - SHA1Init(&ctx->u.sha1); - SHA1Update(&ctx->u.sha1, key, key_len); - SHA1Final(tk, &ctx->u.sha1); - key = tk; - key_len = 20; - } - 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; - 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; - } - - return ctx; -} - - -void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) -{ - if (ctx == NULL) - return; - - switch (ctx->alg) { - case CRYPTO_HASH_ALG_MD5: - case CRYPTO_HASH_ALG_HMAC_MD5: - MD5Update(&ctx->u.md5, data, len); - break; - case CRYPTO_HASH_ALG_SHA1: - 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; - } -} - - -int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) -{ - u8 k_pad[64]; - size_t i; - - if (ctx == NULL) - return -2; - - if (mac == NULL || len == NULL) { - os_free(ctx); - return 0; - } - - switch (ctx->alg) { - case CRYPTO_HASH_ALG_MD5: - if (*len < 16) { - *len = 16; - os_free(ctx); - return -1; - } - *len = 16; - MD5Final(mac, &ctx->u.md5); - break; - case CRYPTO_HASH_ALG_SHA1: - if (*len < 20) { - *len = 20; - os_free(ctx); - return -1; - } - *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; - os_free(ctx); - return -1; - } - *len = 16; - - MD5Final(mac, &ctx->u.md5); - - 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; - MD5Init(&ctx->u.md5); - MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); - MD5Update(&ctx->u.md5, mac, 16); - MD5Final(mac, &ctx->u.md5); - break; - case CRYPTO_HASH_ALG_HMAC_SHA1: - if (*len < 20) { - *len = 20; - os_free(ctx); - return -1; - } - *len = 20; - - SHA1Final(mac, &ctx->u.sha1); - - 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; - SHA1Init(&ctx->u.sha1); - SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); - 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); - - return 0; -} - - -int crypto_global_init(void) -{ - return 0; -} - - -void crypto_global_deinit(void) -{ -} diff --git a/contrib/hostapd/src/crypto/crypto_libtomcrypt.c b/contrib/hostapd/src/crypto/crypto_libtomcrypt.c deleted file mode 100644 index a55edd14e2..0000000000 --- a/contrib/hostapd/src/crypto/crypto_libtomcrypt.c +++ /dev/null @@ -1,726 +0,0 @@ -/* - * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1) - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "crypto.h" - -#ifndef mp_init_multi -#define mp_init_multi ltc_init_multi -#define mp_clear_multi ltc_deinit_multi -#define mp_unsigned_bin_size(a) ltc_mp.unsigned_size(a) -#define mp_to_unsigned_bin(a, b) ltc_mp.unsigned_write(a, b) -#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c) -#define mp_exptmod(a,b,c,d) ltc_mp.exptmod(a,b,c,d) -#endif - - -int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - hash_state md; - size_t i; - - md4_init(&md); - for (i = 0; i < num_elem; i++) - md4_process(&md, addr[i], len[i]); - md4_done(&md, mac); - return 0; -} - - -void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -{ - u8 pkey[8], next, tmp; - int i; - symmetric_key skey; - - /* Add parity bits to the key */ - next = 0; - for (i = 0; i < 7; i++) { - tmp = key[i]; - pkey[i] = (tmp >> i) | next | 1; - next = tmp << (7 - i); - } - pkey[i] = next | 1; - - des_setup(pkey, 8, 0, &skey); - des_ecb_encrypt(clear, cypher, &skey); - des_done(&skey); -} - - -int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - hash_state md; - size_t i; - - md5_init(&md); - for (i = 0; i < num_elem; i++) - md5_process(&md, addr[i], len[i]); - md5_done(&md, mac); - return 0; -} - - -int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - hash_state md; - size_t i; - - sha1_init(&md); - for (i = 0; i < num_elem; i++) - sha1_process(&md, addr[i], len[i]); - sha1_done(&md, mac); - return 0; -} - - -void * aes_encrypt_init(const u8 *key, size_t len) -{ - symmetric_key *skey; - skey = os_malloc(sizeof(*skey)); - if (skey == NULL) - return NULL; - if (aes_setup(key, len, 0, skey) != CRYPT_OK) { - os_free(skey); - return NULL; - } - return skey; -} - - -void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -{ - symmetric_key *skey = ctx; - aes_ecb_encrypt(plain, crypt, skey); -} - - -void aes_encrypt_deinit(void *ctx) -{ - symmetric_key *skey = ctx; - aes_done(skey); - os_free(skey); -} - - -void * aes_decrypt_init(const u8 *key, size_t len) -{ - symmetric_key *skey; - skey = os_malloc(sizeof(*skey)); - if (skey == NULL) - return NULL; - if (aes_setup(key, len, 0, skey) != CRYPT_OK) { - os_free(skey); - return NULL; - } - return skey; -} - - -void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) -{ - symmetric_key *skey = ctx; - aes_ecb_encrypt(plain, (u8 *) crypt, skey); -} - - -void aes_decrypt_deinit(void *ctx) -{ - symmetric_key *skey = ctx; - aes_done(skey); - os_free(skey); -} - - -struct crypto_hash { - enum crypto_hash_alg alg; - int error; - union { - hash_state md; - hmac_state hmac; - } u; -}; - - -struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, - size_t key_len) -{ - struct crypto_hash *ctx; - - ctx = os_zalloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - - ctx->alg = alg; - - switch (alg) { - case CRYPTO_HASH_ALG_MD5: - if (md5_init(&ctx->u.md) != CRYPT_OK) - goto fail; - break; - case CRYPTO_HASH_ALG_SHA1: - if (sha1_init(&ctx->u.md) != CRYPT_OK) - goto fail; - break; - case CRYPTO_HASH_ALG_HMAC_MD5: - if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) != - CRYPT_OK) - goto fail; - break; - case CRYPTO_HASH_ALG_HMAC_SHA1: - if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) != - CRYPT_OK) - goto fail; - break; - default: - goto fail; - } - - return ctx; - -fail: - os_free(ctx); - return NULL; -} - -void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) -{ - if (ctx == NULL || ctx->error) - return; - - switch (ctx->alg) { - case CRYPTO_HASH_ALG_MD5: - ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK; - break; - case CRYPTO_HASH_ALG_SHA1: - ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK; - break; - case CRYPTO_HASH_ALG_HMAC_MD5: - case CRYPTO_HASH_ALG_HMAC_SHA1: - ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK; - break; - } -} - - -int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) -{ - int ret = 0; - unsigned long clen; - - if (ctx == NULL) - return -2; - - if (mac == NULL || len == NULL) { - os_free(ctx); - return 0; - } - - if (ctx->error) { - os_free(ctx); - return -2; - } - - switch (ctx->alg) { - case CRYPTO_HASH_ALG_MD5: - if (*len < 16) { - *len = 16; - os_free(ctx); - return -1; - } - *len = 16; - if (md5_done(&ctx->u.md, mac) != CRYPT_OK) - ret = -2; - break; - case CRYPTO_HASH_ALG_SHA1: - if (*len < 20) { - *len = 20; - os_free(ctx); - return -1; - } - *len = 20; - if (sha1_done(&ctx->u.md, mac) != CRYPT_OK) - ret = -2; - break; - case CRYPTO_HASH_ALG_HMAC_SHA1: - if (*len < 20) { - *len = 20; - os_free(ctx); - return -1; - } - /* continue */ - case CRYPTO_HASH_ALG_HMAC_MD5: - if (*len < 16) { - *len = 16; - os_free(ctx); - return -1; - } - clen = *len; - if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) { - os_free(ctx); - return -1; - } - *len = clen; - break; - default: - ret = -2; - break; - } - - os_free(ctx); - - return ret; -} - - -struct crypto_cipher { - int rc4; - union { - symmetric_CBC cbc; - struct { - size_t used_bytes; - u8 key[16]; - size_t keylen; - } rc4; - } u; -}; - - -struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, - const u8 *iv, const u8 *key, - size_t key_len) -{ - struct crypto_cipher *ctx; - int idx, res, rc4 = 0; - - switch (alg) { - case CRYPTO_CIPHER_ALG_AES: - idx = find_cipher("aes"); - break; - case CRYPTO_CIPHER_ALG_3DES: - idx = find_cipher("3des"); - break; - case CRYPTO_CIPHER_ALG_DES: - idx = find_cipher("des"); - break; - case CRYPTO_CIPHER_ALG_RC2: - idx = find_cipher("rc2"); - break; - case CRYPTO_CIPHER_ALG_RC4: - idx = -1; - rc4 = 1; - break; - default: - return NULL; - } - - ctx = os_zalloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - - if (rc4) { - ctx->rc4 = 1; - if (key_len > sizeof(ctx->u.rc4.key)) { - os_free(ctx); - return NULL; - } - ctx->u.rc4.keylen = key_len; - os_memcpy(ctx->u.rc4.key, key, key_len); - } else { - res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc); - if (res != CRYPT_OK) { - wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start " - "failed: %s", error_to_string(res)); - os_free(ctx); - return NULL; - } - } - - return ctx; -} - -int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, - u8 *crypt, size_t len) -{ - int res; - - if (ctx->rc4) { - if (plain != crypt) - os_memcpy(crypt, plain, len); - rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, - ctx->u.rc4.used_bytes, crypt, len); - ctx->u.rc4.used_bytes += len; - return 0; - } - - res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc); - if (res != CRYPT_OK) { - wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption " - "failed: %s", error_to_string(res)); - return -1; - } - return 0; -} - - -int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, - u8 *plain, size_t len) -{ - int res; - - if (ctx->rc4) { - if (plain != crypt) - os_memcpy(plain, crypt, len); - rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, - ctx->u.rc4.used_bytes, plain, len); - ctx->u.rc4.used_bytes += len; - return 0; - } - - res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc); - if (res != CRYPT_OK) { - wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption " - "failed: %s", error_to_string(res)); - return -1; - } - - return 0; -} - - -void crypto_cipher_deinit(struct crypto_cipher *ctx) -{ - if (!ctx->rc4) - cbc_done(&ctx->u.cbc); - os_free(ctx); -} - - -struct crypto_public_key { - rsa_key rsa; -}; - -struct crypto_private_key { - rsa_key rsa; -}; - - -struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) -{ - int res; - struct crypto_public_key *pk; - - pk = os_zalloc(sizeof(*pk)); - if (pk == NULL) - return NULL; - - res = rsa_import(key, len, &pk->rsa); - if (res != CRYPT_OK) { - wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import " - "public key (res=%d '%s')", - res, error_to_string(res)); - os_free(pk); - return NULL; - } - - if (pk->rsa.type != PK_PUBLIC) { - wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of " - "correct type"); - rsa_free(&pk->rsa); - os_free(pk); - return NULL; - } - - return pk; -} - - -struct crypto_private_key * crypto_private_key_import(const u8 *key, - size_t len, - const char *passwd) -{ - int res; - struct crypto_private_key *pk; - - pk = os_zalloc(sizeof(*pk)); - if (pk == NULL) - return NULL; - - res = rsa_import(key, len, &pk->rsa); - if (res != CRYPT_OK) { - wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import " - "private key (res=%d '%s')", - res, error_to_string(res)); - os_free(pk); - return NULL; - } - - if (pk->rsa.type != PK_PRIVATE) { - wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of " - "correct type"); - rsa_free(&pk->rsa); - os_free(pk); - return NULL; - } - - return pk; -} - - -struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, - size_t len) -{ - /* No X.509 support in LibTomCrypt */ - return NULL; -} - - -static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - size_t ps_len; - u8 *pos; - - /* - * PKCS #1 v1.5, 8.1: - * - * EB = 00 || BT || PS || 00 || D - * BT = 00 or 01 for private-key operation; 02 for public-key operation - * PS = k-3-||D||; at least eight octets - * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero) - * k = length of modulus in octets (modlen) - */ - - if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) { - wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer " - "lengths (modlen=%lu outlen=%lu inlen=%lu)", - __func__, (unsigned long) modlen, - (unsigned long) *outlen, - (unsigned long) inlen); - return -1; - } - - pos = out; - *pos++ = 0x00; - *pos++ = block_type; /* BT */ - ps_len = modlen - inlen - 3; - switch (block_type) { - case 0: - os_memset(pos, 0x00, ps_len); - pos += ps_len; - break; - case 1: - os_memset(pos, 0xff, ps_len); - pos += ps_len; - break; - case 2: - if (os_get_random(pos, ps_len) < 0) { - wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get " - "random data for PS", __func__); - return -1; - } - while (ps_len--) { - if (*pos == 0x00) - *pos = 0x01; - pos++; - } - break; - default: - wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type " - "%d", __func__, block_type); - return -1; - } - *pos++ = 0x00; - os_memcpy(pos, in, inlen); /* D */ - - return 0; -} - - -static int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - unsigned long len, modlen; - int res; - - modlen = mp_unsigned_bin_size(key->N); - - if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen, - out, outlen) < 0) - return -1; - - len = *outlen; - res = rsa_exptmod(out, modlen, out, &len, key_type, key); - if (res != CRYPT_OK) { - wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s", - error_to_string(res)); - return -1; - } - *outlen = len; - - return 0; -} - - -int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen, - out, outlen); -} - - -int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen, - out, outlen); -} - - -void crypto_public_key_free(struct crypto_public_key *key) -{ - if (key) { - rsa_free(&key->rsa); - os_free(key); - } -} - - -void crypto_private_key_free(struct crypto_private_key *key) -{ - if (key) { - rsa_free(&key->rsa); - os_free(key); - } -} - - -int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key, - const u8 *crypt, size_t crypt_len, - u8 *plain, size_t *plain_len) -{ - int res; - unsigned long len; - u8 *pos; - - len = *plain_len; - res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC, - &key->rsa); - if (res != CRYPT_OK) { - wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s", - error_to_string(res)); - return -1; - } - - /* - * PKCS #1 v1.5, 8.1: - * - * EB = 00 || BT || PS || 00 || D - * BT = 01 - * PS = k-3-||D|| times FF - * k = length of modulus in octets - */ - - if (len < 3 + 8 + 16 /* min hash len */ || - plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " - "structure"); - return -1; - } - - pos = plain + 3; - while (pos < plain + len && *pos == 0xff) - pos++; - if (pos - plain - 2 < 8) { - /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ - wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature " - "padding"); - return -1; - } - - if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " - "structure (2)"); - return -1; - } - pos++; - len -= pos - plain; - - /* Strip PKCS #1 header */ - os_memmove(plain, pos, len); - *plain_len = len; - - return 0; -} - - -int crypto_global_init(void) -{ - ltc_mp = tfm_desc; - /* TODO: only register algorithms that are really needed */ - if (register_hash(&md4_desc) < 0 || - register_hash(&md5_desc) < 0 || - register_hash(&sha1_desc) < 0 || - register_cipher(&aes_desc) < 0 || - register_cipher(&des_desc) < 0 || - register_cipher(&des3_desc) < 0) { - wpa_printf(MSG_ERROR, "TLSv1: Failed to register " - "hash/cipher functions"); - return -1; - } - - return 0; -} - - -void crypto_global_deinit(void) -{ -} - - -#ifdef CONFIG_MODEXP - -int crypto_mod_exp(const u8 *base, size_t base_len, - const u8 *power, size_t power_len, - const u8 *modulus, size_t modulus_len, - u8 *result, size_t *result_len) -{ - void *b, *p, *m, *r; - - if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK) - return -1; - - if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK || - mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK || - mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK) - goto fail; - - if (mp_exptmod(b, p, m, r) != CRYPT_OK) - goto fail; - - *result_len = mp_unsigned_bin_size(r); - if (mp_to_unsigned_bin(r, result) != CRYPT_OK) - goto fail; - - mp_clear_multi(b, p, m, r, NULL); - return 0; - -fail: - mp_clear_multi(b, p, m, r, NULL); - return -1; -} - -#endif /* CONFIG_MODEXP */ diff --git a/contrib/hostapd/src/crypto/crypto_none.c b/contrib/hostapd/src/crypto/crypto_none.c deleted file mode 100644 index 011f3f35a0..0000000000 --- a/contrib/hostapd/src/crypto/crypto_none.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * WPA Supplicant / Empty template functions for crypto wrapper - * Copyright (c) 2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" - - -int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - return 0; -} - - -void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -{ -} diff --git a/contrib/hostapd/src/crypto/crypto_nss.c b/contrib/hostapd/src/crypto/crypto_nss.c deleted file mode 100644 index acd0a55281..0000000000 --- a/contrib/hostapd/src/crypto/crypto_nss.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Crypto wrapper functions for NSS - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" -#include "crypto.h" - - -static int nss_hash(HASH_HashType type, unsigned int max_res_len, - size_t num_elem, const u8 *addr[], const size_t *len, - u8 *mac) -{ - HASHContext *ctx; - size_t i; - unsigned int reslen; - - ctx = HASH_Create(type); - if (ctx == NULL) - return -1; - - HASH_Begin(ctx); - for (i = 0; i < num_elem; i++) - HASH_Update(ctx, addr[i], len[i]); - HASH_End(ctx, mac, &reslen, max_res_len); - HASH_Destroy(ctx); - - return 0; -} - - -void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -{ - PK11Context *ctx = NULL; - PK11SlotInfo *slot; - SECItem *param = NULL; - PK11SymKey *symkey = NULL; - SECItem item; - int olen; - u8 pkey[8], next, tmp; - int i; - - /* Add parity bits to the key */ - next = 0; - for (i = 0; i < 7; i++) { - tmp = key[i]; - pkey[i] = (tmp >> i) | next | 1; - next = tmp << (7 - i); - } - pkey[i] = next | 1; - - slot = PK11_GetBestSlot(CKM_DES_ECB, NULL); - if (slot == NULL) { - wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed"); - goto out; - } - - item.type = siBuffer; - item.data = pkey; - item.len = 8; - symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive, - CKA_ENCRYPT, &item, NULL); - if (symkey == NULL) { - wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed"); - goto out; - } - - param = PK11_GenerateNewParam(CKM_DES_ECB, symkey); - if (param == NULL) { - wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed"); - goto out; - } - - ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT, - symkey, param); - if (ctx == NULL) { - wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey(" - "CKM_DES_ECB) failed"); - goto out; - } - - if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) != - SECSuccess) { - wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed"); - goto out; - } - -out: - if (ctx) - PK11_DestroyContext(ctx, PR_TRUE); - if (symkey) - PK11_FreeSymKey(symkey); - if (param) - SECITEM_FreeItem(param, PR_TRUE); -} - - -int rc4_skip(const u8 *key, size_t keylen, size_t skip, - u8 *data, size_t data_len) -{ - return -1; -} - - -int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac); -} - - -int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac); -} - - -int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, - u8 *mac) -{ - return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac); -} - - -void * aes_encrypt_init(const u8 *key, size_t len) -{ - return NULL; -} - - -void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -{ -} - - -void aes_encrypt_deinit(void *ctx) -{ -} - - -void * aes_decrypt_init(const u8 *key, size_t len) -{ - return NULL; -} - - -void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) -{ -} - - -void aes_decrypt_deinit(void *ctx) -{ -} - - -int crypto_mod_exp(const u8 *base, size_t base_len, - const u8 *power, size_t power_len, - const u8 *modulus, size_t modulus_len, - u8 *result, size_t *result_len) -{ - return -1; -} - - -struct crypto_cipher { -}; - - -struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, - const u8 *iv, const u8 *key, - size_t key_len) -{ - return NULL; -} - - -int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, - u8 *crypt, size_t len) -{ - return -1; -} - - -int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, - u8 *plain, size_t len) -{ - return -1; -} - - -void crypto_cipher_deinit(struct crypto_cipher *ctx) -{ -} diff --git a/contrib/hostapd/src/crypto/crypto_openssl.c b/contrib/hostapd/src/crypto/crypto_openssl.c deleted file mode 100644 index 1da2b9f4a3..0000000000 --- a/contrib/hostapd/src/crypto/crypto_openssl.c +++ /dev/null @@ -1,1235 +0,0 @@ -/* - * Wrapper functions for OpenSSL libcrypto - * Copyright (c) 2004-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_OPENSSL_CMAC -#include -#endif /* CONFIG_OPENSSL_CMAC */ -#ifdef CONFIG_ECC -#include -#endif /* CONFIG_ECC */ - -#include "common.h" -#include "wpabuf.h" -#include "dh_group5.h" -#include "sha1.h" -#include "sha256.h" -#include "crypto.h" - -#if OPENSSL_VERSION_NUMBER < 0x00907000 -#define DES_key_schedule des_key_schedule -#define DES_cblock des_cblock -#define DES_set_key(key, schedule) des_set_key((key), *(schedule)) -#define DES_ecb_encrypt(input, output, ks, enc) \ - des_ecb_encrypt((input), (output), *(ks), (enc)) -#endif /* openssl < 0.9.7 */ - -static BIGNUM * get_group5_prime(void) -{ -#if OPENSSL_VERSION_NUMBER < 0x00908000 - static const unsigned char RFC3526_PRIME_1536[] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, - 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, - 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, - 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, - 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, - 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, - 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, - 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, - 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, - 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D, - 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36, - 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, - 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56, - 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D, - 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08, - 0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - }; - return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL); -#else /* openssl < 0.9.8 */ - return get_rfc3526_prime_1536(NULL); -#endif /* openssl < 0.9.8 */ -} - -#if OPENSSL_VERSION_NUMBER < 0x00908000 -#ifndef OPENSSL_NO_SHA256 -#ifndef OPENSSL_FIPS -#define NO_SHA256_WRAPPER -#endif -#endif - -#endif /* openssl < 0.9.8 */ - -#ifdef OPENSSL_NO_SHA256 -#define NO_SHA256_WRAPPER -#endif - -static int openssl_digest_vector(const EVP_MD *type, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac) -{ - EVP_MD_CTX ctx; - size_t i; - unsigned int mac_len; - - EVP_MD_CTX_init(&ctx); - if (!EVP_DigestInit_ex(&ctx, type, NULL)) { - wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - return -1; - } - for (i = 0; i < num_elem; i++) { - if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) { - wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate " - "failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - return -1; - } - } - if (!EVP_DigestFinal(&ctx, mac, &mac_len)) { - wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - return -1; - } - - return 0; -} - - -int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac); -} - - -void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -{ - u8 pkey[8], next, tmp; - int i; - DES_key_schedule ks; - - /* Add parity bits to the key */ - next = 0; - for (i = 0; i < 7; i++) { - tmp = key[i]; - pkey[i] = (tmp >> i) | next | 1; - next = tmp << (7 - i); - } - pkey[i] = next | 1; - - DES_set_key(&pkey, &ks); - DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks, - DES_ENCRYPT); -} - - -int rc4_skip(const u8 *key, size_t keylen, size_t skip, - u8 *data, size_t data_len) -{ -#ifdef OPENSSL_NO_RC4 - return -1; -#else /* OPENSSL_NO_RC4 */ - EVP_CIPHER_CTX ctx; - int outl; - int res = -1; - unsigned char skip_buf[16]; - - EVP_CIPHER_CTX_init(&ctx); - if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) || - !EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) || - !EVP_CIPHER_CTX_set_key_length(&ctx, keylen) || - !EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1)) - goto out; - - while (skip >= sizeof(skip_buf)) { - size_t len = skip; - if (len > sizeof(skip_buf)) - len = sizeof(skip_buf); - if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len)) - goto out; - skip -= len; - } - - if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len)) - res = 0; - -out: - EVP_CIPHER_CTX_cleanup(&ctx); - return res; -#endif /* OPENSSL_NO_RC4 */ -} - - -int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac); -} - - -int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - return openssl_digest_vector(EVP_sha1(), num_elem, addr, len, mac); -} - - -#ifndef NO_SHA256_WRAPPER -int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, - u8 *mac) -{ - return openssl_digest_vector(EVP_sha256(), num_elem, addr, len, mac); -} -#endif /* NO_SHA256_WRAPPER */ - - -static const EVP_CIPHER * aes_get_evp_cipher(size_t keylen) -{ - switch (keylen) { - case 16: - return EVP_aes_128_ecb(); - case 24: - return EVP_aes_192_ecb(); - case 32: - return EVP_aes_256_ecb(); - } - - return NULL; -} - - -void * aes_encrypt_init(const u8 *key, size_t len) -{ - EVP_CIPHER_CTX *ctx; - const EVP_CIPHER *type; - - type = aes_get_evp_cipher(len); - if (type == NULL) - return NULL; - - ctx = os_malloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - EVP_CIPHER_CTX_init(ctx); - if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) { - os_free(ctx); - return NULL; - } - EVP_CIPHER_CTX_set_padding(ctx, 0); - return ctx; -} - - -void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -{ - EVP_CIPHER_CTX *c = ctx; - int clen = 16; - if (EVP_EncryptUpdate(c, crypt, &clen, plain, 16) != 1) { - wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptUpdate failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - } -} - - -void aes_encrypt_deinit(void *ctx) -{ - EVP_CIPHER_CTX *c = ctx; - u8 buf[16]; - int len = sizeof(buf); - if (EVP_EncryptFinal_ex(c, buf, &len) != 1) { - wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptFinal_ex failed: " - "%s", ERR_error_string(ERR_get_error(), NULL)); - } - if (len != 0) { - wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d " - "in AES encrypt", len); - } - EVP_CIPHER_CTX_cleanup(c); - os_free(c); -} - - -void * aes_decrypt_init(const u8 *key, size_t len) -{ - EVP_CIPHER_CTX *ctx; - const EVP_CIPHER *type; - - type = aes_get_evp_cipher(len); - if (type == NULL) - return NULL; - - ctx = os_malloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - EVP_CIPHER_CTX_init(ctx); - if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) { - os_free(ctx); - return NULL; - } - EVP_CIPHER_CTX_set_padding(ctx, 0); - return ctx; -} - - -void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) -{ - EVP_CIPHER_CTX *c = ctx; - int plen = 16; - if (EVP_DecryptUpdate(c, plain, &plen, crypt, 16) != 1) { - wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptUpdate failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - } -} - - -void aes_decrypt_deinit(void *ctx) -{ - EVP_CIPHER_CTX *c = ctx; - u8 buf[16]; - int len = sizeof(buf); - if (EVP_DecryptFinal_ex(c, buf, &len) != 1) { - wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptFinal_ex failed: " - "%s", ERR_error_string(ERR_get_error(), NULL)); - } - if (len != 0) { - wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d " - "in AES decrypt", len); - } - EVP_CIPHER_CTX_cleanup(c); - os_free(ctx); -} - - -int crypto_mod_exp(const u8 *base, size_t base_len, - const u8 *power, size_t power_len, - const u8 *modulus, size_t modulus_len, - u8 *result, size_t *result_len) -{ - BIGNUM *bn_base, *bn_exp, *bn_modulus, *bn_result; - int ret = -1; - BN_CTX *ctx; - - ctx = BN_CTX_new(); - if (ctx == NULL) - return -1; - - bn_base = BN_bin2bn(base, base_len, NULL); - bn_exp = BN_bin2bn(power, power_len, NULL); - bn_modulus = BN_bin2bn(modulus, modulus_len, NULL); - bn_result = BN_new(); - - if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL || - bn_result == NULL) - goto error; - - if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1) - goto error; - - *result_len = BN_bn2bin(bn_result, result); - ret = 0; - -error: - BN_free(bn_base); - BN_free(bn_exp); - BN_free(bn_modulus); - BN_free(bn_result); - BN_CTX_free(ctx); - return ret; -} - - -struct crypto_cipher { - EVP_CIPHER_CTX enc; - EVP_CIPHER_CTX dec; -}; - - -struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, - const u8 *iv, const u8 *key, - size_t key_len) -{ - struct crypto_cipher *ctx; - const EVP_CIPHER *cipher; - - ctx = os_zalloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - - switch (alg) { -#ifndef OPENSSL_NO_RC4 - case CRYPTO_CIPHER_ALG_RC4: - cipher = EVP_rc4(); - break; -#endif /* OPENSSL_NO_RC4 */ -#ifndef OPENSSL_NO_AES - case CRYPTO_CIPHER_ALG_AES: - switch (key_len) { - case 16: - cipher = EVP_aes_128_cbc(); - break; - case 24: - cipher = EVP_aes_192_cbc(); - break; - case 32: - cipher = EVP_aes_256_cbc(); - break; - default: - os_free(ctx); - return NULL; - } - break; -#endif /* OPENSSL_NO_AES */ -#ifndef OPENSSL_NO_DES - case CRYPTO_CIPHER_ALG_3DES: - cipher = EVP_des_ede3_cbc(); - break; - case CRYPTO_CIPHER_ALG_DES: - cipher = EVP_des_cbc(); - break; -#endif /* OPENSSL_NO_DES */ -#ifndef OPENSSL_NO_RC2 - case CRYPTO_CIPHER_ALG_RC2: - cipher = EVP_rc2_ecb(); - break; -#endif /* OPENSSL_NO_RC2 */ - default: - os_free(ctx); - return NULL; - } - - EVP_CIPHER_CTX_init(&ctx->enc); - EVP_CIPHER_CTX_set_padding(&ctx->enc, 0); - if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) || - !EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) || - !EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) { - EVP_CIPHER_CTX_cleanup(&ctx->enc); - os_free(ctx); - return NULL; - } - - EVP_CIPHER_CTX_init(&ctx->dec); - EVP_CIPHER_CTX_set_padding(&ctx->dec, 0); - if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) || - !EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) || - !EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) { - EVP_CIPHER_CTX_cleanup(&ctx->enc); - EVP_CIPHER_CTX_cleanup(&ctx->dec); - os_free(ctx); - return NULL; - } - - return ctx; -} - - -int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, - u8 *crypt, size_t len) -{ - int outl; - if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len)) - return -1; - return 0; -} - - -int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, - u8 *plain, size_t len) -{ - int outl; - outl = len; - if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len)) - return -1; - return 0; -} - - -void crypto_cipher_deinit(struct crypto_cipher *ctx) -{ - EVP_CIPHER_CTX_cleanup(&ctx->enc); - EVP_CIPHER_CTX_cleanup(&ctx->dec); - os_free(ctx); -} - - -void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) -{ - DH *dh; - struct wpabuf *pubkey = NULL, *privkey = NULL; - size_t publen, privlen; - - *priv = NULL; - *publ = NULL; - - dh = DH_new(); - if (dh == NULL) - return NULL; - - dh->g = BN_new(); - if (dh->g == NULL || BN_set_word(dh->g, 2) != 1) - goto err; - - dh->p = get_group5_prime(); - if (dh->p == NULL) - goto err; - - if (DH_generate_key(dh) != 1) - goto err; - - publen = BN_num_bytes(dh->pub_key); - pubkey = wpabuf_alloc(publen); - if (pubkey == NULL) - goto err; - privlen = BN_num_bytes(dh->priv_key); - privkey = wpabuf_alloc(privlen); - if (privkey == NULL) - goto err; - - BN_bn2bin(dh->pub_key, wpabuf_put(pubkey, publen)); - BN_bn2bin(dh->priv_key, wpabuf_put(privkey, privlen)); - - *priv = privkey; - *publ = pubkey; - return dh; - -err: - wpabuf_free(pubkey); - wpabuf_free(privkey); - DH_free(dh); - return NULL; -} - - -void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ) -{ - DH *dh; - - dh = DH_new(); - if (dh == NULL) - return NULL; - - dh->g = BN_new(); - if (dh->g == NULL || BN_set_word(dh->g, 2) != 1) - goto err; - - dh->p = get_group5_prime(); - if (dh->p == NULL) - goto err; - - dh->priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL); - if (dh->priv_key == NULL) - goto err; - - dh->pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL); - if (dh->pub_key == NULL) - goto err; - - if (DH_generate_key(dh) != 1) - goto err; - - return dh; - -err: - DH_free(dh); - return NULL; -} - - -struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, - const struct wpabuf *own_private) -{ - BIGNUM *pub_key; - struct wpabuf *res = NULL; - size_t rlen; - DH *dh = ctx; - int keylen; - - if (ctx == NULL) - return NULL; - - pub_key = BN_bin2bn(wpabuf_head(peer_public), wpabuf_len(peer_public), - NULL); - if (pub_key == NULL) - return NULL; - - rlen = DH_size(dh); - res = wpabuf_alloc(rlen); - if (res == NULL) - goto err; - - keylen = DH_compute_key(wpabuf_mhead(res), pub_key, dh); - if (keylen < 0) - goto err; - wpabuf_put(res, keylen); - BN_free(pub_key); - - return res; - -err: - BN_free(pub_key); - wpabuf_free(res); - return NULL; -} - - -void dh5_free(void *ctx) -{ - DH *dh; - if (ctx == NULL) - return; - dh = ctx; - DH_free(dh); -} - - -struct crypto_hash { - HMAC_CTX ctx; -}; - - -struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, - size_t key_len) -{ - struct crypto_hash *ctx; - const EVP_MD *md; - - switch (alg) { -#ifndef OPENSSL_NO_MD5 - case CRYPTO_HASH_ALG_HMAC_MD5: - md = EVP_md5(); - break; -#endif /* OPENSSL_NO_MD5 */ -#ifndef OPENSSL_NO_SHA - case CRYPTO_HASH_ALG_HMAC_SHA1: - md = EVP_sha1(); - break; -#endif /* OPENSSL_NO_SHA */ -#ifndef OPENSSL_NO_SHA256 -#ifdef CONFIG_SHA256 - case CRYPTO_HASH_ALG_HMAC_SHA256: - md = EVP_sha256(); - break; -#endif /* CONFIG_SHA256 */ -#endif /* OPENSSL_NO_SHA256 */ - default: - return NULL; - } - - ctx = os_zalloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - HMAC_CTX_init(&ctx->ctx); - -#if OPENSSL_VERSION_NUMBER < 0x00909000 - HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL); -#else /* openssl < 0.9.9 */ - if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) { - os_free(ctx); - return NULL; - } -#endif /* openssl < 0.9.9 */ - - return ctx; -} - - -void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) -{ - if (ctx == NULL) - return; - HMAC_Update(&ctx->ctx, data, len); -} - - -int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) -{ - unsigned int mdlen; - int res; - - if (ctx == NULL) - return -2; - - if (mac == NULL || len == NULL) { - os_free(ctx); - return 0; - } - - mdlen = *len; -#if OPENSSL_VERSION_NUMBER < 0x00909000 - HMAC_Final(&ctx->ctx, mac, &mdlen); - res = 1; -#else /* openssl < 0.9.9 */ - res = HMAC_Final(&ctx->ctx, mac, &mdlen); -#endif /* openssl < 0.9.9 */ - HMAC_CTX_cleanup(&ctx->ctx); - os_free(ctx); - - if (res == 1) { - *len = mdlen; - return 0; - } - - return -1; -} - - -int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, - int iterations, u8 *buf, size_t buflen) -{ -#if OPENSSL_VERSION_NUMBER < 0x00908000 - if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), - (unsigned char *) ssid, - ssid_len, 4096, buflen, buf) != 1) - return -1; -#else /* openssl < 0.9.8 */ - if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid, - ssid_len, 4096, buflen, buf) != 1) - return -1; -#endif /* openssl < 0.9.8 */ - return 0; -} - - -int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac) -{ - HMAC_CTX ctx; - size_t i; - unsigned int mdlen; - int res; - - HMAC_CTX_init(&ctx); -#if OPENSSL_VERSION_NUMBER < 0x00909000 - HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL); -#else /* openssl < 0.9.9 */ - if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL) != 1) - return -1; -#endif /* openssl < 0.9.9 */ - - for (i = 0; i < num_elem; i++) - HMAC_Update(&ctx, addr[i], len[i]); - - mdlen = 20; -#if OPENSSL_VERSION_NUMBER < 0x00909000 - HMAC_Final(&ctx, mac, &mdlen); - res = 1; -#else /* openssl < 0.9.9 */ - res = HMAC_Final(&ctx, mac, &mdlen); -#endif /* openssl < 0.9.9 */ - HMAC_CTX_cleanup(&ctx); - - return res == 1 ? 0 : -1; -} - - -int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, - u8 *mac) -{ - return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); -} - - -#ifdef CONFIG_SHA256 - -int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac) -{ - HMAC_CTX ctx; - size_t i; - unsigned int mdlen; - int res; - - HMAC_CTX_init(&ctx); -#if OPENSSL_VERSION_NUMBER < 0x00909000 - HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL); -#else /* openssl < 0.9.9 */ - if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL) != 1) - return -1; -#endif /* openssl < 0.9.9 */ - - for (i = 0; i < num_elem; i++) - HMAC_Update(&ctx, addr[i], len[i]); - - mdlen = 32; -#if OPENSSL_VERSION_NUMBER < 0x00909000 - HMAC_Final(&ctx, mac, &mdlen); - res = 1; -#else /* openssl < 0.9.9 */ - res = HMAC_Final(&ctx, mac, &mdlen); -#endif /* openssl < 0.9.9 */ - HMAC_CTX_cleanup(&ctx); - - return res == 1 ? 0 : -1; -} - - -int hmac_sha256(const u8 *key, size_t key_len, const u8 *data, - size_t data_len, u8 *mac) -{ - return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); -} - -#endif /* CONFIG_SHA256 */ - - -int crypto_get_random(void *buf, size_t len) -{ - if (RAND_bytes(buf, len) != 1) - return -1; - return 0; -} - - -#ifdef CONFIG_OPENSSL_CMAC -int omac1_aes_128_vector(const u8 *key, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac) -{ - CMAC_CTX *ctx; - int ret = -1; - size_t outlen, i; - - ctx = CMAC_CTX_new(); - if (ctx == NULL) - return -1; - - if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL)) - goto fail; - for (i = 0; i < num_elem; i++) { - if (!CMAC_Update(ctx, addr[i], len[i])) - goto fail; - } - if (!CMAC_Final(ctx, mac, &outlen) || outlen != 16) - goto fail; - - ret = 0; -fail: - CMAC_CTX_free(ctx); - return ret; -} - - -int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) -{ - return omac1_aes_128_vector(key, 1, &data, &data_len, mac); -} -#endif /* CONFIG_OPENSSL_CMAC */ - - -struct crypto_bignum * crypto_bignum_init(void) -{ - return (struct crypto_bignum *) BN_new(); -} - - -struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len) -{ - BIGNUM *bn = BN_bin2bn(buf, len, NULL); - return (struct crypto_bignum *) bn; -} - - -void crypto_bignum_deinit(struct crypto_bignum *n, int clear) -{ - if (clear) - BN_clear_free((BIGNUM *) n); - else - BN_free((BIGNUM *) n); -} - - -int crypto_bignum_to_bin(const struct crypto_bignum *a, - u8 *buf, size_t buflen, size_t padlen) -{ - int num_bytes, offset; - - if (padlen > buflen) - return -1; - - num_bytes = BN_num_bytes((const BIGNUM *) a); - if ((size_t) num_bytes > buflen) - return -1; - if (padlen > (size_t) num_bytes) - offset = padlen - num_bytes; - else - offset = 0; - - os_memset(buf, 0, offset); - BN_bn2bin((const BIGNUM *) a, buf + offset); - - return num_bytes + offset; -} - - -int crypto_bignum_add(const struct crypto_bignum *a, - const struct crypto_bignum *b, - struct crypto_bignum *c) -{ - return BN_add((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b) ? - 0 : -1; -} - - -int crypto_bignum_mod(const struct crypto_bignum *a, - const struct crypto_bignum *b, - struct crypto_bignum *c) -{ - int res; - BN_CTX *bnctx; - - bnctx = BN_CTX_new(); - if (bnctx == NULL) - return -1; - res = BN_mod((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b, - bnctx); - BN_CTX_free(bnctx); - - return res ? 0 : -1; -} - - -int crypto_bignum_exptmod(const struct crypto_bignum *a, - const struct crypto_bignum *b, - const struct crypto_bignum *c, - struct crypto_bignum *d) -{ - int res; - BN_CTX *bnctx; - - bnctx = BN_CTX_new(); - if (bnctx == NULL) - return -1; - res = BN_mod_exp((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b, - (const BIGNUM *) c, bnctx); - BN_CTX_free(bnctx); - - return res ? 0 : -1; -} - - -int crypto_bignum_rshift(const struct crypto_bignum *a, int n, - struct crypto_bignum *b) -{ - return BN_rshift((BIGNUM *) b, (const BIGNUM *) a, n) ? 0 : -1; -} - - -int crypto_bignum_inverse(const struct crypto_bignum *a, - const struct crypto_bignum *b, - struct crypto_bignum *c) -{ - BIGNUM *res; - BN_CTX *bnctx; - - bnctx = BN_CTX_new(); - if (bnctx == NULL) - return -1; - res = BN_mod_inverse((BIGNUM *) c, (const BIGNUM *) a, - (const BIGNUM *) b, bnctx); - BN_CTX_free(bnctx); - - return res ? 0 : -1; -} - - -int crypto_bignum_sub(const struct crypto_bignum *a, - const struct crypto_bignum *b, - struct crypto_bignum *c) -{ - return BN_sub((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b) ? - 0 : -1; -} - - -int crypto_bignum_div(const struct crypto_bignum *a, - const struct crypto_bignum *b, - struct crypto_bignum *c) -{ - int res; - - BN_CTX *bnctx; - - bnctx = BN_CTX_new(); - if (bnctx == NULL) - return -1; - res = BN_div((BIGNUM *) c, NULL, (const BIGNUM *) a, - (const BIGNUM *) b, bnctx); - BN_CTX_free(bnctx); - - return res ? 0 : -1; -} - - -int crypto_bignum_mulmod(const struct crypto_bignum *a, - const struct crypto_bignum *b, - const struct crypto_bignum *c, - struct crypto_bignum *d) -{ - int res; - - BN_CTX *bnctx; - - bnctx = BN_CTX_new(); - if (bnctx == NULL) - return -1; - res = BN_mod_mul((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b, - (const BIGNUM *) c, bnctx); - BN_CTX_free(bnctx); - - return res ? 0 : -1; -} - - -int crypto_bignum_cmp(const struct crypto_bignum *a, - const struct crypto_bignum *b) -{ - return BN_cmp((const BIGNUM *) a, (const BIGNUM *) b); -} - - -int crypto_bignum_bits(const struct crypto_bignum *a) -{ - return BN_num_bits((const BIGNUM *) a); -} - - -int crypto_bignum_is_zero(const struct crypto_bignum *a) -{ - return BN_is_zero((const BIGNUM *) a); -} - - -int crypto_bignum_is_one(const struct crypto_bignum *a) -{ - return BN_is_one((const BIGNUM *) a); -} - - -#ifdef CONFIG_ECC - -struct crypto_ec { - EC_GROUP *group; - BN_CTX *bnctx; - BIGNUM *prime; - BIGNUM *order; -}; - -struct crypto_ec * crypto_ec_init(int group) -{ - struct crypto_ec *e; - int nid; - - /* Map from IANA registry for IKE D-H groups to OpenSSL NID */ - switch (group) { - case 19: - nid = NID_X9_62_prime256v1; - break; - case 20: - nid = NID_secp384r1; - break; - case 21: - nid = NID_secp521r1; - break; - case 25: - nid = NID_X9_62_prime192v1; - break; - case 26: - nid = NID_secp224r1; - break; - default: - return NULL; - } - - e = os_zalloc(sizeof(*e)); - if (e == NULL) - return NULL; - - e->bnctx = BN_CTX_new(); - e->group = EC_GROUP_new_by_curve_name(nid); - e->prime = BN_new(); - e->order = BN_new(); - if (e->group == NULL || e->bnctx == NULL || e->prime == NULL || - e->order == NULL || - !EC_GROUP_get_curve_GFp(e->group, e->prime, NULL, NULL, e->bnctx) || - !EC_GROUP_get_order(e->group, e->order, e->bnctx)) { - crypto_ec_deinit(e); - e = NULL; - } - - return e; -} - - -void crypto_ec_deinit(struct crypto_ec *e) -{ - if (e == NULL) - return; - BN_free(e->order); - EC_GROUP_free(e->group); - BN_CTX_free(e->bnctx); - os_free(e); -} - - -struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e) -{ - if (e == NULL) - return NULL; - return (struct crypto_ec_point *) EC_POINT_new(e->group); -} - - -size_t crypto_ec_prime_len(struct crypto_ec *e) -{ - return BN_num_bytes(e->prime); -} - - -size_t crypto_ec_prime_len_bits(struct crypto_ec *e) -{ - return BN_num_bits(e->prime); -} - - -const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e) -{ - return (const struct crypto_bignum *) e->prime; -} - - -const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e) -{ - return (const struct crypto_bignum *) e->order; -} - - -void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear) -{ - if (clear) - EC_POINT_clear_free((EC_POINT *) p); - else - EC_POINT_free((EC_POINT *) p); -} - - -int crypto_ec_point_to_bin(struct crypto_ec *e, - const struct crypto_ec_point *point, u8 *x, u8 *y) -{ - BIGNUM *x_bn, *y_bn; - int ret = -1; - int len = BN_num_bytes(e->prime); - - x_bn = BN_new(); - y_bn = BN_new(); - - if (x_bn && y_bn && - EC_POINT_get_affine_coordinates_GFp(e->group, (EC_POINT *) point, - x_bn, y_bn, e->bnctx)) { - if (x) { - crypto_bignum_to_bin((struct crypto_bignum *) x_bn, - x, len, len); - } - if (y) { - crypto_bignum_to_bin((struct crypto_bignum *) y_bn, - y, len, len); - } - ret = 0; - } - - BN_free(x_bn); - BN_free(y_bn); - return ret; -} - - -struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e, - const u8 *val) -{ - BIGNUM *x, *y; - EC_POINT *elem; - int len = BN_num_bytes(e->prime); - - x = BN_bin2bn(val, len, NULL); - y = BN_bin2bn(val + len, len, NULL); - elem = EC_POINT_new(e->group); - if (x == NULL || y == NULL || elem == NULL) { - BN_free(x); - BN_free(y); - EC_POINT_free(elem); - return NULL; - } - - if (!EC_POINT_set_affine_coordinates_GFp(e->group, elem, x, y, - e->bnctx)) { - EC_POINT_free(elem); - elem = NULL; - } - - BN_free(x); - BN_free(y); - - return (struct crypto_ec_point *) elem; -} - - -int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a, - const struct crypto_ec_point *b, - struct crypto_ec_point *c) -{ - return EC_POINT_add(e->group, (EC_POINT *) c, (const EC_POINT *) a, - (const EC_POINT *) b, e->bnctx) ? 0 : -1; -} - - -int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p, - const struct crypto_bignum *b, - struct crypto_ec_point *res) -{ - return EC_POINT_mul(e->group, (EC_POINT *) res, NULL, - (const EC_POINT *) p, (const BIGNUM *) b, e->bnctx) - ? 0 : -1; -} - - -int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p) -{ - return EC_POINT_invert(e->group, (EC_POINT *) p, e->bnctx) ? 0 : -1; -} - - -int crypto_ec_point_solve_y_coord(struct crypto_ec *e, - struct crypto_ec_point *p, - const struct crypto_bignum *x, int y_bit) -{ - if (!EC_POINT_set_compressed_coordinates_GFp(e->group, (EC_POINT *) p, - (const BIGNUM *) x, y_bit, - e->bnctx) || - !EC_POINT_is_on_curve(e->group, (EC_POINT *) p, e->bnctx)) - return -1; - return 0; -} - - -int crypto_ec_point_is_at_infinity(struct crypto_ec *e, - const struct crypto_ec_point *p) -{ - return EC_POINT_is_at_infinity(e->group, (const EC_POINT *) p); -} - - -int crypto_ec_point_is_on_curve(struct crypto_ec *e, - const struct crypto_ec_point *p) -{ - return EC_POINT_is_on_curve(e->group, (const EC_POINT *) p, e->bnctx); -} - -#endif /* CONFIG_ECC */ diff --git a/contrib/hostapd/src/crypto/des-internal.c b/contrib/hostapd/src/crypto/des-internal.c deleted file mode 100644 index dec39ef8c6..0000000000 --- a/contrib/hostapd/src/crypto/des-internal.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * DES and 3DES-EDE ciphers - * - * Modifications to LibTomCrypt implementation: - * Copyright (c) 2006-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" -#include "des_i.h" - -/* - * This implementation is based on a DES implementation included in - * LibTomCrypt. The version here is modified to fit in wpa_supplicant/hostapd - * coding style. - */ - -/* LibTomCrypt, modular cryptographic library -- Tom St Denis - * - * LibTomCrypt is a library that provides various cryptographic - * algorithms in a highly modular and flexible manner. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com - */ - -/** - DES code submitted by Dobes Vandermeer -*/ - -#define ROLc(x, y) \ - ((((unsigned long) (x) << (unsigned long) ((y) & 31)) | \ - (((unsigned long) (x) & 0xFFFFFFFFUL) >> \ - (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) -#define RORc(x, y) \ - (((((unsigned long) (x) & 0xFFFFFFFFUL) >> \ - (unsigned long) ((y) & 31)) | \ - ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & \ - 0xFFFFFFFFUL) - - -static const u32 bytebit[8] = -{ - 0200, 0100, 040, 020, 010, 04, 02, 01 -}; - -static const u32 bigbyte[24] = -{ - 0x800000UL, 0x400000UL, 0x200000UL, 0x100000UL, - 0x80000UL, 0x40000UL, 0x20000UL, 0x10000UL, - 0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL, - 0x800UL, 0x400UL, 0x200UL, 0x100UL, - 0x80UL, 0x40UL, 0x20UL, 0x10UL, - 0x8UL, 0x4UL, 0x2UL, 0x1L -}; - -/* Use the key schedule specific in the standard (ANSI X3.92-1981) */ - -static const u8 pc1[56] = { - 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, - 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, - 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, - 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 -}; - -static const u8 totrot[16] = { - 1, 2, 4, 6, - 8, 10, 12, 14, - 15, 17, 19, 21, - 23, 25, 27, 28 -}; - -static const u8 pc2[48] = { - 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, - 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, - 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, - 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 -}; - - -static const u32 SP1[64] = -{ - 0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL, - 0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL, - 0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL, - 0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL, - 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL, - 0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL, - 0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL, - 0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL, - 0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL, - 0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL, - 0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL, - 0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL, - 0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL, - 0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL, - 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL, - 0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL -}; - -static const u32 SP2[64] = -{ - 0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL, - 0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL, - 0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL, - 0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL, - 0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL, - 0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL, - 0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL, - 0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL, - 0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL, - 0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL, - 0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL, - 0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL, - 0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL, - 0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL, - 0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL, - 0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL -}; - -static const u32 SP3[64] = -{ - 0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL, - 0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL, - 0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL, - 0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL, - 0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL, - 0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL, - 0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL, - 0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL, - 0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL, - 0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL, - 0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL, - 0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL, - 0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL, - 0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL, - 0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL, - 0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL -}; - -static const u32 SP4[64] = -{ - 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, - 0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL, - 0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL, - 0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL, - 0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL, - 0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL, - 0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL, - 0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL, - 0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL, - 0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL, - 0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL, - 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, - 0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL, - 0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL, - 0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL, - 0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL -}; - -static const u32 SP5[64] = -{ - 0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL, - 0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL, - 0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL, - 0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL, - 0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL, - 0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL, - 0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL, - 0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL, - 0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL, - 0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL, - 0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL, - 0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL, - 0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL, - 0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL, - 0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL, - 0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL -}; - -static const u32 SP6[64] = -{ - 0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL, - 0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL, - 0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL, - 0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, - 0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL, - 0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL, - 0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL, - 0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL, - 0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL, - 0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL, - 0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, - 0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL, - 0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL, - 0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL, - 0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL, - 0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL -}; - -static const u32 SP7[64] = -{ - 0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL, - 0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL, - 0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL, - 0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL, - 0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL, - 0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL, - 0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL, - 0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL, - 0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL, - 0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL, - 0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL, - 0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL, - 0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL, - 0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL, - 0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL, - 0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL -}; - -static const u32 SP8[64] = -{ - 0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL, - 0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL, - 0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL, - 0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL, - 0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL, - 0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL, - 0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL, - 0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL, - 0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL, - 0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL, - 0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL, - 0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL, - 0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL, - 0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL, - 0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL, - 0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL -}; - - -static void cookey(const u32 *raw1, u32 *keyout) -{ - u32 *cook; - const u32 *raw0; - u32 dough[32]; - int i; - - cook = dough; - for (i = 0; i < 16; i++, raw1++) { - raw0 = raw1++; - *cook = (*raw0 & 0x00fc0000L) << 6; - *cook |= (*raw0 & 0x00000fc0L) << 10; - *cook |= (*raw1 & 0x00fc0000L) >> 10; - *cook++ |= (*raw1 & 0x00000fc0L) >> 6; - *cook = (*raw0 & 0x0003f000L) << 12; - *cook |= (*raw0 & 0x0000003fL) << 16; - *cook |= (*raw1 & 0x0003f000L) >> 4; - *cook++ |= (*raw1 & 0x0000003fL); - } - - os_memcpy(keyout, dough, sizeof(dough)); -} - - -static void deskey(const u8 *key, int decrypt, u32 *keyout) -{ - u32 i, j, l, m, n, kn[32]; - u8 pc1m[56], pcr[56]; - - for (j = 0; j < 56; j++) { - l = (u32) pc1[j]; - m = l & 7; - pc1m[j] = (u8) - ((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0); - } - - for (i = 0; i < 16; i++) { - if (decrypt) - m = (15 - i) << 1; - else - m = i << 1; - n = m + 1; - kn[m] = kn[n] = 0L; - for (j = 0; j < 28; j++) { - l = j + (u32) totrot[i]; - if (l < 28) - pcr[j] = pc1m[l]; - else - pcr[j] = pc1m[l - 28]; - } - for (/* j = 28 */; j < 56; j++) { - l = j + (u32) totrot[i]; - if (l < 56) - pcr[j] = pc1m[l]; - else - pcr[j] = pc1m[l - 28]; - } - for (j = 0; j < 24; j++) { - if ((int) pcr[(int) pc2[j]] != 0) - kn[m] |= bigbyte[j]; - if ((int) pcr[(int) pc2[j + 24]] != 0) - kn[n] |= bigbyte[j]; - } - } - - cookey(kn, keyout); -} - - -static void desfunc(u32 *block, const u32 *keys) -{ - u32 work, right, leftt; - int cur_round; - - leftt = block[0]; - right = block[1]; - - work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; - right ^= work; - leftt ^= (work << 4); - - work = ((leftt >> 16) ^ right) & 0x0000ffffL; - right ^= work; - leftt ^= (work << 16); - - work = ((right >> 2) ^ leftt) & 0x33333333L; - leftt ^= work; - right ^= (work << 2); - - work = ((right >> 8) ^ leftt) & 0x00ff00ffL; - leftt ^= work; - right ^= (work << 8); - - right = ROLc(right, 1); - work = (leftt ^ right) & 0xaaaaaaaaL; - - leftt ^= work; - right ^= work; - leftt = ROLc(leftt, 1); - - for (cur_round = 0; cur_round < 8; cur_round++) { - work = RORc(right, 4) ^ *keys++; - leftt ^= SP7[work & 0x3fL] - ^ SP5[(work >> 8) & 0x3fL] - ^ SP3[(work >> 16) & 0x3fL] - ^ SP1[(work >> 24) & 0x3fL]; - work = right ^ *keys++; - leftt ^= SP8[ work & 0x3fL] - ^ SP6[(work >> 8) & 0x3fL] - ^ SP4[(work >> 16) & 0x3fL] - ^ SP2[(work >> 24) & 0x3fL]; - - work = RORc(leftt, 4) ^ *keys++; - right ^= SP7[ work & 0x3fL] - ^ SP5[(work >> 8) & 0x3fL] - ^ SP3[(work >> 16) & 0x3fL] - ^ SP1[(work >> 24) & 0x3fL]; - work = leftt ^ *keys++; - right ^= SP8[ work & 0x3fL] - ^ SP6[(work >> 8) & 0x3fL] - ^ SP4[(work >> 16) & 0x3fL] - ^ SP2[(work >> 24) & 0x3fL]; - } - - right = RORc(right, 1); - work = (leftt ^ right) & 0xaaaaaaaaL; - leftt ^= work; - right ^= work; - leftt = RORc(leftt, 1); - work = ((leftt >> 8) ^ right) & 0x00ff00ffL; - right ^= work; - leftt ^= (work << 8); - /* -- */ - work = ((leftt >> 2) ^ right) & 0x33333333L; - right ^= work; - leftt ^= (work << 2); - work = ((right >> 16) ^ leftt) & 0x0000ffffL; - leftt ^= work; - right ^= (work << 16); - work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; - leftt ^= work; - right ^= (work << 4); - - block[0] = right; - block[1] = leftt; -} - - -/* wpa_supplicant/hostapd specific wrapper */ - -void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -{ - u8 pkey[8], next, tmp; - int i; - u32 ek[32], work[2]; - - /* Add parity bits to the key */ - next = 0; - for (i = 0; i < 7; i++) { - tmp = key[i]; - pkey[i] = (tmp >> i) | next | 1; - next = tmp << (7 - i); - } - pkey[i] = next | 1; - - deskey(pkey, 0, ek); - - work[0] = WPA_GET_BE32(clear); - work[1] = WPA_GET_BE32(clear + 4); - desfunc(work, ek); - WPA_PUT_BE32(cypher, work[0]); - WPA_PUT_BE32(cypher + 4, work[1]); - - os_memset(pkey, 0, sizeof(pkey)); - os_memset(ek, 0, sizeof(ek)); -} - - -void des_key_setup(const u8 *key, u32 *ek, u32 *dk) -{ - deskey(key, 0, ek); - deskey(key, 1, dk); -} - - -void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt) -{ - u32 work[2]; - work[0] = WPA_GET_BE32(plain); - work[1] = WPA_GET_BE32(plain + 4); - desfunc(work, ek); - WPA_PUT_BE32(crypt, work[0]); - WPA_PUT_BE32(crypt + 4, work[1]); -} - - -void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain) -{ - u32 work[2]; - work[0] = WPA_GET_BE32(crypt); - work[1] = WPA_GET_BE32(crypt + 4); - desfunc(work, dk); - WPA_PUT_BE32(plain, work[0]); - WPA_PUT_BE32(plain + 4, work[1]); -} - - -void des3_key_setup(const u8 *key, struct des3_key_s *dkey) -{ - deskey(key, 0, dkey->ek[0]); - deskey(key + 8, 1, dkey->ek[1]); - deskey(key + 16, 0, dkey->ek[2]); - - deskey(key, 1, dkey->dk[2]); - deskey(key + 8, 0, dkey->dk[1]); - deskey(key + 16, 1, dkey->dk[0]); -} - - -void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt) -{ - u32 work[2]; - - work[0] = WPA_GET_BE32(plain); - work[1] = WPA_GET_BE32(plain + 4); - desfunc(work, key->ek[0]); - desfunc(work, key->ek[1]); - desfunc(work, key->ek[2]); - WPA_PUT_BE32(crypt, work[0]); - WPA_PUT_BE32(crypt + 4, work[1]); -} - - -void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain) -{ - u32 work[2]; - - work[0] = WPA_GET_BE32(crypt); - work[1] = WPA_GET_BE32(crypt + 4); - desfunc(work, key->dk[0]); - desfunc(work, key->dk[1]); - desfunc(work, key->dk[2]); - WPA_PUT_BE32(plain, work[0]); - WPA_PUT_BE32(plain + 4, work[1]); -} diff --git a/contrib/hostapd/src/crypto/des_i.h b/contrib/hostapd/src/crypto/des_i.h deleted file mode 100644 index c9563d2204..0000000000 --- a/contrib/hostapd/src/crypto/des_i.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * DES and 3DES-EDE ciphers - * Copyright (c) 2006-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef DES_I_H -#define DES_I_H - -struct des3_key_s { - u32 ek[3][32]; - u32 dk[3][32]; -}; - -void des_key_setup(const u8 *key, u32 *ek, u32 *dk); -void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt); -void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain); - -void des3_key_setup(const u8 *key, struct des3_key_s *dkey); -void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt); -void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain); - -#endif /* DES_I_H */ diff --git a/contrib/hostapd/src/crypto/dh_group5.c b/contrib/hostapd/src/crypto/dh_group5.c deleted file mode 100644 index ccdbfc8129..0000000000 --- a/contrib/hostapd/src/crypto/dh_group5.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Diffie-Hellman group 5 operations - * Copyright (c) 2009, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "dh_groups.h" -#include "dh_group5.h" - - -void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) -{ - *publ = dh_init(dh_groups_get(5), priv); - if (*publ == NULL) - return NULL; - return (void *) 1; -} - - -void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ) -{ - return (void *) 1; -} - - -struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, - const struct wpabuf *own_private) -{ - return dh_derive_shared(peer_public, own_private, dh_groups_get(5)); -} - - -void dh5_free(void *ctx) -{ -} diff --git a/contrib/hostapd/src/crypto/dh_group5.h b/contrib/hostapd/src/crypto/dh_group5.h deleted file mode 100644 index abee8eaafb..0000000000 --- a/contrib/hostapd/src/crypto/dh_group5.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Diffie-Hellman group 5 operations - * Copyright (c) 2009, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef DH_GROUP5_H -#define DH_GROUP5_H - -void * dh5_init(struct wpabuf **priv, struct wpabuf **publ); -void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ); -struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, - const struct wpabuf *own_private); -void dh5_free(void *ctx); - -#endif /* DH_GROUP5_H */ diff --git a/contrib/hostapd/src/crypto/dh_groups.c b/contrib/hostapd/src/crypto/dh_groups.c deleted file mode 100644 index 58e94c393c..0000000000 --- a/contrib/hostapd/src/crypto/dh_groups.c +++ /dev/null @@ -1,1271 +0,0 @@ -/* - * Diffie-Hellman groups - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" -#include "random.h" -#include "dh_groups.h" - - -#ifdef ALL_DH_GROUPS - -/* RFC 4306, B.1. Group 1 - 768 Bit MODP - * Generator: 2 - * Prime: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } - */ -static const u8 dh_group1_generator[1] = { 0x02 }; -static const u8 dh_group1_prime[96] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, - 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, - 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, - 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, - 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, - 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, - 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, - 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, - 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, - 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; -static const u8 dh_group1_order[96] = { - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, - 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, - 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, - 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, - 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, - 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, - 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, - 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, - 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, - 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1D, 0x1B, 0x10, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - -/* RFC 4306, B.2. Group 2 - 1024 Bit MODP - * Generator: 2 - * Prime: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } - */ -static const u8 dh_group2_generator[1] = { 0x02 }; -static const u8 dh_group2_prime[128] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, - 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, - 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, - 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, - 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, - 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, - 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, - 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, - 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, - 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, - 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, - 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, - 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, - 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; -static const u8 dh_group2_order[128] = { - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, - 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, - 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, - 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, - 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, - 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, - 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, - 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, - 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, - 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, - 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, - 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, - 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, - 0x24, 0x94, 0x33, 0x28, 0xF6, 0x73, 0x29, 0xC0, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - -#endif /* ALL_DH_GROUPS */ - -/* RFC 3526, 2. Group 5 - 1536 Bit MODP - * Generator: 2 - * Prime: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 } - */ -static const u8 dh_group5_generator[1] = { 0x02 }; -static const u8 dh_group5_prime[192] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, - 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, - 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, - 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, - 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, - 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, - 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, - 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, - 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, - 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, - 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, - 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, - 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, - 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, - 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, - 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, - 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, - 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, - 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, - 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, - 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, - 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; -static const u8 dh_group5_order[192] = { - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, - 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, - 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, - 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, - 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, - 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, - 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, - 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, - 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, - 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, - 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, - 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, - 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, - 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E, - 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82, - 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD, - 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF, - 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB, - 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, - 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36, - 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02, - 0x78, 0xBA, 0x36, 0x04, 0x65, 0x11, 0xB9, 0x93, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - -#ifdef ALL_DH_GROUPS - -/* RFC 3526, 3. Group 14 - 2048 Bit MODP - * Generator: 2 - * Prime: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 } - */ -static const u8 dh_group14_generator[1] = { 0x02 }; -static const u8 dh_group14_prime[256] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, - 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, - 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, - 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, - 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, - 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, - 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, - 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, - 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, - 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, - 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, - 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, - 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, - 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, - 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, - 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, - 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, - 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, - 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, - 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, - 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, - 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, - 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, - 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, - 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, - 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, - 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, - 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, - 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, - 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; -static const u8 dh_group14_order[256] = { - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, - 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, - 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, - 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, - 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, - 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, - 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, - 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, - 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, - 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, - 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, - 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, - 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, - 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E, - 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82, - 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD, - 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF, - 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB, - 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, - 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36, - 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02, - 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE, - 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D, - 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01, - 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47, - 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, - 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C, - 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72, - 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88, - 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x56, 0x55, 0x34, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - -/* RFC 3526, 4. Group 15 - 3072 Bit MODP - * Generator: 2 - * Prime: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 } - */ -static const u8 dh_group15_generator[1] = { 0x02 }; -static const u8 dh_group15_prime[384] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, - 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, - 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, - 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, - 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, - 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, - 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, - 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, - 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, - 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, - 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, - 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, - 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, - 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, - 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, - 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, - 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, - 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, - 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, - 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, - 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, - 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, - 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, - 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, - 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, - 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, - 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, - 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, - 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, - 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, - 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, - 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, - 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, - 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, - 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, - 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, - 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, - 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, - 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, - 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, - 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, - 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, - 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, - 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, - 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, - 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; -static const u8 dh_group15_order[384] = { - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, - 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, - 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, - 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, - 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, - 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, - 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, - 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, - 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, - 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, - 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, - 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, - 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, - 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E, - 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82, - 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD, - 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF, - 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB, - 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, - 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36, - 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02, - 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE, - 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D, - 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01, - 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47, - 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, - 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C, - 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72, - 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88, - 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16, - 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19, - 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32, - 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85, - 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E, - 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63, - 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB, - 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE, - 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35, - 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32, - 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32, - 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06, - 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6, - 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71, - 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98, - 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47, - 0x25, 0xC1, 0x68, 0x90, 0x54, 0x9D, 0x69, 0x65, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - -/* RFC 3526, 5. Group 16 - 4096 Bit MODP - * Generator: 2 - * Prime: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } - */ -static const u8 dh_group16_generator[1] = { 0x02 }; -static const u8 dh_group16_prime[512] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, - 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, - 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, - 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, - 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, - 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, - 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, - 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, - 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, - 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, - 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, - 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, - 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, - 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, - 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, - 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, - 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, - 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, - 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, - 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, - 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, - 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, - 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, - 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, - 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, - 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, - 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, - 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, - 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, - 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, - 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, - 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, - 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, - 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, - 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, - 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, - 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, - 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, - 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, - 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, - 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, - 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, - 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, - 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, - 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, - 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, - 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, - 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, - 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, - 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, - 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, - 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, - 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, - 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, - 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, - 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, - 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, - 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, - 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, - 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, - 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, - 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; -static const u8 dh_group16_order[512] = { - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, - 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, - 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, - 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, - 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, - 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, - 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, - 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, - 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, - 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, - 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, - 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, - 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, - 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E, - 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82, - 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD, - 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF, - 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB, - 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, - 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36, - 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02, - 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE, - 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D, - 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01, - 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47, - 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, - 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C, - 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72, - 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88, - 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16, - 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19, - 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32, - 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85, - 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E, - 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63, - 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB, - 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE, - 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35, - 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32, - 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32, - 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06, - 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6, - 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71, - 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98, - 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47, - 0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00, - 0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B, - 0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93, - 0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E, - 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED, - 0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74, - 0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C, - 0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53, - 0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E, - 0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1, - 0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6, - 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7, - 0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E, - 0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54, - 0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0, - 0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47, - 0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x03, 0x18, 0xCC, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - -/* RFC 3526, 6. Group 17 - 6144 Bit MODP - * Generator: 2 - * Prime: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 } - */ -static const u8 dh_group17_generator[1] = { 0x02 }; -static const u8 dh_group17_prime[768] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, - 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, - 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, - 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, - 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, - 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, - 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, - 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, - 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, - 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, - 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, - 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, - 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, - 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, - 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, - 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, - 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, - 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, - 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, - 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, - 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, - 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, - 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, - 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, - 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, - 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, - 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, - 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, - 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, - 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, - 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, - 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, - 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, - 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, - 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, - 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, - 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, - 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, - 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, - 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, - 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, - 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, - 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, - 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, - 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, - 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, - 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, - 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, - 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, - 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, - 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, - 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, - 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, - 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, - 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, - 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, - 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, - 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, - 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, - 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, - 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, - 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, - 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, - 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, - 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, - 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, - 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE, - 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, - 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, - 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, - 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, - 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, - 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42, - 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, - 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, - 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, - 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, - 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, - 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E, - 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, - 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, - 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, - 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, - 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, - 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0, - 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, - 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, - 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, - 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, - 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, - 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68, - 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, - 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, - 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; -static const u8 dh_group17_order[768] = { - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, - 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, - 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, - 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, - 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, - 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, - 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, - 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, - 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, - 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, - 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, - 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, - 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, - 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E, - 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82, - 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD, - 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF, - 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB, - 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, - 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36, - 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02, - 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE, - 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D, - 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01, - 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47, - 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, - 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C, - 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72, - 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88, - 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16, - 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19, - 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32, - 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85, - 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E, - 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63, - 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB, - 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE, - 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35, - 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32, - 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32, - 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06, - 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6, - 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71, - 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98, - 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47, - 0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00, - 0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B, - 0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93, - 0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E, - 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED, - 0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74, - 0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C, - 0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53, - 0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E, - 0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1, - 0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6, - 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7, - 0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E, - 0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54, - 0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0, - 0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47, - 0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x01, 0x42, 0x49, - 0x1B, 0x61, 0xFD, 0x5A, 0x69, 0x3E, 0x38, 0x13, - 0x60, 0xEA, 0x6E, 0x59, 0x30, 0x13, 0x23, 0x6F, - 0x64, 0xBA, 0x8F, 0x3B, 0x1E, 0xDD, 0x1B, 0xDE, - 0xFC, 0x7F, 0xCA, 0x03, 0x56, 0xCF, 0x29, 0x87, - 0x72, 0xED, 0x9C, 0x17, 0xA0, 0x98, 0x00, 0xD7, - 0x58, 0x35, 0x29, 0xF6, 0xC8, 0x13, 0xEC, 0x18, - 0x8B, 0xCB, 0x93, 0xD8, 0x43, 0x2D, 0x44, 0x8C, - 0x6D, 0x1F, 0x6D, 0xF5, 0xE7, 0xCD, 0x8A, 0x76, - 0xA2, 0x67, 0x36, 0x5D, 0x67, 0x6A, 0x5D, 0x8D, - 0xED, 0xBF, 0x8A, 0x23, 0xF3, 0x66, 0x12, 0xA5, - 0x99, 0x90, 0x28, 0xA8, 0x95, 0xEB, 0xD7, 0xA1, - 0x37, 0xDC, 0x7A, 0x00, 0x9B, 0xC6, 0x69, 0x5F, - 0xAC, 0xC1, 0xE5, 0x00, 0xE3, 0x25, 0xC9, 0x76, - 0x78, 0x19, 0x75, 0x0A, 0xE8, 0xB9, 0x0E, 0x81, - 0xFA, 0x41, 0x6B, 0xE7, 0x37, 0x3A, 0x7F, 0x7B, - 0x6A, 0xAF, 0x38, 0x17, 0xA3, 0x4C, 0x06, 0x41, - 0x5A, 0xD4, 0x20, 0x18, 0xC8, 0x05, 0x8E, 0x4F, - 0x2C, 0xF3, 0xE4, 0xBF, 0xDF, 0x63, 0xF4, 0x79, - 0x91, 0xD4, 0xBD, 0x3F, 0x1B, 0x66, 0x44, 0x5F, - 0x07, 0x8E, 0xA2, 0xDB, 0xFF, 0xAC, 0x2D, 0x62, - 0xA5, 0xEA, 0x03, 0xD9, 0x15, 0xA0, 0xAA, 0x55, - 0x66, 0x47, 0xB6, 0xBF, 0x5F, 0xA4, 0x70, 0xEC, - 0x0A, 0x66, 0x2F, 0x69, 0x07, 0xC0, 0x1B, 0xF0, - 0x53, 0xCB, 0x8A, 0xF7, 0x79, 0x4D, 0xF1, 0x94, - 0x03, 0x50, 0xEA, 0xC5, 0xDB, 0xE2, 0xED, 0x3B, - 0x7A, 0xA8, 0x55, 0x1E, 0xC5, 0x0F, 0xDF, 0xF8, - 0x75, 0x8C, 0xE6, 0x58, 0xD1, 0x89, 0xEA, 0xAE, - 0x6D, 0x2B, 0x64, 0xF6, 0x17, 0x79, 0x4B, 0x19, - 0x1C, 0x3F, 0xF4, 0x6B, 0xB7, 0x1E, 0x02, 0x34, - 0x02, 0x1F, 0x47, 0xB3, 0x1F, 0xA4, 0x30, 0x77, - 0x09, 0x5F, 0x96, 0xAD, 0x85, 0xBA, 0x3A, 0x6B, - 0x73, 0x4A, 0x7C, 0x8F, 0x36, 0xE6, 0x20, 0x12, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - -/* RFC 3526, 7. Group 18 - 8192 Bit MODP - * Generator: 2 - * Prime: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 } - */ -static const u8 dh_group18_generator[1] = { 0x02 }; -static const u8 dh_group18_prime[1024] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, - 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, - 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, - 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, - 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, - 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, - 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, - 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, - 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, - 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, - 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, - 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, - 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, - 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, - 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, - 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, - 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, - 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, - 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, - 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, - 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, - 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, - 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, - 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, - 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, - 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, - 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, - 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, - 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, - 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, - 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, - 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, - 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, - 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, - 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, - 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, - 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, - 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, - 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, - 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, - 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, - 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, - 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, - 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, - 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, - 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, - 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, - 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, - 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, - 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, - 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, - 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, - 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, - 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, - 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, - 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, - 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, - 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, - 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, - 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, - 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, - 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, - 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, - 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, - 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, - 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, - 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE, - 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, - 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, - 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, - 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, - 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, - 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42, - 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, - 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, - 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, - 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, - 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, - 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E, - 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, - 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, - 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, - 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, - 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, - 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0, - 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, - 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, - 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, - 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, - 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, - 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68, - 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, - 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, - 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59, - 0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4, - 0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C, - 0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA, - 0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00, - 0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED, - 0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66, - 0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68, - 0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78, - 0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D, - 0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9, - 0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07, - 0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7, - 0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B, - 0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD, - 0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8, - 0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A, - 0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6, - 0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D, - 0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36, - 0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1, - 0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D, - 0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1, - 0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73, - 0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68, - 0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92, - 0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7, - 0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B, - 0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47, - 0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA, - 0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF, - 0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71, - 0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; -static const u8 dh_group18_order[1024] = { - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, - 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, - 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, - 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, - 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, - 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, - 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, - 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, - 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, - 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, - 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, - 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, - 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, - 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E, - 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82, - 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD, - 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF, - 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB, - 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, - 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36, - 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02, - 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE, - 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D, - 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01, - 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47, - 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, - 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C, - 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72, - 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88, - 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16, - 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19, - 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32, - 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85, - 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E, - 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63, - 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB, - 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE, - 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35, - 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32, - 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32, - 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06, - 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6, - 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71, - 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98, - 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47, - 0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00, - 0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B, - 0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93, - 0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E, - 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED, - 0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74, - 0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C, - 0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53, - 0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E, - 0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1, - 0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6, - 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7, - 0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E, - 0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54, - 0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0, - 0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47, - 0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x01, 0x42, 0x49, - 0x1B, 0x61, 0xFD, 0x5A, 0x69, 0x3E, 0x38, 0x13, - 0x60, 0xEA, 0x6E, 0x59, 0x30, 0x13, 0x23, 0x6F, - 0x64, 0xBA, 0x8F, 0x3B, 0x1E, 0xDD, 0x1B, 0xDE, - 0xFC, 0x7F, 0xCA, 0x03, 0x56, 0xCF, 0x29, 0x87, - 0x72, 0xED, 0x9C, 0x17, 0xA0, 0x98, 0x00, 0xD7, - 0x58, 0x35, 0x29, 0xF6, 0xC8, 0x13, 0xEC, 0x18, - 0x8B, 0xCB, 0x93, 0xD8, 0x43, 0x2D, 0x44, 0x8C, - 0x6D, 0x1F, 0x6D, 0xF5, 0xE7, 0xCD, 0x8A, 0x76, - 0xA2, 0x67, 0x36, 0x5D, 0x67, 0x6A, 0x5D, 0x8D, - 0xED, 0xBF, 0x8A, 0x23, 0xF3, 0x66, 0x12, 0xA5, - 0x99, 0x90, 0x28, 0xA8, 0x95, 0xEB, 0xD7, 0xA1, - 0x37, 0xDC, 0x7A, 0x00, 0x9B, 0xC6, 0x69, 0x5F, - 0xAC, 0xC1, 0xE5, 0x00, 0xE3, 0x25, 0xC9, 0x76, - 0x78, 0x19, 0x75, 0x0A, 0xE8, 0xB9, 0x0E, 0x81, - 0xFA, 0x41, 0x6B, 0xE7, 0x37, 0x3A, 0x7F, 0x7B, - 0x6A, 0xAF, 0x38, 0x17, 0xA3, 0x4C, 0x06, 0x41, - 0x5A, 0xD4, 0x20, 0x18, 0xC8, 0x05, 0x8E, 0x4F, - 0x2C, 0xF3, 0xE4, 0xBF, 0xDF, 0x63, 0xF4, 0x79, - 0x91, 0xD4, 0xBD, 0x3F, 0x1B, 0x66, 0x44, 0x5F, - 0x07, 0x8E, 0xA2, 0xDB, 0xFF, 0xAC, 0x2D, 0x62, - 0xA5, 0xEA, 0x03, 0xD9, 0x15, 0xA0, 0xAA, 0x55, - 0x66, 0x47, 0xB6, 0xBF, 0x5F, 0xA4, 0x70, 0xEC, - 0x0A, 0x66, 0x2F, 0x69, 0x07, 0xC0, 0x1B, 0xF0, - 0x53, 0xCB, 0x8A, 0xF7, 0x79, 0x4D, 0xF1, 0x94, - 0x03, 0x50, 0xEA, 0xC5, 0xDB, 0xE2, 0xED, 0x3B, - 0x7A, 0xA8, 0x55, 0x1E, 0xC5, 0x0F, 0xDF, 0xF8, - 0x75, 0x8C, 0xE6, 0x58, 0xD1, 0x89, 0xEA, 0xAE, - 0x6D, 0x2B, 0x64, 0xF6, 0x17, 0x79, 0x4B, 0x19, - 0x1C, 0x3F, 0xF4, 0x6B, 0xB7, 0x1E, 0x02, 0x34, - 0x02, 0x1F, 0x47, 0xB3, 0x1F, 0xA4, 0x30, 0x77, - 0x09, 0x5F, 0x96, 0xAD, 0x85, 0xBA, 0x3A, 0x6B, - 0x73, 0x4A, 0x7C, 0x8F, 0x36, 0xDF, 0x08, 0xAC, - 0xBA, 0x51, 0xC9, 0x37, 0x89, 0x7F, 0x72, 0xF2, - 0x1C, 0x3B, 0xBE, 0x5B, 0x54, 0x99, 0x6F, 0xC6, - 0x6C, 0x5F, 0x62, 0x68, 0x39, 0xDC, 0x98, 0xDD, - 0x1D, 0xE4, 0x19, 0x5B, 0x46, 0xCE, 0xE9, 0x80, - 0x3A, 0x0F, 0xD3, 0xDF, 0xC5, 0x7E, 0x23, 0xF6, - 0x92, 0xBB, 0x7B, 0x49, 0xB5, 0xD2, 0x12, 0x33, - 0x1D, 0x55, 0xB1, 0xCE, 0x2D, 0x72, 0x7A, 0xB4, - 0x1A, 0x11, 0xDA, 0x3A, 0x15, 0xF8, 0xE4, 0xBC, - 0x11, 0xC7, 0x8B, 0x65, 0xF1, 0xCE, 0xB2, 0x96, - 0xF1, 0xFE, 0xDC, 0x5F, 0x7E, 0x42, 0x45, 0x6C, - 0x91, 0x11, 0x17, 0x02, 0x52, 0x01, 0xBE, 0x03, - 0x89, 0xF5, 0xAB, 0xD4, 0x0D, 0x11, 0xF8, 0x63, - 0x9A, 0x39, 0xFE, 0x32, 0x36, 0x75, 0x18, 0x35, - 0xA5, 0xE5, 0xE4, 0x43, 0x17, 0xC1, 0xC2, 0xEE, - 0xFD, 0x4E, 0xA5, 0xBF, 0xD1, 0x60, 0x43, 0xF4, - 0x3C, 0xB4, 0x19, 0x81, 0xF6, 0xAD, 0xEE, 0x9D, - 0x03, 0x15, 0x9E, 0x7A, 0xD9, 0xD1, 0x3C, 0x53, - 0x36, 0x95, 0x09, 0xFC, 0x1F, 0xA2, 0x7C, 0x16, - 0xEF, 0x98, 0x87, 0x70, 0x3A, 0x55, 0xB5, 0x1B, - 0x22, 0xCB, 0xF4, 0x4C, 0xD0, 0x12, 0xAE, 0xE0, - 0xB2, 0x79, 0x8E, 0x62, 0x84, 0x23, 0x42, 0x8E, - 0xFC, 0xD5, 0xA4, 0x0C, 0xAE, 0xF6, 0xBF, 0x50, - 0xD8, 0xEA, 0x88, 0x5E, 0xBF, 0x73, 0xA6, 0xB9, - 0xFD, 0x79, 0xB5, 0xE1, 0x8F, 0x67, 0xD1, 0x34, - 0x1A, 0xC8, 0x23, 0x7A, 0x75, 0xC3, 0xCF, 0xC9, - 0x20, 0x04, 0xA1, 0xC5, 0xA4, 0x0E, 0x36, 0x6B, - 0xC4, 0x4D, 0x00, 0x17, 0x6A, 0xF7, 0x1C, 0x15, - 0xE4, 0x8C, 0x86, 0xD3, 0x7E, 0x01, 0x37, 0x23, - 0xCA, 0xAC, 0x72, 0x23, 0xAB, 0x3B, 0xF4, 0xD5, - 0x4F, 0x18, 0x28, 0x71, 0x3B, 0x2B, 0x4A, 0x6F, - 0xE4, 0x0F, 0xAB, 0x74, 0x40, 0x5C, 0xB7, 0x38, - 0xB0, 0x64, 0xC0, 0x6E, 0xCC, 0x76, 0xE9, 0xEF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - -/* - * RFC 5114, 2.1. - * Group 22 - 1024-bit MODP Group with 160-bit Prime Order Subgroup - */ -static const u8 dh_group22_generator[] = { - 0xA4, 0xD1, 0xCB, 0xD5, 0xC3, 0xFD, 0x34, 0x12, - 0x67, 0x65, 0xA4, 0x42, 0xEF, 0xB9, 0x99, 0x05, - 0xF8, 0x10, 0x4D, 0xD2, 0x58, 0xAC, 0x50, 0x7F, - 0xD6, 0x40, 0x6C, 0xFF, 0x14, 0x26, 0x6D, 0x31, - 0x26, 0x6F, 0xEA, 0x1E, 0x5C, 0x41, 0x56, 0x4B, - 0x77, 0x7E, 0x69, 0x0F, 0x55, 0x04, 0xF2, 0x13, - 0x16, 0x02, 0x17, 0xB4, 0xB0, 0x1B, 0x88, 0x6A, - 0x5E, 0x91, 0x54, 0x7F, 0x9E, 0x27, 0x49, 0xF4, - 0xD7, 0xFB, 0xD7, 0xD3, 0xB9, 0xA9, 0x2E, 0xE1, - 0x90, 0x9D, 0x0D, 0x22, 0x63, 0xF8, 0x0A, 0x76, - 0xA6, 0xA2, 0x4C, 0x08, 0x7A, 0x09, 0x1F, 0x53, - 0x1D, 0xBF, 0x0A, 0x01, 0x69, 0xB6, 0xA2, 0x8A, - 0xD6, 0x62, 0xA4, 0xD1, 0x8E, 0x73, 0xAF, 0xA3, - 0x2D, 0x77, 0x9D, 0x59, 0x18, 0xD0, 0x8B, 0xC8, - 0x85, 0x8F, 0x4D, 0xCE, 0xF9, 0x7C, 0x2A, 0x24, - 0x85, 0x5E, 0x6E, 0xEB, 0x22, 0xB3, 0xB2, 0xE5 -}; -static const u8 dh_group22_prime[] = { - 0xB1, 0x0B, 0x8F, 0x96, 0xA0, 0x80, 0xE0, 0x1D, - 0xDE, 0x92, 0xDE, 0x5E, 0xAE, 0x5D, 0x54, 0xEC, - 0x52, 0xC9, 0x9F, 0xBC, 0xFB, 0x06, 0xA3, 0xC6, - 0x9A, 0x6A, 0x9D, 0xCA, 0x52, 0xD2, 0x3B, 0x61, - 0x60, 0x73, 0xE2, 0x86, 0x75, 0xA2, 0x3D, 0x18, - 0x98, 0x38, 0xEF, 0x1E, 0x2E, 0xE6, 0x52, 0xC0, - 0x13, 0xEC, 0xB4, 0xAE, 0xA9, 0x06, 0x11, 0x23, - 0x24, 0x97, 0x5C, 0x3C, 0xD4, 0x9B, 0x83, 0xBF, - 0xAC, 0xCB, 0xDD, 0x7D, 0x90, 0xC4, 0xBD, 0x70, - 0x98, 0x48, 0x8E, 0x9C, 0x21, 0x9A, 0x73, 0x72, - 0x4E, 0xFF, 0xD6, 0xFA, 0xE5, 0x64, 0x47, 0x38, - 0xFA, 0xA3, 0x1A, 0x4F, 0xF5, 0x5B, 0xCC, 0xC0, - 0xA1, 0x51, 0xAF, 0x5F, 0x0D, 0xC8, 0xB4, 0xBD, - 0x45, 0xBF, 0x37, 0xDF, 0x36, 0x5C, 0x1A, 0x65, - 0xE6, 0x8C, 0xFD, 0xA7, 0x6D, 0x4D, 0xA7, 0x08, - 0xDF, 0x1F, 0xB2, 0xBC, 0x2E, 0x4A, 0x43, 0x71 -}; -static const u8 dh_group22_order[] = { - 0xF5, 0x18, 0xAA, 0x87, 0x81, 0xA8, 0xDF, 0x27, - 0x8A, 0xBA, 0x4E, 0x7D, 0x64, 0xB7, 0xCB, 0x9D, - 0x49, 0x46, 0x23, 0x53 -}; - -/* - * RFC 5114, 2.2. - * Group 23 - 2048-bit MODP Group with 224-bit Prime Order Subgroup - */ -static const u8 dh_group23_generator[] = { - 0xAC, 0x40, 0x32, 0xEF, 0x4F, 0x2D, 0x9A, 0xE3, - 0x9D, 0xF3, 0x0B, 0x5C, 0x8F, 0xFD, 0xAC, 0x50, - 0x6C, 0xDE, 0xBE, 0x7B, 0x89, 0x99, 0x8C, 0xAF, - 0x74, 0x86, 0x6A, 0x08, 0xCF, 0xE4, 0xFF, 0xE3, - 0xA6, 0x82, 0x4A, 0x4E, 0x10, 0xB9, 0xA6, 0xF0, - 0xDD, 0x92, 0x1F, 0x01, 0xA7, 0x0C, 0x4A, 0xFA, - 0xAB, 0x73, 0x9D, 0x77, 0x00, 0xC2, 0x9F, 0x52, - 0xC5, 0x7D, 0xB1, 0x7C, 0x62, 0x0A, 0x86, 0x52, - 0xBE, 0x5E, 0x90, 0x01, 0xA8, 0xD6, 0x6A, 0xD7, - 0xC1, 0x76, 0x69, 0x10, 0x19, 0x99, 0x02, 0x4A, - 0xF4, 0xD0, 0x27, 0x27, 0x5A, 0xC1, 0x34, 0x8B, - 0xB8, 0xA7, 0x62, 0xD0, 0x52, 0x1B, 0xC9, 0x8A, - 0xE2, 0x47, 0x15, 0x04, 0x22, 0xEA, 0x1E, 0xD4, - 0x09, 0x93, 0x9D, 0x54, 0xDA, 0x74, 0x60, 0xCD, - 0xB5, 0xF6, 0xC6, 0xB2, 0x50, 0x71, 0x7C, 0xBE, - 0xF1, 0x80, 0xEB, 0x34, 0x11, 0x8E, 0x98, 0xD1, - 0x19, 0x52, 0x9A, 0x45, 0xD6, 0xF8, 0x34, 0x56, - 0x6E, 0x30, 0x25, 0xE3, 0x16, 0xA3, 0x30, 0xEF, - 0xBB, 0x77, 0xA8, 0x6F, 0x0C, 0x1A, 0xB1, 0x5B, - 0x05, 0x1A, 0xE3, 0xD4, 0x28, 0xC8, 0xF8, 0xAC, - 0xB7, 0x0A, 0x81, 0x37, 0x15, 0x0B, 0x8E, 0xEB, - 0x10, 0xE1, 0x83, 0xED, 0xD1, 0x99, 0x63, 0xDD, - 0xD9, 0xE2, 0x63, 0xE4, 0x77, 0x05, 0x89, 0xEF, - 0x6A, 0xA2, 0x1E, 0x7F, 0x5F, 0x2F, 0xF3, 0x81, - 0xB5, 0x39, 0xCC, 0xE3, 0x40, 0x9D, 0x13, 0xCD, - 0x56, 0x6A, 0xFB, 0xB4, 0x8D, 0x6C, 0x01, 0x91, - 0x81, 0xE1, 0xBC, 0xFE, 0x94, 0xB3, 0x02, 0x69, - 0xED, 0xFE, 0x72, 0xFE, 0x9B, 0x6A, 0xA4, 0xBD, - 0x7B, 0x5A, 0x0F, 0x1C, 0x71, 0xCF, 0xFF, 0x4C, - 0x19, 0xC4, 0x18, 0xE1, 0xF6, 0xEC, 0x01, 0x79, - 0x81, 0xBC, 0x08, 0x7F, 0x2A, 0x70, 0x65, 0xB3, - 0x84, 0xB8, 0x90, 0xD3, 0x19, 0x1F, 0x2B, 0xFA -}; -static const u8 dh_group23_prime[] = { - 0xAD, 0x10, 0x7E, 0x1E, 0x91, 0x23, 0xA9, 0xD0, - 0xD6, 0x60, 0xFA, 0xA7, 0x95, 0x59, 0xC5, 0x1F, - 0xA2, 0x0D, 0x64, 0xE5, 0x68, 0x3B, 0x9F, 0xD1, - 0xB5, 0x4B, 0x15, 0x97, 0xB6, 0x1D, 0x0A, 0x75, - 0xE6, 0xFA, 0x14, 0x1D, 0xF9, 0x5A, 0x56, 0xDB, - 0xAF, 0x9A, 0x3C, 0x40, 0x7B, 0xA1, 0xDF, 0x15, - 0xEB, 0x3D, 0x68, 0x8A, 0x30, 0x9C, 0x18, 0x0E, - 0x1D, 0xE6, 0xB8, 0x5A, 0x12, 0x74, 0xA0, 0xA6, - 0x6D, 0x3F, 0x81, 0x52, 0xAD, 0x6A, 0xC2, 0x12, - 0x90, 0x37, 0xC9, 0xED, 0xEF, 0xDA, 0x4D, 0xF8, - 0xD9, 0x1E, 0x8F, 0xEF, 0x55, 0xB7, 0x39, 0x4B, - 0x7A, 0xD5, 0xB7, 0xD0, 0xB6, 0xC1, 0x22, 0x07, - 0xC9, 0xF9, 0x8D, 0x11, 0xED, 0x34, 0xDB, 0xF6, - 0xC6, 0xBA, 0x0B, 0x2C, 0x8B, 0xBC, 0x27, 0xBE, - 0x6A, 0x00, 0xE0, 0xA0, 0xB9, 0xC4, 0x97, 0x08, - 0xB3, 0xBF, 0x8A, 0x31, 0x70, 0x91, 0x88, 0x36, - 0x81, 0x28, 0x61, 0x30, 0xBC, 0x89, 0x85, 0xDB, - 0x16, 0x02, 0xE7, 0x14, 0x41, 0x5D, 0x93, 0x30, - 0x27, 0x82, 0x73, 0xC7, 0xDE, 0x31, 0xEF, 0xDC, - 0x73, 0x10, 0xF7, 0x12, 0x1F, 0xD5, 0xA0, 0x74, - 0x15, 0x98, 0x7D, 0x9A, 0xDC, 0x0A, 0x48, 0x6D, - 0xCD, 0xF9, 0x3A, 0xCC, 0x44, 0x32, 0x83, 0x87, - 0x31, 0x5D, 0x75, 0xE1, 0x98, 0xC6, 0x41, 0xA4, - 0x80, 0xCD, 0x86, 0xA1, 0xB9, 0xE5, 0x87, 0xE8, - 0xBE, 0x60, 0xE6, 0x9C, 0xC9, 0x28, 0xB2, 0xB9, - 0xC5, 0x21, 0x72, 0xE4, 0x13, 0x04, 0x2E, 0x9B, - 0x23, 0xF1, 0x0B, 0x0E, 0x16, 0xE7, 0x97, 0x63, - 0xC9, 0xB5, 0x3D, 0xCF, 0x4B, 0xA8, 0x0A, 0x29, - 0xE3, 0xFB, 0x73, 0xC1, 0x6B, 0x8E, 0x75, 0xB9, - 0x7E, 0xF3, 0x63, 0xE2, 0xFF, 0xA3, 0x1F, 0x71, - 0xCF, 0x9D, 0xE5, 0x38, 0x4E, 0x71, 0xB8, 0x1C, - 0x0A, 0xC4, 0xDF, 0xFE, 0x0C, 0x10, 0xE6, 0x4F -}; -static const u8 dh_group23_order[] = { - 0x80, 0x1C, 0x0D, 0x34, 0xC5, 0x8D, 0x93, 0xFE, - 0x99, 0x71, 0x77, 0x10, 0x1F, 0x80, 0x53, 0x5A, - 0x47, 0x38, 0xCE, 0xBC, 0xBF, 0x38, 0x9A, 0x99, - 0xB3, 0x63, 0x71, 0xEB -}; - -/* - * RFC 5114, 2.3. - * Group 24 - 2048-bit MODP Group with 256-bit Prime Order Subgroup - */ -static const u8 dh_group24_generator[] = { - 0x3F, 0xB3, 0x2C, 0x9B, 0x73, 0x13, 0x4D, 0x0B, - 0x2E, 0x77, 0x50, 0x66, 0x60, 0xED, 0xBD, 0x48, - 0x4C, 0xA7, 0xB1, 0x8F, 0x21, 0xEF, 0x20, 0x54, - 0x07, 0xF4, 0x79, 0x3A, 0x1A, 0x0B, 0xA1, 0x25, - 0x10, 0xDB, 0xC1, 0x50, 0x77, 0xBE, 0x46, 0x3F, - 0xFF, 0x4F, 0xED, 0x4A, 0xAC, 0x0B, 0xB5, 0x55, - 0xBE, 0x3A, 0x6C, 0x1B, 0x0C, 0x6B, 0x47, 0xB1, - 0xBC, 0x37, 0x73, 0xBF, 0x7E, 0x8C, 0x6F, 0x62, - 0x90, 0x12, 0x28, 0xF8, 0xC2, 0x8C, 0xBB, 0x18, - 0xA5, 0x5A, 0xE3, 0x13, 0x41, 0x00, 0x0A, 0x65, - 0x01, 0x96, 0xF9, 0x31, 0xC7, 0x7A, 0x57, 0xF2, - 0xDD, 0xF4, 0x63, 0xE5, 0xE9, 0xEC, 0x14, 0x4B, - 0x77, 0x7D, 0xE6, 0x2A, 0xAA, 0xB8, 0xA8, 0x62, - 0x8A, 0xC3, 0x76, 0xD2, 0x82, 0xD6, 0xED, 0x38, - 0x64, 0xE6, 0x79, 0x82, 0x42, 0x8E, 0xBC, 0x83, - 0x1D, 0x14, 0x34, 0x8F, 0x6F, 0x2F, 0x91, 0x93, - 0xB5, 0x04, 0x5A, 0xF2, 0x76, 0x71, 0x64, 0xE1, - 0xDF, 0xC9, 0x67, 0xC1, 0xFB, 0x3F, 0x2E, 0x55, - 0xA4, 0xBD, 0x1B, 0xFF, 0xE8, 0x3B, 0x9C, 0x80, - 0xD0, 0x52, 0xB9, 0x85, 0xD1, 0x82, 0xEA, 0x0A, - 0xDB, 0x2A, 0x3B, 0x73, 0x13, 0xD3, 0xFE, 0x14, - 0xC8, 0x48, 0x4B, 0x1E, 0x05, 0x25, 0x88, 0xB9, - 0xB7, 0xD2, 0xBB, 0xD2, 0xDF, 0x01, 0x61, 0x99, - 0xEC, 0xD0, 0x6E, 0x15, 0x57, 0xCD, 0x09, 0x15, - 0xB3, 0x35, 0x3B, 0xBB, 0x64, 0xE0, 0xEC, 0x37, - 0x7F, 0xD0, 0x28, 0x37, 0x0D, 0xF9, 0x2B, 0x52, - 0xC7, 0x89, 0x14, 0x28, 0xCD, 0xC6, 0x7E, 0xB6, - 0x18, 0x4B, 0x52, 0x3D, 0x1D, 0xB2, 0x46, 0xC3, - 0x2F, 0x63, 0x07, 0x84, 0x90, 0xF0, 0x0E, 0xF8, - 0xD6, 0x47, 0xD1, 0x48, 0xD4, 0x79, 0x54, 0x51, - 0x5E, 0x23, 0x27, 0xCF, 0xEF, 0x98, 0xC5, 0x82, - 0x66, 0x4B, 0x4C, 0x0F, 0x6C, 0xC4, 0x16, 0x59 -}; -static const u8 dh_group24_prime[] = { - 0x87, 0xA8, 0xE6, 0x1D, 0xB4, 0xB6, 0x66, 0x3C, - 0xFF, 0xBB, 0xD1, 0x9C, 0x65, 0x19, 0x59, 0x99, - 0x8C, 0xEE, 0xF6, 0x08, 0x66, 0x0D, 0xD0, 0xF2, - 0x5D, 0x2C, 0xEE, 0xD4, 0x43, 0x5E, 0x3B, 0x00, - 0xE0, 0x0D, 0xF8, 0xF1, 0xD6, 0x19, 0x57, 0xD4, - 0xFA, 0xF7, 0xDF, 0x45, 0x61, 0xB2, 0xAA, 0x30, - 0x16, 0xC3, 0xD9, 0x11, 0x34, 0x09, 0x6F, 0xAA, - 0x3B, 0xF4, 0x29, 0x6D, 0x83, 0x0E, 0x9A, 0x7C, - 0x20, 0x9E, 0x0C, 0x64, 0x97, 0x51, 0x7A, 0xBD, - 0x5A, 0x8A, 0x9D, 0x30, 0x6B, 0xCF, 0x67, 0xED, - 0x91, 0xF9, 0xE6, 0x72, 0x5B, 0x47, 0x58, 0xC0, - 0x22, 0xE0, 0xB1, 0xEF, 0x42, 0x75, 0xBF, 0x7B, - 0x6C, 0x5B, 0xFC, 0x11, 0xD4, 0x5F, 0x90, 0x88, - 0xB9, 0x41, 0xF5, 0x4E, 0xB1, 0xE5, 0x9B, 0xB8, - 0xBC, 0x39, 0xA0, 0xBF, 0x12, 0x30, 0x7F, 0x5C, - 0x4F, 0xDB, 0x70, 0xC5, 0x81, 0xB2, 0x3F, 0x76, - 0xB6, 0x3A, 0xCA, 0xE1, 0xCA, 0xA6, 0xB7, 0x90, - 0x2D, 0x52, 0x52, 0x67, 0x35, 0x48, 0x8A, 0x0E, - 0xF1, 0x3C, 0x6D, 0x9A, 0x51, 0xBF, 0xA4, 0xAB, - 0x3A, 0xD8, 0x34, 0x77, 0x96, 0x52, 0x4D, 0x8E, - 0xF6, 0xA1, 0x67, 0xB5, 0xA4, 0x18, 0x25, 0xD9, - 0x67, 0xE1, 0x44, 0xE5, 0x14, 0x05, 0x64, 0x25, - 0x1C, 0xCA, 0xCB, 0x83, 0xE6, 0xB4, 0x86, 0xF6, - 0xB3, 0xCA, 0x3F, 0x79, 0x71, 0x50, 0x60, 0x26, - 0xC0, 0xB8, 0x57, 0xF6, 0x89, 0x96, 0x28, 0x56, - 0xDE, 0xD4, 0x01, 0x0A, 0xBD, 0x0B, 0xE6, 0x21, - 0xC3, 0xA3, 0x96, 0x0A, 0x54, 0xE7, 0x10, 0xC3, - 0x75, 0xF2, 0x63, 0x75, 0xD7, 0x01, 0x41, 0x03, - 0xA4, 0xB5, 0x43, 0x30, 0xC1, 0x98, 0xAF, 0x12, - 0x61, 0x16, 0xD2, 0x27, 0x6E, 0x11, 0x71, 0x5F, - 0x69, 0x38, 0x77, 0xFA, 0xD7, 0xEF, 0x09, 0xCA, - 0xDB, 0x09, 0x4A, 0xE9, 0x1E, 0x1A, 0x15, 0x97 -}; -static const u8 dh_group24_order[] = { - 0x8C, 0xF8, 0x36, 0x42, 0xA7, 0x09, 0xA0, 0x97, - 0xB4, 0x47, 0x99, 0x76, 0x40, 0x12, 0x9D, 0xA2, - 0x99, 0xB1, 0xA4, 0x7D, 0x1E, 0xB3, 0x75, 0x0B, - 0xA3, 0x08, 0xB0, 0xFE, 0x64, 0xF5, 0xFB, 0xD3 -}; - -#endif /* ALL_DH_GROUPS */ - - -#define DH_GROUP(id,safe) \ -{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \ -dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime), \ -dh_group ## id ## _order, sizeof(dh_group ## id ## _order), safe } - - -static struct dh_group dh_groups[] = { - DH_GROUP(5, 1), -#ifdef ALL_DH_GROUPS - DH_GROUP(1, 1), - DH_GROUP(2, 1), - DH_GROUP(14, 1), - DH_GROUP(15, 1), - DH_GROUP(16, 1), - DH_GROUP(17, 1), - DH_GROUP(18, 1), - DH_GROUP(22, 0), - DH_GROUP(23, 0), - DH_GROUP(24, 0) -#endif /* ALL_DH_GROUPS */ -}; - -#define NUM_DH_GROUPS ARRAY_SIZE(dh_groups) - - -const struct dh_group * dh_groups_get(int id) -{ - size_t i; - - for (i = 0; i < NUM_DH_GROUPS; i++) { - if (dh_groups[i].id == id) - return &dh_groups[i]; - } - return NULL; -} - - -/** - * dh_init - Initialize Diffie-Hellman handshake - * @dh: Selected Diffie-Hellman group - * @priv: Pointer for returning Diffie-Hellman private key - * Returns: Diffie-Hellman public value - */ -struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv) -{ - struct wpabuf *pv; - size_t pv_len; - - if (dh == NULL) - return NULL; - - wpabuf_free(*priv); - *priv = wpabuf_alloc(dh->prime_len); - if (*priv == NULL) - return NULL; - - if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len)) - { - wpabuf_free(*priv); - *priv = NULL; - return NULL; - } - - if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) { - /* Make sure private value is smaller than prime */ - *(wpabuf_mhead_u8(*priv)) = 0; - } - wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv); - - pv_len = dh->prime_len; - pv = wpabuf_alloc(pv_len); - if (pv == NULL) - return NULL; - if (crypto_mod_exp(dh->generator, dh->generator_len, - wpabuf_head(*priv), wpabuf_len(*priv), - dh->prime, dh->prime_len, wpabuf_mhead(pv), - &pv_len) < 0) { - wpabuf_free(pv); - wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); - return NULL; - } - wpabuf_put(pv, pv_len); - wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv); - - return pv; -} - - -/** - * dh_derive_shared - Derive shared Diffie-Hellman key - * @peer_public: Diffie-Hellman public value from peer - * @own_private: Diffie-Hellman private key from dh_init() - * @dh: Selected Diffie-Hellman group - * Returns: Diffie-Hellman shared key - */ -struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public, - const struct wpabuf *own_private, - const struct dh_group *dh) -{ - struct wpabuf *shared; - size_t shared_len; - - if (dh == NULL || peer_public == NULL || own_private == NULL) - return NULL; - - shared_len = dh->prime_len; - shared = wpabuf_alloc(shared_len); - if (shared == NULL) - return NULL; - if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public), - wpabuf_head(own_private), wpabuf_len(own_private), - dh->prime, dh->prime_len, - wpabuf_mhead(shared), &shared_len) < 0) { - wpabuf_free(shared); - wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); - return NULL; - } - wpabuf_put(shared, shared_len); - wpa_hexdump_buf_key(MSG_DEBUG, "DH: shared key", shared); - - return shared; -} diff --git a/contrib/hostapd/src/crypto/dh_groups.h b/contrib/hostapd/src/crypto/dh_groups.h deleted file mode 100644 index d0e74b9206..0000000000 --- a/contrib/hostapd/src/crypto/dh_groups.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Diffie-Hellman groups - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef DH_GROUPS_H -#define DH_GROUPS_H - -struct dh_group { - int id; - const u8 *generator; - size_t generator_len; - const u8 *prime; - size_t prime_len; - const u8 *order; - size_t order_len; - unsigned int safe_prime:1; -}; - -const struct dh_group * dh_groups_get(int id); -struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv); -struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public, - const struct wpabuf *own_private, - const struct dh_group *dh); - -#endif /* DH_GROUPS_H */ diff --git a/contrib/hostapd/src/crypto/fips_prf_cryptoapi.c b/contrib/hostapd/src/crypto/fips_prf_cryptoapi.c deleted file mode 100644 index dca93a3d33..0000000000 --- a/contrib/hostapd/src/crypto/fips_prf_cryptoapi.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * FIPS 186-2 PRF for Microsoft CryptoAPI - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" - - -int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) -{ - /* FIX: how to do this with CryptoAPI? */ - return -1; -} diff --git a/contrib/hostapd/src/crypto/fips_prf_gnutls.c b/contrib/hostapd/src/crypto/fips_prf_gnutls.c deleted file mode 100644 index 947e6f6414..0000000000 --- a/contrib/hostapd/src/crypto/fips_prf_gnutls.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * FIPS 186-2 PRF for libgcrypt - * Copyright (c) 2004-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "crypto.h" - - -int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) -{ - /* FIX: how to do this with libgcrypt? */ - return -1; -} diff --git a/contrib/hostapd/src/crypto/fips_prf_internal.c b/contrib/hostapd/src/crypto/fips_prf_internal.c deleted file mode 100644 index a4bf50a47f..0000000000 --- a/contrib/hostapd/src/crypto/fips_prf_internal.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * FIPS 186-2 PRF for internal crypto implementation - * Copyright (c) 2006-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "sha1.h" -#include "sha1_i.h" -#include "crypto.h" - - -int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) -{ - u8 xkey[64]; - u32 t[5], _t[5]; - int i, j, m, k; - u8 *xpos = x; - u32 carry; - - 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); - t[0] = 0x67452301; - t[1] = 0xEFCDAB89; - t[2] = 0x98BADCFE; - t[3] = 0x10325476; - t[4] = 0xC3D2E1F0; - - m = xlen / 40; - for (j = 0; j < m; j++) { - /* XSEED_j = 0 */ - for (i = 0; i < 2; i++) { - /* XVAL = (XKEY + XSEED_j) mod 2^b */ - - /* w_i = G(t, XVAL) */ - os_memcpy(_t, t, 20); - SHA1Transform(_t, xkey); - _t[0] = host_to_be32(_t[0]); - _t[1] = host_to_be32(_t[1]); - _t[2] = host_to_be32(_t[2]); - _t[3] = host_to_be32(_t[3]); - _t[4] = host_to_be32(_t[4]); - os_memcpy(xpos, _t, 20); - - /* XKEY = (1 + XKEY + w_i) mod 2^b */ - carry = 1; - for (k = 19; k >= 0; k--) { - carry += xkey[k] + xpos[k]; - xkey[k] = carry & 0xff; - carry >>= 8; - } - - xpos += SHA1_MAC_LEN; - } - /* x_j = w_0|w_1 */ - } - - return 0; -} diff --git a/contrib/hostapd/src/crypto/fips_prf_nss.c b/contrib/hostapd/src/crypto/fips_prf_nss.c deleted file mode 100644 index 2c962f4f13..0000000000 --- a/contrib/hostapd/src/crypto/fips_prf_nss.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * FIPS 186-2 PRF for NSS - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "crypto.h" - - -int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) -{ - return -1; -} diff --git a/contrib/hostapd/src/crypto/fips_prf_openssl.c b/contrib/hostapd/src/crypto/fips_prf_openssl.c deleted file mode 100644 index d69eceabff..0000000000 --- a/contrib/hostapd/src/crypto/fips_prf_openssl.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * FIPS 186-2 PRF for libcrypto - * Copyright (c) 2004-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "crypto.h" - - -static void sha1_transform(u8 *state, const u8 data[64]) -{ - SHA_CTX context; - os_memset(&context, 0, sizeof(context)); - os_memcpy(&context.h0, state, 5 * 4); - SHA1_Transform(&context, data); - os_memcpy(state, &context.h0, 5 * 4); -} - - -int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) -{ - u8 xkey[64]; - u32 t[5], _t[5]; - int i, j, m, k; - u8 *xpos = x; - u32 carry; - - 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); - t[0] = 0x67452301; - t[1] = 0xEFCDAB89; - t[2] = 0x98BADCFE; - t[3] = 0x10325476; - t[4] = 0xC3D2E1F0; - - m = xlen / 40; - for (j = 0; j < m; j++) { - /* XSEED_j = 0 */ - for (i = 0; i < 2; i++) { - /* XVAL = (XKEY + XSEED_j) mod 2^b */ - - /* w_i = G(t, XVAL) */ - os_memcpy(_t, t, 20); - sha1_transform((u8 *) _t, xkey); - _t[0] = host_to_be32(_t[0]); - _t[1] = host_to_be32(_t[1]); - _t[2] = host_to_be32(_t[2]); - _t[3] = host_to_be32(_t[3]); - _t[4] = host_to_be32(_t[4]); - os_memcpy(xpos, _t, 20); - - /* XKEY = (1 + XKEY + w_i) mod 2^b */ - carry = 1; - for (k = 19; k >= 0; k--) { - carry += xkey[k] + xpos[k]; - xkey[k] = carry & 0xff; - carry >>= 8; - } - - xpos += 20; - } - /* x_j = w_0|w_1 */ - } - - return 0; -} diff --git a/contrib/hostapd/src/crypto/md4-internal.c b/contrib/hostapd/src/crypto/md4-internal.c deleted file mode 100644 index cd5e6ca8cc..0000000000 --- a/contrib/hostapd/src/crypto/md4-internal.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * MD4 hash implementation - * Copyright (c) 2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" - -#define MD4_BLOCK_LENGTH 64 -#define MD4_DIGEST_LENGTH 16 - -typedef struct MD4Context { - u32 state[4]; /* state */ - u64 count; /* number of bits, mod 2^64 */ - u8 buffer[MD4_BLOCK_LENGTH]; /* input buffer */ -} MD4_CTX; - - -static void MD4Init(MD4_CTX *ctx); -static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len); -static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx); - - -int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - MD4_CTX ctx; - size_t i; - - MD4Init(&ctx); - for (i = 0; i < num_elem; i++) - MD4Update(&ctx, addr[i], len[i]); - MD4Final(mac, &ctx); - return 0; -} - - -/* ===== start - public domain MD4 implementation ===== */ -/* $OpenBSD: md4.c,v 1.7 2005/08/08 08:05:35 espie Exp $ */ - -/* - * This code implements the MD4 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD4Context structure, pass it to MD4Init, call MD4Update as - * needed on buffers full of bytes, and then call MD4Final, which - * will fill a supplied 16-byte array with the digest. - */ - -#define MD4_DIGEST_STRING_LENGTH (MD4_DIGEST_LENGTH * 2 + 1) - - -static void -MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]); - -#define PUT_64BIT_LE(cp, value) do { \ - (cp)[7] = (value) >> 56; \ - (cp)[6] = (value) >> 48; \ - (cp)[5] = (value) >> 40; \ - (cp)[4] = (value) >> 32; \ - (cp)[3] = (value) >> 24; \ - (cp)[2] = (value) >> 16; \ - (cp)[1] = (value) >> 8; \ - (cp)[0] = (value); } while (0) - -#define PUT_32BIT_LE(cp, value) do { \ - (cp)[3] = (value) >> 24; \ - (cp)[2] = (value) >> 16; \ - (cp)[1] = (value) >> 8; \ - (cp)[0] = (value); } while (0) - -static u8 PADDING[MD4_BLOCK_LENGTH] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* - * Start MD4 accumulation. - * Set bit count to 0 and buffer to mysterious initialization constants. - */ -static void MD4Init(MD4_CTX *ctx) -{ - ctx->count = 0; - ctx->state[0] = 0x67452301; - ctx->state[1] = 0xefcdab89; - ctx->state[2] = 0x98badcfe; - ctx->state[3] = 0x10325476; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len) -{ - size_t have, need; - - /* Check how many bytes we already have and how many more we need. */ - have = (size_t)((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1)); - need = MD4_BLOCK_LENGTH - have; - - /* Update bitcount */ - ctx->count += (u64)len << 3; - - if (len >= need) { - if (have != 0) { - os_memcpy(ctx->buffer + have, input, need); - MD4Transform(ctx->state, ctx->buffer); - input += need; - len -= need; - have = 0; - } - - /* Process data in MD4_BLOCK_LENGTH-byte chunks. */ - while (len >= MD4_BLOCK_LENGTH) { - MD4Transform(ctx->state, input); - input += MD4_BLOCK_LENGTH; - len -= MD4_BLOCK_LENGTH; - } - } - - /* Handle any remaining bytes of data. */ - if (len != 0) - os_memcpy(ctx->buffer + have, input, len); -} - -/* - * Pad pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -static void MD4Pad(MD4_CTX *ctx) -{ - u8 count[8]; - size_t padlen; - - /* Convert count to 8 bytes in little endian order. */ - PUT_64BIT_LE(count, ctx->count); - - /* Pad out to 56 mod 64. */ - padlen = MD4_BLOCK_LENGTH - - ((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1)); - if (padlen < 1 + 8) - padlen += MD4_BLOCK_LENGTH; - MD4Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */ - MD4Update(ctx, count, 8); -} - -/* - * Final wrapup--call MD4Pad, fill in digest and zero out ctx. - */ -static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx) -{ - int i; - - MD4Pad(ctx); - if (digest != NULL) { - for (i = 0; i < 4; i++) - PUT_32BIT_LE(digest + i * 4, ctx->state[i]); - os_memset(ctx, 0, sizeof(*ctx)); - } -} - - -/* The three core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) ((x & y) | (x & z) | (y & z)) -#define F3(x, y, z) (x ^ y ^ z) - -/* This is the central step in the MD4 algorithm. */ -#define MD4STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<>(32-s) ) - -/* - * The core of the MD4 algorithm, this alters an existing MD4 hash to - * reflect the addition of 16 longwords of new data. MD4Update blocks - * the data and converts bytes into longwords for this routine. - */ -static void -MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]) -{ - u32 a, b, c, d, in[MD4_BLOCK_LENGTH / 4]; - -#if BYTE_ORDER == LITTLE_ENDIAN - os_memcpy(in, block, sizeof(in)); -#else - for (a = 0; a < MD4_BLOCK_LENGTH / 4; a++) { - in[a] = (u32)( - (u32)(block[a * 4 + 0]) | - (u32)(block[a * 4 + 1]) << 8 | - (u32)(block[a * 4 + 2]) << 16 | - (u32)(block[a * 4 + 3]) << 24); - } -#endif - - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - - MD4STEP(F1, a, b, c, d, in[ 0], 3); - MD4STEP(F1, d, a, b, c, in[ 1], 7); - MD4STEP(F1, c, d, a, b, in[ 2], 11); - MD4STEP(F1, b, c, d, a, in[ 3], 19); - MD4STEP(F1, a, b, c, d, in[ 4], 3); - MD4STEP(F1, d, a, b, c, in[ 5], 7); - MD4STEP(F1, c, d, a, b, in[ 6], 11); - MD4STEP(F1, b, c, d, a, in[ 7], 19); - MD4STEP(F1, a, b, c, d, in[ 8], 3); - MD4STEP(F1, d, a, b, c, in[ 9], 7); - MD4STEP(F1, c, d, a, b, in[10], 11); - MD4STEP(F1, b, c, d, a, in[11], 19); - MD4STEP(F1, a, b, c, d, in[12], 3); - MD4STEP(F1, d, a, b, c, in[13], 7); - MD4STEP(F1, c, d, a, b, in[14], 11); - MD4STEP(F1, b, c, d, a, in[15], 19); - - MD4STEP(F2, a, b, c, d, in[ 0] + 0x5a827999, 3); - MD4STEP(F2, d, a, b, c, in[ 4] + 0x5a827999, 5); - MD4STEP(F2, c, d, a, b, in[ 8] + 0x5a827999, 9); - MD4STEP(F2, b, c, d, a, in[12] + 0x5a827999, 13); - MD4STEP(F2, a, b, c, d, in[ 1] + 0x5a827999, 3); - MD4STEP(F2, d, a, b, c, in[ 5] + 0x5a827999, 5); - MD4STEP(F2, c, d, a, b, in[ 9] + 0x5a827999, 9); - MD4STEP(F2, b, c, d, a, in[13] + 0x5a827999, 13); - MD4STEP(F2, a, b, c, d, in[ 2] + 0x5a827999, 3); - MD4STEP(F2, d, a, b, c, in[ 6] + 0x5a827999, 5); - MD4STEP(F2, c, d, a, b, in[10] + 0x5a827999, 9); - MD4STEP(F2, b, c, d, a, in[14] + 0x5a827999, 13); - MD4STEP(F2, a, b, c, d, in[ 3] + 0x5a827999, 3); - MD4STEP(F2, d, a, b, c, in[ 7] + 0x5a827999, 5); - MD4STEP(F2, c, d, a, b, in[11] + 0x5a827999, 9); - MD4STEP(F2, b, c, d, a, in[15] + 0x5a827999, 13); - - MD4STEP(F3, a, b, c, d, in[ 0] + 0x6ed9eba1, 3); - MD4STEP(F3, d, a, b, c, in[ 8] + 0x6ed9eba1, 9); - MD4STEP(F3, c, d, a, b, in[ 4] + 0x6ed9eba1, 11); - MD4STEP(F3, b, c, d, a, in[12] + 0x6ed9eba1, 15); - MD4STEP(F3, a, b, c, d, in[ 2] + 0x6ed9eba1, 3); - MD4STEP(F3, d, a, b, c, in[10] + 0x6ed9eba1, 9); - MD4STEP(F3, c, d, a, b, in[ 6] + 0x6ed9eba1, 11); - MD4STEP(F3, b, c, d, a, in[14] + 0x6ed9eba1, 15); - MD4STEP(F3, a, b, c, d, in[ 1] + 0x6ed9eba1, 3); - MD4STEP(F3, d, a, b, c, in[ 9] + 0x6ed9eba1, 9); - MD4STEP(F3, c, d, a, b, in[ 5] + 0x6ed9eba1, 11); - MD4STEP(F3, b, c, d, a, in[13] + 0x6ed9eba1, 15); - MD4STEP(F3, a, b, c, d, in[ 3] + 0x6ed9eba1, 3); - MD4STEP(F3, d, a, b, c, in[11] + 0x6ed9eba1, 9); - MD4STEP(F3, c, d, a, b, in[ 7] + 0x6ed9eba1, 11); - MD4STEP(F3, b, c, d, a, in[15] + 0x6ed9eba1, 15); - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; -} -/* ===== end - public domain MD4 implementation ===== */ diff --git a/contrib/hostapd/src/crypto/md5-internal.c b/contrib/hostapd/src/crypto/md5-internal.c deleted file mode 100644 index f0a2a5d3a5..0000000000 --- a/contrib/hostapd/src/crypto/md5-internal.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * MD5 hash implementation and interface functions - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "md5.h" -#include "md5_i.h" -#include "crypto.h" - - -static void MD5Transform(u32 buf[4], u32 const in[16]); - - -typedef struct MD5Context MD5_CTX; - - -/** - * md5_vector - MD5 hash for data vector - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash - * Returns: 0 on success, -1 of failure - */ -int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - MD5_CTX ctx; - size_t i; - - MD5Init(&ctx); - for (i = 0; i < num_elem; i++) - MD5Update(&ctx, addr[i], len[i]); - MD5Final(mac, &ctx); - return 0; -} - - -/* ===== start - public domain MD5 implementation ===== */ -/* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - */ - -#ifndef WORDS_BIGENDIAN -#define byteReverse(buf, len) /* Nothing */ -#else -/* - * Note: this code is harmless on little-endian machines. - */ -static void byteReverse(unsigned char *buf, unsigned longs) -{ - u32 t; - do { - t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - *(u32 *) buf = t; - buf += 4; - } while (--longs); -} -#endif - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void MD5Init(struct MD5Context *ctx) -{ - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) -{ - u32 t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((u32) len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; - - t = 64 - t; - if (len < t) { - os_memcpy(p, buf, len); - return; - } - os_memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (u32 *) ctx->in); - buf += t; - len -= t; - } - /* Process data in 64-byte chunks */ - - while (len >= 64) { - os_memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (u32 *) ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - os_memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void MD5Final(unsigned char digest[16], struct MD5Context *ctx) -{ - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - os_memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (u32 *) ctx->in); - - /* Now fill the next block with 56 bytes */ - os_memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - os_memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((u32 *) aliasing_hide_typecast(ctx->in, u32))[14] = ctx->bits[0]; - ((u32 *) aliasing_hide_typecast(ctx->in, u32))[15] = ctx->bits[1]; - - 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 */ -} - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -static void MD5Transform(u32 buf[4], u32 const in[16]) -{ - register u32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} -/* ===== end - public domain MD5 implementation ===== */ diff --git a/contrib/hostapd/src/crypto/md5.c b/contrib/hostapd/src/crypto/md5.c deleted file mode 100644 index db2b8cc316..0000000000 --- a/contrib/hostapd/src/crypto/md5.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * MD5 hash implementation and interface functions - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "md5.h" -#include "crypto.h" - - -/** - * hmac_md5_vector - HMAC-MD5 over data vector (RFC 2104) - * @key: Key for HMAC operations - * @key_len: Length of the key in bytes - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash (16 bytes) - * Returns: 0 on success, -1 on failure - */ -int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac) -{ - u8 k_pad[64]; /* padding - key XORd with ipad/opad */ - u8 tk[16]; - const u8 *_addr[6]; - size_t i, _len[6]; - - if (num_elem > 5) { - /* - * Fixed limit on the number of fragments to avoid having to - * allocate memory (which could fail). - */ - return -1; - } - - /* if key is longer than 64 bytes reset it to key = MD5(key) */ - if (key_len > 64) { - if (md5_vector(1, &key, &key_len, tk)) - return -1; - key = tk; - key_len = 16; - } - - /* the HMAC_MD5 transform looks like: - * - * MD5(K XOR opad, MD5(K XOR ipad, text)) - * - * where K is an n byte key - * ipad is the byte 0x36 repeated 64 times - * opad is the byte 0x5c repeated 64 times - * and text is the data being protected */ - - /* start out by storing key in ipad */ - os_memset(k_pad, 0, sizeof(k_pad)); - os_memcpy(k_pad, key, key_len); - - /* XOR key with ipad values */ - for (i = 0; i < 64; i++) - k_pad[i] ^= 0x36; - - /* perform inner MD5 */ - _addr[0] = k_pad; - _len[0] = 64; - for (i = 0; i < num_elem; i++) { - _addr[i + 1] = addr[i]; - _len[i + 1] = len[i]; - } - if (md5_vector(1 + num_elem, _addr, _len, mac)) - return -1; - - os_memset(k_pad, 0, sizeof(k_pad)); - os_memcpy(k_pad, key, key_len); - /* XOR key with opad values */ - for (i = 0; i < 64; i++) - k_pad[i] ^= 0x5c; - - /* perform outer MD5 */ - _addr[0] = k_pad; - _len[0] = 64; - _addr[1] = mac; - _len[1] = MD5_MAC_LEN; - return md5_vector(2, _addr, _len, mac); -} - - -/** - * hmac_md5 - HMAC-MD5 over data buffer (RFC 2104) - * @key: Key for HMAC operations - * @key_len: Length of the key in bytes - * @data: Pointers to the data area - * @data_len: Length of the data area - * @mac: Buffer for the hash (16 bytes) - * Returns: 0 on success, -1 on failure - */ -int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, - u8 *mac) -{ - return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac); -} diff --git a/contrib/hostapd/src/crypto/md5.h b/contrib/hostapd/src/crypto/md5.h deleted file mode 100644 index 33f8426c57..0000000000 --- a/contrib/hostapd/src/crypto/md5.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * MD5 hash implementation and interface functions - * Copyright (c) 2003-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef MD5_H -#define MD5_H - -#define MD5_MAC_LEN 16 - -int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac); -int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, - u8 *mac); - -#endif /* MD5_H */ diff --git a/contrib/hostapd/src/crypto/md5_i.h b/contrib/hostapd/src/crypto/md5_i.h deleted file mode 100644 index 7dfc10037d..0000000000 --- a/contrib/hostapd/src/crypto/md5_i.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * MD5 internal definitions - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef MD5_I_H -#define MD5_I_H - -struct MD5Context { - u32 buf[4]; - u32 bits[2]; - u8 in[64]; -}; - -void MD5Init(struct MD5Context *context); -void MD5Update(struct MD5Context *context, unsigned char const *buf, - unsigned len); -void MD5Final(unsigned char digest[16], struct MD5Context *context); - -#endif /* MD5_I_H */ diff --git a/contrib/hostapd/src/crypto/milenage.c b/contrib/hostapd/src/crypto/milenage.c deleted file mode 100644 index a7f9c6a286..0000000000 --- a/contrib/hostapd/src/crypto/milenage.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208) - * Copyright (c) 2006-2007 - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file implements an example authentication algorithm defined for 3GPP - * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow - * EAP-AKA to be tested properly with real USIM cards. - * - * This implementations assumes that the r1..r5 and c1..c5 constants defined in - * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00, - * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to - * be AES (Rijndael). - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/aes_wrap.h" -#include "milenage.h" - - -/** - * milenage_f1 - Milenage f1 and f1* algorithms - * @opc: OPc = 128-bit value derived from OP and K - * @k: K = 128-bit subscriber key - * @_rand: RAND = 128-bit random challenge - * @sqn: SQN = 48-bit sequence number - * @amf: AMF = 16-bit authentication management field - * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL - * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL - * Returns: 0 on success, -1 on failure - */ -int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, - const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s) -{ - u8 tmp1[16], tmp2[16], tmp3[16]; - int i; - - /* tmp1 = TEMP = E_K(RAND XOR OP_C) */ - for (i = 0; i < 16; i++) - tmp1[i] = _rand[i] ^ opc[i]; - if (aes_128_encrypt_block(k, tmp1, tmp1)) - return -1; - - /* tmp2 = IN1 = SQN || AMF || SQN || AMF */ - os_memcpy(tmp2, sqn, 6); - os_memcpy(tmp2 + 6, amf, 2); - os_memcpy(tmp2 + 8, tmp2, 8); - - /* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */ - - /* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */ - for (i = 0; i < 16; i++) - tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i]; - /* XOR with TEMP = E_K(RAND XOR OP_C) */ - for (i = 0; i < 16; i++) - tmp3[i] ^= tmp1[i]; - /* XOR with c1 (= ..00, i.e., NOP) */ - - /* f1 || f1* = E_K(tmp3) XOR OP_c */ - if (aes_128_encrypt_block(k, tmp3, tmp1)) - return -1; - for (i = 0; i < 16; i++) - tmp1[i] ^= opc[i]; - if (mac_a) - os_memcpy(mac_a, tmp1, 8); /* f1 */ - if (mac_s) - os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */ - return 0; -} - - -/** - * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms - * @opc: OPc = 128-bit value derived from OP and K - * @k: K = 128-bit subscriber key - * @_rand: RAND = 128-bit random challenge - * @res: Buffer for RES = 64-bit signed response (f2), or %NULL - * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL - * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL - * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL - * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL - * Returns: 0 on success, -1 on failure - */ -int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, - u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar) -{ - u8 tmp1[16], tmp2[16], tmp3[16]; - int i; - - /* tmp2 = TEMP = E_K(RAND XOR OP_C) */ - for (i = 0; i < 16; i++) - tmp1[i] = _rand[i] ^ opc[i]; - if (aes_128_encrypt_block(k, tmp1, tmp2)) - return -1; - - /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */ - /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */ - /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */ - /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */ - - /* f2 and f5 */ - /* rotate by r2 (= 0, i.e., NOP) */ - for (i = 0; i < 16; i++) - tmp1[i] = tmp2[i] ^ opc[i]; - tmp1[15] ^= 1; /* XOR c2 (= ..01) */ - /* f5 || f2 = E_K(tmp1) XOR OP_c */ - if (aes_128_encrypt_block(k, tmp1, tmp3)) - return -1; - for (i = 0; i < 16; i++) - tmp3[i] ^= opc[i]; - if (res) - os_memcpy(res, tmp3 + 8, 8); /* f2 */ - if (ak) - os_memcpy(ak, tmp3, 6); /* f5 */ - - /* f3 */ - if (ck) { - /* rotate by r3 = 0x20 = 4 bytes */ - for (i = 0; i < 16; i++) - tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i]; - tmp1[15] ^= 2; /* XOR c3 (= ..02) */ - if (aes_128_encrypt_block(k, tmp1, ck)) - return -1; - for (i = 0; i < 16; i++) - ck[i] ^= opc[i]; - } - - /* f4 */ - if (ik) { - /* rotate by r4 = 0x40 = 8 bytes */ - for (i = 0; i < 16; i++) - tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i]; - tmp1[15] ^= 4; /* XOR c4 (= ..04) */ - if (aes_128_encrypt_block(k, tmp1, ik)) - return -1; - for (i = 0; i < 16; i++) - ik[i] ^= opc[i]; - } - - /* f5* */ - if (akstar) { - /* rotate by r5 = 0x60 = 12 bytes */ - for (i = 0; i < 16; i++) - tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i]; - tmp1[15] ^= 8; /* XOR c5 (= ..08) */ - if (aes_128_encrypt_block(k, tmp1, tmp1)) - return -1; - for (i = 0; i < 6; i++) - akstar[i] = tmp1[i] ^ opc[i]; - } - - return 0; -} - - -/** - * milenage_generate - Generate AKA AUTN,IK,CK,RES - * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) - * @amf: AMF = 16-bit authentication management field - * @k: K = 128-bit subscriber key - * @sqn: SQN = 48-bit sequence number - * @_rand: RAND = 128-bit random challenge - * @autn: Buffer for AUTN = 128-bit authentication token - * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL - * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL - * @res: Buffer for RES = 64-bit signed response (f2), or %NULL - * @res_len: Max length for res; set to used length or 0 on failure - */ -void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k, - const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik, - u8 *ck, u8 *res, size_t *res_len) -{ - int i; - u8 mac_a[8], ak[6]; - - if (*res_len < 8) { - *res_len = 0; - return; - } - if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) || - milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) { - *res_len = 0; - return; - } - *res_len = 8; - - /* AUTN = (SQN ^ AK) || AMF || MAC */ - for (i = 0; i < 6; i++) - autn[i] = sqn[i] ^ ak[i]; - os_memcpy(autn + 6, amf, 2); - os_memcpy(autn + 8, mac_a, 8); -} - - -/** - * milenage_auts - Milenage AUTS validation - * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) - * @k: K = 128-bit subscriber key - * @_rand: RAND = 128-bit random challenge - * @auts: AUTS = 112-bit authentication token from client - * @sqn: Buffer for SQN = 48-bit sequence number - * Returns: 0 = success (sqn filled), -1 on failure - */ -int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts, - u8 *sqn) -{ - u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ - u8 ak[6], mac_s[8]; - int i; - - if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) - return -1; - for (i = 0; i < 6; i++) - sqn[i] = auts[i] ^ ak[i]; - if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) || - memcmp(mac_s, auts + 6, 8) != 0) - return -1; - return 0; -} - - -/** - * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet - * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) - * @k: K = 128-bit subscriber key - * @_rand: RAND = 128-bit random challenge - * @sres: Buffer for SRES = 32-bit SRES - * @kc: Buffer for Kc = 64-bit Kc - * Returns: 0 on success, -1 on failure - */ -int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc) -{ - u8 res[8], ck[16], ik[16]; - int i; - - if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL)) - return -1; - - for (i = 0; i < 8; i++) - kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8]; - -#ifdef GSM_MILENAGE_ALT_SRES - os_memcpy(sres, res, 4); -#else /* GSM_MILENAGE_ALT_SRES */ - for (i = 0; i < 4; i++) - sres[i] = res[i] ^ res[i + 4]; -#endif /* GSM_MILENAGE_ALT_SRES */ - return 0; -} - - -/** - * milenage_generate - Generate AKA AUTN,IK,CK,RES - * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) - * @k: K = 128-bit subscriber key - * @sqn: SQN = 48-bit sequence number - * @_rand: RAND = 128-bit random challenge - * @autn: AUTN = 128-bit authentication token - * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL - * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL - * @res: Buffer for RES = 64-bit signed response (f2), or %NULL - * @res_len: Variable that will be set to RES length - * @auts: 112-bit buffer for AUTS - * Returns: 0 on success, -1 on failure, or -2 on synchronization failure - */ -int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, - const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, - u8 *auts) -{ - int i; - u8 mac_a[8], ak[6], rx_sqn[6]; - const u8 *amf; - - wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16); - wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16); - - if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) - return -1; - - *res_len = 8; - wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len); - wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16); - wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16); - wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6); - - /* AUTN = (SQN ^ AK) || AMF || MAC */ - for (i = 0; i < 6; i++) - rx_sqn[i] = autn[i] ^ ak[i]; - wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6); - - if (os_memcmp(rx_sqn, sqn, 6) <= 0) { - u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ - if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) - return -1; - wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6); - for (i = 0; i < 6; i++) - auts[i] = sqn[i] ^ ak[i]; - if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6)) - return -1; - wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14); - return -2; - } - - amf = autn + 6; - wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2); - if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL)) - return -1; - - wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8); - - if (os_memcmp(mac_a, autn + 8, 8) != 0) { - wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch"); - wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A", - autn + 8, 8); - return -1; - } - - return 0; -} diff --git a/contrib/hostapd/src/crypto/milenage.h b/contrib/hostapd/src/crypto/milenage.h deleted file mode 100644 index 62137d95ce..0000000000 --- a/contrib/hostapd/src/crypto/milenage.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * UMTS AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208) - * Copyright (c) 2006-2007 - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef MILENAGE_H -#define MILENAGE_H - -void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k, - const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik, - u8 *ck, u8 *res, size_t *res_len); -int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts, - u8 *sqn); -int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, - u8 *kc); -int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, - const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, - u8 *auts); -int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, - const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s); -int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, - u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar); - -#endif /* MILENAGE_H */ diff --git a/contrib/hostapd/src/crypto/ms_funcs.c b/contrib/hostapd/src/crypto/ms_funcs.c deleted file mode 100644 index b2bbab2b5c..0000000000 --- a/contrib/hostapd/src/crypto/ms_funcs.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759 - * Copyright (c) 2004-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "sha1.h" -#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 - * @peer_challenge: 16-octet PeerChallenge (IN) - * @auth_challenge: 16-octet AuthenticatorChallenge (IN) - * @username: 0-to-256-char UserName (IN) - * @username_len: Length of username - * @challenge: 8-octet Challenge (OUT) - * Returns: 0 on success, -1 on failure - */ -static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge, - const u8 *username, size_t username_len, - u8 *challenge) -{ - u8 hash[SHA1_MAC_LEN]; - const unsigned char *addr[3]; - size_t len[3]; - - addr[0] = peer_challenge; - len[0] = 16; - addr[1] = auth_challenge; - len[1] = 16; - addr[2] = username; - len[2] = username_len; - - if (sha1_vector(3, addr, len, hash)) - return -1; - os_memcpy(challenge, hash, 8); - return 0; -} - - -/** - * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3 - * @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 - */ -int nt_password_hash(const u8 *password, size_t password_len, - u8 *password_hash) -{ - u8 buf[512], *pos; - size_t len, max_len; - - max_len = sizeof(buf); - if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0) - return -1; - - len *= 2; - pos = buf; - return md4_vector(1, (const u8 **) &pos, &len, password_hash); -} - - -/** - * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4 - * @password_hash: 16-octet PasswordHash (IN) - * @password_hash_hash: 16-octet PasswordHashHash (OUT) - * Returns: 0 on success, -1 on failure - */ -int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash) -{ - size_t len = 16; - return md4_vector(1, &password_hash, &len, password_hash_hash); -} - - -/** - * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5 - * @challenge: 8-octet Challenge (IN) - * @password_hash: 16-octet PasswordHash (IN) - * @response: 24-octet Response (OUT) - */ -void challenge_response(const u8 *challenge, const u8 *password_hash, - u8 *response) -{ - u8 zpwd[7]; - des_encrypt(challenge, password_hash, response); - des_encrypt(challenge, password_hash + 7, response + 8); - zpwd[0] = password_hash[14]; - zpwd[1] = password_hash[15]; - os_memset(zpwd + 2, 0, 5); - des_encrypt(challenge, zpwd, response + 16); -} - - -/** - * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1 - * @auth_challenge: 16-octet AuthenticatorChallenge (IN) - * @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; UTF-8) - * @password_len: Length of password - * @response: 24-octet Response (OUT) - * Returns: 0 on success, -1 on failure - */ -int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, - const u8 *username, size_t username_len, - const u8 *password, size_t password_len, - u8 *response) -{ - u8 challenge[8]; - u8 password_hash[16]; - - if (challenge_hash(peer_challenge, auth_challenge, username, - username_len, challenge)) - return -1; - if (nt_password_hash(password, password_len, password_hash)) - return -1; - challenge_response(challenge, password_hash, response); - return 0; -} - - -/** - * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1 - * @auth_challenge: 16-octet AuthenticatorChallenge (IN) - * @peer_challenge: 16-octet PeerChallenge (IN) - * @username: 0-to-256-char UserName (IN) - * @username_len: Length of username - * @password_hash: 16-octet PasswordHash (IN) - * @response: 24-octet Response (OUT) - * Returns: 0 on success, -1 on failure - */ -int generate_nt_response_pwhash(const u8 *auth_challenge, - const u8 *peer_challenge, - const u8 *username, size_t username_len, - const u8 *password_hash, - u8 *response) -{ - u8 challenge[8]; - - if (challenge_hash(peer_challenge, auth_challenge, - username, username_len, - challenge)) - return -1; - challenge_response(challenge, password_hash, response); - return 0; -} - - -/** - * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7 - * @password_hash: 16-octet PasswordHash (IN) - * @nt_response: 24-octet NT-Response (IN) - * @peer_challenge: 16-octet PeerChallenge (IN) - * @auth_challenge: 16-octet AuthenticatorChallenge (IN) - * @username: 0-to-256-char UserName (IN) - * @username_len: Length of username - * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually - * encoded as a 42-octet ASCII string (S=hexdump_of_response) - * Returns: 0 on success, -1 on failure - */ -int generate_authenticator_response_pwhash( - const u8 *password_hash, - const u8 *peer_challenge, const u8 *auth_challenge, - const u8 *username, size_t username_len, - const u8 *nt_response, u8 *response) -{ - static const u8 magic1[39] = { - 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, - 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, - 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 - }; - static const u8 magic2[41] = { - 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, - 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, - 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, - 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, - 0x6E - }; - - u8 password_hash_hash[16], challenge[8]; - const unsigned char *addr1[3]; - const size_t len1[3] = { 16, 24, sizeof(magic1) }; - const unsigned char *addr2[3]; - const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) }; - - addr1[0] = password_hash_hash; - addr1[1] = nt_response; - addr1[2] = magic1; - - addr2[0] = response; - addr2[1] = challenge; - addr2[2] = magic2; - - if (hash_nt_password_hash(password_hash, password_hash_hash)) - return -1; - if (sha1_vector(3, addr1, len1, response)) - return -1; - - if (challenge_hash(peer_challenge, auth_challenge, username, - username_len, challenge)) - return -1; - return sha1_vector(3, addr2, len2, response); -} - - -/** - * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7 - * @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) - * @auth_challenge: 16-octet AuthenticatorChallenge (IN) - * @username: 0-to-256-char UserName (IN) - * @username_len: Length of username - * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually - * encoded as a 42-octet ASCII string (S=hexdump_of_response) - * Returns: 0 on success, -1 on failure - */ -int generate_authenticator_response(const u8 *password, size_t password_len, - const u8 *peer_challenge, - const u8 *auth_challenge, - const u8 *username, size_t username_len, - const u8 *nt_response, u8 *response) -{ - u8 password_hash[16]; - if (nt_password_hash(password, password_len, password_hash)) - return -1; - return generate_authenticator_response_pwhash( - password_hash, peer_challenge, auth_challenge, - username, username_len, nt_response, response); -} - - -/** - * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5 - * @challenge: 8-octet Challenge (IN) - * @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 - */ -int nt_challenge_response(const u8 *challenge, const u8 *password, - size_t password_len, u8 *response) -{ - u8 password_hash[16]; - if (nt_password_hash(password, password_len, password_hash)) - return -1; - challenge_response(challenge, password_hash, response); - return 0; -} - - -/** - * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4 - * @password_hash_hash: 16-octet PasswordHashHash (IN) - * @nt_response: 24-octet NTResponse (IN) - * @master_key: 16-octet MasterKey (OUT) - * Returns: 0 on success, -1 on failure - */ -int get_master_key(const u8 *password_hash_hash, const u8 *nt_response, - u8 *master_key) -{ - static const u8 magic1[27] = { - 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, - 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 - }; - const unsigned char *addr[3]; - const size_t len[3] = { 16, 24, sizeof(magic1) }; - u8 hash[SHA1_MAC_LEN]; - - addr[0] = password_hash_hash; - addr[1] = nt_response; - addr[2] = magic1; - - if (sha1_vector(3, addr, len, hash)) - return -1; - os_memcpy(master_key, hash, 16); - return 0; -} - - -/** - * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4 - * @master_key: 16-octet MasterKey (IN) - * @session_key: 8-to-16 octet SessionKey (OUT) - * @session_key_len: SessionKeyLength (Length of session_key) (IN) - * @is_send: IsSend (IN, BOOLEAN) - * @is_server: IsServer (IN, BOOLEAN) - * Returns: 0 on success, -1 on failure - */ -int get_asymetric_start_key(const u8 *master_key, u8 *session_key, - size_t session_key_len, int is_send, - int is_server) -{ - static const u8 magic2[84] = { - 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, - 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, - 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, - 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, - 0x6b, 0x65, 0x79, 0x2e - }; - static const u8 magic3[84] = { - 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, - 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, - 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, - 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, - 0x6b, 0x65, 0x79, 0x2e - }; - static const u8 shs_pad1[40] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - static const u8 shs_pad2[40] = { - 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, - 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, - 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, - 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 - }; - u8 digest[SHA1_MAC_LEN]; - const unsigned char *addr[4]; - const size_t len[4] = { 16, 40, 84, 40 }; - - addr[0] = master_key; - addr[1] = shs_pad1; - if (is_send) { - addr[2] = is_server ? magic3 : magic2; - } else { - addr[2] = is_server ? magic2 : magic3; - } - addr[3] = shs_pad2; - - if (sha1_vector(4, addr, len, digest)) - return -1; - - if (session_key_len > SHA1_MAC_LEN) - session_key_len = SHA1_MAC_LEN; - os_memcpy(session_key, digest, session_key_len); - return 0; -} - - -#define PWBLOCK_LEN 516 - -/** - * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10 - * @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) - * Returns: 0 on success, -1 on failure - */ -int encrypt_pw_block_with_password_hash( - const u8 *password, size_t password_len, - const u8 *password_hash, u8 *pw_block) -{ - size_t ucs2_len, offset; - u8 *pos; - - os_memset(pw_block, 0, PWBLOCK_LEN); - - if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0) - return -1; - - if (ucs2_len > 256) - return -1; - - 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. - */ - pos = &pw_block[2 * 256]; - WPA_PUT_LE16(pos, password_len * 2); - rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN); - return 0; -} - - -/** - * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9 - * @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; UTF-8) - * @old_password_len: Length of old_password - * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT) - * Returns: 0 on success, -1 on failure - */ -int new_password_encrypted_with_old_nt_password_hash( - const u8 *new_password, size_t new_password_len, - const u8 *old_password, size_t old_password_len, - u8 *encrypted_pw_block) -{ - u8 password_hash[16]; - - if (nt_password_hash(old_password, old_password_len, password_hash)) - return -1; - if (encrypt_pw_block_with_password_hash(new_password, new_password_len, - password_hash, - encrypted_pw_block)) - return -1; - return 0; -} - - -/** - * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13 - * @password_hash: 16-octer PasswordHash (IN) - * @block: 16-octet Block (IN) - * @cypher: 16-octer Cypher (OUT) - */ -void nt_password_hash_encrypted_with_block(const u8 *password_hash, - const u8 *block, u8 *cypher) -{ - des_encrypt(password_hash, block, cypher); - des_encrypt(password_hash + 8, block + 7, cypher + 8); -} - - -/** - * 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; UTF-8) - * @new_password_len: Length of new_password - * @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 - */ -int old_nt_password_hash_encrypted_with_new_nt_password_hash( - const u8 *new_password, size_t new_password_len, - const u8 *old_password, size_t old_password_len, - u8 *encrypted_password_hash) -{ - u8 old_password_hash[16], new_password_hash[16]; - - if (nt_password_hash(old_password, old_password_len, - old_password_hash) || - nt_password_hash(new_password, new_password_len, - new_password_hash)) - return -1; - nt_password_hash_encrypted_with_block(old_password_hash, - new_password_hash, - encrypted_password_hash); - return 0; -} diff --git a/contrib/hostapd/src/crypto/ms_funcs.h b/contrib/hostapd/src/crypto/ms_funcs.h deleted file mode 100644 index bd9bfee95b..0000000000 --- a/contrib/hostapd/src/crypto/ms_funcs.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759 - * Copyright (c) 2004-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef MS_FUNCS_H -#define MS_FUNCS_H - -int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, - const u8 *username, size_t username_len, - const u8 *password, size_t password_len, - u8 *response); -int generate_nt_response_pwhash(const u8 *auth_challenge, - const u8 *peer_challenge, - const u8 *username, size_t username_len, - const u8 *password_hash, - u8 *response); -int generate_authenticator_response(const u8 *password, size_t password_len, - const u8 *peer_challenge, - const u8 *auth_challenge, - const u8 *username, size_t username_len, - const u8 *nt_response, u8 *response); -int generate_authenticator_response_pwhash( - const u8 *password_hash, - const u8 *peer_challenge, const u8 *auth_challenge, - const u8 *username, size_t username_len, - const u8 *nt_response, u8 *response); -int nt_challenge_response(const u8 *challenge, const u8 *password, - size_t password_len, u8 *response); - -void challenge_response(const u8 *challenge, const u8 *password_hash, - u8 *response); -int nt_password_hash(const u8 *password, size_t password_len, - u8 *password_hash); -int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash); -int get_master_key(const u8 *password_hash_hash, const u8 *nt_response, - u8 *master_key); -int get_asymetric_start_key(const u8 *master_key, u8 *session_key, - size_t session_key_len, int is_send, - int is_server); -int __must_check encrypt_pw_block_with_password_hash( - const u8 *password, size_t password_len, - const u8 *password_hash, u8 *pw_block); -int __must_check new_password_encrypted_with_old_nt_password_hash( - const u8 *new_password, size_t new_password_len, - const u8 *old_password, size_t old_password_len, - u8 *encrypted_pw_block); -void nt_password_hash_encrypted_with_block(const u8 *password_hash, - const u8 *block, u8 *cypher); -int old_nt_password_hash_encrypted_with_new_nt_password_hash( - const u8 *new_password, size_t new_password_len, - const u8 *old_password, size_t old_password_len, - u8 *encrypted_password_hash); - -#endif /* MS_FUNCS_H */ diff --git a/contrib/hostapd/src/crypto/random.c b/contrib/hostapd/src/crypto/random.c deleted file mode 100644 index 053740e9bf..0000000000 --- a/contrib/hostapd/src/crypto/random.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Random number generator - * Copyright (c) 2010-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This random number generator is used to provide additional entropy to the - * one provided by the operating system (os_get_random()) for session key - * generation. The os_get_random() output is expected to be secure and the - * implementation here is expected to provide only limited protection against - * cases where os_get_random() cannot provide strong randomness. This - * implementation shall not be assumed to be secure as the sole source of - * randomness. The random_get_bytes() function mixes in randomness from - * os_get_random() and as such, calls to os_get_random() can be replaced with - * calls to random_get_bytes() without reducing security. - * - * The design here follows partially the design used in the Linux - * drivers/char/random.c, but the implementation here is simpler and not as - * strong. This is a compromise to reduce duplicated CPU effort and to avoid - * extra code/memory size. As pointed out above, os_get_random() needs to be - * guaranteed to be secure for any of the security assumptions to hold. - */ - -#include "utils/includes.h" -#ifdef __linux__ -#include -#endif /* __linux__ */ - -#include "utils/common.h" -#include "utils/eloop.h" -#include "crypto/crypto.h" -#include "sha1.h" -#include "random.h" - -#define POOL_WORDS 32 -#define POOL_WORDS_MASK (POOL_WORDS - 1) -#define POOL_TAP1 26 -#define POOL_TAP2 20 -#define POOL_TAP3 14 -#define POOL_TAP4 7 -#define POOL_TAP5 1 -#define EXTRACT_LEN 16 -#define MIN_READY_MARK 2 - -static u32 pool[POOL_WORDS]; -static unsigned int input_rotate = 0; -static unsigned int pool_pos = 0; -static u8 dummy_key[20]; -#ifdef __linux__ -static size_t dummy_key_avail = 0; -static int random_fd = -1; -#endif /* __linux__ */ -static unsigned int own_pool_ready = 0; -#define RANDOM_ENTROPY_SIZE 20 -static char *random_entropy_file = NULL; -static int random_entropy_file_read = 0; - -#define MIN_COLLECT_ENTROPY 1000 -static unsigned int entropy = 0; -static unsigned int total_collected = 0; - - -static void random_write_entropy(void); - - -static u32 __ROL32(u32 x, u32 y) -{ - return (x << (y & 31)) | (x >> (32 - (y & 31))); -} - - -static void random_mix_pool(const void *buf, size_t len) -{ - static const u32 twist[8] = { - 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, - 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 - }; - const u8 *pos = buf; - u32 w; - - wpa_hexdump_key(MSG_EXCESSIVE, "random_mix_pool", buf, len); - - while (len--) { - w = __ROL32(*pos++, input_rotate & 31); - input_rotate += pool_pos ? 7 : 14; - pool_pos = (pool_pos - 1) & POOL_WORDS_MASK; - w ^= pool[pool_pos]; - w ^= pool[(pool_pos + POOL_TAP1) & POOL_WORDS_MASK]; - w ^= pool[(pool_pos + POOL_TAP2) & POOL_WORDS_MASK]; - w ^= pool[(pool_pos + POOL_TAP3) & POOL_WORDS_MASK]; - w ^= pool[(pool_pos + POOL_TAP4) & POOL_WORDS_MASK]; - w ^= pool[(pool_pos + POOL_TAP5) & POOL_WORDS_MASK]; - pool[pool_pos] = (w >> 3) ^ twist[w & 7]; - } -} - - -static void random_extract(u8 *out) -{ - unsigned int i; - u8 hash[SHA1_MAC_LEN]; - u32 *hash_ptr; - u32 buf[POOL_WORDS / 2]; - - /* First, add hash back to pool to make backtracking more difficult. */ - hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) pool, - sizeof(pool), hash); - random_mix_pool(hash, sizeof(hash)); - /* Hash half the pool to extra data */ - for (i = 0; i < POOL_WORDS / 2; i++) - buf[i] = pool[(pool_pos - i) & POOL_WORDS_MASK]; - hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) buf, - sizeof(buf), hash); - /* - * Fold the hash to further reduce any potential output pattern. - * Though, compromise this to reduce CPU use for the most common output - * length (32) and return 16 bytes from instead of only half. - */ - hash_ptr = (u32 *) hash; - hash_ptr[0] ^= hash_ptr[4]; - os_memcpy(out, hash, EXTRACT_LEN); -} - - -void random_add_randomness(const void *buf, size_t len) -{ - struct os_time t; - static unsigned int count = 0; - - count++; - if (entropy > MIN_COLLECT_ENTROPY && (count & 0x3ff) != 0) { - /* - * No need to add more entropy at this point, so save CPU and - * skip the update. - */ - return; - } - wpa_printf(MSG_EXCESSIVE, "Add randomness: count=%u entropy=%u", - count, entropy); - - os_get_time(&t); - wpa_hexdump_key(MSG_EXCESSIVE, "random pool", - (const u8 *) pool, sizeof(pool)); - random_mix_pool(&t, sizeof(t)); - random_mix_pool(buf, len); - wpa_hexdump_key(MSG_EXCESSIVE, "random pool", - (const u8 *) pool, sizeof(pool)); - entropy++; - total_collected++; -} - - -int random_get_bytes(void *buf, size_t len) -{ - int ret; - u8 *bytes = buf; - size_t left; - - wpa_printf(MSG_MSGDUMP, "Get randomness: len=%u entropy=%u", - (unsigned int) len, entropy); - - /* Start with assumed strong randomness from OS */ - ret = os_get_random(buf, len); - wpa_hexdump_key(MSG_EXCESSIVE, "random from os_get_random", - buf, len); - - /* Mix in additional entropy extracted from the internal pool */ - left = len; - while (left) { - size_t siz, i; - u8 tmp[EXTRACT_LEN]; - random_extract(tmp); - wpa_hexdump_key(MSG_EXCESSIVE, "random from internal pool", - tmp, sizeof(tmp)); - siz = left > EXTRACT_LEN ? EXTRACT_LEN : left; - for (i = 0; i < siz; i++) - *bytes++ ^= tmp[i]; - left -= siz; - } - -#ifdef CONFIG_FIPS - /* Mix in additional entropy from the crypto module */ - left = len; - while (left) { - size_t siz, i; - u8 tmp[EXTRACT_LEN]; - if (crypto_get_random(tmp, sizeof(tmp)) < 0) { - wpa_printf(MSG_ERROR, "random: No entropy available " - "for generating strong random bytes"); - return -1; - } - wpa_hexdump_key(MSG_EXCESSIVE, "random from crypto module", - tmp, sizeof(tmp)); - siz = left > EXTRACT_LEN ? EXTRACT_LEN : left; - for (i = 0; i < siz; i++) - *bytes++ ^= tmp[i]; - left -= siz; - } -#endif /* CONFIG_FIPS */ - - wpa_hexdump_key(MSG_EXCESSIVE, "mixed random", buf, len); - - if (entropy < len) - entropy = 0; - else - entropy -= len; - - return ret; -} - - -int random_pool_ready(void) -{ -#ifdef __linux__ - int fd; - ssize_t res; - - /* - * Make sure that there is reasonable entropy available before allowing - * some key derivation operations to proceed. - */ - - if (dummy_key_avail == sizeof(dummy_key)) - return 1; /* Already initialized - good to continue */ - - /* - * Try to fetch some more data from the kernel high quality - * /dev/random. There may not be enough data available at this point, - * so use non-blocking read to avoid blocking the application - * completely. - */ - fd = open("/dev/random", O_RDONLY | O_NONBLOCK); - if (fd < 0) { -#ifndef CONFIG_NO_STDOUT_DEBUG - int error = errno; - perror("open(/dev/random)"); - wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s", - strerror(error)); -#endif /* CONFIG_NO_STDOUT_DEBUG */ - return -1; - } - - res = read(fd, dummy_key + dummy_key_avail, - sizeof(dummy_key) - dummy_key_avail); - if (res < 0) { - wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: " - "%s", strerror(errno)); - res = 0; - } - wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from " - "/dev/random", (unsigned) res, - (unsigned) (sizeof(dummy_key) - dummy_key_avail)); - dummy_key_avail += res; - close(fd); - - if (dummy_key_avail == sizeof(dummy_key)) { - if (own_pool_ready < MIN_READY_MARK) - own_pool_ready = MIN_READY_MARK; - random_write_entropy(); - return 1; - } - - wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong " - "random data available from /dev/random", - (unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key)); - - if (own_pool_ready >= MIN_READY_MARK || - total_collected + 10 * own_pool_ready > MIN_COLLECT_ENTROPY) { - wpa_printf(MSG_INFO, "random: Allow operation to proceed " - "based on internal entropy"); - return 1; - } - - wpa_printf(MSG_INFO, "random: Not enough entropy pool available for " - "secure operations"); - return 0; -#else /* __linux__ */ - /* TODO: could do similar checks on non-Linux platforms */ - return 1; -#endif /* __linux__ */ -} - - -void random_mark_pool_ready(void) -{ - own_pool_ready++; - wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be " - "ready (count=%u/%u)", own_pool_ready, MIN_READY_MARK); - random_write_entropy(); -} - - -#ifdef __linux__ - -static void random_close_fd(void) -{ - if (random_fd >= 0) { - eloop_unregister_read_sock(random_fd); - close(random_fd); - random_fd = -1; - } -} - - -static void random_read_fd(int sock, void *eloop_ctx, void *sock_ctx) -{ - ssize_t res; - - if (dummy_key_avail == sizeof(dummy_key)) { - random_close_fd(); - return; - } - - res = read(sock, dummy_key + dummy_key_avail, - sizeof(dummy_key) - dummy_key_avail); - if (res < 0) { - wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: " - "%s", strerror(errno)); - return; - } - - wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from /dev/random", - (unsigned) res, - (unsigned) (sizeof(dummy_key) - dummy_key_avail)); - dummy_key_avail += res; - - if (dummy_key_avail == sizeof(dummy_key)) { - random_close_fd(); - if (own_pool_ready < MIN_READY_MARK) - own_pool_ready = MIN_READY_MARK; - random_write_entropy(); - } -} - -#endif /* __linux__ */ - - -static void random_read_entropy(void) -{ - char *buf; - size_t len; - - if (!random_entropy_file) - return; - - buf = os_readfile(random_entropy_file, &len); - if (buf == NULL) - return; /* entropy file not yet available */ - - if (len != 1 + RANDOM_ENTROPY_SIZE) { - wpa_printf(MSG_DEBUG, "random: Invalid entropy file %s", - random_entropy_file); - os_free(buf); - return; - } - - own_pool_ready = (u8) buf[0]; - random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE); - random_entropy_file_read = 1; - os_free(buf); - wpa_printf(MSG_DEBUG, "random: Added entropy from %s " - "(own_pool_ready=%u)", - random_entropy_file, own_pool_ready); -} - - -static void random_write_entropy(void) -{ - char buf[RANDOM_ENTROPY_SIZE]; - FILE *f; - u8 opr; - int fail = 0; - - if (!random_entropy_file) - return; - - 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 open entropy file %s " - "for writing", random_entropy_file); - return; - } - - opr = own_pool_ready > 0xff ? 0xff : own_pool_ready; - 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)", - random_entropy_file, own_pool_ready); -} - - -void random_init(const char *entropy_file) -{ - os_free(random_entropy_file); - if (entropy_file) - random_entropy_file = os_strdup(entropy_file); - else - random_entropy_file = NULL; - random_read_entropy(); - -#ifdef __linux__ - if (random_fd >= 0) - return; - - random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK); - if (random_fd < 0) { -#ifndef CONFIG_NO_STDOUT_DEBUG - int error = errno; - perror("open(/dev/random)"); - wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s", - strerror(error)); -#endif /* CONFIG_NO_STDOUT_DEBUG */ - return; - } - wpa_printf(MSG_DEBUG, "random: Trying to read entropy from " - "/dev/random"); - - eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL); -#endif /* __linux__ */ - - random_write_entropy(); -} - - -void random_deinit(void) -{ -#ifdef __linux__ - random_close_fd(); -#endif /* __linux__ */ - random_write_entropy(); - os_free(random_entropy_file); - random_entropy_file = NULL; -} diff --git a/contrib/hostapd/src/crypto/random.h b/contrib/hostapd/src/crypto/random.h deleted file mode 100644 index d13e1c4929..0000000000 --- a/contrib/hostapd/src/crypto/random.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Random number generator - * Copyright (c) 2010-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef RANDOM_H -#define RANDOM_H - -#ifdef CONFIG_NO_RANDOM_POOL -#define random_init(e) do { } while (0) -#define random_deinit() do { } while (0) -#define random_add_randomness(b, l) do { } while (0) -#define random_get_bytes(b, l) os_get_random((b), (l)) -#define random_pool_ready() 1 -#define random_mark_pool_ready() do { } while (0) -#else /* CONFIG_NO_RANDOM_POOL */ -void random_init(const char *entropy_file); -void random_deinit(void); -void random_add_randomness(const void *buf, size_t len); -int random_get_bytes(void *buf, size_t len); -int random_pool_ready(void); -void random_mark_pool_ready(void); -#endif /* CONFIG_NO_RANDOM_POOL */ - -#endif /* RANDOM_H */ diff --git a/contrib/hostapd/src/crypto/rc4.c b/contrib/hostapd/src/crypto/rc4.c deleted file mode 100644 index 98ae269a63..0000000000 --- a/contrib/hostapd/src/crypto/rc4.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * RC4 stream cipher - * Copyright (c) 2002-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" - -#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) - -int rc4_skip(const u8 *key, size_t keylen, size_t skip, - u8 *data, size_t data_len) -{ - u32 i, j, k; - u8 S[256], *pos; - size_t kpos; - - /* Setup RC4 state */ - for (i = 0; i < 256; i++) - S[i] = i; - j = 0; - kpos = 0; - for (i = 0; i < 256; i++) { - j = (j + S[i] + key[kpos]) & 0xff; - kpos++; - if (kpos >= keylen) - kpos = 0; - S_SWAP(i, j); - } - - /* Skip the start of the stream */ - i = j = 0; - for (k = 0; k < skip; k++) { - i = (i + 1) & 0xff; - j = (j + S[i]) & 0xff; - S_SWAP(i, j); - } - - /* Apply RC4 to data */ - pos = data; - for (k = 0; k < data_len; k++) { - i = (i + 1) & 0xff; - j = (j + S[i]) & 0xff; - S_SWAP(i, j); - *pos++ ^= S[(S[i] + S[j]) & 0xff]; - } - - return 0; -} diff --git a/contrib/hostapd/src/crypto/sha1-internal.c b/contrib/hostapd/src/crypto/sha1-internal.c deleted file mode 100644 index 10bf153ca3..0000000000 --- a/contrib/hostapd/src/crypto/sha1-internal.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * SHA1 hash implementation and interface functions - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "sha1.h" -#include "sha1_i.h" -#include "md5.h" -#include "crypto.h" - -typedef struct SHA1Context SHA1_CTX; - -void SHA1Transform(u32 state[5], const unsigned char buffer[64]); - - -/** - * sha1_vector - SHA-1 hash for data vector - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash - * Returns: 0 on success, -1 of failure - */ -int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - SHA1_CTX ctx; - size_t i; - - SHA1Init(&ctx); - for (i = 0; i < num_elem; i++) - SHA1Update(&ctx, addr[i], len[i]); - SHA1Final(mac, &ctx); - return 0; -} - - -/* ===== start - public domain SHA1 implementation ===== */ - -/* -SHA-1 in C -By Steve Reid -100% Public Domain - ------------------ -Modified 7/98 -By James H. Brown -Still 100% Public Domain - -Corrected a problem which generated improper hash values on 16 bit machines -Routine SHA1Update changed from - void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int -len) -to - void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned -long len) - -The 'len' parameter was declared an int which works fine on 32 bit machines. -However, on 16 bit machines an int is too small for the shifts being done -against -it. This caused the hash function to generate incorrect values if len was -greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). - -Since the file IO in main() reads 16K at a time, any file 8K or larger would -be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million -"a"s). - -I also changed the declaration of variables i & j in SHA1Update to -unsigned long from unsigned int for the same reason. - -These changes should make no difference to any 32 bit implementations since -an -int and a long are the same size in those environments. - --- -I also corrected a few compiler warnings generated by Borland C. -1. Added #include for exit() prototype -2. Removed unused variable 'j' in SHA1Final -3. Changed exit(0) to return(0) at end of main. - -ALL changes I made can be located by searching for comments containing 'JHB' ------------------ -Modified 8/98 -By Steve Reid -Still 100% public domain - -1- Removed #include and used return() instead of exit() -2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) -3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net - ------------------ -Modified 4/01 -By Saul Kravitz -Still 100% PD -Modified to run on Compaq Alpha hardware. - ------------------ -Modified 4/01 -By Jouni Malinen -Minor changes to match the coding style used in Dynamics. - -Modified September 24, 2004 -By Jouni Malinen -Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined. - -*/ - -/* -Test Vectors (from FIPS PUB 180-1) -"abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D -"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 -A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -#define SHA1HANDSOFF - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from SSLeay */ -#ifndef WORDS_BIGENDIAN -#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ - (rol(block->l[i], 8) & 0x00FF00FF)) -#else -#define blk0(i) block->l[i] -#endif -#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ - block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) \ - z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ - w = rol(w, 30); -#define R1(v,w,x,y,z,i) \ - z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ - w = rol(w, 30); -#define R2(v,w,x,y,z,i) \ - z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); -#define R3(v,w,x,y,z,i) \ - z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ - w = rol(w, 30); -#define R4(v,w,x,y,z,i) \ - z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ - w=rol(w, 30); - - -#ifdef VERBOSE /* SAK */ -void SHAPrintContext(SHA1_CTX *context, char *msg) -{ - printf("%s (%d,%d) %x %x %x %x %x\n", - msg, - context->count[0], context->count[1], - context->state[0], - context->state[1], - context->state[2], - context->state[3], - context->state[4]); -} -#endif - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -void SHA1Transform(u32 state[5], const unsigned char buffer[64]) -{ - u32 a, b, c, d, e; - typedef union { - unsigned char c[64]; - u32 l[16]; - } CHAR64LONG16; - CHAR64LONG16* block; -#ifdef SHA1HANDSOFF - CHAR64LONG16 workspace; - block = &workspace; - os_memcpy(block, buffer, 64); -#else - block = (CHAR64LONG16 *) buffer; -#endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; -#ifdef SHA1HANDSOFF - os_memset(block, 0, 64); -#endif -} - - -/* SHA1Init - Initialize new context */ - -void SHA1Init(SHA1_CTX* context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* Run your data through this. */ - -void SHA1Update(SHA1_CTX* context, const void *_data, u32 len) -{ - u32 i, j; - const unsigned char *data = _data; - -#ifdef VERBOSE - SHAPrintContext(context, "before"); -#endif - j = (context->count[0] >> 3) & 63; - if ((context->count[0] += len << 3) < (len << 3)) - context->count[1]++; - context->count[1] += (len >> 29); - if ((j + len) > 63) { - os_memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); - } - j = 0; - } - else i = 0; - os_memcpy(&context->buffer[j], &data[i], len - i); -#ifdef VERBOSE - SHAPrintContext(context, "after "); -#endif -} - - -/* Add padding and return the message digest. */ - -void SHA1Final(unsigned char digest[20], SHA1_CTX* context) -{ - u32 i; - unsigned char finalcount[8]; - - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char) - ((context->count[(i >= 4 ? 0 : 1)] >> - ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - SHA1Update(context, (unsigned char *) "\200", 1); - while ((context->count[0] & 504) != 448) { - SHA1Update(context, (unsigned char *) "\0", 1); - } - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() - */ - for (i = 0; i < 20; i++) { - digest[i] = (unsigned char) - ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & - 255); - } - /* Wipe variables */ - i = 0; - os_memset(context->buffer, 0, 64); - os_memset(context->state, 0, 20); - os_memset(context->count, 0, 8); - os_memset(finalcount, 0, 8); -} - -/* ===== end - public domain SHA1 implementation ===== */ diff --git a/contrib/hostapd/src/crypto/sha1-pbkdf2.c b/contrib/hostapd/src/crypto/sha1-pbkdf2.c deleted file mode 100644 index 8effe2fe06..0000000000 --- a/contrib/hostapd/src/crypto/sha1-pbkdf2.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * SHA1-based key derivation function (PBKDF2) for IEEE 802.11i - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "sha1.h" - -static int pbkdf2_sha1_f(const char *passphrase, const u8 *ssid, - size_t ssid_len, int iterations, unsigned int count, - u8 *digest) -{ - unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; - int i, j; - unsigned char count_buf[4]; - const u8 *addr[2]; - size_t len[2]; - size_t passphrase_len = os_strlen(passphrase); - - addr[0] = ssid; - len[0] = ssid_len; - addr[1] = count_buf; - len[1] = 4; - - /* F(P, S, c, i) = U1 xor U2 xor ... Uc - * U1 = PRF(P, S || i) - * U2 = PRF(P, U1) - * Uc = PRF(P, Uc-1) - */ - - count_buf[0] = (count >> 24) & 0xff; - count_buf[1] = (count >> 16) & 0xff; - count_buf[2] = (count >> 8) & 0xff; - count_buf[3] = count & 0xff; - if (hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, - tmp)) - return -1; - os_memcpy(digest, tmp, SHA1_MAC_LEN); - - for (i = 1; i < iterations; i++) { - if (hmac_sha1((u8 *) passphrase, passphrase_len, tmp, - SHA1_MAC_LEN, tmp2)) - return -1; - os_memcpy(tmp, tmp2, SHA1_MAC_LEN); - for (j = 0; j < SHA1_MAC_LEN; j++) - digest[j] ^= tmp2[j]; - } - - return 0; -} - - -/** - * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i - * @passphrase: ASCII passphrase - * @ssid: SSID - * @ssid_len: SSID length in bytes - * @iterations: Number of iterations to run - * @buf: Buffer for the generated key - * @buflen: Length of the buffer in bytes - * Returns: 0 on success, -1 of failure - * - * This function is used to derive PSK for WPA-PSK. For this protocol, - * iterations is set to 4096 and buflen to 32. This function is described in - * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0. - */ -int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, - int iterations, u8 *buf, size_t buflen) -{ - unsigned int count = 0; - unsigned char *pos = buf; - size_t left = buflen, plen; - unsigned char digest[SHA1_MAC_LEN]; - - while (left > 0) { - count++; - if (pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, - count, digest)) - return -1; - plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left; - os_memcpy(pos, digest, plen); - pos += plen; - left -= plen; - } - - return 0; -} diff --git a/contrib/hostapd/src/crypto/sha1-prf.c b/contrib/hostapd/src/crypto/sha1-prf.c deleted file mode 100644 index 90b9e74b74..0000000000 --- a/contrib/hostapd/src/crypto/sha1-prf.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SHA1-based PRF - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "sha1.h" -#include "crypto.h" - - -/** - * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1) - * @key: Key for PRF - * @key_len: Length of the key in bytes - * @label: A unique label for each purpose of the PRF - * @data: Extra data to bind into the key - * @data_len: Length of the data - * @buf: Buffer for the generated pseudo-random key - * @buf_len: Number of bytes of key to generate - * Returns: 0 on success, -1 of failure - * - * This function is used to derive new, cryptographically separate keys from a - * given key (e.g., PMK in IEEE 802.11i). - */ -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) -{ - u8 counter = 0; - size_t pos, plen; - u8 hash[SHA1_MAC_LEN]; - size_t label_len = os_strlen(label) + 1; - const unsigned char *addr[3]; - size_t len[3]; - - addr[0] = (u8 *) label; - len[0] = label_len; - addr[1] = data; - len[1] = data_len; - addr[2] = &counter; - len[2] = 1; - - pos = 0; - while (pos < buf_len) { - plen = buf_len - pos; - if (plen >= SHA1_MAC_LEN) { - if (hmac_sha1_vector(key, key_len, 3, addr, len, - &buf[pos])) - return -1; - pos += SHA1_MAC_LEN; - } else { - if (hmac_sha1_vector(key, key_len, 3, addr, len, - hash)) - return -1; - os_memcpy(&buf[pos], hash, plen); - break; - } - counter++; - } - - return 0; -} diff --git a/contrib/hostapd/src/crypto/sha1-tlsprf.c b/contrib/hostapd/src/crypto/sha1-tlsprf.c deleted file mode 100644 index 0effd9b76d..0000000000 --- a/contrib/hostapd/src/crypto/sha1-tlsprf.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * TLS PRF (SHA1 + MD5) - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "sha1.h" -#include "md5.h" - - -/** - * 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 - * @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. - */ -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; - u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN]; - u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN]; - int MD5_pos, SHA1_pos; - const u8 *MD5_addr[3]; - size_t MD5_len[3]; - const unsigned char *SHA1_addr[3]; - size_t SHA1_len[3]; - - if (secret_len & 1) - return -1; - - MD5_addr[0] = A_MD5; - MD5_len[0] = MD5_MAC_LEN; - MD5_addr[1] = (unsigned char *) label; - MD5_len[1] = os_strlen(label); - MD5_addr[2] = seed; - MD5_len[2] = seed_len; - - SHA1_addr[0] = A_SHA1; - SHA1_len[0] = SHA1_MAC_LEN; - SHA1_addr[1] = (unsigned char *) label; - SHA1_len[1] = os_strlen(label); - SHA1_addr[2] = seed; - SHA1_len[2] = seed_len; - - /* RFC 2246, 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 = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed) - */ - - L_S1 = L_S2 = (secret_len + 1) / 2; - S1 = secret; - S2 = secret + L_S1; - if (secret_len & 1) { - /* The last byte of S1 will be shared with S2 */ - S2--; - } - - hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5); - hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1); - - MD5_pos = MD5_MAC_LEN; - SHA1_pos = SHA1_MAC_LEN; - for (i = 0; i < outlen; i++) { - if (MD5_pos == MD5_MAC_LEN) { - hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5); - MD5_pos = 0; - hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5); - } - if (SHA1_pos == SHA1_MAC_LEN) { - hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len, - P_SHA1); - SHA1_pos = 0; - hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1); - } - - out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos]; - - MD5_pos++; - SHA1_pos++; - } - - return 0; -} diff --git a/contrib/hostapd/src/crypto/sha1-tprf.c b/contrib/hostapd/src/crypto/sha1-tprf.c deleted file mode 100644 index a52949462f..0000000000 --- a/contrib/hostapd/src/crypto/sha1-tprf.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SHA1 T-PRF for EAP-FAST - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "sha1.h" -#include "crypto.h" - -/** - * sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF) - * @key: Key for PRF - * @key_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 - * @buf: Buffer for the generated pseudo-random key - * @buf_len: Number of bytes of key to generate - * Returns: 0 on success, -1 of failure - * - * This function is used to derive new, cryptographically separate keys from a - * given key for EAP-FAST. T-PRF is defined in RFC 4851, Section 5.5. - */ -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) -{ - unsigned char counter = 0; - size_t pos, plen; - u8 hash[SHA1_MAC_LEN]; - size_t label_len = os_strlen(label); - u8 output_len[2]; - const unsigned char *addr[5]; - size_t len[5]; - - addr[0] = hash; - len[0] = 0; - addr[1] = (unsigned char *) label; - len[1] = label_len + 1; - addr[2] = seed; - len[2] = seed_len; - addr[3] = output_len; - len[3] = 2; - addr[4] = &counter; - len[4] = 1; - - output_len[0] = (buf_len >> 8) & 0xff; - output_len[1] = buf_len & 0xff; - pos = 0; - while (pos < buf_len) { - counter++; - plen = buf_len - pos; - if (hmac_sha1_vector(key, key_len, 5, addr, len, hash)) - return -1; - if (plen >= SHA1_MAC_LEN) { - os_memcpy(&buf[pos], hash, SHA1_MAC_LEN); - pos += SHA1_MAC_LEN; - } else { - os_memcpy(&buf[pos], hash, plen); - break; - } - len[0] = SHA1_MAC_LEN; - } - - return 0; -} diff --git a/contrib/hostapd/src/crypto/sha1.c b/contrib/hostapd/src/crypto/sha1.c deleted file mode 100644 index d48c77d75c..0000000000 --- a/contrib/hostapd/src/crypto/sha1.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * SHA1 hash implementation and interface functions - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "sha1.h" -#include "crypto.h" - - -/** - * hmac_sha1_vector - HMAC-SHA1 over data vector (RFC 2104) - * @key: Key for HMAC operations - * @key_len: Length of the key in bytes - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash (20 bytes) - * Returns: 0 on success, -1 on failure - */ -int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac) -{ - unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ - unsigned char tk[20]; - const u8 *_addr[6]; - size_t _len[6], i; - - if (num_elem > 5) { - /* - * Fixed limit on the number of fragments to avoid having to - * allocate memory (which could fail). - */ - return -1; - } - - /* if key is longer than 64 bytes reset it to key = SHA1(key) */ - if (key_len > 64) { - if (sha1_vector(1, &key, &key_len, tk)) - return -1; - key = tk; - key_len = 20; - } - - /* the HMAC_SHA1 transform looks like: - * - * SHA1(K XOR opad, SHA1(K XOR ipad, text)) - * - * where K is an n byte key - * ipad is the byte 0x36 repeated 64 times - * opad is the byte 0x5c repeated 64 times - * and text is the data being protected */ - - /* start out by storing key in ipad */ - os_memset(k_pad, 0, sizeof(k_pad)); - os_memcpy(k_pad, key, key_len); - /* XOR key with ipad values */ - for (i = 0; i < 64; i++) - k_pad[i] ^= 0x36; - - /* perform inner SHA1 */ - _addr[0] = k_pad; - _len[0] = 64; - for (i = 0; i < num_elem; i++) { - _addr[i + 1] = addr[i]; - _len[i + 1] = len[i]; - } - if (sha1_vector(1 + num_elem, _addr, _len, mac)) - return -1; - - os_memset(k_pad, 0, sizeof(k_pad)); - os_memcpy(k_pad, key, key_len); - /* XOR key with opad values */ - for (i = 0; i < 64; i++) - k_pad[i] ^= 0x5c; - - /* perform outer SHA1 */ - _addr[0] = k_pad; - _len[0] = 64; - _addr[1] = mac; - _len[1] = SHA1_MAC_LEN; - return sha1_vector(2, _addr, _len, mac); -} - - -/** - * hmac_sha1 - HMAC-SHA1 over data buffer (RFC 2104) - * @key: Key for HMAC operations - * @key_len: Length of the key in bytes - * @data: Pointers to the data area - * @data_len: Length of the data area - * @mac: Buffer for the hash (20 bytes) - * Returns: 0 on success, -1 of failure - */ -int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, - u8 *mac) -{ - return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); -} diff --git a/contrib/hostapd/src/crypto/sha1.h b/contrib/hostapd/src/crypto/sha1.h deleted file mode 100644 index 933cd81b95..0000000000 --- a/contrib/hostapd/src/crypto/sha1.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * SHA1 hash implementation and interface functions - * Copyright (c) 2003-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef SHA1_H -#define SHA1_H - -#define SHA1_MAC_LEN 20 - -int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac); -int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, - u8 *mac); -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_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 u8 *ssid, size_t ssid_len, - int iterations, u8 *buf, size_t buflen); -#endif /* SHA1_H */ diff --git a/contrib/hostapd/src/crypto/sha1_i.h b/contrib/hostapd/src/crypto/sha1_i.h deleted file mode 100644 index 344387e973..0000000000 --- a/contrib/hostapd/src/crypto/sha1_i.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SHA1 internal definitions - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef SHA1_I_H -#define SHA1_I_H - -struct SHA1Context { - u32 state[5]; - u32 count[2]; - unsigned char buffer[64]; -}; - -void SHA1Init(struct SHA1Context *context); -void SHA1Update(struct SHA1Context *context, const void *data, u32 len); -void SHA1Final(unsigned char digest[20], struct SHA1Context *context); -void SHA1Transform(u32 state[5], const unsigned char buffer[64]); - -#endif /* SHA1_I_H */ diff --git a/contrib/hostapd/src/crypto/sha256-internal.c b/contrib/hostapd/src/crypto/sha256-internal.c deleted file mode 100644 index 35299b0524..0000000000 --- a/contrib/hostapd/src/crypto/sha256-internal.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * SHA-256 hash implementation and interface functions - * Copyright (c) 2003-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "sha256.h" -#include "sha256_i.h" -#include "crypto.h" - - -/** - * sha256_vector - SHA256 hash for data vector - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash - * Returns: 0 on success, -1 of failure - */ -int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, - u8 *mac) -{ - struct sha256_state ctx; - size_t i; - - sha256_init(&ctx); - for (i = 0; i < num_elem; i++) - if (sha256_process(&ctx, addr[i], len[i])) - return -1; - if (sha256_done(&ctx, mac)) - return -1; - return 0; -} - - -/* ===== start - public domain SHA256 implementation ===== */ - -/* This is based on SHA256 implementation in LibTomCrypt that was released into - * public domain by Tom St Denis. */ - -/* the K array */ -static const unsigned long K[64] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, - 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, - 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, - 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, - 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, - 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, - 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, - 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, - 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, - 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, - 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, - 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL -}; - - -/* Various logical functions */ -#define RORc(x, y) \ -( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ - ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S(x, n) RORc((x), (n)) -#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) -#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) -#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) -#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) -#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) -#ifndef MIN -#define MIN(x, y) (((x) < (y)) ? (x) : (y)) -#endif - -/* compress 512-bits */ -static int sha256_compress(struct sha256_state *md, unsigned char *buf) -{ - u32 S[8], W[64], t0, t1; - u32 t; - int i; - - /* copy state into S */ - for (i = 0; i < 8; i++) { - S[i] = md->state[i]; - } - - /* copy the state into 512-bits into W[0..15] */ - for (i = 0; i < 16; i++) - W[i] = WPA_GET_BE32(buf + (4 * i)); - - /* fill W[16..63] */ - for (i = 16; i < 64; i++) { - W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + - W[i - 16]; - } - - /* Compress */ -#define RND(a,b,c,d,e,f,g,h,i) \ - t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ - t1 = Sigma0(a) + Maj(a, b, c); \ - d += t0; \ - h = t0 + t1; - - for (i = 0; i < 64; ++i) { - RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); - t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; - S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; - } - - /* feedback */ - for (i = 0; i < 8; i++) { - md->state[i] = md->state[i] + S[i]; - } - return 0; -} - - -/* Initialize the hash state */ -void sha256_init(struct sha256_state *md) -{ - md->curlen = 0; - md->length = 0; - md->state[0] = 0x6A09E667UL; - md->state[1] = 0xBB67AE85UL; - md->state[2] = 0x3C6EF372UL; - md->state[3] = 0xA54FF53AUL; - md->state[4] = 0x510E527FUL; - md->state[5] = 0x9B05688CUL; - md->state[6] = 0x1F83D9ABUL; - md->state[7] = 0x5BE0CD19UL; -} - -/** - Process a block of memory though the hash - @param md The hash state - @param in The data to hash - @param inlen The length of the data (octets) - @return CRYPT_OK if successful -*/ -int sha256_process(struct sha256_state *md, const unsigned char *in, - unsigned long inlen) -{ - unsigned long n; - - if (md->curlen >= sizeof(md->buf)) - return -1; - - while (inlen > 0) { - if (md->curlen == 0 && inlen >= SHA256_BLOCK_SIZE) { - if (sha256_compress(md, (unsigned char *) in) < 0) - return -1; - md->length += SHA256_BLOCK_SIZE * 8; - in += SHA256_BLOCK_SIZE; - inlen -= SHA256_BLOCK_SIZE; - } else { - 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 == SHA256_BLOCK_SIZE) { - if (sha256_compress(md, md->buf) < 0) - return -1; - md->length += 8 * SHA256_BLOCK_SIZE; - md->curlen = 0; - } - } - } - - return 0; -} - - -/** - Terminate the hash to get the digest - @param md The hash state - @param out [out] The destination of the hash (32 bytes) - @return CRYPT_OK if successful -*/ -int sha256_done(struct sha256_state *md, unsigned char *out) -{ - int i; - - if (md->curlen >= sizeof(md->buf)) - return -1; - - /* increase the length of the message */ - md->length += md->curlen * 8; - - /* append the '1' bit */ - md->buf[md->curlen++] = (unsigned char) 0x80; - - /* if the length is currently above 56 bytes we append zeros - * then compress. Then we can fall back to padding zeros and length - * encoding like normal. - */ - if (md->curlen > 56) { - while (md->curlen < SHA256_BLOCK_SIZE) { - md->buf[md->curlen++] = (unsigned char) 0; - } - sha256_compress(md, md->buf); - md->curlen = 0; - } - - /* pad up to 56 bytes of zeroes */ - while (md->curlen < 56) { - md->buf[md->curlen++] = (unsigned char) 0; - } - - /* store length */ - WPA_PUT_BE64(md->buf + 56, md->length); - sha256_compress(md, md->buf); - - /* copy output */ - for (i = 0; i < 8; i++) - WPA_PUT_BE32(out + (4 * i), md->state[i]); - - return 0; -} - -/* ===== end - public domain SHA256 implementation ===== */ diff --git a/contrib/hostapd/src/crypto/sha256-prf.c b/contrib/hostapd/src/crypto/sha256-prf.c deleted file mode 100644 index 9a11208f5a..0000000000 --- a/contrib/hostapd/src/crypto/sha256-prf.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SHA256-based PRF (IEEE 802.11r) - * Copyright (c) 2003-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "sha256.h" -#include "crypto.h" - - -/** - * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2) - * @key: Key for PRF - * @key_len: Length of the key in bytes - * @label: A unique label for each purpose of the PRF - * @data: Extra data to bind into the key - * @data_len: Length of the data - * @buf: Buffer for the generated pseudo-random key - * @buf_len: Number of bytes of key to generate - * - * This function is used to derive new, cryptographically separate keys from a - * given key. - */ -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) -{ - sha256_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8); -} - - -/** - * sha256_prf_bits - IEEE Std 802.11-2012, 11.6.1.7.2 Key derivation function - * @key: Key for KDF - * @key_len: Length of the key in bytes - * @label: A unique label for each purpose of the PRF - * @data: Extra data to bind into the key - * @data_len: Length of the data - * @buf: Buffer for the generated pseudo-random key - * @buf_len: Number of bits of key to generate - * - * This function is used to derive new, cryptographically separate keys from a - * given key. If the requested buf_len is not divisible by eight, the least - * significant 1-7 bits of the last octet in the output are not part of the - * requested output. - */ -void sha256_prf_bits(const u8 *key, size_t key_len, const char *label, - const u8 *data, size_t data_len, u8 *buf, - size_t buf_len_bits) -{ - u16 counter = 1; - size_t pos, plen; - u8 hash[SHA256_MAC_LEN]; - const u8 *addr[4]; - size_t len[4]; - u8 counter_le[2], length_le[2]; - size_t buf_len = (buf_len_bits + 7) / 8; - - addr[0] = counter_le; - len[0] = 2; - addr[1] = (u8 *) label; - len[1] = os_strlen(label); - addr[2] = data; - len[2] = data_len; - addr[3] = length_le; - len[3] = sizeof(length_le); - - WPA_PUT_LE16(length_le, buf_len_bits); - pos = 0; - while (pos < buf_len) { - plen = buf_len - pos; - WPA_PUT_LE16(counter_le, counter); - if (plen >= SHA256_MAC_LEN) { - hmac_sha256_vector(key, key_len, 4, addr, len, - &buf[pos]); - pos += SHA256_MAC_LEN; - } else { - hmac_sha256_vector(key, key_len, 4, addr, len, hash); - os_memcpy(&buf[pos], hash, plen); - pos += plen; - break; - } - counter++; - } - - /* - * Mask out unused bits in the last octet if it does not use all the - * bits. - */ - if (buf_len_bits % 8) { - u8 mask = 0xff << (8 - buf_len_bits % 8); - buf[pos - 1] &= mask; - } -} diff --git a/contrib/hostapd/src/crypto/sha256-tlsprf.c b/contrib/hostapd/src/crypto/sha256-tlsprf.c deleted file mode 100644 index 0528dadfdc..0000000000 --- a/contrib/hostapd/src/crypto/sha256-tlsprf.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * TLS PRF P_SHA256 - * Copyright (c) 2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README 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/contrib/hostapd/src/crypto/sha256.c b/contrib/hostapd/src/crypto/sha256.c deleted file mode 100644 index b55e976f37..0000000000 --- a/contrib/hostapd/src/crypto/sha256.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * SHA-256 hash implementation and interface functions - * Copyright (c) 2003-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "sha256.h" -#include "crypto.h" - - -/** - * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104) - * @key: Key for HMAC operations - * @key_len: Length of the key in bytes - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash (32 bytes) - * Returns: 0 on success, -1 on failure - */ -int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac) -{ - unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ - unsigned char tk[32]; - const u8 *_addr[6]; - size_t _len[6], i; - - if (num_elem > 5) { - /* - * Fixed limit on the number of fragments to avoid having to - * allocate memory (which could fail). - */ - return -1; - } - - /* if key is longer than 64 bytes reset it to key = SHA256(key) */ - if (key_len > 64) { - if (sha256_vector(1, &key, &key_len, tk) < 0) - return -1; - key = tk; - key_len = 32; - } - - /* the HMAC_SHA256 transform looks like: - * - * SHA256(K XOR opad, SHA256(K XOR ipad, text)) - * - * where K is an n byte key - * ipad is the byte 0x36 repeated 64 times - * opad is the byte 0x5c repeated 64 times - * and text is the data being protected */ - - /* start out by storing key in ipad */ - os_memset(k_pad, 0, sizeof(k_pad)); - os_memcpy(k_pad, key, key_len); - /* XOR key with ipad values */ - for (i = 0; i < 64; i++) - k_pad[i] ^= 0x36; - - /* perform inner SHA256 */ - _addr[0] = k_pad; - _len[0] = 64; - for (i = 0; i < num_elem; i++) { - _addr[i + 1] = addr[i]; - _len[i + 1] = len[i]; - } - if (sha256_vector(1 + num_elem, _addr, _len, mac) < 0) - return -1; - - os_memset(k_pad, 0, sizeof(k_pad)); - os_memcpy(k_pad, key, key_len); - /* XOR key with opad values */ - for (i = 0; i < 64; i++) - k_pad[i] ^= 0x5c; - - /* perform outer SHA256 */ - _addr[0] = k_pad; - _len[0] = 64; - _addr[1] = mac; - _len[1] = SHA256_MAC_LEN; - return sha256_vector(2, _addr, _len, mac); -} - - -/** - * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104) - * @key: Key for HMAC operations - * @key_len: Length of the key in bytes - * @data: Pointers to the data area - * @data_len: Length of the data area - * @mac: Buffer for the hash (32 bytes) - * Returns: 0 on success, -1 on failure - */ -int hmac_sha256(const u8 *key, size_t key_len, const u8 *data, - size_t data_len, u8 *mac) -{ - return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); -} diff --git a/contrib/hostapd/src/crypto/sha256.h b/contrib/hostapd/src/crypto/sha256.h deleted file mode 100644 index 7596a52219..0000000000 --- a/contrib/hostapd/src/crypto/sha256.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * SHA256 hash implementation and interface functions - * Copyright (c) 2003-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef SHA256_H -#define SHA256_H - -#define SHA256_MAC_LEN 32 - -int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac); -int 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 sha256_prf_bits(const u8 *key, size_t key_len, const char *label, - const u8 *data, size_t data_len, u8 *buf, - size_t buf_len_bits); -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/contrib/hostapd/src/crypto/sha256_i.h b/contrib/hostapd/src/crypto/sha256_i.h deleted file mode 100644 index a502d2ba5d..0000000000 --- a/contrib/hostapd/src/crypto/sha256_i.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SHA-256 internal definitions - * Copyright (c) 2003-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README 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/contrib/hostapd/src/crypto/tls.h b/contrib/hostapd/src/crypto/tls.h deleted file mode 100644 index 287fd333f6..0000000000 --- a/contrib/hostapd/src/crypto/tls.h +++ /dev/null @@ -1,539 +0,0 @@ -/* - * SSL/TLS interface definition - * Copyright (c) 2004-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef TLS_H -#define TLS_H - -struct tls_connection; - -struct tls_keys { - const u8 *master_key; /* TLS master secret */ - size_t master_key_len; - const u8 *client_random; - size_t client_random_len; - const u8 *server_random; - size_t server_random_len; -}; - -enum tls_event { - TLS_CERT_CHAIN_SUCCESS, - TLS_CERT_CHAIN_FAILURE, - TLS_PEER_CERTIFICATE, - TLS_ALERT -}; - -/* - * Note: These are used as identifier with external programs and as such, the - * values must not be changed. - */ -enum tls_fail_reason { - TLS_FAIL_UNSPECIFIED = 0, - TLS_FAIL_UNTRUSTED = 1, - TLS_FAIL_REVOKED = 2, - TLS_FAIL_NOT_YET_VALID = 3, - TLS_FAIL_EXPIRED = 4, - TLS_FAIL_SUBJECT_MISMATCH = 5, - TLS_FAIL_ALTSUBJECT_MISMATCH = 6, - TLS_FAIL_BAD_CERTIFICATE = 7, - TLS_FAIL_SERVER_CHAIN_PROBE = 8, - TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9, - TLS_FAIL_SERVER_USED_CLIENT_CERT = 10 -}; - -union tls_event_data { - struct { - int depth; - const char *subject; - enum tls_fail_reason reason; - const char *reason_txt; - const struct wpabuf *cert; - } cert_fail; - - struct { - int depth; - const char *subject; - const struct wpabuf *cert; - const u8 *hash; - size_t hash_len; - } peer_cert; - - struct { - int is_local; - const char *type; - const char *description; - } alert; -}; - -struct tls_config { - const char *opensc_engine_path; - 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); - void *cb_ctx; -}; - -#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0) -#define TLS_CONN_DISABLE_TIME_CHECKS BIT(1) -#define TLS_CONN_DISABLE_SESSION_TICKET BIT(2) -#define TLS_CONN_REQUEST_OCSP BIT(3) -#define TLS_CONN_REQUIRE_OCSP BIT(4) - -/** - * struct tls_connection_params - Parameters for TLS connection - * @ca_cert: File or reference name for CA X.509 certificate in PEM or DER - * format - * @ca_cert_blob: ca_cert as inlined data or %NULL if not used - * @ca_cert_blob_len: ca_cert_blob length - * @ca_path: Path to CA certificates (OpenSSL specific) - * @subject_match: String to match in the subject of the peer certificate or - * %NULL to allow all subjects - * @altsubject_match: String to match in the alternative subject of the peer - * certificate or %NULL to allow all alternative subjects - * @suffix_match: String to suffix match in the dNSName or CN of the peer - * certificate or %NULL to allow all domain names - * @client_cert: File or reference name for client X.509 certificate in PEM or - * DER format - * @client_cert_blob: client_cert as inlined data or %NULL if not used - * @client_cert_blob_len: client_cert_blob length - * @private_key: File or reference name for client private key in PEM or DER - * format (traditional format (RSA PRIVATE KEY) or PKCS#8 (PRIVATE KEY) - * @private_key_blob: private_key as inlined data or %NULL if not used - * @private_key_blob_len: private_key_blob length - * @private_key_passwd: Passphrase for decrypted private key, %NULL if no - * passphrase is used. - * @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used - * @dh_blob: dh_file as inlined data or %NULL if not used - * @dh_blob_len: dh_blob length - * @engine: 1 = use engine (e.g., a smartcard) for private key operations - * (this is OpenSSL specific for now) - * @engine_id: engine id string (this is OpenSSL specific for now) - * @ppin: pointer to the pin variable in the configuration - * (this is OpenSSL specific for now) - * @key_id: the private key's id when using engine (this is OpenSSL - * specific for now) - * @cert_id: the certificate's id when using engine - * @ca_cert_id: the CA certificate's id when using engine - * @flags: Parameter options (TLS_CONN_*) - * @ocsp_stapling_response: DER encoded file with cached OCSP stapling response - * or %NULL if OCSP is not enabled - * - * TLS connection parameters to be configured with tls_connection_set_params() - * and tls_global_set_params(). - * - * Certificates and private key can be configured either as a reference name - * (file path or reference to certificate store) or by providing the same data - * as a pointer to the data in memory. Only one option will be used for each - * field. - */ -struct tls_connection_params { - const char *ca_cert; - const u8 *ca_cert_blob; - size_t ca_cert_blob_len; - const char *ca_path; - const char *subject_match; - const char *altsubject_match; - const char *suffix_match; - const char *client_cert; - const u8 *client_cert_blob; - size_t client_cert_blob_len; - const char *private_key; - const u8 *private_key_blob; - size_t private_key_blob_len; - const char *private_key_passwd; - const char *dh_file; - const u8 *dh_blob; - size_t dh_blob_len; - - /* OpenSSL specific variables */ - int engine; - const char *engine_id; - const char *pin; - const char *key_id; - const char *cert_id; - const char *ca_cert_id; - - unsigned int flags; - const char *ocsp_stapling_response; -}; - - -/** - * tls_init - Initialize TLS library - * @conf: Configuration data for TLS library - * Returns: Context data to be used as tls_ctx in calls to other functions, - * or %NULL on failure. - * - * Called once during program startup and once for each RSN pre-authentication - * session. In other words, there can be two concurrent TLS contexts. If global - * library initialization is needed (i.e., one that is shared between both - * authentication types), the TLS library wrapper should maintain a reference - * counter and do global initialization only when moving from 0 to 1 reference. - */ -void * tls_init(const struct tls_config *conf); - -/** - * tls_deinit - Deinitialize TLS library - * @tls_ctx: TLS context data from tls_init() - * - * Called once during program shutdown and once for each RSN pre-authentication - * session. If global library deinitialization is needed (i.e., one that is - * shared between both authentication types), the TLS library wrapper should - * maintain a reference counter and do global deinitialization only when moving - * from 1 to 0 references. - */ -void tls_deinit(void *tls_ctx); - -/** - * tls_get_errors - Process pending errors - * @tls_ctx: TLS context data from tls_init() - * Returns: Number of found error, 0 if no errors detected. - * - * Process all pending TLS errors. - */ -int tls_get_errors(void *tls_ctx); - -/** - * tls_connection_init - Initialize a new TLS connection - * @tls_ctx: TLS context data from tls_init() - * Returns: Connection context data, conn for other function calls - */ -struct tls_connection * tls_connection_init(void *tls_ctx); - -/** - * tls_connection_deinit - Free TLS connection data - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * - * Release all resources allocated for TLS connection. - */ -void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn); - -/** - * tls_connection_established - Has the TLS connection been completed? - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * Returns: 1 if TLS connection has been completed, 0 if not. - */ -int tls_connection_established(void *tls_ctx, struct tls_connection *conn); - -/** - * tls_connection_shutdown - Shutdown TLS connection - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * Returns: 0 on success, -1 on failure - * - * Shutdown current TLS connection without releasing all resources. New - * connection can be started by using the same conn without having to call - * tls_connection_init() or setting certificates etc. again. The new - * connection should try to use session resumption. - */ -int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn); - -enum { - TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3, - TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2 -}; - -/** - * tls_connection_set_params - Set TLS connection parameters - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * @params: Connection parameters - * Returns: 0 on success, -1 on failure, - * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing - * PKCS#11 engine failure, or - * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the - * PKCS#11 engine private key. - */ -int __must_check -tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, - const struct tls_connection_params *params); - -/** - * tls_global_set_params - Set TLS parameters for all TLS connection - * @tls_ctx: TLS context data from tls_init() - * @params: Global TLS parameters - * Returns: 0 on success, -1 on failure, - * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing - * PKCS#11 engine failure, or - * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the - * PKCS#11 engine private key. - */ -int __must_check tls_global_set_params( - void *tls_ctx, const struct tls_connection_params *params); - -/** - * tls_global_set_verify - Set global certificate verification options - * @tls_ctx: TLS context data from tls_init() - * @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate, - * 2 = verify CRL for all certificates - * Returns: 0 on success, -1 on failure - */ -int __must_check tls_global_set_verify(void *tls_ctx, int check_crl); - -/** - * tls_connection_set_verify - Set certificate verification options - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * @verify_peer: 1 = verify peer certificate - * Returns: 0 on success, -1 on failure - */ -int __must_check tls_connection_set_verify(void *tls_ctx, - struct tls_connection *conn, - int verify_peer); - -/** - * 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() - * @keys: Structure of key/random data (filled on success) - * Returns: 0 on success, -1 on failure - */ -int __must_check tls_connection_get_keys(void *tls_ctx, - struct tls_connection *conn, - struct tls_keys *keys); - -/** - * tls_connection_prf - Use TLS-PRF to derive keying material - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * @label: Label (e.g., description of the key) for PRF - * @server_random_first: seed is 0 = client_random|server_random, - * 1 = server_random|client_random - * @out: Buffer for output data from TLS-PRF - * @out_len: Length of the output buffer - * Returns: 0 on success, -1 on failure - * - * This function is optional to implement if tls_connection_get_keys() provides - * access to master secret and server/client random values. If these values are - * 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_sha1_md5() - * when it is called with seed set to client_random|server_random (or - * server_random|client_random). - */ -int __must_check tls_connection_prf(void *tls_ctx, - struct tls_connection *conn, - const char *label, - int server_random_first, - u8 *out, size_t out_len); - -/** - * tls_connection_handshake - Process TLS handshake (client side) - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * @in_data: Input data from TLS server - * @appl_data: Pointer to application data pointer, or %NULL if dropped - * Returns: Output data, %NULL on failure - * - * The caller is responsible for freeing the returned output data. If the final - * handshake message includes application data, this is decrypted and - * appl_data (if not %NULL) is set to point this data. The caller is - * responsible for freeing appl_data. - * - * This function is used during TLS handshake. The first call is done with - * in_data == %NULL and the library is expected to return ClientHello packet. - * This packet is then send to the server and a response from server is given - * to TLS library by calling this function again with in_data pointing to the - * TLS message from the server. - * - * If the TLS handshake fails, this function may return %NULL. However, if the - * TLS library has a TLS alert to send out, that should be returned as the - * output data. In this case, tls_connection_get_failed() must return failure - * (> 0). - * - * tls_connection_established() should return 1 once the TLS handshake has been - * completed successfully. - */ -struct wpabuf * tls_connection_handshake(void *tls_ctx, - struct tls_connection *conn, - 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() - * @conn: Connection context data from tls_connection_init() - * @in_data: Input data from TLS peer - * @appl_data: Pointer to application data pointer, or %NULL if dropped - * Returns: Output data, %NULL on failure - * - * The caller is responsible for freeing the returned output data. - */ -struct wpabuf * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data); - -/** - * tls_connection_encrypt - Encrypt data into TLS tunnel - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * @in_data: Plaintext data to be encrypted - * Returns: Encrypted TLS data or %NULL on failure - * - * This function is used after TLS handshake has been completed successfully to - * send data in the encrypted tunnel. The caller is responsible for freeing the - * returned output data. - */ -struct wpabuf * tls_connection_encrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data); - -/** - * tls_connection_decrypt - Decrypt data from TLS tunnel - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * @in_data: Encrypted TLS data - * Returns: Decrypted TLS data or %NULL on failure - * - * This function is used after TLS handshake has been completed successfully to - * receive data from the encrypted tunnel. The caller is responsible for - * freeing the returned output data. - */ -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() - * @conn: Connection context data from tls_connection_init() - * Returns: 1 if current session used session resumption, 0 if not - */ -int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn); - -enum { - TLS_CIPHER_NONE, - TLS_CIPHER_RC4_SHA /* 0x0005 */, - TLS_CIPHER_AES128_SHA /* 0x002f */, - TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */, - TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */ -}; - -/** - * tls_connection_set_cipher_list - Configure acceptable cipher suites - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers - * (TLS_CIPHER_*). - * Returns: 0 on success, -1 on failure - */ -int __must_check tls_connection_set_cipher_list(void *tls_ctx, - struct tls_connection *conn, - u8 *ciphers); - -/** - * tls_get_cipher - Get current cipher name - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * @buf: Buffer for the cipher name - * @buflen: buf size - * Returns: 0 on success, -1 on failure - * - * Get the name of the currently used cipher. - */ -int __must_check tls_get_cipher(void *tls_ctx, struct tls_connection *conn, - char *buf, size_t buflen); - -/** - * tls_connection_enable_workaround - Enable TLS workaround options - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * Returns: 0 on success, -1 on failure - * - * This function is used to enable connection-specific workaround options for - * buffer SSL/TLS implementations. - */ -int __must_check tls_connection_enable_workaround(void *tls_ctx, - struct tls_connection *conn); - -/** - * tls_connection_client_hello_ext - Set TLS extension for ClientHello - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * @ext_type: Extension type - * @data: Extension payload (%NULL to remove extension) - * @data_len: Extension payload length - * Returns: 0 on success, -1 on failure - */ -int __must_check tls_connection_client_hello_ext(void *tls_ctx, - struct tls_connection *conn, - int ext_type, const u8 *data, - size_t data_len); - -/** - * tls_connection_get_failed - Get connection failure status - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * - * Returns >0 if connection has failed, 0 if not. - */ -int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn); - -/** - * tls_connection_get_read_alerts - Get connection read alert status - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * Returns: Number of times a fatal read (remote end reported error) has - * happened during this connection. - */ -int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn); - -/** - * tls_connection_get_write_alerts - Get connection write alert status - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * Returns: Number of times a fatal write (locally detected error) has happened - * during this connection. - */ -int tls_connection_get_write_alerts(void *tls_ctx, - struct tls_connection *conn); - -/** - * tls_connection_get_keyblock_size - Get TLS key_block size - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * Returns: Size of the key_block for the negotiated cipher suite or -1 on - * failure - */ -int tls_connection_get_keyblock_size(void *tls_ctx, - struct tls_connection *conn); - -/** - * tls_capabilities - Get supported TLS capabilities - * @tls_ctx: TLS context data from tls_init() - * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*) - */ -unsigned int tls_capabilities(void *tls_ctx); - -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); - -int __must_check tls_connection_set_session_ticket_cb( - void *tls_ctx, struct tls_connection *conn, - tls_session_ticket_cb cb, void *ctx); - -#endif /* TLS_H */ diff --git a/contrib/hostapd/src/crypto/tls_gnutls.c b/contrib/hostapd/src/crypto/tls_gnutls.c deleted file mode 100644 index cb23eb9c5f..0000000000 --- a/contrib/hostapd/src/crypto/tls_gnutls.c +++ /dev/null @@ -1,1190 +0,0 @@ -/* - * SSL/TLS interface functions for GnuTLS - * Copyright (c) 2004-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include -#include -#ifdef PKCS12_FUNCS -#include -#endif /* PKCS12_FUNCS */ - -#include "common.h" -#include "tls.h" - - -#define WPA_TLS_RANDOM_SIZE 32 -#define WPA_TLS_MASTER_SIZE 48 - - -#if LIBGNUTLS_VERSION_NUMBER < 0x010302 -/* GnuTLS 1.3.2 added functions for using master secret. Older versions require - * use of internal structures to get the master_secret and - * {server,client}_random. - */ -#define GNUTLS_INTERNAL_STRUCTURE_HACK -#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */ - - -#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK -/* - * It looks like gnutls does not provide access to client/server_random and - * master_key. This is somewhat unfortunate since these are needed for key - * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible - * hack that copies the gnutls_session_int definition from gnutls_int.h so that - * we can get the needed information. - */ - -typedef u8 uint8; -typedef unsigned char opaque; -typedef struct { - uint8 suite[2]; -} cipher_suite_st; - -typedef struct { - gnutls_connection_end_t entity; - gnutls_kx_algorithm_t kx_algorithm; - gnutls_cipher_algorithm_t read_bulk_cipher_algorithm; - gnutls_mac_algorithm_t read_mac_algorithm; - gnutls_compression_method_t read_compression_algorithm; - gnutls_cipher_algorithm_t write_bulk_cipher_algorithm; - gnutls_mac_algorithm_t write_mac_algorithm; - gnutls_compression_method_t write_compression_algorithm; - cipher_suite_st current_cipher_suite; - 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; - -struct gnutls_session_int { - security_parameters_st security_parameters; - /* followed by things we are not interested in */ -}; -#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */ - -static int tls_gnutls_ref_count = 0; - -struct tls_global { - /* Data for session resumption */ - void *session_data; - size_t session_data_size; - - int server; - - int params_set; - gnutls_certificate_credentials_t xcred; -}; - -struct tls_connection { - gnutls_session session; - char *subject_match, *altsubject_match; - int read_alerts, write_alerts, failed; - - u8 *pre_shared_secret; - size_t pre_shared_secret_len; - int established; - int verify_peer; - - struct wpabuf *push_buf; - struct wpabuf *pull_buf; - const u8 *pull_buf_offset; - - int params_set; - gnutls_certificate_credentials_t xcred; -}; - - -static void tls_log_func(int level, const char *msg) -{ - char *s, *pos; - if (level == 6 || level == 7) { - /* These levels seem to be mostly I/O debug and msg dumps */ - return; - } - - s = os_strdup(msg); - if (s == NULL) - return; - - pos = s; - while (*pos != '\0') { - if (*pos == '\n') { - *pos = '\0'; - break; - } - pos++; - } - wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG, - "gnutls<%d> %s", level, s); - os_free(s); -} - - -void * tls_init(const struct tls_config *conf) -{ - struct tls_global *global; - -#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK - /* Because of the horrible hack to get master_secret and client/server - * random, we need to make sure that the gnutls version is something - * that is expected to have same structure definition for the session - * data.. */ - const char *ver; - const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9", - "1.3.2", - NULL }; - int i; -#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ - - global = os_zalloc(sizeof(*global)); - if (global == NULL) - return NULL; - - if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) { - os_free(global); - return NULL; - } - tls_gnutls_ref_count++; - -#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK - ver = gnutls_check_version(NULL); - if (ver == NULL) { - tls_deinit(global); - return NULL; - } - wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver); - for (i = 0; ok_ver[i]; i++) { - if (strcmp(ok_ver[i], ver) == 0) - break; - } - if (ok_ver[i] == NULL) { - wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs " - "to be tested and enabled in tls_gnutls.c", ver); - tls_deinit(global); - return NULL; - } -#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ - - gnutls_global_set_log_function(tls_log_func); - if (wpa_debug_show_keys) - gnutls_global_set_log_level(11); - return global; -} - - -void tls_deinit(void *ssl_ctx) -{ - struct tls_global *global = ssl_ctx; - if (global) { - if (global->params_set) - gnutls_certificate_free_credentials(global->xcred); - os_free(global->session_data); - os_free(global); - } - - tls_gnutls_ref_count--; - if (tls_gnutls_ref_count == 0) - gnutls_global_deinit(); -} - - -int tls_get_errors(void *ssl_ctx) -{ - return 0; -} - - -static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf, - size_t len) -{ - struct tls_connection *conn = (struct tls_connection *) ptr; - const u8 *end; - if (conn->pull_buf == NULL) { - errno = EWOULDBLOCK; - return -1; - } - - end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf); - if ((size_t) (end - conn->pull_buf_offset) < len) - len = end - conn->pull_buf_offset; - os_memcpy(buf, conn->pull_buf_offset, len); - conn->pull_buf_offset += len; - if (conn->pull_buf_offset == end) { - wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__); - wpabuf_free(conn->pull_buf); - conn->pull_buf = NULL; - conn->pull_buf_offset = NULL; - } else { - wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf", - __func__, - (unsigned long) (end - conn->pull_buf_offset)); - } - return len; -} - - -static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf, - size_t len) -{ - struct tls_connection *conn = (struct tls_connection *) ptr; - - if (wpabuf_resize(&conn->push_buf, len) < 0) { - errno = ENOMEM; - return -1; - } - wpabuf_put_data(conn->push_buf, buf, len); - - return len; -} - - -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, - global->server ? GNUTLS_SERVER : GNUTLS_CLIENT); - if (ret < 0) { - wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS " - "connection: %s", gnutls_strerror(ret)); - return -1; - } - - ret = gnutls_set_default_priority(conn->session); - 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; - - 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); - gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn); - - return 0; - -fail: - wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s", - gnutls_strerror(ret)); - gnutls_deinit(conn->session); - return -1; -} - - -struct tls_connection * tls_connection_init(void *ssl_ctx) -{ - struct tls_global *global = ssl_ctx; - struct tls_connection *conn; - int ret; - - conn = os_zalloc(sizeof(*conn)); - if (conn == NULL) - return NULL; - - if (tls_gnutls_init_session(global, conn)) { - os_free(conn); - return NULL; - } - - if (global->params_set) { - ret = gnutls_credentials_set(conn->session, - GNUTLS_CRD_CERTIFICATE, - global->xcred); - if (ret < 0) { - wpa_printf(MSG_INFO, "Failed to configure " - "credentials: %s", gnutls_strerror(ret)); - os_free(conn); - return NULL; - } - } - - if (gnutls_certificate_allocate_credentials(&conn->xcred)) { - os_free(conn); - return NULL; - } - - return conn; -} - - -void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return; - - gnutls_certificate_free_credentials(conn->xcred); - gnutls_deinit(conn->session); - os_free(conn->pre_shared_secret); - os_free(conn->subject_match); - os_free(conn->altsubject_match); - wpabuf_free(conn->push_buf); - wpabuf_free(conn->pull_buf); - os_free(conn); -} - - -int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) -{ - return conn ? conn->established : 0; -} - - -int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) -{ - struct tls_global *global = ssl_ctx; - int ret; - - if (conn == NULL) - return -1; - - /* Shutdown previous TLS connection without notifying the peer - * because the connection was already terminated in practice - * and "close notify" shutdown alert would confuse AS. */ - gnutls_bye(conn->session, GNUTLS_SHUT_RDWR); - wpabuf_free(conn->push_buf); - conn->push_buf = NULL; - conn->established = 0; - - gnutls_deinit(conn->session); - if (tls_gnutls_init_session(global, conn)) { - wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session " - "for session resumption use"); - return -1; - } - - ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, - conn->params_set ? conn->xcred : - global->xcred); - if (ret < 0) { - wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials " - "for session resumption: %s", gnutls_strerror(ret)); - return -1; - } - - if (global->session_data) { - ret = gnutls_session_set_data(conn->session, - global->session_data, - global->session_data_size); - if (ret < 0) { - wpa_printf(MSG_INFO, "GnuTLS: Failed to set session " - "data: %s", gnutls_strerror(ret)); - return -1; - } - } - - return 0; -} - - -#if 0 -static int tls_match_altsubject(X509 *cert, const char *match) -{ - GENERAL_NAME *gen; - char *field, *tmp; - void *ext; - int i, found = 0; - size_t len; - - ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); - - for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { - gen = sk_GENERAL_NAME_value(ext, i); - switch (gen->type) { - case GEN_EMAIL: - field = "EMAIL"; - break; - case GEN_DNS: - field = "DNS"; - break; - case GEN_URI: - field = "URI"; - break; - default: - field = NULL; - wpa_printf(MSG_DEBUG, "TLS: altSubjectName: " - "unsupported type=%d", gen->type); - break; - } - - if (!field) - continue; - - wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s", - field, gen->d.ia5->data); - len = os_strlen(field) + 1 + - strlen((char *) gen->d.ia5->data) + 1; - tmp = os_malloc(len); - if (tmp == NULL) - continue; - snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data); - if (strstr(tmp, match)) - found++; - os_free(tmp); - } - - return found; -} -#endif - - -#if 0 -static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) -{ - char buf[256]; - X509 *err_cert; - int err, depth; - SSL *ssl; - struct tls_connection *conn; - char *match, *altmatch; - - err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); - err = X509_STORE_CTX_get_error(x509_ctx); - depth = X509_STORE_CTX_get_error_depth(x509_ctx); - ssl = X509_STORE_CTX_get_ex_data(x509_ctx, - SSL_get_ex_data_X509_STORE_CTX_idx()); - X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); - - conn = SSL_get_app_data(ssl); - match = conn ? conn->subject_match : NULL; - altmatch = conn ? conn->altsubject_match : NULL; - - if (!preverify_ok) { - wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," - " error %d (%s) depth %d for '%s'", err, - X509_verify_cert_error_string(err), depth, buf); - } else { - wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - " - "preverify_ok=%d err=%d (%s) depth=%d buf='%s'", - preverify_ok, err, - X509_verify_cert_error_string(err), depth, buf); - if (depth == 0 && match && strstr(buf, match) == NULL) { - wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " - "match with '%s'", buf, match); - preverify_ok = 0; - } else if (depth == 0 && altmatch && - !tls_match_altsubject(err_cert, altmatch)) { - wpa_printf(MSG_WARNING, "TLS: altSubjectName match " - "'%s' not found", altmatch); - preverify_ok = 0; - } - } - - return preverify_ok; -} -#endif - - -int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, - const struct tls_connection_params *params) -{ - int ret; - - if (conn == NULL || params == NULL) - return -1; - - os_free(conn->subject_match); - conn->subject_match = NULL; - if (params->subject_match) { - conn->subject_match = os_strdup(params->subject_match); - if (conn->subject_match == NULL) - return -1; - } - - os_free(conn->altsubject_match); - conn->altsubject_match = NULL; - if (params->altsubject_match) { - conn->altsubject_match = os_strdup(params->altsubject_match); - if (conn->altsubject_match == NULL) - return -1; - } - - /* TODO: gnutls_certificate_set_verify_flags(xcred, flags); - * to force peer validation(?) */ - - if (params->ca_cert) { - conn->verify_peer = 1; - ret = gnutls_certificate_set_x509_trust_file( - conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' " - "in PEM format: %s", params->ca_cert, - gnutls_strerror(ret)); - ret = gnutls_certificate_set_x509_trust_file( - conn->xcred, params->ca_cert, - GNUTLS_X509_FMT_DER); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "Failed to read CA cert " - "'%s' in DER format: %s", - params->ca_cert, - gnutls_strerror(ret)); - return -1; - } - } - - if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) { - gnutls_certificate_set_verify_flags( - 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) { - /* TODO: private_key_passwd? */ - ret = gnutls_certificate_set_x509_key_file( - conn->xcred, params->client_cert, params->private_key, - GNUTLS_X509_FMT_PEM); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "Failed to read client cert/key " - "in PEM format: %s", gnutls_strerror(ret)); - ret = gnutls_certificate_set_x509_key_file( - conn->xcred, params->client_cert, - params->private_key, GNUTLS_X509_FMT_DER); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "Failed to read client " - "cert/key in DER format: %s", - gnutls_strerror(ret)); - return ret; - } - } - } else if (params->private_key) { - int pkcs12_ok = 0; -#ifdef PKCS12_FUNCS - /* Try to load in PKCS#12 format */ -#if LIBGNUTLS_VERSION_NUMBER >= 0x010302 - ret = gnutls_certificate_set_x509_simple_pkcs12_file( - conn->xcred, params->private_key, GNUTLS_X509_FMT_DER, - params->private_key_passwd); - if (ret != 0) { - wpa_printf(MSG_DEBUG, "Failed to load private_key in " - "PKCS#12 format: %s", gnutls_strerror(ret)); - return -1; - } else - pkcs12_ok = 1; -#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ -#endif /* PKCS12_FUNCS */ - - if (!pkcs12_ok) { - wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not " - "included"); - return -1; - } - } - - conn->params_set = 1; - - ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, - conn->xcred); - if (ret < 0) { - wpa_printf(MSG_INFO, "Failed to configure credentials: %s", - gnutls_strerror(ret)); - } - - return ret; -} - - -int tls_global_set_params(void *tls_ctx, - const struct tls_connection_params *params) -{ - struct tls_global *global = tls_ctx; - int ret; - - /* Currently, global parameters are only set when running in server - * mode. */ - global->server = 1; - - if (global->params_set) { - gnutls_certificate_free_credentials(global->xcred); - global->params_set = 0; - } - - ret = gnutls_certificate_allocate_credentials(&global->xcred); - if (ret) { - wpa_printf(MSG_DEBUG, "Failed to allocate global credentials " - "%s", gnutls_strerror(ret)); - return -1; - } - - if (params->ca_cert) { - ret = gnutls_certificate_set_x509_trust_file( - global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' " - "in PEM format: %s", params->ca_cert, - gnutls_strerror(ret)); - ret = gnutls_certificate_set_x509_trust_file( - global->xcred, params->ca_cert, - GNUTLS_X509_FMT_DER); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "Failed to read CA cert " - "'%s' in DER format: %s", - params->ca_cert, - gnutls_strerror(ret)); - goto fail; - } - } - - if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) { - gnutls_certificate_set_verify_flags( - global->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( - global->xcred, - GNUTLS_VERIFY_DISABLE_TIME_CHECKS); - } -#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */ - } - - if (params->client_cert && params->private_key) { - /* TODO: private_key_passwd? */ - ret = gnutls_certificate_set_x509_key_file( - global->xcred, params->client_cert, - params->private_key, GNUTLS_X509_FMT_PEM); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "Failed to read client cert/key " - "in PEM format: %s", gnutls_strerror(ret)); - ret = gnutls_certificate_set_x509_key_file( - global->xcred, params->client_cert, - params->private_key, GNUTLS_X509_FMT_DER); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "Failed to read client " - "cert/key in DER format: %s", - gnutls_strerror(ret)); - goto fail; - } - } - } else if (params->private_key) { - int pkcs12_ok = 0; -#ifdef PKCS12_FUNCS - /* Try to load in PKCS#12 format */ -#if LIBGNUTLS_VERSION_NUMBER >= 0x010302 - ret = gnutls_certificate_set_x509_simple_pkcs12_file( - global->xcred, params->private_key, - GNUTLS_X509_FMT_DER, params->private_key_passwd); - if (ret != 0) { - wpa_printf(MSG_DEBUG, "Failed to load private_key in " - "PKCS#12 format: %s", gnutls_strerror(ret)); - goto fail; - } else - pkcs12_ok = 1; -#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ -#endif /* PKCS12_FUNCS */ - - if (!pkcs12_ok) { - wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not " - "included"); - goto fail; - } - } - - global->params_set = 1; - - return 0; - -fail: - gnutls_certificate_free_credentials(global->xcred); - return -1; -} - - -int tls_global_set_verify(void *ssl_ctx, int check_crl) -{ - /* TODO */ - return 0; -} - - -int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, - int verify_peer) -{ - if (conn == NULL || conn->session == NULL) - return -1; - - conn->verify_peer = verify_peer; - gnutls_certificate_server_set_request(conn->session, - verify_peer ? GNUTLS_CERT_REQUIRE - : GNUTLS_CERT_REQUEST); - - return 0; -} - - -int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, - struct tls_keys *keys) -{ -#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK - security_parameters_st *sec; -#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ - - if (conn == NULL || conn->session == NULL || keys == NULL) - return -1; - - 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 = WPA_TLS_MASTER_SIZE; - keys->client_random = sec->client_random; - keys->server_random = sec->server_random; -#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */ - keys->client_random = - (u8 *) gnutls_session_get_client_random(conn->session); - keys->server_random = - (u8 *) gnutls_session_get_server_random(conn->session); - /* No access to master_secret */ -#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ -#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */ - -#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; -} - - -int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, - const char *label, int server_random_first, - u8 *out, size_t out_len) -{ -#if LIBGNUTLS_VERSION_NUMBER >= 0x010302 - if (conn == NULL || conn->session == NULL) - return -1; - - return gnutls_prf(conn->session, os_strlen(label), label, - server_random_first, 0, NULL, out_len, (char *) out); -#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ - return -1; -#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ -} - - -static int tls_connection_verify_peer(struct tls_connection *conn, - gnutls_alert_description_t *err) -{ - unsigned int status, num_certs, i; - struct os_time now; - const gnutls_datum_t *certs; - gnutls_x509_crt_t cert; - - if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) { - wpa_printf(MSG_INFO, "TLS: Failed to verify peer " - "certificate chain"); - *err = GNUTLS_A_INTERNAL_ERROR; - return -1; - } - - 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"); - *err = GNUTLS_A_CERTIFICATE_EXPIRED; - } - if (status & GNUTLS_CERT_EXPIRED) { - wpa_printf(MSG_INFO, "TLS: Certificate expired"); - *err = GNUTLS_A_CERTIFICATE_EXPIRED; - } -#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */ - return -1; - } - - if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { - wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a " - "known issuer"); - *err = GNUTLS_A_UNKNOWN_CA; - return -1; - } - - if (status & GNUTLS_CERT_REVOKED) { - wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked"); - *err = GNUTLS_A_CERTIFICATE_REVOKED; - return -1; - } - - os_get_time(&now); - - certs = gnutls_certificate_get_peers(conn->session, &num_certs); - if (certs == NULL) { - wpa_printf(MSG_INFO, "TLS: No peer certificate chain " - "received"); - *err = GNUTLS_A_UNKNOWN_CA; - return -1; - } - - for (i = 0; i < num_certs; i++) { - char *buf; - size_t len; - if (gnutls_x509_crt_init(&cert) < 0) { - wpa_printf(MSG_INFO, "TLS: Certificate initialization " - "failed"); - *err = GNUTLS_A_BAD_CERTIFICATE; - return -1; - } - - if (gnutls_x509_crt_import(cert, &certs[i], - GNUTLS_X509_FMT_DER) < 0) { - wpa_printf(MSG_INFO, "TLS: Could not parse peer " - "certificate %d/%d", i + 1, num_certs); - gnutls_x509_crt_deinit(cert); - *err = GNUTLS_A_BAD_CERTIFICATE; - return -1; - } - - gnutls_x509_crt_get_dn(cert, NULL, &len); - len++; - buf = os_malloc(len + 1); - if (buf) { - buf[0] = buf[len] = '\0'; - gnutls_x509_crt_get_dn(cert, buf, &len); - } - wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s", - i + 1, num_certs, buf); - - if (i == 0) { - /* TODO: validate subject_match and altsubject_match */ - } - - os_free(buf); - - if (gnutls_x509_crt_get_expiration_time(cert) < now.sec || - gnutls_x509_crt_get_activation_time(cert) > now.sec) { - wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is " - "not valid at this time", - i + 1, num_certs); - gnutls_x509_crt_deinit(cert); - *err = GNUTLS_A_CERTIFICATE_EXPIRED; - return -1; - } - - gnutls_x509_crt_deinit(cert); - } - - return 0; -} - - -static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn) -{ - int res; - struct wpabuf *ad; - wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data"); - ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3); - if (ad == NULL) - return NULL; - - res = gnutls_record_recv(conn->session, wpabuf_mhead(ad), - wpabuf_size(ad)); - wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res); - if (res < 0) { - wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d " - "(%s)", __func__, (int) res, - gnutls_strerror(res)); - wpabuf_free(ad); - return NULL; - } - - wpabuf_put(ad, res); - wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data", - res); - return ad; -} - - -struct wpabuf * tls_connection_handshake(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data) -{ - struct tls_global *global = tls_ctx; - struct wpabuf *out_data; - int ret; - - if (appl_data) - *appl_data = NULL; - - if (in_data && wpabuf_len(in_data) > 0) { - if (conn->pull_buf) { - wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " - "pull_buf", __func__, - (unsigned long) wpabuf_len(conn->pull_buf)); - wpabuf_free(conn->pull_buf); - } - conn->pull_buf = wpabuf_dup(in_data); - if (conn->pull_buf == NULL) - return NULL; - conn->pull_buf_offset = wpabuf_head(conn->pull_buf); - } - - ret = gnutls_handshake(conn->session); - if (ret < 0) { - switch (ret) { - case GNUTLS_E_AGAIN: - if (global->server && conn->established && - conn->push_buf == NULL) { - /* Need to return something to trigger - * completion of EAP-TLS. */ - conn->push_buf = wpabuf_alloc(0); - } - break; - case GNUTLS_E_FATAL_ALERT_RECEIVED: - wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert", - __func__, gnutls_alert_get_name( - gnutls_alert_get(conn->session))); - conn->read_alerts++; - /* continue */ - default: - wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed " - "-> %s", __func__, gnutls_strerror(ret)); - conn->failed++; - } - } else { - size_t size; - gnutls_alert_description_t err; - - if (conn->verify_peer && - tls_connection_verify_peer(conn, &err)) { - wpa_printf(MSG_INFO, "TLS: Peer certificate chain " - "failed validation"); - conn->failed++; - gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err); - goto out; - } - - 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. */ - conn->push_buf = wpabuf_alloc(0); - } - - gnutls_session_get_data(conn->session, NULL, &size); - if (global->session_data == NULL || - global->session_data_size < size) { - os_free(global->session_data); - global->session_data = os_malloc(size); - } - if (global->session_data) { - global->session_data_size = size; - gnutls_session_get_data(conn->session, - global->session_data, - &global->session_data_size); - } - - if (conn->pull_buf && appl_data) - *appl_data = gnutls_get_appl_data(conn); - } - -out: - out_data = conn->push_buf; - conn->push_buf = NULL; - return out_data; -} - - -struct wpabuf * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data) -{ - return tls_connection_handshake(tls_ctx, conn, in_data, appl_data); -} - - -struct wpabuf * tls_connection_encrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data) -{ - ssize_t res; - struct wpabuf *buf; - - res = gnutls_record_send(conn->session, wpabuf_head(in_data), - wpabuf_len(in_data)); - if (res < 0) { - wpa_printf(MSG_INFO, "%s: Encryption failed: %s", - __func__, gnutls_strerror(res)); - return NULL; - } - - buf = conn->push_buf; - conn->push_buf = NULL; - return buf; -} - - -struct wpabuf * tls_connection_decrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data) -{ - ssize_t res; - struct wpabuf *out; - - if (conn->pull_buf) { - wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " - "pull_buf", __func__, - (unsigned long) wpabuf_len(conn->pull_buf)); - wpabuf_free(conn->pull_buf); - } - conn->pull_buf = wpabuf_dup(in_data); - if (conn->pull_buf == NULL) - return NULL; - conn->pull_buf_offset = wpabuf_head(conn->pull_buf); - - /* - * Even though we try to disable TLS compression, it is possible that - * this cannot be done with all TLS libraries. Add extra buffer space - * to handle the possibility of the decrypted data being longer than - * input data. - */ - out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); - if (out == NULL) - return NULL; - - res = gnutls_record_recv(conn->session, wpabuf_mhead(out), - wpabuf_size(out)); - if (res < 0) { - wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d " - "(%s)", __func__, (int) res, gnutls_strerror(res)); - wpabuf_free(out); - return NULL; - } - wpabuf_put(out, res); - - return out; -} - - -int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return 0; - return gnutls_session_is_resumed(conn->session); -} - - -int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, - u8 *ciphers) -{ - /* TODO */ - return -1; -} - - -int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, - char *buf, size_t buflen) -{ - /* TODO */ - buf[0] = '\0'; - return 0; -} - - -int tls_connection_enable_workaround(void *ssl_ctx, - struct tls_connection *conn) -{ - gnutls_record_disable_padding(conn->session); - return 0; -} - - -int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, - int ext_type, const u8 *data, - size_t data_len) -{ - /* TODO */ - return -1; -} - - -int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - return conn->failed; -} - - -int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - return conn->read_alerts; -} - - -int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - return conn->write_alerts; -} - - -int tls_connection_get_keyblock_size(void *tls_ctx, - struct tls_connection *conn) -{ - /* TODO */ - return -1; -} - - -unsigned int tls_capabilities(void *tls_ctx) -{ - return 0; -} - - -int tls_connection_set_session_ticket_cb(void *tls_ctx, - struct tls_connection *conn, - tls_session_ticket_cb cb, void *ctx) -{ - return -1; -} diff --git a/contrib/hostapd/src/crypto/tls_internal.c b/contrib/hostapd/src/crypto/tls_internal.c deleted file mode 100644 index 91f0690032..0000000000 --- a/contrib/hostapd/src/crypto/tls_internal.c +++ /dev/null @@ -1,630 +0,0 @@ -/* - * TLS interface functions and an internal TLS implementation - * Copyright (c) 2004-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file interface functions for hostapd/wpa_supplicant to use the - * integrated TLSv1 implementation. - */ - -#include "includes.h" - -#include "common.h" -#include "tls.h" -#include "tls/tlsv1_client.h" -#include "tls/tlsv1_server.h" - - -static int tls_ref_count = 0; - -struct tls_global { - int server; - struct tlsv1_credentials *server_cred; - int check_crl; -}; - -struct tls_connection { - struct tlsv1_client *client; - struct tlsv1_server *server; -}; - - -void * tls_init(const struct tls_config *conf) -{ - struct tls_global *global; - - if (tls_ref_count == 0) { -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (tlsv1_client_global_init()) - return NULL; -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (tlsv1_server_global_init()) - return NULL; -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - } - tls_ref_count++; - - global = os_zalloc(sizeof(*global)); - if (global == NULL) - return NULL; - - return global; -} - -void tls_deinit(void *ssl_ctx) -{ - struct tls_global *global = ssl_ctx; - tls_ref_count--; - if (tls_ref_count == 0) { -#ifdef CONFIG_TLS_INTERNAL_CLIENT - tlsv1_client_global_deinit(); -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - tlsv1_cred_free(global->server_cred); - tlsv1_server_global_deinit(); -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - } - os_free(global); -} - - -int tls_get_errors(void *tls_ctx) -{ - return 0; -} - - -struct tls_connection * tls_connection_init(void *tls_ctx) -{ - struct tls_connection *conn; - struct tls_global *global = tls_ctx; - - conn = os_zalloc(sizeof(*conn)); - if (conn == NULL) - return NULL; - -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (!global->server) { - conn->client = tlsv1_client_init(); - if (conn->client == NULL) { - os_free(conn); - return NULL; - } - } -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (global->server) { - conn->server = tlsv1_server_init(global->server_cred); - if (conn->server == NULL) { - os_free(conn); - return NULL; - } - } -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - - return conn; -} - - -void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return; -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (conn->client) - tlsv1_client_deinit(conn->client); -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (conn->server) - tlsv1_server_deinit(conn->server); -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - os_free(conn); -} - - -int tls_connection_established(void *tls_ctx, struct tls_connection *conn) -{ -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (conn->client) - return tlsv1_client_established(conn->client); -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (conn->server) - return tlsv1_server_established(conn->server); -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - return 0; -} - - -int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) -{ -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (conn->client) - return tlsv1_client_shutdown(conn->client); -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (conn->server) - return tlsv1_server_shutdown(conn->server); -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; -} - - -int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, - const struct tls_connection_params *params) -{ -#ifdef CONFIG_TLS_INTERNAL_CLIENT - struct tlsv1_credentials *cred; - - if (conn->client == NULL) - return -1; - - cred = tlsv1_cred_alloc(); - if (cred == NULL) - return -1; - - if (tlsv1_set_ca_cert(cred, params->ca_cert, - params->ca_cert_blob, params->ca_cert_blob_len, - params->ca_path)) { - wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA " - "certificates"); - tlsv1_cred_free(cred); - return -1; - } - - if (tlsv1_set_cert(cred, params->client_cert, - params->client_cert_blob, - params->client_cert_blob_len)) { - wpa_printf(MSG_INFO, "TLS: Failed to configure client " - "certificate"); - tlsv1_cred_free(cred); - return -1; - } - - if (tlsv1_set_private_key(cred, params->private_key, - params->private_key_passwd, - params->private_key_blob, - params->private_key_blob_len)) { - wpa_printf(MSG_INFO, "TLS: Failed to load private key"); - tlsv1_cred_free(cred); - return -1; - } - - if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob, - params->dh_blob_len)) { - wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters"); - tlsv1_cred_free(cred); - return -1; - } - - if (tlsv1_client_set_cred(conn->client, cred) < 0) { - tlsv1_cred_free(cred); - return -1; - } - - tlsv1_client_set_time_checks( - conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS)); - - return 0; -#else /* CONFIG_TLS_INTERNAL_CLIENT */ - return -1; -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -} - - -int tls_global_set_params(void *tls_ctx, - const struct tls_connection_params *params) -{ -#ifdef CONFIG_TLS_INTERNAL_SERVER - struct tls_global *global = tls_ctx; - struct tlsv1_credentials *cred; - - /* Currently, global parameters are only set when running in server - * mode. */ - global->server = 1; - tlsv1_cred_free(global->server_cred); - global->server_cred = cred = tlsv1_cred_alloc(); - if (cred == NULL) - return -1; - - if (tlsv1_set_ca_cert(cred, params->ca_cert, params->ca_cert_blob, - params->ca_cert_blob_len, params->ca_path)) { - wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA " - "certificates"); - return -1; - } - - if (tlsv1_set_cert(cred, params->client_cert, params->client_cert_blob, - params->client_cert_blob_len)) { - wpa_printf(MSG_INFO, "TLS: Failed to configure server " - "certificate"); - return -1; - } - - if (tlsv1_set_private_key(cred, params->private_key, - params->private_key_passwd, - params->private_key_blob, - params->private_key_blob_len)) { - wpa_printf(MSG_INFO, "TLS: Failed to load private key"); - return -1; - } - - if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob, - params->dh_blob_len)) { - wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters"); - return -1; - } - - return 0; -#else /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; -#endif /* CONFIG_TLS_INTERNAL_SERVER */ -} - - -int tls_global_set_verify(void *tls_ctx, int check_crl) -{ - struct tls_global *global = tls_ctx; - global->check_crl = check_crl; - return 0; -} - - -int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, - int verify_peer) -{ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (conn->server) - return tlsv1_server_set_verify(conn->server, verify_peer); -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; -} - - -int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, - struct tls_keys *keys) -{ -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (conn->client) - return tlsv1_client_get_keys(conn->client, keys); -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (conn->server) - return tlsv1_server_get_keys(conn->server, keys); -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; -} - - -int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, - const char *label, int server_random_first, - u8 *out, size_t out_len) -{ -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (conn->client) { - return tlsv1_client_prf(conn->client, label, - server_random_first, - out, out_len); - } -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (conn->server) { - return tlsv1_server_prf(conn->server, label, - server_random_first, - out, out_len); - } -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; -} - - -struct wpabuf * tls_connection_handshake(void *tls_ctx, - struct tls_connection *conn, - 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; - struct wpabuf *out; - - if (conn->client == NULL) - return NULL; - - ad = NULL; - 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, need_more_data); - if (res == NULL) - return NULL; - out = wpabuf_alloc_ext_data(res, res_len); - if (out == NULL) { - os_free(res); - os_free(ad); - return NULL; - } - if (appl_data) { - if (ad) { - *appl_data = wpabuf_alloc_ext_data(ad, ad_len); - if (*appl_data == NULL) - os_free(ad); - } else - *appl_data = NULL; - } else - os_free(ad); - - return out; -#else /* CONFIG_TLS_INTERNAL_CLIENT */ - return NULL; -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -} - - -struct wpabuf * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data) -{ -#ifdef CONFIG_TLS_INTERNAL_SERVER - u8 *res; - size_t res_len; - struct wpabuf *out; - - if (conn->server == NULL) - return NULL; - - if (appl_data) - *appl_data = NULL; - - res = tlsv1_server_handshake(conn->server, wpabuf_head(in_data), - wpabuf_len(in_data), &res_len); - if (res == NULL && tlsv1_server_established(conn->server)) - return wpabuf_alloc(0); - if (res == NULL) - return NULL; - out = wpabuf_alloc_ext_data(res, res_len); - if (out == NULL) { - os_free(res); - return NULL; - } - - return out; -#else /* CONFIG_TLS_INTERNAL_SERVER */ - return NULL; -#endif /* CONFIG_TLS_INTERNAL_SERVER */ -} - - -struct wpabuf * tls_connection_encrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data) -{ -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (conn->client) { - struct wpabuf *buf; - int res; - buf = wpabuf_alloc(wpabuf_len(in_data) + 300); - if (buf == NULL) - return NULL; - res = tlsv1_client_encrypt(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; - } -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (conn->server) { - struct wpabuf *buf; - int res; - buf = wpabuf_alloc(wpabuf_len(in_data) + 300); - if (buf == NULL) - return NULL; - res = tlsv1_server_encrypt(conn->server, 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; - } -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - return NULL; -} - - -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) { - 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 - if (conn->server) { - struct wpabuf *buf; - int res; - buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); - if (buf == NULL) - return NULL; - res = tlsv1_server_decrypt(conn->server, 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; - } -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - return NULL; -} - - -int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) -{ -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (conn->client) - return tlsv1_client_resumed(conn->client); -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (conn->server) - return tlsv1_server_resumed(conn->server); -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; -} - - -int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, - u8 *ciphers) -{ -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (conn->client) - return tlsv1_client_set_cipher_list(conn->client, ciphers); -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (conn->server) - return tlsv1_server_set_cipher_list(conn->server, ciphers); -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; -} - - -int tls_get_cipher(void *tls_ctx, struct tls_connection *conn, - char *buf, size_t buflen) -{ - if (conn == NULL) - return -1; -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (conn->client) - return tlsv1_client_get_cipher(conn->client, buf, buflen); -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (conn->server) - return tlsv1_server_get_cipher(conn->server, buf, buflen); -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; -} - - -int tls_connection_enable_workaround(void *tls_ctx, - struct tls_connection *conn) -{ - return -1; -} - - -int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, - int ext_type, const u8 *data, - size_t data_len) -{ -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (conn->client) { - return tlsv1_client_hello_ext(conn->client, ext_type, - data, data_len); - } -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ - return -1; -} - - -int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) -{ - return 0; -} - - -int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) -{ - return 0; -} - - -int tls_connection_get_write_alerts(void *tls_ctx, - struct tls_connection *conn) -{ - return 0; -} - - -int tls_connection_get_keyblock_size(void *tls_ctx, - struct tls_connection *conn) -{ -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (conn->client) - return tlsv1_client_get_keyblock_size(conn->client); -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (conn->server) - return tlsv1_server_get_keyblock_size(conn->server); -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; -} - - -unsigned int tls_capabilities(void *tls_ctx) -{ - return 0; -} - - -int tls_connection_set_session_ticket_cb(void *tls_ctx, - struct tls_connection *conn, - tls_session_ticket_cb cb, - void *ctx) -{ -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (conn->client) { - tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx); - return 0; - } -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (conn->server) { - tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx); - return 0; - } -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; -} diff --git a/contrib/hostapd/src/crypto/tls_none.c b/contrib/hostapd/src/crypto/tls_none.c deleted file mode 100644 index 1a1092a184..0000000000 --- a/contrib/hostapd/src/crypto/tls_none.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * SSL/TLS interface functions for no TLS case - * Copyright (c) 2004-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "tls.h" - -void * tls_init(const struct tls_config *conf) -{ - return (void *) 1; -} - - -void tls_deinit(void *ssl_ctx) -{ -} - - -int tls_get_errors(void *tls_ctx) -{ - return 0; -} - - -struct tls_connection * tls_connection_init(void *tls_ctx) -{ - return NULL; -} - - -void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) -{ -} - - -int tls_connection_established(void *tls_ctx, struct tls_connection *conn) -{ - return -1; -} - - -int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) -{ - return -1; -} - - -int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, - const struct tls_connection_params *params) -{ - return -1; -} - - -int tls_global_set_params(void *tls_ctx, - const struct tls_connection_params *params) -{ - return -1; -} - - -int tls_global_set_verify(void *tls_ctx, int check_crl) -{ - return -1; -} - - -int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, - int verify_peer) -{ - return -1; -} - - -int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, - struct tls_keys *keys) -{ - return -1; -} - - -int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, - const char *label, int server_random_first, - u8 *out, size_t out_len) -{ - return -1; -} - - -struct wpabuf * tls_connection_handshake(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data) -{ - return NULL; -} - - -struct wpabuf * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data) -{ - return NULL; -} - - -struct wpabuf * tls_connection_encrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data) -{ - return NULL; -} - - -struct wpabuf * tls_connection_decrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data) -{ - return NULL; -} - - -int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) -{ - return 0; -} - - -int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, - u8 *ciphers) -{ - return -1; -} - - -int tls_get_cipher(void *tls_ctx, struct tls_connection *conn, - char *buf, size_t buflen) -{ - return -1; -} - - -int tls_connection_enable_workaround(void *tls_ctx, - struct tls_connection *conn) -{ - return -1; -} - - -int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, - int ext_type, const u8 *data, - size_t data_len) -{ - return -1; -} - - -int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) -{ - return 0; -} - - -int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) -{ - return 0; -} - - -int tls_connection_get_write_alerts(void *tls_ctx, - struct tls_connection *conn) -{ - return 0; -} - - -int tls_connection_get_keyblock_size(void *tls_ctx, - struct tls_connection *conn) -{ - return -1; -} - - -unsigned int tls_capabilities(void *tls_ctx) -{ - return 0; -} diff --git a/contrib/hostapd/src/crypto/tls_nss.c b/contrib/hostapd/src/crypto/tls_nss.c deleted file mode 100644 index c53c192a1c..0000000000 --- a/contrib/hostapd/src/crypto/tls_nss.c +++ /dev/null @@ -1,645 +0,0 @@ -/* - * SSL/TLS interface functions for NSS - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" -#include "tls.h" - -static int tls_nss_ref_count = 0; - -static PRDescIdentity nss_layer_id; - - -struct tls_connection { - PRFileDesc *fd; - - int established; - int verify_peer; - u8 *push_buf, *pull_buf, *pull_buf_offset; - size_t push_buf_len, pull_buf_len; -}; - - -static PRStatus nss_io_close(PRFileDesc *fd) -{ - wpa_printf(MSG_DEBUG, "NSS: I/O close"); - return PR_SUCCESS; -} - - -static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount) -{ - wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount); - return PR_FAILURE; -} - - -static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount) -{ - wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount); - return PR_FAILURE; -} - - -static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov, - PRInt32 iov_size, PRIntervalTime timeout) -{ - wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size); - return PR_FAILURE; -} - - -static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount, - PRIntn flags, PRIntervalTime timeout) -{ - struct tls_connection *conn = (struct tls_connection *) fd->secret; - u8 *end; - - wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount); - - if (conn->pull_buf == NULL) { - wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet"); - return PR_FAILURE; - } - - end = conn->pull_buf + conn->pull_buf_len; - if (end - conn->pull_buf_offset < amount) - amount = end - conn->pull_buf_offset; - os_memcpy(buf, conn->pull_buf_offset, amount); - conn->pull_buf_offset += amount; - if (conn->pull_buf_offset == end) { - wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__); - os_free(conn->pull_buf); - conn->pull_buf = conn->pull_buf_offset = NULL; - conn->pull_buf_len = 0; - } else { - wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf", - __func__, - (unsigned long) (end - conn->pull_buf_offset)); - } - return amount; -} - - -static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount, - PRIntn flags, PRIntervalTime timeout) -{ - struct tls_connection *conn = (struct tls_connection *) fd->secret; - u8 *nbuf; - - wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); - wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount); - - nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount); - if (nbuf == NULL) { - wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the " - "data to be sent"); - return PR_FAILURE; - } - os_memcpy(nbuf + conn->push_buf_len, buf, amount); - conn->push_buf = nbuf; - conn->push_buf_len += amount; - - return amount; -} - - -static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, - PRIntn flags, PRNetAddr *addr, - PRIntervalTime timeout) -{ - wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); - return PR_FAILURE; -} - - -static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount, - PRIntn flags, const PRNetAddr *addr, - PRIntervalTime timeout) -{ - wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); - return PR_FAILURE; -} - - -static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr) -{ - wpa_printf(MSG_DEBUG, "NSS: I/O getpeername"); - - /* - * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a - * fake IPv4 address to work around this even though we are not really - * using TCP. - */ - os_memset(addr, 0, sizeof(*addr)); - addr->inet.family = PR_AF_INET; - - return PR_SUCCESS; -} - - -static PRStatus nss_io_getsocketoption(PRFileDesc *fd, - PRSocketOptionData *data) -{ - switch (data->option) { - case PR_SockOpt_Nonblocking: - wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)"); - data->value.non_blocking = PR_TRUE; - return PR_SUCCESS; - default: - wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)", - data->option); - return PR_FAILURE; - } -} - - -static const PRIOMethods nss_io = { - PR_DESC_LAYERED, - nss_io_close, - nss_io_read, - nss_io_write, - NULL /* available */, - NULL /* available64 */, - NULL /* fsync */, - NULL /* fseek */, - NULL /* fseek64 */, - NULL /* fileinfo */, - NULL /* fileinfo64 */, - nss_io_writev, - NULL /* connect */, - NULL /* accept */, - NULL /* bind */, - NULL /* listen */, - NULL /* shutdown */, - nss_io_recv, - nss_io_send, - nss_io_recvfrom, - nss_io_sendto, - NULL /* poll */, - NULL /* acceptread */, - NULL /* transmitfile */, - NULL /* getsockname */, - nss_io_getpeername, - NULL /* reserved_fn_6 */, - NULL /* reserved_fn_5 */, - nss_io_getsocketoption, - NULL /* setsocketoption */, - NULL /* sendfile */, - NULL /* connectcontinue */, - NULL /* reserved_fn_3 */, - NULL /* reserved_fn_2 */, - NULL /* reserved_fn_1 */, - NULL /* reserved_fn_0 */ -}; - - -static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg) -{ - wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__); - return NULL; -} - - -void * tls_init(const struct tls_config *conf) -{ - char *dir; - - tls_nss_ref_count++; - if (tls_nss_ref_count > 1) - return (void *) 1; - - PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); - - nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant"); - - PK11_SetPasswordFunc(nss_password_cb); - - dir = getenv("SSL_DIR"); - if (dir) { - if (NSS_Init(dir) != SECSuccess) { - wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) " - "failed", dir); - return NULL; - } - } else { - if (NSS_NoDB_Init(NULL) != SECSuccess) { - wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) " - "failed"); - return NULL; - } - } - - if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) != - SECSuccess || - SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess || - SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess || - SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) { - wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed"); - return NULL; - } - - if (NSS_SetDomesticPolicy() != SECSuccess) { - wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed"); - return NULL; - } - - return (void *) 1; -} - -void tls_deinit(void *ssl_ctx) -{ - tls_nss_ref_count--; - if (tls_nss_ref_count == 0) { - if (NSS_Shutdown() != SECSuccess) - wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed"); - } -} - - -int tls_get_errors(void *tls_ctx) -{ - return 0; -} - - -static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd) -{ - struct tls_connection *conn = arg; - SECStatus res = SECSuccess; - PRErrorCode err; - CERTCertificate *cert; - char *subject, *issuer; - - err = PR_GetError(); - if (IS_SEC_ERROR(err)) - wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err " - "%d)", err - SEC_ERROR_BASE); - else - wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)", - err); - cert = SSL_PeerCertificate(fd); - subject = CERT_NameToAscii(&cert->subject); - issuer = CERT_NameToAscii(&cert->issuer); - wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'", - subject, issuer); - CERT_DestroyCertificate(cert); - PR_Free(subject); - PR_Free(issuer); - if (conn->verify_peer) - res = SECFailure; - - return res; -} - - -static void nss_handshake_cb(PRFileDesc *fd, void *client_data) -{ - struct tls_connection *conn = client_data; - wpa_printf(MSG_DEBUG, "NSS: Handshake completed"); - conn->established = 1; -} - - -struct tls_connection * tls_connection_init(void *tls_ctx) -{ - struct tls_connection *conn; - - conn = os_zalloc(sizeof(*conn)); - if (conn == NULL) - return NULL; - - conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io); - if (conn->fd == NULL) { - os_free(conn); - return NULL; - } - conn->fd->secret = (void *) conn; - - conn->fd = SSL_ImportFD(NULL, conn->fd); - if (conn->fd == NULL) { - os_free(conn); - return NULL; - } - - if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess || - SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != - SECSuccess || - SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != - SECSuccess || - SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess || - SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess || - SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) != - SECSuccess) { - wpa_printf(MSG_ERROR, "NSS: Failed to set options"); - PR_Close(conn->fd); - os_free(conn); - return NULL; - } - - SSL_ResetHandshake(conn->fd, PR_FALSE); - - return conn; -} - - -void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) -{ - PR_Close(conn->fd); - os_free(conn->push_buf); - os_free(conn->pull_buf); - os_free(conn); -} - - -int tls_connection_established(void *tls_ctx, struct tls_connection *conn) -{ - return conn->established; -} - - -int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) -{ - return -1; -} - - -int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, - const struct tls_connection_params *params) -{ - wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__); - return 0; -} - - -int tls_global_set_params(void *tls_ctx, - const struct tls_connection_params *params) -{ - return -1; -} - - -int tls_global_set_verify(void *tls_ctx, int check_crl) -{ - return -1; -} - - -int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, - int verify_peer) -{ - conn->verify_peer = verify_peer; - return 0; -} - - -int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, - struct tls_keys *keys) -{ - /* NSS does not export master secret or client/server random. */ - return -1; -} - - -int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, - const char *label, int server_random_first, - u8 *out, size_t out_len) -{ - if (conn == NULL || server_random_first) { - wpa_printf(MSG_INFO, "NSS: Unsupported PRF request " - "(server_random_first=%d)", - server_random_first); - return -1; - } - - if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) != - SECSuccess) { - wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor " - "(label='%s' out_len=%d", label, (int) out_len); - return -1; - } - - return 0; -} - - -struct wpabuf * tls_connection_handshake(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data) -{ - struct wpabuf *out_data; - - wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u", - in_data ? (unsigned int) wpabuf_len(in_data) : 0); - - if (appl_data) - *appl_data = NULL; - - if (in_data && wpabuf_len(in_data) > 0) { - if (conn->pull_buf) { - wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " - "pull_buf", __func__, - (unsigned long) conn->pull_buf_len); - os_free(conn->pull_buf); - } - conn->pull_buf = os_malloc(wpabuf_len(in_data)); - if (conn->pull_buf == NULL) - return NULL; - os_memcpy(conn->pull_buf, wpabuf_head(in_data), - wpabuf_len(in_data)); - conn->pull_buf_offset = conn->pull_buf; - conn->pull_buf_len = wpabuf_len(in_data); - } - - SSL_ForceHandshake(conn->fd); - - if (conn->established && conn->push_buf == NULL) { - /* Need to return something to get final TLS ACK. */ - conn->push_buf = os_malloc(1); - } - - if (conn->push_buf == NULL) - return NULL; - out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); - if (out_data == NULL) - os_free(conn->push_buf); - conn->push_buf = NULL; - conn->push_buf_len = 0; - return out_data; -} - - -struct wpabuf * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data) -{ - return NULL; -} - - -struct wpabuf * tls_connection_encrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data) -{ - PRInt32 res; - struct wpabuf *buf; - - wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes", - (int) wpabuf_len(in_data)); - res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0, - 0); - if (res < 0) { - wpa_printf(MSG_ERROR, "NSS: Encryption failed"); - return NULL; - } - if (conn->push_buf == NULL) - return NULL; - buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); - if (buf == NULL) - os_free(conn->push_buf); - conn->push_buf = NULL; - conn->push_buf_len = 0; - return buf; -} - - -struct wpabuf * tls_connection_decrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data) -{ - PRInt32 res; - struct wpabuf *out; - - wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes", - (int) wpabuf_len(in_data)); - if (conn->pull_buf) { - wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " - "pull_buf", __func__, - (unsigned long) conn->pull_buf_len); - os_free(conn->pull_buf); - } - conn->pull_buf = os_malloc(wpabuf_len(in_data)); - if (conn->pull_buf == NULL) - return NULL; - os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data)); - conn->pull_buf_offset = conn->pull_buf; - conn->pull_buf_len = wpabuf_len(in_data); - - /* - * Even though we try to disable TLS compression, it is possible that - * this cannot be done with all TLS libraries. Add extra buffer space - * to handle the possibility of the decrypted data being longer than - * input data. - */ - out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); - if (out == NULL) - return NULL; - - res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0); - wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res); - if (res < 0) { - wpabuf_free(out); - return NULL; - } - wpabuf_put(out, res); - - return out; -} - - -int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) -{ - return 0; -} - - -int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, - u8 *ciphers) -{ - return -1; -} - - -int tls_get_cipher(void *tls_ctx, struct tls_connection *conn, - char *buf, size_t buflen) -{ - return -1; -} - - -int tls_connection_enable_workaround(void *tls_ctx, - struct tls_connection *conn) -{ - return -1; -} - - -int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, - int ext_type, const u8 *data, - size_t data_len) -{ - return -1; -} - - -int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) -{ - return 0; -} - - -int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) -{ - return 0; -} - - -int tls_connection_get_write_alerts(void *tls_ctx, - struct tls_connection *conn) -{ - return 0; -} - - -int tls_connection_get_keyblock_size(void *tls_ctx, - struct tls_connection *conn) -{ - return -1; -} - - -unsigned int tls_capabilities(void *tls_ctx) -{ - return 0; -} - - -int tls_connection_set_session_ticket_cb(void *tls_ctx, - struct tls_connection *conn, - tls_session_ticket_cb cb, - void *ctx) -{ - return -1; -} diff --git a/contrib/hostapd/src/crypto/tls_openssl.c b/contrib/hostapd/src/crypto/tls_openssl.c deleted file mode 100644 index d025ae0a8a..0000000000 --- a/contrib/hostapd/src/crypto/tls_openssl.c +++ /dev/null @@ -1,3463 +0,0 @@ -/* - * SSL/TLS interface functions for OpenSSL - * Copyright (c) 2004-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#ifndef CONFIG_SMARTCARD -#ifndef OPENSSL_NO_ENGINE -#ifndef ANDROID -#define OPENSSL_NO_ENGINE -#endif -#endif -#endif - -#include -#include -#include -#include -#ifndef OPENSSL_NO_ENGINE -#include -#endif /* OPENSSL_NO_ENGINE */ - -#include "common.h" -#include "crypto.h" -#include "tls.h" - -#if OPENSSL_VERSION_NUMBER >= 0x0090800fL -#define OPENSSL_d2i_TYPE const unsigned char ** -#else -#define OPENSSL_d2i_TYPE unsigned char ** -#endif - -#if defined(SSL_CTX_get_app_data) && defined(SSL_CTX_set_app_data) -#define OPENSSL_SUPPORTS_CTX_APP_DATA -#endif - -#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT -#ifdef SSL_OP_NO_TICKET -/* - * Session ticket override patch was merged into OpenSSL 0.9.9 tree on - * 2008-11-15. This version uses a bit different API compared to the old patch. - */ -#define CONFIG_OPENSSL_TICKET_OVERRIDE -#endif -#endif - -#ifdef SSL_set_tlsext_status_type -#ifndef OPENSSL_NO_TLSEXT -#define HAVE_OCSP -#include -#endif /* OPENSSL_NO_TLSEXT */ -#endif /* SSL_set_tlsext_status_type */ - -#ifdef ANDROID -#include -#include - -static BIO * BIO_from_keystore(const char *key) -{ - BIO *bio = NULL; - uint8_t *value = NULL; - int length = keystore_get(key, strlen(key), &value); - if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL) - BIO_write(bio, value, length); - free(value); - return bio; -} -#endif /* ANDROID */ - -static int tls_openssl_ref_count = 0; - -struct tls_context { - void (*event_cb)(void *ctx, enum tls_event ev, - union tls_event_data *data); - void *cb_ctx; - int cert_in_cb; - char *ocsp_stapling_response; -}; - -static struct tls_context *tls_global = NULL; - - -struct tls_connection { - struct tls_context *context; - SSL *ssl; - BIO *ssl_in, *ssl_out; -#ifndef OPENSSL_NO_ENGINE - ENGINE *engine; /* functional reference to the engine */ - EVP_PKEY *private_key; /* the private key if using engine */ -#endif /* OPENSSL_NO_ENGINE */ - char *subject_match, *altsubject_match, *suffix_match; - int read_alerts, write_alerts, failed; - - tls_session_ticket_cb session_ticket_cb; - void *session_ticket_cb_ctx; - - /* SessionTicket received from OpenSSL hello_extension_cb (server) */ - u8 *session_ticket; - size_t session_ticket_len; - - unsigned int ca_cert_verify:1; - unsigned int cert_probe:1; - unsigned int server_cert_only:1; - unsigned int server:1; - - u8 srv_cert_hash[32]; - - unsigned int flags; - - X509 *peer_cert; - X509 *peer_issuer; - X509 *peer_issuer_issuer; -}; - - -static struct tls_context * tls_context_new(const struct tls_config *conf) -{ - struct tls_context *context = os_zalloc(sizeof(*context)); - if (context == NULL) - return NULL; - if (conf) { - context->event_cb = conf->event_cb; - context->cb_ctx = conf->cb_ctx; - context->cert_in_cb = conf->cert_in_cb; - } - return context; -} - - -#ifdef CONFIG_NO_STDOUT_DEBUG - -static void _tls_show_errors(void) -{ - unsigned long err; - - while ((err = ERR_get_error())) { - /* Just ignore the errors, since stdout is disabled */ - } -} -#define tls_show_errors(l, f, t) _tls_show_errors() - -#else /* CONFIG_NO_STDOUT_DEBUG */ - -static void tls_show_errors(int level, const char *func, const char *txt) -{ - unsigned long err; - - wpa_printf(level, "OpenSSL: %s - %s %s", - func, txt, ERR_error_string(ERR_get_error(), NULL)); - - while ((err = ERR_get_error())) { - wpa_printf(MSG_INFO, "OpenSSL: pending error: %s", - ERR_error_string(err, NULL)); - } -} - -#endif /* CONFIG_NO_STDOUT_DEBUG */ - - -#ifdef CONFIG_NATIVE_WINDOWS - -/* Windows CryptoAPI and access to certificate stores */ -#include - -#ifdef __MINGW32_VERSION -/* - * MinGW does not yet include all the needed definitions for CryptoAPI, so - * define here whatever extra is needed. - */ -#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16) -#define CERT_STORE_READONLY_FLAG 0x00008000 -#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 - -#endif /* __MINGW32_VERSION */ - - -struct cryptoapi_rsa_data { - const CERT_CONTEXT *cert; - HCRYPTPROV crypt_prov; - DWORD key_spec; - BOOL free_crypt_prov; -}; - - -static void cryptoapi_error(const char *msg) -{ - wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u", - msg, (unsigned int) GetLastError()); -} - - -static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from, - unsigned char *to, RSA *rsa, int padding) -{ - wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); - return 0; -} - - -static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from, - unsigned char *to, RSA *rsa, int padding) -{ - wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); - return 0; -} - - -static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from, - unsigned char *to, RSA *rsa, int padding) -{ - struct cryptoapi_rsa_data *priv = - (struct cryptoapi_rsa_data *) rsa->meth->app_data; - HCRYPTHASH hash; - DWORD hash_size, len, i; - unsigned char *buf = NULL; - int ret = 0; - - if (priv == NULL) { - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, - ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - - if (padding != RSA_PKCS1_PADDING) { - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, - RSA_R_UNKNOWN_PADDING_TYPE); - return 0; - } - - if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) { - wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported", - __func__); - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, - RSA_R_INVALID_MESSAGE_LENGTH); - return 0; - } - - if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash)) - { - cryptoapi_error("CryptCreateHash failed"); - return 0; - } - - len = sizeof(hash_size); - if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, - 0)) { - cryptoapi_error("CryptGetHashParam failed"); - goto err; - } - - if ((int) hash_size != flen) { - wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)", - (unsigned) hash_size, flen); - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, - RSA_R_INVALID_MESSAGE_LENGTH); - goto err; - } - if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) { - cryptoapi_error("CryptSetHashParam failed"); - goto err; - } - - len = RSA_size(rsa); - buf = os_malloc(len); - if (buf == NULL) { - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE); - goto err; - } - - if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) { - cryptoapi_error("CryptSignHash failed"); - goto err; - } - - for (i = 0; i < len; i++) - to[i] = buf[len - i - 1]; - ret = len; - -err: - os_free(buf); - CryptDestroyHash(hash); - - return ret; -} - - -static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from, - unsigned char *to, RSA *rsa, int padding) -{ - wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); - return 0; -} - - -static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv) -{ - if (priv == NULL) - return; - if (priv->crypt_prov && priv->free_crypt_prov) - CryptReleaseContext(priv->crypt_prov, 0); - if (priv->cert) - CertFreeCertificateContext(priv->cert); - os_free(priv); -} - - -static int cryptoapi_finish(RSA *rsa) -{ - cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data); - os_free((void *) rsa->meth); - rsa->meth = NULL; - return 1; -} - - -static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store) -{ - HCERTSTORE cs; - const CERT_CONTEXT *ret = NULL; - - cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, - store | CERT_STORE_OPEN_EXISTING_FLAG | - CERT_STORE_READONLY_FLAG, L"MY"); - if (cs == NULL) { - cryptoapi_error("Failed to open 'My system store'"); - return NULL; - } - - if (strncmp(name, "cert://", 7) == 0) { - unsigned short wbuf[255]; - MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255); - ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING | - PKCS_7_ASN_ENCODING, - 0, CERT_FIND_SUBJECT_STR, - wbuf, NULL); - } else if (strncmp(name, "hash://", 7) == 0) { - CRYPT_HASH_BLOB blob; - int len; - const char *hash = name + 7; - unsigned char *buf; - - len = os_strlen(hash) / 2; - buf = os_malloc(len); - if (buf && hexstr2bin(hash, buf, len) == 0) { - blob.cbData = len; - blob.pbData = buf; - ret = CertFindCertificateInStore(cs, - X509_ASN_ENCODING | - PKCS_7_ASN_ENCODING, - 0, CERT_FIND_HASH, - &blob, NULL); - } - os_free(buf); - } - - CertCloseStore(cs, 0); - - return ret; -} - - -static int tls_cryptoapi_cert(SSL *ssl, const char *name) -{ - X509 *cert = NULL; - RSA *rsa = NULL, *pub_rsa; - struct cryptoapi_rsa_data *priv; - RSA_METHOD *rsa_meth; - - if (name == NULL || - (strncmp(name, "cert://", 7) != 0 && - strncmp(name, "hash://", 7) != 0)) - return -1; - - priv = os_zalloc(sizeof(*priv)); - rsa_meth = os_zalloc(sizeof(*rsa_meth)); - if (priv == NULL || rsa_meth == NULL) { - wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory " - "for CryptoAPI RSA method"); - os_free(priv); - os_free(rsa_meth); - return -1; - } - - priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER); - if (priv->cert == NULL) { - priv->cert = cryptoapi_find_cert( - name, CERT_SYSTEM_STORE_LOCAL_MACHINE); - } - if (priv->cert == NULL) { - wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate " - "'%s'", name); - goto err; - } - - cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded, - priv->cert->cbCertEncoded); - if (cert == NULL) { - wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER " - "encoding"); - goto err; - } - - if (!CryptAcquireCertificatePrivateKey(priv->cert, - CRYPT_ACQUIRE_COMPARE_KEY_FLAG, - NULL, &priv->crypt_prov, - &priv->key_spec, - &priv->free_crypt_prov)) { - cryptoapi_error("Failed to acquire a private key for the " - "certificate"); - goto err; - } - - rsa_meth->name = "Microsoft CryptoAPI RSA Method"; - rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc; - rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec; - rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc; - rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec; - rsa_meth->finish = cryptoapi_finish; - rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; - rsa_meth->app_data = (char *) priv; - - rsa = RSA_new(); - if (rsa == NULL) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, - ERR_R_MALLOC_FAILURE); - goto err; - } - - if (!SSL_use_certificate(ssl, cert)) { - RSA_free(rsa); - rsa = NULL; - goto err; - } - pub_rsa = cert->cert_info->key->pkey->pkey.rsa; - X509_free(cert); - cert = NULL; - - rsa->n = BN_dup(pub_rsa->n); - rsa->e = BN_dup(pub_rsa->e); - if (!RSA_set_method(rsa, rsa_meth)) - goto err; - - if (!SSL_use_RSAPrivateKey(ssl, rsa)) - goto err; - RSA_free(rsa); - - return 0; - -err: - if (cert) - X509_free(cert); - if (rsa) - RSA_free(rsa); - else { - os_free(rsa_meth); - cryptoapi_free_data(priv); - } - return -1; -} - - -static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name) -{ - HCERTSTORE cs; - PCCERT_CONTEXT ctx = NULL; - X509 *cert; - char buf[128]; - const char *store; -#ifdef UNICODE - WCHAR *wstore; -#endif /* UNICODE */ - - if (name == NULL || strncmp(name, "cert_store://", 13) != 0) - return -1; - - store = name + 13; -#ifdef UNICODE - wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR)); - if (wstore == NULL) - return -1; - wsprintf(wstore, L"%S", store); - cs = CertOpenSystemStore(0, wstore); - os_free(wstore); -#else /* UNICODE */ - cs = CertOpenSystemStore(0, store); -#endif /* UNICODE */ - if (cs == NULL) { - wpa_printf(MSG_DEBUG, "%s: failed to open system cert store " - "'%s': error=%d", __func__, store, - (int) GetLastError()); - return -1; - } - - while ((ctx = CertEnumCertificatesInStore(cs, ctx))) { - cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded, - ctx->cbCertEncoded); - if (cert == NULL) { - wpa_printf(MSG_INFO, "CryptoAPI: Could not process " - "X509 DER encoding for CA cert"); - continue; - } - - X509_NAME_oneline(X509_get_subject_name(cert), buf, - sizeof(buf)); - wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for " - "system certificate store: subject='%s'", buf); - - if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { - tls_show_errors(MSG_WARNING, __func__, - "Failed to add ca_cert to OpenSSL " - "certificate store"); - } - - X509_free(cert); - } - - if (!CertCloseStore(cs, 0)) { - wpa_printf(MSG_DEBUG, "%s: failed to close system cert store " - "'%s': error=%d", __func__, name + 13, - (int) GetLastError()); - } - - return 0; -} - - -#else /* CONFIG_NATIVE_WINDOWS */ - -static int tls_cryptoapi_cert(SSL *ssl, const char *name) -{ - return -1; -} - -#endif /* CONFIG_NATIVE_WINDOWS */ - - -static void ssl_info_cb(const SSL *ssl, int where, int ret) -{ - const char *str; - int w; - - wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret); - w = where & ~SSL_ST_MASK; - if (w & SSL_ST_CONNECT) - str = "SSL_connect"; - else if (w & SSL_ST_ACCEPT) - str = "SSL_accept"; - else - str = "undefined"; - - if (where & SSL_CB_LOOP) { - wpa_printf(MSG_DEBUG, "SSL: %s:%s", - str, SSL_state_string_long(ssl)); - } else if (where & SSL_CB_ALERT) { - struct tls_connection *conn = SSL_get_app_data((SSL *) ssl); - wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s", - where & SSL_CB_READ ? - "read (remote end reported an error)" : - "write (local SSL3 detected an error)", - SSL_alert_type_string_long(ret), - SSL_alert_desc_string_long(ret)); - if ((ret >> 8) == SSL3_AL_FATAL) { - if (where & SSL_CB_READ) - conn->read_alerts++; - else - conn->write_alerts++; - } - if (conn->context->event_cb != NULL) { - union tls_event_data ev; - struct tls_context *context = conn->context; - os_memset(&ev, 0, sizeof(ev)); - ev.alert.is_local = !(where & SSL_CB_READ); - ev.alert.type = SSL_alert_type_string_long(ret); - ev.alert.description = SSL_alert_desc_string_long(ret); - context->event_cb(context->cb_ctx, TLS_ALERT, &ev); - } - } else if (where & SSL_CB_EXIT && ret <= 0) { - wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s", - str, ret == 0 ? "failed" : "error", - SSL_state_string_long(ssl)); - } -} - - -#ifndef OPENSSL_NO_ENGINE -/** - * tls_engine_load_dynamic_generic - load any openssl engine - * @pre: an array of commands and values that load an engine initialized - * in the engine specific function - * @post: an array of commands and values that initialize an already loaded - * engine (or %NULL if not required) - * @id: the engine id of the engine to load (only required if post is not %NULL - * - * This function is a generic function that loads any openssl engine. - * - * Returns: 0 on success, -1 on failure - */ -static int tls_engine_load_dynamic_generic(const char *pre[], - const char *post[], const char *id) -{ - ENGINE *engine; - const char *dynamic_id = "dynamic"; - - engine = ENGINE_by_id(id); - if (engine) { - ENGINE_free(engine); - wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already " - "available", id); - return 0; - } - ERR_clear_error(); - - engine = ENGINE_by_id(dynamic_id); - if (engine == NULL) { - wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", - dynamic_id, - ERR_error_string(ERR_get_error(), NULL)); - return -1; - } - - /* Perform the pre commands. This will load the engine. */ - while (pre && pre[0]) { - wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]); - if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) { - wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: " - "%s %s [%s]", pre[0], pre[1], - ERR_error_string(ERR_get_error(), NULL)); - ENGINE_free(engine); - return -1; - } - pre += 2; - } - - /* - * Free the reference to the "dynamic" engine. The loaded engine can - * now be looked up using ENGINE_by_id(). - */ - ENGINE_free(engine); - - engine = ENGINE_by_id(id); - if (engine == NULL) { - wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", - id, ERR_error_string(ERR_get_error(), NULL)); - return -1; - } - - while (post && post[0]) { - wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]); - if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) { - wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:" - " %s %s [%s]", post[0], post[1], - ERR_error_string(ERR_get_error(), NULL)); - ENGINE_remove(engine); - ENGINE_free(engine); - return -1; - } - post += 2; - } - ENGINE_free(engine); - - return 0; -} - - -/** - * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc - * @pkcs11_so_path: pksc11_so_path from the configuration - * @pcks11_module_path: pkcs11_module_path from the configuration - */ -static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path, - const char *pkcs11_module_path) -{ - char *engine_id = "pkcs11"; - const char *pre_cmd[] = { - "SO_PATH", NULL /* pkcs11_so_path */, - "ID", NULL /* engine_id */, - "LIST_ADD", "1", - /* "NO_VCHECK", "1", */ - "LOAD", NULL, - NULL, NULL - }; - const char *post_cmd[] = { - "MODULE_PATH", NULL /* pkcs11_module_path */, - NULL, NULL - }; - - if (!pkcs11_so_path || !pkcs11_module_path) - return 0; - - pre_cmd[1] = pkcs11_so_path; - pre_cmd[3] = engine_id; - post_cmd[1] = pkcs11_module_path; - - wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s", - pkcs11_so_path); - - return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id); -} - - -/** - * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc - * @opensc_so_path: opensc_so_path from the configuration - */ -static int tls_engine_load_dynamic_opensc(const char *opensc_so_path) -{ - char *engine_id = "opensc"; - const char *pre_cmd[] = { - "SO_PATH", NULL /* opensc_so_path */, - "ID", NULL /* engine_id */, - "LIST_ADD", "1", - "LOAD", NULL, - NULL, NULL - }; - - if (!opensc_so_path) - return 0; - - pre_cmd[1] = opensc_so_path; - pre_cmd[3] = engine_id; - - wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s", - opensc_so_path); - - return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id); -} -#endif /* OPENSSL_NO_ENGINE */ - - -void * tls_init(const struct tls_config *conf) -{ - SSL_CTX *ssl; - struct tls_context *context; - - if (tls_openssl_ref_count == 0) { - tls_global = context = tls_context_new(conf); - if (context == NULL) - return NULL; -#ifdef CONFIG_FIPS -#ifdef OPENSSL_FIPS - if (conf && conf->fips_mode) { - if (!FIPS_mode_set(1)) { - wpa_printf(MSG_ERROR, "Failed to enable FIPS " - "mode"); - ERR_load_crypto_strings(); - ERR_print_errors_fp(stderr); - os_free(tls_global); - tls_global = NULL; - return NULL; - } else - wpa_printf(MSG_INFO, "Running in FIPS mode"); - } -#else /* OPENSSL_FIPS */ - if (conf && conf->fips_mode) { - wpa_printf(MSG_ERROR, "FIPS mode requested, but not " - "supported"); - os_free(tls_global); - tls_global = NULL; - return NULL; - } -#endif /* OPENSSL_FIPS */ -#endif /* CONFIG_FIPS */ - SSL_load_error_strings(); - SSL_library_init(); -#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) - EVP_add_digest(EVP_sha256()); -#endif /* OPENSSL_NO_SHA256 */ - /* TODO: if /dev/urandom is available, PRNG is seeded - * automatically. If this is not the case, random data should - * be added here. */ - -#ifdef PKCS12_FUNCS -#ifndef OPENSSL_NO_RC2 - /* - * 40-bit RC2 is commonly used in PKCS#12 files, so enable it. - * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8 - * versions, but it looks like OpenSSL 1.0.0 does not do that - * anymore. - */ - EVP_add_cipher(EVP_rc2_40_cbc()); -#endif /* OPENSSL_NO_RC2 */ - PKCS12_PBE_add(); -#endif /* PKCS12_FUNCS */ - } else { - context = tls_global; -#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA - /* Newer OpenSSL can store app-data per-SSL */ - context = tls_context_new(conf); - if (context == NULL) - return NULL; -#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */ - } - tls_openssl_ref_count++; - - ssl = SSL_CTX_new(TLSv1_method()); - if (ssl == NULL) { - tls_openssl_ref_count--; -#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA - if (context != tls_global) - os_free(context); -#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */ - if (tls_openssl_ref_count == 0) { - os_free(tls_global); - tls_global = NULL; - } - return NULL; - } - - SSL_CTX_set_info_callback(ssl, ssl_info_cb); -#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA - SSL_CTX_set_app_data(ssl, context); -#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */ - -#ifndef OPENSSL_NO_ENGINE - if (conf && - (conf->opensc_engine_path || conf->pkcs11_engine_path || - conf->pkcs11_module_path)) { - wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine"); - ERR_load_ENGINE_strings(); - ENGINE_load_dynamic(); - - if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) || - tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path, - conf->pkcs11_module_path)) { - tls_deinit(ssl); - return NULL; - } - } -#endif /* OPENSSL_NO_ENGINE */ - - return ssl; -} - - -void tls_deinit(void *ssl_ctx) -{ - SSL_CTX *ssl = ssl_ctx; -#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA - struct tls_context *context = SSL_CTX_get_app_data(ssl); - if (context != tls_global) - os_free(context); -#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */ - SSL_CTX_free(ssl); - - tls_openssl_ref_count--; - if (tls_openssl_ref_count == 0) { -#ifndef OPENSSL_NO_ENGINE - ENGINE_cleanup(); -#endif /* OPENSSL_NO_ENGINE */ - CRYPTO_cleanup_all_ex_data(); - ERR_remove_state(0); - ERR_free_strings(); - EVP_cleanup(); - os_free(tls_global->ocsp_stapling_response); - tls_global->ocsp_stapling_response = NULL; - os_free(tls_global); - tls_global = NULL; - } -} - - -static int tls_engine_init(struct tls_connection *conn, const char *engine_id, - const char *pin, const char *key_id, - const char *cert_id, const char *ca_cert_id) -{ -#ifndef OPENSSL_NO_ENGINE - int ret = -1; - if (engine_id == NULL) { - wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set"); - return -1; - } -#ifndef ANDROID - if (pin == NULL) { - wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set"); - return -1; - } -#endif - if (key_id == NULL) { - wpa_printf(MSG_ERROR, "ENGINE: Key Id not set"); - return -1; - } - - ERR_clear_error(); -#ifdef ANDROID - ENGINE_load_dynamic(); -#endif - conn->engine = ENGINE_by_id(engine_id); - if (!conn->engine) { - wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]", - engine_id, ERR_error_string(ERR_get_error(), NULL)); - goto err; - } - if (ENGINE_init(conn->engine) != 1) { - wpa_printf(MSG_ERROR, "ENGINE: engine init failed " - "(engine: %s) [%s]", engine_id, - ERR_error_string(ERR_get_error(), NULL)); - goto err; - } - wpa_printf(MSG_DEBUG, "ENGINE: engine initialized"); - -#ifndef ANDROID - if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) { - wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]", - ERR_error_string(ERR_get_error(), NULL)); - goto err; - } -#endif - /* load private key first in-case PIN is required for cert */ - conn->private_key = ENGINE_load_private_key(conn->engine, - key_id, NULL, NULL); - if (!conn->private_key) { - wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id" - " '%s' [%s]", key_id, - ERR_error_string(ERR_get_error(), NULL)); - ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; - goto err; - } - - /* handle a certificate and/or CA certificate */ - if (cert_id || ca_cert_id) { - const char *cmd_name = "LOAD_CERT_CTRL"; - - /* test if the engine supports a LOAD_CERT_CTRL */ - if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME, - 0, (void *)cmd_name, NULL)) { - wpa_printf(MSG_ERROR, "ENGINE: engine does not support" - " loading certificates"); - ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; - goto err; - } - } - - return 0; - -err: - if (conn->engine) { - ENGINE_free(conn->engine); - conn->engine = NULL; - } - - if (conn->private_key) { - EVP_PKEY_free(conn->private_key); - conn->private_key = NULL; - } - - return ret; -#else /* OPENSSL_NO_ENGINE */ - return 0; -#endif /* OPENSSL_NO_ENGINE */ -} - - -static void tls_engine_deinit(struct tls_connection *conn) -{ -#ifndef OPENSSL_NO_ENGINE - wpa_printf(MSG_DEBUG, "ENGINE: engine deinit"); - if (conn->private_key) { - EVP_PKEY_free(conn->private_key); - conn->private_key = NULL; - } - if (conn->engine) { - ENGINE_finish(conn->engine); - conn->engine = NULL; - } -#endif /* OPENSSL_NO_ENGINE */ -} - - -int tls_get_errors(void *ssl_ctx) -{ - int count = 0; - unsigned long err; - - while ((err = ERR_get_error())) { - wpa_printf(MSG_INFO, "TLS - SSL error: %s", - ERR_error_string(err, NULL)); - count++; - } - - return count; -} - -struct tls_connection * tls_connection_init(void *ssl_ctx) -{ - SSL_CTX *ssl = ssl_ctx; - struct tls_connection *conn; - long options; - struct tls_context *context = tls_global; -#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA - context = SSL_CTX_get_app_data(ssl); -#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */ - - conn = os_zalloc(sizeof(*conn)); - if (conn == NULL) - return NULL; - conn->ssl = SSL_new(ssl); - if (conn->ssl == NULL) { - tls_show_errors(MSG_INFO, __func__, - "Failed to initialize new SSL connection"); - os_free(conn); - return NULL; - } - - conn->context = context; - SSL_set_app_data(conn->ssl, conn); - options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | - SSL_OP_SINGLE_DH_USE; -#ifdef SSL_OP_NO_COMPRESSION - options |= SSL_OP_NO_COMPRESSION; -#endif /* SSL_OP_NO_COMPRESSION */ - SSL_set_options(conn->ssl, options); - - conn->ssl_in = BIO_new(BIO_s_mem()); - if (!conn->ssl_in) { - tls_show_errors(MSG_INFO, __func__, - "Failed to create a new BIO for ssl_in"); - SSL_free(conn->ssl); - os_free(conn); - return NULL; - } - - conn->ssl_out = BIO_new(BIO_s_mem()); - if (!conn->ssl_out) { - tls_show_errors(MSG_INFO, __func__, - "Failed to create a new BIO for ssl_out"); - SSL_free(conn->ssl); - BIO_free(conn->ssl_in); - os_free(conn); - return NULL; - } - - SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out); - - return conn; -} - - -void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return; - SSL_free(conn->ssl); - tls_engine_deinit(conn); - os_free(conn->subject_match); - os_free(conn->altsubject_match); - os_free(conn->suffix_match); - os_free(conn->session_ticket); - os_free(conn); -} - - -int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) -{ - return conn ? SSL_is_init_finished(conn->ssl) : 0; -} - - -int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - - /* Shutdown previous TLS connection without notifying the peer - * because the connection was already terminated in practice - * and "close notify" shutdown alert would confuse AS. */ - SSL_set_quiet_shutdown(conn->ssl, 1); - SSL_shutdown(conn->ssl); - return 0; -} - - -static int tls_match_altsubject_component(X509 *cert, int type, - const char *value, size_t len) -{ - GENERAL_NAME *gen; - void *ext; - int i, found = 0; - - ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); - - for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { - gen = sk_GENERAL_NAME_value(ext, i); - if (gen->type != type) - continue; - if (os_strlen((char *) gen->d.ia5->data) == len && - os_memcmp(value, gen->d.ia5->data, len) == 0) - found++; - } - - return found; -} - - -static int tls_match_altsubject(X509 *cert, const char *match) -{ - int type; - const char *pos, *end; - size_t len; - - pos = match; - do { - if (os_strncmp(pos, "EMAIL:", 6) == 0) { - type = GEN_EMAIL; - pos += 6; - } else if (os_strncmp(pos, "DNS:", 4) == 0) { - type = GEN_DNS; - pos += 4; - } else if (os_strncmp(pos, "URI:", 4) == 0) { - type = GEN_URI; - pos += 4; - } else { - wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName " - "match '%s'", pos); - return 0; - } - end = os_strchr(pos, ';'); - while (end) { - if (os_strncmp(end + 1, "EMAIL:", 6) == 0 || - os_strncmp(end + 1, "DNS:", 4) == 0 || - os_strncmp(end + 1, "URI:", 4) == 0) - break; - end = os_strchr(end + 1, ';'); - } - if (end) - len = end - pos; - else - len = os_strlen(pos); - if (tls_match_altsubject_component(cert, type, pos, len) > 0) - return 1; - pos = end + 1; - } while (end); - - return 0; -} - - -#ifndef CONFIG_NATIVE_WINDOWS -static int domain_suffix_match(const u8 *val, size_t len, const char *match) -{ - size_t i, match_len; - - /* Check for embedded nuls that could mess up suffix matching */ - for (i = 0; i < len; i++) { - if (val[i] == '\0') { - wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject"); - return 0; - } - } - - match_len = os_strlen(match); - if (match_len > len) - return 0; - - if (os_strncasecmp((const char *) val + len - match_len, match, - match_len) != 0) - return 0; /* no match */ - - if (match_len == len) - return 1; /* exact match */ - - if (val[len - match_len - 1] == '.') - return 1; /* full label match completes suffix match */ - - wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match"); - return 0; -} -#endif /* CONFIG_NATIVE_WINDOWS */ - - -static int tls_match_suffix(X509 *cert, const char *match) -{ -#ifdef CONFIG_NATIVE_WINDOWS - /* wincrypt.h has conflicting X509_NAME definition */ - return -1; -#else /* CONFIG_NATIVE_WINDOWS */ - GENERAL_NAME *gen; - void *ext; - int i; - int dns_name = 0; - X509_NAME *name; - - wpa_printf(MSG_DEBUG, "TLS: Match domain against suffix %s", match); - - ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); - - for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { - gen = sk_GENERAL_NAME_value(ext, i); - if (gen->type != GEN_DNS) - continue; - dns_name++; - wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName", - gen->d.dNSName->data, - gen->d.dNSName->length); - if (domain_suffix_match(gen->d.dNSName->data, - gen->d.dNSName->length, match) == 1) { - wpa_printf(MSG_DEBUG, "TLS: Suffix match in dNSName found"); - return 1; - } - } - - if (dns_name) { - wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched"); - return 0; - } - - name = X509_get_subject_name(cert); - i = -1; - for (;;) { - X509_NAME_ENTRY *e; - ASN1_STRING *cn; - - i = X509_NAME_get_index_by_NID(name, NID_commonName, i); - if (i == -1) - break; - e = X509_NAME_get_entry(name, i); - if (e == NULL) - continue; - cn = X509_NAME_ENTRY_get_data(e); - if (cn == NULL) - continue; - wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName", - cn->data, cn->length); - if (domain_suffix_match(cn->data, cn->length, match) == 1) { - wpa_printf(MSG_DEBUG, "TLS: Suffix match in commonName found"); - return 1; - } - } - - wpa_printf(MSG_DEBUG, "TLS: No CommonName suffix match found"); - return 0; -#endif /* CONFIG_NATIVE_WINDOWS */ -} - - -static enum tls_fail_reason openssl_tls_fail_reason(int err) -{ - switch (err) { - case X509_V_ERR_CERT_REVOKED: - return TLS_FAIL_REVOKED; - case X509_V_ERR_CERT_NOT_YET_VALID: - case X509_V_ERR_CRL_NOT_YET_VALID: - return TLS_FAIL_NOT_YET_VALID; - case X509_V_ERR_CERT_HAS_EXPIRED: - case X509_V_ERR_CRL_HAS_EXPIRED: - return TLS_FAIL_EXPIRED; - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: - case X509_V_ERR_UNABLE_TO_GET_CRL: - case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: - case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: - case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: - case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: - case X509_V_ERR_CERT_CHAIN_TOO_LONG: - case X509_V_ERR_PATH_LENGTH_EXCEEDED: - case X509_V_ERR_INVALID_CA: - return TLS_FAIL_UNTRUSTED; - case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: - case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: - case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: - case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: - case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: - case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: - case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: - case X509_V_ERR_CERT_UNTRUSTED: - case X509_V_ERR_CERT_REJECTED: - return TLS_FAIL_BAD_CERTIFICATE; - default: - return TLS_FAIL_UNSPECIFIED; - } -} - - -static struct wpabuf * get_x509_cert(X509 *cert) -{ - struct wpabuf *buf; - u8 *tmp; - - int cert_len = i2d_X509(cert, NULL); - if (cert_len <= 0) - return NULL; - - buf = wpabuf_alloc(cert_len); - if (buf == NULL) - return NULL; - - tmp = wpabuf_put(buf, cert_len); - i2d_X509(cert, &tmp); - return buf; -} - - -static void openssl_tls_fail_event(struct tls_connection *conn, - X509 *err_cert, int err, int depth, - const char *subject, const char *err_str, - enum tls_fail_reason reason) -{ - union tls_event_data ev; - struct wpabuf *cert = NULL; - struct tls_context *context = conn->context; - - if (context->event_cb == NULL) - return; - - cert = get_x509_cert(err_cert); - os_memset(&ev, 0, sizeof(ev)); - ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ? - reason : openssl_tls_fail_reason(err); - ev.cert_fail.depth = depth; - ev.cert_fail.subject = subject; - ev.cert_fail.reason_txt = err_str; - ev.cert_fail.cert = cert; - context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev); - wpabuf_free(cert); -} - - -static void openssl_tls_cert_event(struct tls_connection *conn, - X509 *err_cert, int depth, - const char *subject) -{ - struct wpabuf *cert = NULL; - union tls_event_data ev; - struct tls_context *context = conn->context; -#ifdef CONFIG_SHA256 - u8 hash[32]; -#endif /* CONFIG_SHA256 */ - - if (context->event_cb == NULL) - return; - - os_memset(&ev, 0, sizeof(ev)); - if (conn->cert_probe || context->cert_in_cb) { - cert = get_x509_cert(err_cert); - ev.peer_cert.cert = cert; - } -#ifdef CONFIG_SHA256 - if (cert) { - const u8 *addr[1]; - size_t len[1]; - addr[0] = wpabuf_head(cert); - len[0] = wpabuf_len(cert); - if (sha256_vector(1, addr, len, hash) == 0) { - ev.peer_cert.hash = hash; - ev.peer_cert.hash_len = sizeof(hash); - } - } -#endif /* CONFIG_SHA256 */ - ev.peer_cert.depth = depth; - ev.peer_cert.subject = subject; - context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev); - wpabuf_free(cert); -} - - -static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) -{ - char buf[256]; - X509 *err_cert; - int err, depth; - SSL *ssl; - struct tls_connection *conn; - struct tls_context *context; - char *match, *altmatch, *suffix_match; - const char *err_str; - - err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); - err = X509_STORE_CTX_get_error(x509_ctx); - depth = X509_STORE_CTX_get_error_depth(x509_ctx); - ssl = X509_STORE_CTX_get_ex_data(x509_ctx, - SSL_get_ex_data_X509_STORE_CTX_idx()); - X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); - - conn = SSL_get_app_data(ssl); - if (conn == NULL) - return 0; - - if (depth == 0) - conn->peer_cert = err_cert; - else if (depth == 1) - conn->peer_issuer = err_cert; - else if (depth == 2) - conn->peer_issuer_issuer = err_cert; - - context = conn->context; - match = conn->subject_match; - altmatch = conn->altsubject_match; - suffix_match = conn->suffix_match; - - if (!preverify_ok && !conn->ca_cert_verify) - preverify_ok = 1; - if (!preverify_ok && depth > 0 && conn->server_cert_only) - preverify_ok = 1; - if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) && - (err == X509_V_ERR_CERT_HAS_EXPIRED || - err == X509_V_ERR_CERT_NOT_YET_VALID)) { - wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity " - "time mismatch"); - preverify_ok = 1; - } - - err_str = X509_verify_cert_error_string(err); - -#ifdef CONFIG_SHA256 - if (preverify_ok && depth == 0 && conn->server_cert_only) { - struct wpabuf *cert; - cert = get_x509_cert(err_cert); - if (!cert) { - wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch " - "server certificate data"); - preverify_ok = 0; - } else { - u8 hash[32]; - const u8 *addr[1]; - size_t len[1]; - addr[0] = wpabuf_head(cert); - len[0] = wpabuf_len(cert); - if (sha256_vector(1, addr, len, hash) < 0 || - os_memcmp(conn->srv_cert_hash, hash, 32) != 0) { - err_str = "Server certificate mismatch"; - err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; - preverify_ok = 0; - } - wpabuf_free(cert); - } - } -#endif /* CONFIG_SHA256 */ - - if (!preverify_ok) { - wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," - " error %d (%s) depth %d for '%s'", err, err_str, - depth, buf); - openssl_tls_fail_event(conn, err_cert, err, depth, buf, - err_str, TLS_FAIL_UNSPECIFIED); - return preverify_ok; - } - - wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d " - "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'", - preverify_ok, err, err_str, - conn->ca_cert_verify, depth, buf); - if (depth == 0 && match && os_strstr(buf, match) == NULL) { - wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " - "match with '%s'", buf, match); - preverify_ok = 0; - openssl_tls_fail_event(conn, err_cert, err, depth, buf, - "Subject mismatch", - TLS_FAIL_SUBJECT_MISMATCH); - } else if (depth == 0 && altmatch && - !tls_match_altsubject(err_cert, altmatch)) { - wpa_printf(MSG_WARNING, "TLS: altSubjectName match " - "'%s' not found", altmatch); - preverify_ok = 0; - openssl_tls_fail_event(conn, err_cert, err, depth, buf, - "AltSubject mismatch", - TLS_FAIL_ALTSUBJECT_MISMATCH); - } else if (depth == 0 && suffix_match && - !tls_match_suffix(err_cert, suffix_match)) { - wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found", - suffix_match); - preverify_ok = 0; - openssl_tls_fail_event(conn, err_cert, err, depth, buf, - "Domain suffix mismatch", - TLS_FAIL_DOMAIN_SUFFIX_MISMATCH); - } else - openssl_tls_cert_event(conn, err_cert, depth, buf); - - if (conn->cert_probe && preverify_ok && depth == 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate " - "on probe-only run"); - preverify_ok = 0; - openssl_tls_fail_event(conn, err_cert, err, depth, buf, - "Server certificate chain probe", - TLS_FAIL_SERVER_CHAIN_PROBE); - } - - if (!conn->server && err_cert && preverify_ok && depth == 0 && - (err_cert->ex_flags & EXFLAG_XKUSAGE) && - (err_cert->ex_xkusage & XKU_SSL_CLIENT)) { - wpa_printf(MSG_WARNING, "TLS: Server used client certificate"); - openssl_tls_fail_event(conn, err_cert, err, depth, buf, - "Server used client certificate", - TLS_FAIL_SERVER_USED_CLIENT_CERT); - preverify_ok = 0; - } - - if (preverify_ok && context->event_cb != NULL) - context->event_cb(context->cb_ctx, - TLS_CERT_CHAIN_SUCCESS, NULL); - - return preverify_ok; -} - - -#ifndef OPENSSL_NO_STDIO -static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert) -{ - SSL_CTX *ssl_ctx = _ssl_ctx; - X509_LOOKUP *lookup; - int ret = 0; - - lookup = X509_STORE_add_lookup(ssl_ctx->cert_store, - X509_LOOKUP_file()); - if (lookup == NULL) { - tls_show_errors(MSG_WARNING, __func__, - "Failed add lookup for X509 store"); - return -1; - } - - if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) { - unsigned long err = ERR_peek_error(); - tls_show_errors(MSG_WARNING, __func__, - "Failed load CA in DER format"); - if (ERR_GET_LIB(err) == ERR_LIB_X509 && - ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { - wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " - "cert already in hash table error", - __func__); - } else - ret = -1; - } - - return ret; -} -#endif /* OPENSSL_NO_STDIO */ - - -static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn, - const char *ca_cert, const u8 *ca_cert_blob, - size_t ca_cert_blob_len, const char *ca_path) -{ - SSL_CTX *ssl_ctx = _ssl_ctx; - - /* - * Remove previously configured trusted CA certificates before adding - * new ones. - */ - X509_STORE_free(ssl_ctx->cert_store); - ssl_ctx->cert_store = X509_STORE_new(); - if (ssl_ctx->cert_store == NULL) { - wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " - "certificate store", __func__); - return -1; - } - - SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); - conn->ca_cert_verify = 1; - - if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate " - "chain"); - conn->cert_probe = 1; - conn->ca_cert_verify = 0; - return 0; - } - - if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) { -#ifdef CONFIG_SHA256 - const char *pos = ca_cert + 7; - if (os_strncmp(pos, "server/sha256/", 14) != 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert " - "hash value '%s'", ca_cert); - return -1; - } - pos += 14; - if (os_strlen(pos) != 32 * 2) { - wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 " - "hash length in ca_cert '%s'", ca_cert); - return -1; - } - if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash " - "value in ca_cert '%s'", ca_cert); - return -1; - } - conn->server_cert_only = 1; - wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server " - "certificate match"); - return 0; -#else /* CONFIG_SHA256 */ - wpa_printf(MSG_INFO, "No SHA256 included in the build - " - "cannot validate server certificate hash"); - return -1; -#endif /* CONFIG_SHA256 */ - } - - if (ca_cert_blob) { - X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob, - ca_cert_blob_len); - if (cert == NULL) { - tls_show_errors(MSG_WARNING, __func__, - "Failed to parse ca_cert_blob"); - return -1; - } - - if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { - unsigned long err = ERR_peek_error(); - tls_show_errors(MSG_WARNING, __func__, - "Failed to add ca_cert_blob to " - "certificate store"); - if (ERR_GET_LIB(err) == ERR_LIB_X509 && - ERR_GET_REASON(err) == - X509_R_CERT_ALREADY_IN_HASH_TABLE) { - wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " - "cert already in hash table error", - __func__); - } else { - X509_free(cert); - return -1; - } - } - X509_free(cert); - wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob " - "to certificate store", __func__); - return 0; - } - -#ifdef ANDROID - if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) { - BIO *bio = BIO_from_keystore(&ca_cert[11]); - STACK_OF(X509_INFO) *stack = NULL; - int i; - - if (bio) { - stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL); - BIO_free(bio); - } - if (!stack) - return -1; - - for (i = 0; i < sk_X509_INFO_num(stack); ++i) { - X509_INFO *info = sk_X509_INFO_value(stack, i); - if (info->x509) { - X509_STORE_add_cert(ssl_ctx->cert_store, - info->x509); - } - if (info->crl) { - X509_STORE_add_crl(ssl_ctx->cert_store, - info->crl); - } - } - sk_X509_INFO_pop_free(stack, X509_INFO_free); - SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); - return 0; - } -#endif /* ANDROID */ - -#ifdef CONFIG_NATIVE_WINDOWS - if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) == - 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from " - "system certificate store"); - return 0; - } -#endif /* CONFIG_NATIVE_WINDOWS */ - - if (ca_cert || ca_path) { -#ifndef OPENSSL_NO_STDIO - if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) != - 1) { - tls_show_errors(MSG_WARNING, __func__, - "Failed to load root certificates"); - if (ca_cert && - tls_load_ca_der(ssl_ctx, ca_cert) == 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded " - "DER format CA certificate", - __func__); - } else - return -1; - } else { - wpa_printf(MSG_DEBUG, "TLS: Trusted root " - "certificate(s) loaded"); - tls_get_errors(ssl_ctx); - } -#else /* OPENSSL_NO_STDIO */ - wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", - __func__); - return -1; -#endif /* OPENSSL_NO_STDIO */ - } else { - /* No ca_cert configured - do not try to verify server - * certificate */ - conn->ca_cert_verify = 0; - } - - return 0; -} - - -static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert) -{ - if (ca_cert) { - if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1) - { - tls_show_errors(MSG_WARNING, __func__, - "Failed to load root certificates"); - return -1; - } - - wpa_printf(MSG_DEBUG, "TLS: Trusted root " - "certificate(s) loaded"); - -#ifndef OPENSSL_NO_STDIO - /* Add the same CAs to the client certificate requests */ - SSL_CTX_set_client_CA_list(ssl_ctx, - SSL_load_client_CA_file(ca_cert)); -#endif /* OPENSSL_NO_STDIO */ - } - - return 0; -} - - -int tls_global_set_verify(void *ssl_ctx, int check_crl) -{ - int flags; - - if (check_crl) { - X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx); - if (cs == NULL) { - tls_show_errors(MSG_INFO, __func__, "Failed to get " - "certificate store when enabling " - "check_crl"); - return -1; - } - flags = X509_V_FLAG_CRL_CHECK; - if (check_crl == 2) - flags |= X509_V_FLAG_CRL_CHECK_ALL; - X509_STORE_set_flags(cs, flags); - } - return 0; -} - - -static int tls_connection_set_subject_match(struct tls_connection *conn, - const char *subject_match, - const char *altsubject_match, - const char *suffix_match) -{ - os_free(conn->subject_match); - conn->subject_match = NULL; - if (subject_match) { - conn->subject_match = os_strdup(subject_match); - if (conn->subject_match == NULL) - return -1; - } - - os_free(conn->altsubject_match); - conn->altsubject_match = NULL; - if (altsubject_match) { - conn->altsubject_match = os_strdup(altsubject_match); - if (conn->altsubject_match == NULL) - return -1; - } - - os_free(conn->suffix_match); - conn->suffix_match = NULL; - if (suffix_match) { - conn->suffix_match = os_strdup(suffix_match); - if (conn->suffix_match == NULL) - return -1; - } - - return 0; -} - - -int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, - int verify_peer) -{ - static int counter = 0; - - if (conn == NULL) - return -1; - - if (verify_peer) { - conn->ca_cert_verify = 1; - SSL_set_verify(conn->ssl, SSL_VERIFY_PEER | - SSL_VERIFY_FAIL_IF_NO_PEER_CERT | - SSL_VERIFY_CLIENT_ONCE, tls_verify_cb); - } else { - conn->ca_cert_verify = 0; - SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); - } - - SSL_set_accept_state(conn->ssl); - - /* - * Set session id context in order to avoid fatal errors when client - * tries to resume a session. However, set the context to a unique - * value in order to effectively disable session resumption for now - * since not all areas of the server code are ready for it (e.g., - * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS - * handshake). - */ - counter++; - SSL_set_session_id_context(conn->ssl, - (const unsigned char *) &counter, - sizeof(counter)); - - return 0; -} - - -static int tls_connection_client_cert(struct tls_connection *conn, - const char *client_cert, - const u8 *client_cert_blob, - size_t client_cert_blob_len) -{ - if (client_cert == NULL && client_cert_blob == NULL) - return 0; - - if (client_cert_blob && - SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob, - client_cert_blob_len) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> " - "OK"); - return 0; - } else if (client_cert_blob) { - tls_show_errors(MSG_DEBUG, __func__, - "SSL_use_certificate_ASN1 failed"); - } - - if (client_cert == NULL) - return -1; - -#ifdef ANDROID - if (os_strncmp("keystore://", client_cert, 11) == 0) { - BIO *bio = BIO_from_keystore(&client_cert[11]); - X509 *x509 = NULL; - int ret = -1; - if (bio) { - x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); - BIO_free(bio); - } - if (x509) { - if (SSL_use_certificate(conn->ssl, x509) == 1) - ret = 0; - X509_free(x509); - } - return ret; - } -#endif /* ANDROID */ - -#ifndef OPENSSL_NO_STDIO - if (SSL_use_certificate_file(conn->ssl, client_cert, - SSL_FILETYPE_ASN1) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)" - " --> OK"); - return 0; - } - - if (SSL_use_certificate_file(conn->ssl, client_cert, - SSL_FILETYPE_PEM) == 1) { - ERR_clear_error(); - wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)" - " --> OK"); - return 0; - } - - tls_show_errors(MSG_DEBUG, __func__, - "SSL_use_certificate_file failed"); -#else /* OPENSSL_NO_STDIO */ - wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); -#endif /* OPENSSL_NO_STDIO */ - - return -1; -} - - -static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert) -{ -#ifndef OPENSSL_NO_STDIO - if (client_cert == NULL) - return 0; - - 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__, - "Failed to load client certificate"); - return -1; - } - return 0; -#else /* OPENSSL_NO_STDIO */ - if (client_cert == NULL) - return 0; - wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); - return -1; -#endif /* OPENSSL_NO_STDIO */ -} - - -static int tls_passwd_cb(char *buf, int size, int rwflag, void *password) -{ - if (password == NULL) { - return 0; - } - os_strlcpy(buf, (char *) password, size); - return os_strlen(buf); -} - - -#ifdef PKCS12_FUNCS -static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12, - const char *passwd) -{ - EVP_PKEY *pkey; - X509 *cert; - STACK_OF(X509) *certs; - int res = 0; - char buf[256]; - - pkey = NULL; - cert = NULL; - certs = NULL; - if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) { - tls_show_errors(MSG_DEBUG, __func__, - "Failed to parse PKCS12 file"); - PKCS12_free(p12); - return -1; - } - wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data"); - - if (cert) { - X509_NAME_oneline(X509_get_subject_name(cert), buf, - sizeof(buf)); - wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: " - "subject='%s'", buf); - if (ssl) { - if (SSL_use_certificate(ssl, cert) != 1) - res = -1; - } else { - if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1) - res = -1; - } - X509_free(cert); - } - - if (pkey) { - wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12"); - if (ssl) { - if (SSL_use_PrivateKey(ssl, pkey) != 1) - res = -1; - } else { - if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1) - res = -1; - } - EVP_PKEY_free(pkey); - } - - if (certs) { - while ((cert = sk_X509_pop(certs)) != NULL) { - X509_NAME_oneline(X509_get_subject_name(cert), buf, - sizeof(buf)); - wpa_printf(MSG_DEBUG, "TLS: additional certificate" - " from PKCS12: subject='%s'", buf); - /* - * There is no SSL equivalent for the chain cert - so - * always add it to the context... - */ - if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) { - res = -1; - break; - } - } - sk_X509_free(certs); - } - - PKCS12_free(p12); - - if (res < 0) - tls_get_errors(ssl_ctx); - - return res; -} -#endif /* PKCS12_FUNCS */ - - -static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key, - const char *passwd) -{ -#ifdef PKCS12_FUNCS - FILE *f; - PKCS12 *p12; - - f = fopen(private_key, "rb"); - if (f == NULL) - return -1; - - p12 = d2i_PKCS12_fp(f, NULL); - fclose(f); - - if (p12 == NULL) { - tls_show_errors(MSG_INFO, __func__, - "Failed to use PKCS#12 file"); - return -1; - } - - return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd); - -#else /* PKCS12_FUNCS */ - wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read " - "p12/pfx files"); - return -1; -#endif /* PKCS12_FUNCS */ -} - - -static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl, - const u8 *blob, size_t len, const char *passwd) -{ -#ifdef PKCS12_FUNCS - PKCS12 *p12; - - p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len); - if (p12 == NULL) { - tls_show_errors(MSG_INFO, __func__, - "Failed to use PKCS#12 blob"); - return -1; - } - - return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd); - -#else /* PKCS12_FUNCS */ - wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse " - "p12/pfx blobs"); - return -1; -#endif /* PKCS12_FUNCS */ -} - - -#ifndef OPENSSL_NO_ENGINE -static int tls_engine_get_cert(struct tls_connection *conn, - const char *cert_id, - X509 **cert) -{ - /* this runs after the private key is loaded so no PIN is required */ - struct { - const char *cert_id; - X509 *cert; - } params; - params.cert_id = cert_id; - params.cert = NULL; - - if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL", - 0, ¶ms, NULL, 1)) { - wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id" - " '%s' [%s]", cert_id, - ERR_error_string(ERR_get_error(), NULL)); - return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; - } - if (!params.cert) { - wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id" - " '%s'", cert_id); - return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; - } - *cert = params.cert; - return 0; -} -#endif /* OPENSSL_NO_ENGINE */ - - -static int tls_connection_engine_client_cert(struct tls_connection *conn, - const char *cert_id) -{ -#ifndef OPENSSL_NO_ENGINE - X509 *cert; - - if (tls_engine_get_cert(conn, cert_id, &cert)) - return -1; - - if (!SSL_use_certificate(conn->ssl, cert)) { - tls_show_errors(MSG_ERROR, __func__, - "SSL_use_certificate failed"); - X509_free(cert); - return -1; - } - X509_free(cert); - wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> " - "OK"); - return 0; - -#else /* OPENSSL_NO_ENGINE */ - return -1; -#endif /* OPENSSL_NO_ENGINE */ -} - - -static int tls_connection_engine_ca_cert(void *_ssl_ctx, - struct tls_connection *conn, - const char *ca_cert_id) -{ -#ifndef OPENSSL_NO_ENGINE - X509 *cert; - SSL_CTX *ssl_ctx = _ssl_ctx; - - if (tls_engine_get_cert(conn, ca_cert_id, &cert)) - return -1; - - /* start off the same as tls_connection_ca_cert */ - X509_STORE_free(ssl_ctx->cert_store); - ssl_ctx->cert_store = X509_STORE_new(); - if (ssl_ctx->cert_store == NULL) { - wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " - "certificate store", __func__); - X509_free(cert); - return -1; - } - if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { - unsigned long err = ERR_peek_error(); - tls_show_errors(MSG_WARNING, __func__, - "Failed to add CA certificate from engine " - "to certificate store"); - if (ERR_GET_LIB(err) == ERR_LIB_X509 && - ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { - wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert" - " already in hash table error", - __func__); - } else { - X509_free(cert); - return -1; - } - } - X509_free(cert); - wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine " - "to certificate store", __func__); - SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); - conn->ca_cert_verify = 1; - - return 0; - -#else /* OPENSSL_NO_ENGINE */ - return -1; -#endif /* OPENSSL_NO_ENGINE */ -} - - -static int tls_connection_engine_private_key(struct tls_connection *conn) -{ -#ifndef OPENSSL_NO_ENGINE - if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) { - tls_show_errors(MSG_ERROR, __func__, - "ENGINE: cannot use private key for TLS"); - return -1; - } - if (!SSL_check_private_key(conn->ssl)) { - tls_show_errors(MSG_INFO, __func__, - "Private key failed verification"); - return -1; - } - return 0; -#else /* OPENSSL_NO_ENGINE */ - wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but " - "engine support was not compiled in"); - return -1; -#endif /* OPENSSL_NO_ENGINE */ -} - - -static int tls_connection_private_key(void *_ssl_ctx, - struct tls_connection *conn, - const char *private_key, - const char *private_key_passwd, - const u8 *private_key_blob, - size_t private_key_blob_len) -{ - SSL_CTX *ssl_ctx = _ssl_ctx; - char *passwd; - int ok; - - if (private_key == NULL && private_key_blob == NULL) - return 0; - - if (private_key_passwd) { - passwd = os_strdup(private_key_passwd); - if (passwd == NULL) - return -1; - } else - passwd = NULL; - - SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); - SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); - - ok = 0; - while (private_key_blob) { - if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl, - (u8 *) private_key_blob, - private_key_blob_len) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" - "ASN1(EVP_PKEY_RSA) --> OK"); - ok = 1; - break; - } - - if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl, - (u8 *) private_key_blob, - private_key_blob_len) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" - "ASN1(EVP_PKEY_DSA) --> OK"); - ok = 1; - break; - } - - if (SSL_use_RSAPrivateKey_ASN1(conn->ssl, - (u8 *) private_key_blob, - private_key_blob_len) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: " - "SSL_use_RSAPrivateKey_ASN1 --> OK"); - ok = 1; - break; - } - - if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob, - private_key_blob_len, passwd) == 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> " - "OK"); - ok = 1; - break; - } - - break; - } - - while (!ok && private_key) { -#ifndef OPENSSL_NO_STDIO - if (SSL_use_PrivateKey_file(conn->ssl, private_key, - SSL_FILETYPE_ASN1) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: " - "SSL_use_PrivateKey_File (DER) --> OK"); - ok = 1; - break; - } - - if (SSL_use_PrivateKey_file(conn->ssl, private_key, - SSL_FILETYPE_PEM) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: " - "SSL_use_PrivateKey_File (PEM) --> OK"); - ok = 1; - break; - } -#else /* OPENSSL_NO_STDIO */ - wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", - __func__); -#endif /* OPENSSL_NO_STDIO */ - - if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd) - == 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file " - "--> OK"); - ok = 1; - break; - } - - if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to " - "access certificate store --> OK"); - ok = 1; - break; - } - - break; - } - - if (!ok) { - tls_show_errors(MSG_INFO, __func__, - "Failed to load private key"); - os_free(passwd); - return -1; - } - ERR_clear_error(); - SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); - os_free(passwd); - - if (!SSL_check_private_key(conn->ssl)) { - tls_show_errors(MSG_INFO, __func__, "Private key failed " - "verification"); - return -1; - } - - wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully"); - return 0; -} - - -static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key, - const char *private_key_passwd) -{ - char *passwd; - - if (private_key == NULL) - return 0; - - if (private_key_passwd) { - passwd = os_strdup(private_key_passwd); - if (passwd == NULL) - return -1; - } else - passwd = NULL; - - SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); - SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); - if ( -#ifndef OPENSSL_NO_STDIO - SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, - SSL_FILETYPE_ASN1) != 1 && - SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, - SSL_FILETYPE_PEM) != 1 && -#endif /* OPENSSL_NO_STDIO */ - tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) { - tls_show_errors(MSG_INFO, __func__, - "Failed to load private key"); - os_free(passwd); - ERR_clear_error(); - return -1; - } - os_free(passwd); - ERR_clear_error(); - SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); - - if (!SSL_CTX_check_private_key(ssl_ctx)) { - tls_show_errors(MSG_INFO, __func__, - "Private key failed verification"); - return -1; - } - - return 0; -} - - -static int tls_connection_dh(struct tls_connection *conn, const char *dh_file) -{ -#ifdef OPENSSL_NO_DH - if (dh_file == NULL) - return 0; - wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " - "dh_file specified"); - return -1; -#else /* OPENSSL_NO_DH */ - DH *dh; - BIO *bio; - - /* TODO: add support for dh_blob */ - if (dh_file == NULL) - return 0; - if (conn == NULL) - return -1; - - bio = BIO_new_file(dh_file, "r"); - if (bio == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", - dh_file, ERR_error_string(ERR_get_error(), NULL)); - return -1; - } - dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); - BIO_free(bio); -#ifndef OPENSSL_NO_DSA - while (dh == NULL) { - DSA *dsa; - wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" - " trying to parse as DSA params", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - bio = BIO_new_file(dh_file, "r"); - if (bio == NULL) - break; - dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); - BIO_free(bio); - if (!dsa) { - wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " - "'%s': %s", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - break; - } - - wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); - dh = DSA_dup_DH(dsa); - DSA_free(dsa); - if (dh == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " - "params into DH params"); - break; - } - break; - } -#endif /* !OPENSSL_NO_DSA */ - if (dh == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " - "'%s'", dh_file); - return -1; - } - - if (SSL_set_tmp_dh(conn->ssl, dh) != 1) { - wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " - "%s", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - DH_free(dh); - return -1; - } - DH_free(dh); - return 0; -#endif /* OPENSSL_NO_DH */ -} - - -static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file) -{ -#ifdef OPENSSL_NO_DH - if (dh_file == NULL) - return 0; - wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " - "dh_file specified"); - return -1; -#else /* OPENSSL_NO_DH */ - DH *dh; - BIO *bio; - - /* TODO: add support for dh_blob */ - if (dh_file == NULL) - return 0; - if (ssl_ctx == NULL) - return -1; - - bio = BIO_new_file(dh_file, "r"); - if (bio == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", - dh_file, ERR_error_string(ERR_get_error(), NULL)); - return -1; - } - dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); - BIO_free(bio); -#ifndef OPENSSL_NO_DSA - while (dh == NULL) { - DSA *dsa; - wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" - " trying to parse as DSA params", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - bio = BIO_new_file(dh_file, "r"); - if (bio == NULL) - break; - dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); - BIO_free(bio); - if (!dsa) { - wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " - "'%s': %s", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - break; - } - - wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); - dh = DSA_dup_DH(dsa); - DSA_free(dsa); - if (dh == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " - "params into DH params"); - break; - } - break; - } -#endif /* !OPENSSL_NO_DSA */ - if (dh == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " - "'%s'", dh_file); - return -1; - } - - if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) { - wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " - "%s", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - DH_free(dh); - return -1; - } - DH_free(dh); - return 0; -#endif /* OPENSSL_NO_DH */ -} - - -int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, - struct tls_keys *keys) -{ -#ifdef CONFIG_FIPS - wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS " - "mode"); - return -1; -#else /* CONFIG_FIPS */ - SSL *ssl; - - if (conn == NULL || keys == NULL) - return -1; - ssl = conn->ssl; - if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL) - return -1; - - os_memset(keys, 0, sizeof(*keys)); - keys->master_key = ssl->session->master_key; - keys->master_key_len = ssl->session->master_key_length; - keys->client_random = ssl->s3->client_random; - keys->client_random_len = SSL3_RANDOM_SIZE; - keys->server_random = ssl->s3->server_random; - keys->server_random_len = SSL3_RANDOM_SIZE; - - return 0; -#endif /* CONFIG_FIPS */ -} - - -int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, - const char *label, int server_random_first, - u8 *out, size_t out_len) -{ -#if OPENSSL_VERSION_NUMBER >= 0x10001000L - SSL *ssl; - if (conn == NULL) - return -1; - if (server_random_first) - return -1; - ssl = conn->ssl; - if (SSL_export_keying_material(ssl, out, out_len, label, - os_strlen(label), NULL, 0, 0) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF"); - return 0; - } -#endif - return -1; -} - - -static struct wpabuf * -openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data, - int server) -{ - int res; - struct wpabuf *out_data; - - conn->server = !!server; - - /* - * Give TLS handshake data from the server (if available) to OpenSSL - * for processing. - */ - if (in_data && - BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data)) - < 0) { - tls_show_errors(MSG_INFO, __func__, - "Handshake failed - BIO_write"); - return NULL; - } - - /* Initiate TLS handshake or continue the existing handshake */ - if (server) - res = SSL_accept(conn->ssl); - else - res = SSL_connect(conn->ssl); - if (res != 1) { - int err = SSL_get_error(conn->ssl, res); - if (err == SSL_ERROR_WANT_READ) - wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want " - "more data"); - else if (err == SSL_ERROR_WANT_WRITE) - wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to " - "write"); - else { - tls_show_errors(MSG_INFO, __func__, "SSL_connect"); - conn->failed++; - } - } - - /* Get the TLS handshake data to be sent to the server */ - res = BIO_ctrl_pending(conn->ssl_out); - wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); - out_data = wpabuf_alloc(res); - if (out_data == NULL) { - wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " - "handshake output (%d bytes)", res); - if (BIO_reset(conn->ssl_out) < 0) { - tls_show_errors(MSG_INFO, __func__, - "BIO_reset failed"); - } - return NULL; - } - res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data), - res); - if (res < 0) { - tls_show_errors(MSG_INFO, __func__, - "Handshake failed - BIO_read"); - if (BIO_reset(conn->ssl_out) < 0) { - tls_show_errors(MSG_INFO, __func__, - "BIO_reset failed"); - } - wpabuf_free(out_data); - return NULL; - } - wpabuf_put(out_data, res); - - return out_data; -} - - -static struct wpabuf * -openssl_get_appl_data(struct tls_connection *conn, size_t max_len) -{ - struct wpabuf *appl_data; - int res; - - appl_data = wpabuf_alloc(max_len + 100); - if (appl_data == NULL) - return NULL; - - res = SSL_read(conn->ssl, wpabuf_mhead(appl_data), - wpabuf_size(appl_data)); - if (res < 0) { - int err = SSL_get_error(conn->ssl, res); - if (err == SSL_ERROR_WANT_READ || - err == SSL_ERROR_WANT_WRITE) { - wpa_printf(MSG_DEBUG, "SSL: No Application Data " - "included"); - } else { - tls_show_errors(MSG_INFO, __func__, - "Failed to read possible " - "Application Data"); - } - wpabuf_free(appl_data); - return NULL; - } - - wpabuf_put(appl_data, res); - wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished " - "message", appl_data); - - return appl_data; -} - - -static struct wpabuf * -openssl_connection_handshake(struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data, int server) -{ - struct wpabuf *out_data; - - if (appl_data) - *appl_data = NULL; - - out_data = openssl_handshake(conn, in_data, server); - if (out_data == NULL) - return NULL; - - if (SSL_is_init_finished(conn->ssl) && appl_data && in_data) - *appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data)); - - return out_data; -} - - -struct wpabuf * -tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data) -{ - return openssl_connection_handshake(conn, in_data, appl_data, 0); -} - - -struct wpabuf * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data) -{ - return openssl_connection_handshake(conn, in_data, appl_data, 1); -} - - -struct wpabuf * tls_connection_encrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data) -{ - int res; - struct wpabuf *buf; - - if (conn == NULL) - return NULL; - - /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */ - if ((res = BIO_reset(conn->ssl_in)) < 0 || - (res = BIO_reset(conn->ssl_out)) < 0) { - tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); - return NULL; - } - res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data)); - if (res < 0) { - tls_show_errors(MSG_INFO, __func__, - "Encryption failed - SSL_write"); - return NULL; - } - - /* Read encrypted data to be sent to the server */ - buf = wpabuf_alloc(wpabuf_len(in_data) + 300); - if (buf == NULL) - return NULL; - res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf)); - if (res < 0) { - tls_show_errors(MSG_INFO, __func__, - "Encryption failed - BIO_read"); - wpabuf_free(buf); - return NULL; - } - wpabuf_put(buf, res); - - return buf; -} - - -struct wpabuf * tls_connection_decrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data) -{ - int res; - struct wpabuf *buf; - - /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */ - res = BIO_write(conn->ssl_in, wpabuf_head(in_data), - wpabuf_len(in_data)); - if (res < 0) { - tls_show_errors(MSG_INFO, __func__, - "Decryption failed - BIO_write"); - return NULL; - } - if (BIO_reset(conn->ssl_out) < 0) { - tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); - return NULL; - } - - /* Read decrypted data for further processing */ - /* - * Even though we try to disable TLS compression, it is possible that - * this cannot be done with all TLS libraries. Add extra buffer space - * to handle the possibility of the decrypted data being longer than - * input data. - */ - buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); - if (buf == NULL) - return NULL; - res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf)); - if (res < 0) { - tls_show_errors(MSG_INFO, __func__, - "Decryption failed - SSL_read"); - wpabuf_free(buf); - return NULL; - } - wpabuf_put(buf, res); - - return buf; -} - - -int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) -{ - return conn ? conn->ssl->hit : 0; -} - - -int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, - u8 *ciphers) -{ - char buf[100], *pos, *end; - u8 *c; - int ret; - - if (conn == NULL || conn->ssl == NULL || ciphers == NULL) - return -1; - - buf[0] = '\0'; - pos = buf; - end = pos + sizeof(buf); - - c = ciphers; - while (*c != TLS_CIPHER_NONE) { - const char *suite; - - switch (*c) { - case TLS_CIPHER_RC4_SHA: - suite = "RC4-SHA"; - break; - case TLS_CIPHER_AES128_SHA: - suite = "AES128-SHA"; - break; - case TLS_CIPHER_RSA_DHE_AES128_SHA: - suite = "DHE-RSA-AES128-SHA"; - break; - case TLS_CIPHER_ANON_DH_AES128_SHA: - suite = "ADH-AES128-SHA"; - break; - default: - wpa_printf(MSG_DEBUG, "TLS: Unsupported " - "cipher selection: %d", *c); - return -1; - } - ret = os_snprintf(pos, end - pos, ":%s", suite); - if (ret < 0 || ret >= end - pos) - break; - pos += ret; - - c++; - } - - wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1); - - if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) { - tls_show_errors(MSG_INFO, __func__, - "Cipher suite configuration failed"); - return -1; - } - - return 0; -} - - -int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, - char *buf, size_t buflen) -{ - const char *name; - if (conn == NULL || conn->ssl == NULL) - return -1; - - name = SSL_get_cipher(conn->ssl); - if (name == NULL) - return -1; - - os_strlcpy(buf, name, buflen); - return 0; -} - - -int tls_connection_enable_workaround(void *ssl_ctx, - struct tls_connection *conn) -{ - SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); - - return 0; -} - - -#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) -/* ClientHello TLS extensions require a patch to openssl, so this function is - * commented out unless explicitly needed for EAP-FAST in order to be able to - * build this file with unmodified openssl. */ -int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, - int ext_type, const u8 *data, - size_t data_len) -{ - if (conn == NULL || conn->ssl == NULL || ext_type != 35) - return -1; - -#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE - if (SSL_set_session_ticket_ext(conn->ssl, (void *) data, - data_len) != 1) - return -1; -#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ - if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data, - data_len) != 1) - return -1; -#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ - - return 0; -} -#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ - - -int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - return conn->failed; -} - - -int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - return conn->read_alerts; -} - - -int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - return conn->write_alerts; -} - - -#ifdef HAVE_OCSP - -static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp) -{ -#ifndef CONFIG_NO_STDOUT_DEBUG - BIO *out; - size_t rlen; - char *txt; - int res; - - if (wpa_debug_level > MSG_DEBUG) - return; - - out = BIO_new(BIO_s_mem()); - if (!out) - return; - - OCSP_RESPONSE_print(out, rsp, 0); - rlen = BIO_ctrl_pending(out); - txt = os_malloc(rlen + 1); - if (!txt) { - BIO_free(out); - return; - } - - res = BIO_read(out, txt, rlen); - if (res > 0) { - txt[res] = '\0'; - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt); - } - os_free(txt); - BIO_free(out); -#endif /* CONFIG_NO_STDOUT_DEBUG */ -} - - -static int ocsp_resp_cb(SSL *s, void *arg) -{ - struct tls_connection *conn = arg; - const unsigned char *p; - int len, status, reason; - OCSP_RESPONSE *rsp; - OCSP_BASICRESP *basic; - OCSP_CERTID *id; - ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update; - X509_STORE *store; - STACK_OF(X509) *certs = NULL; - - len = SSL_get_tlsext_status_ocsp_resp(s, &p); - if (!p) { - wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received"); - return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1; - } - - wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len); - - rsp = d2i_OCSP_RESPONSE(NULL, &p, len); - if (!rsp) { - wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response"); - return 0; - } - - ocsp_debug_print_resp(rsp); - - status = OCSP_response_status(rsp); - if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { - wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)", - status, OCSP_response_status_str(status)); - return 0; - } - - basic = OCSP_response_get1_basic(rsp); - if (!basic) { - wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse"); - return 0; - } - - store = SSL_CTX_get_cert_store(s->ctx); - if (conn->peer_issuer) { - wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer"); - X509_print_fp(stdout, conn->peer_issuer); - - if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) { - tls_show_errors(MSG_INFO, __func__, - "OpenSSL: Could not add issuer to certificate store\n"); - } - certs = sk_X509_new_null(); - if (certs) { - X509 *cert; - cert = X509_dup(conn->peer_issuer); - if (cert && !sk_X509_push(certs, cert)) { - tls_show_errors( - MSG_INFO, __func__, - "OpenSSL: Could not add issuer to OCSP responder trust store\n"); - X509_free(cert); - sk_X509_free(certs); - certs = NULL; - } - if (conn->peer_issuer_issuer) { - cert = X509_dup(conn->peer_issuer_issuer); - if (cert && !sk_X509_push(certs, cert)) { - tls_show_errors( - MSG_INFO, __func__, - "OpenSSL: Could not add issuer to OCSP responder trust store\n"); - X509_free(cert); - } - } - } - } - - status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER); - sk_X509_pop_free(certs, X509_free); - if (status <= 0) { - tls_show_errors(MSG_INFO, __func__, - "OpenSSL: OCSP response failed verification"); - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - return 0; - } - - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded"); - - if (!conn->peer_cert) { - wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check"); - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - return 0; - } - - if (!conn->peer_issuer) { - wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check"); - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - return 0; - } - - id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer); - if (!id) { - wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier"); - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - return 0; - } - - if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at, - &this_update, &next_update)) { - wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s", - (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" : - " (OCSP not required)"); - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1; - } - - if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) { - tls_show_errors(MSG_INFO, __func__, - "OpenSSL: OCSP status times invalid"); - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - return 0; - } - - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s", - OCSP_cert_status_str(status)); - - if (status == V_OCSP_CERTSTATUS_GOOD) - return 1; - if (status == V_OCSP_CERTSTATUS_REVOKED) - return 0; - if (conn->flags & TLS_CONN_REQUIRE_OCSP) { - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required"); - return 0; - } - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue"); - return 1; -} - - -static int ocsp_status_cb(SSL *s, void *arg) -{ - char *tmp; - char *resp; - size_t len; - - if (tls_global->ocsp_stapling_response == NULL) { - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured"); - return SSL_TLSEXT_ERR_OK; - } - - resp = os_readfile(tls_global->ocsp_stapling_response, &len); - if (resp == NULL) { - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file"); - /* TODO: Build OCSPResponse with responseStatus = internalError - */ - return SSL_TLSEXT_ERR_OK; - } - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response"); - tmp = OPENSSL_malloc(len); - if (tmp == NULL) { - os_free(resp); - return SSL_TLSEXT_ERR_ALERT_FATAL; - } - - os_memcpy(tmp, resp, len); - os_free(resp); - SSL_set_tlsext_status_ocsp_resp(s, tmp, len); - - return SSL_TLSEXT_ERR_OK; -} - -#endif /* HAVE_OCSP */ - - -int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, - const struct tls_connection_params *params) -{ - int ret; - unsigned long err; - - if (conn == NULL) - return -1; - - while ((err = ERR_get_error())) { - wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", - __func__, ERR_error_string(err, NULL)); - } - - if (params->engine) { - wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine"); - ret = tls_engine_init(conn, params->engine_id, params->pin, - params->key_id, params->cert_id, - params->ca_cert_id); - if (ret) - return ret; - } - if (tls_connection_set_subject_match(conn, - params->subject_match, - params->altsubject_match, - params->suffix_match)) - return -1; - - if (params->engine && params->ca_cert_id) { - if (tls_connection_engine_ca_cert(tls_ctx, conn, - params->ca_cert_id)) - return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; - } else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert, - params->ca_cert_blob, - params->ca_cert_blob_len, - params->ca_path)) - return -1; - - if (params->engine && params->cert_id) { - if (tls_connection_engine_client_cert(conn, params->cert_id)) - return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; - } else if (tls_connection_client_cert(conn, params->client_cert, - params->client_cert_blob, - params->client_cert_blob_len)) - return -1; - - if (params->engine && params->key_id) { - wpa_printf(MSG_DEBUG, "TLS: Using private key from engine"); - if (tls_connection_engine_private_key(conn)) - return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; - } else if (tls_connection_private_key(tls_ctx, conn, - params->private_key, - params->private_key_passwd, - params->private_key_blob, - params->private_key_blob_len)) { - wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'", - params->private_key); - return -1; - } - - if (tls_connection_dh(conn, params->dh_file)) { - wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", - params->dh_file); - return -1; - } - -#ifdef SSL_OP_NO_TICKET - if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET) - SSL_set_options(conn->ssl, SSL_OP_NO_TICKET); -#ifdef SSL_clear_options - else - SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET); -#endif /* SSL_clear_options */ -#endif /* SSL_OP_NO_TICKET */ - -#ifdef HAVE_OCSP - if (params->flags & TLS_CONN_REQUEST_OCSP) { - SSL_CTX *ssl_ctx = tls_ctx; - SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp); - SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb); - SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn); - } -#endif /* HAVE_OCSP */ - - conn->flags = params->flags; - - tls_get_errors(tls_ctx); - - return 0; -} - - -int tls_global_set_params(void *tls_ctx, - const struct tls_connection_params *params) -{ - SSL_CTX *ssl_ctx = tls_ctx; - unsigned long err; - - while ((err = ERR_get_error())) { - wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", - __func__, ERR_error_string(err, NULL)); - } - - if (tls_global_ca_cert(ssl_ctx, params->ca_cert)) - return -1; - - if (tls_global_client_cert(ssl_ctx, params->client_cert)) - return -1; - - if (tls_global_private_key(ssl_ctx, params->private_key, - params->private_key_passwd)) - return -1; - - if (tls_global_dh(ssl_ctx, params->dh_file)) { - wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", - params->dh_file); - return -1; - } - -#ifdef SSL_OP_NO_TICKET - if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET) - SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET); -#ifdef SSL_CTX_clear_options - else - SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET); -#endif /* SSL_clear_options */ -#endif /* SSL_OP_NO_TICKET */ - -#ifdef HAVE_OCSP - SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb); - SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx); - os_free(tls_global->ocsp_stapling_response); - if (params->ocsp_stapling_response) - tls_global->ocsp_stapling_response = - os_strdup(params->ocsp_stapling_response); - else - tls_global->ocsp_stapling_response = NULL; -#endif /* HAVE_OCSP */ - - return 0; -} - - -int tls_connection_get_keyblock_size(void *tls_ctx, - struct tls_connection *conn) -{ - const EVP_CIPHER *c; - const EVP_MD *h; - int md_size; - - if (conn == NULL || conn->ssl == NULL || - conn->ssl->enc_read_ctx == NULL || - conn->ssl->enc_read_ctx->cipher == NULL || - conn->ssl->read_hash == NULL) - return -1; - - c = conn->ssl->enc_read_ctx->cipher; -#if OPENSSL_VERSION_NUMBER >= 0x00909000L - h = EVP_MD_CTX_md(conn->ssl->read_hash); -#else - h = conn->ssl->read_hash; -#endif - if (h) - md_size = EVP_MD_size(h); -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - else if (conn->ssl->s3) - md_size = conn->ssl->s3->tmp.new_mac_secret_size; -#endif - else - return -1; - - wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d " - "IV_len=%d", EVP_CIPHER_key_length(c), md_size, - EVP_CIPHER_iv_length(c)); - return 2 * (EVP_CIPHER_key_length(c) + - md_size + - EVP_CIPHER_iv_length(c)); -} - - -unsigned int tls_capabilities(void *tls_ctx) -{ - return 0; -} - - -#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 - * build this file with unmodified openssl. */ - -static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, - STACK_OF(SSL_CIPHER) *peer_ciphers, - SSL_CIPHER **cipher, void *arg) -{ - struct tls_connection *conn = arg; - int ret; - - if (conn == NULL || conn->session_ticket_cb == NULL) - return 0; - - ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx, - conn->session_ticket, - conn->session_ticket_len, - s->s3->client_random, - s->s3->server_random, secret); - os_free(conn->session_ticket); - conn->session_ticket = NULL; - - if (ret <= 0) - return 0; - - *secret_len = SSL_MAX_MASTER_KEY_LENGTH; - return 1; -} - - -#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE -static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data, - int len, void *arg) -{ - struct tls_connection *conn = arg; - - if (conn == NULL || conn->session_ticket_cb == NULL) - return 0; - - wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len); - - os_free(conn->session_ticket); - conn->session_ticket = NULL; - - wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " - "extension", data, len); - - conn->session_ticket = os_malloc(len); - if (conn->session_ticket == NULL) - return 0; - - os_memcpy(conn->session_ticket, data, len); - conn->session_ticket_len = len; - - return 1; -} -#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ -#ifdef SSL_OP_NO_TICKET -static void tls_hello_ext_cb(SSL *s, int client_server, int type, - unsigned char *data, int len, void *arg) -{ - struct tls_connection *conn = arg; - - if (conn == NULL || conn->session_ticket_cb == NULL) - return; - - wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, - type, len); - - if (type == TLSEXT_TYPE_session_ticket && !client_server) { - os_free(conn->session_ticket); - conn->session_ticket = NULL; - - wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " - "extension", data, len); - conn->session_ticket = os_malloc(len); - if (conn->session_ticket == NULL) - return; - - os_memcpy(conn->session_ticket, data, len); - conn->session_ticket_len = len; - } -} -#else /* SSL_OP_NO_TICKET */ -static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg) -{ - struct tls_connection *conn = arg; - - if (conn == NULL || conn->session_ticket_cb == NULL) - return 0; - - wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, - ext->type, ext->length); - - os_free(conn->session_ticket); - conn->session_ticket = NULL; - - if (ext->type == 35) { - wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " - "extension", ext->data, ext->length); - conn->session_ticket = os_malloc(ext->length); - if (conn->session_ticket == NULL) - return SSL_AD_INTERNAL_ERROR; - - os_memcpy(conn->session_ticket, ext->data, ext->length); - conn->session_ticket_len = ext->length; - } - - return 0; -} -#endif /* SSL_OP_NO_TICKET */ -#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ -#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ - - -int tls_connection_set_session_ticket_cb(void *tls_ctx, - struct tls_connection *conn, - tls_session_ticket_cb cb, - void *ctx) -{ -#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) - conn->session_ticket_cb = cb; - conn->session_ticket_cb_ctx = ctx; - - if (cb) { - if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb, - conn) != 1) - return -1; -#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE - SSL_set_session_ticket_ext_cb(conn->ssl, - tls_session_ticket_ext_cb, conn); -#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ -#ifdef SSL_OP_NO_TICKET - SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb); - SSL_set_tlsext_debug_arg(conn->ssl, conn); -#else /* SSL_OP_NO_TICKET */ - if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb, - conn) != 1) - return -1; -#endif /* SSL_OP_NO_TICKET */ -#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ - } else { - if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1) - return -1; -#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE - SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL); -#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ -#ifdef SSL_OP_NO_TICKET - SSL_set_tlsext_debug_callback(conn->ssl, NULL); - SSL_set_tlsext_debug_arg(conn->ssl, conn); -#else /* SSL_OP_NO_TICKET */ - if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1) - return -1; -#endif /* SSL_OP_NO_TICKET */ -#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ - } - - return 0; -#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ - return -1; -#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ -} diff --git a/contrib/hostapd/src/crypto/tls_schannel.c b/contrib/hostapd/src/crypto/tls_schannel.c deleted file mode 100644 index 2c2daa8a80..0000000000 --- a/contrib/hostapd/src/crypto/tls_schannel.c +++ /dev/null @@ -1,732 +0,0 @@ -/* - * SSL/TLS interface functions for Microsoft Schannel - * Copyright (c) 2005-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -/* - * FIX: Go through all SSPI functions and verify what needs to be freed - * FIX: session resumption - * TODO: add support for server cert chain validation - * TODO: add support for CA cert validation - * TODO: add support for EAP-TLS (client cert/key conf) - */ - -#include "includes.h" -#include -#include -#include -#define SECURITY_WIN32 -#include -#include - -#include "common.h" -#include "tls.h" - - -struct tls_global { - HMODULE hsecurity; - PSecurityFunctionTable sspi; - HCERTSTORE my_cert_store; -}; - -struct tls_connection { - int established, start; - int failed, read_alerts, write_alerts; - - SCHANNEL_CRED schannel_cred; - CredHandle creds; - CtxtHandle context; - - u8 eap_tls_prf[128]; - int eap_tls_prf_set; -}; - - -static int schannel_load_lib(struct tls_global *global) -{ - INIT_SECURITY_INTERFACE pInitSecurityInterface; - - global->hsecurity = LoadLibrary(TEXT("Secur32.dll")); - if (global->hsecurity == NULL) { - wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x", - __func__, (unsigned int) GetLastError()); - return -1; - } - - pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress( - global->hsecurity, "InitSecurityInterfaceA"); - if (pInitSecurityInterface == NULL) { - wpa_printf(MSG_ERROR, "%s: Could not find " - "InitSecurityInterfaceA from Secur32.dll", - __func__); - FreeLibrary(global->hsecurity); - global->hsecurity = NULL; - return -1; - } - - global->sspi = pInitSecurityInterface(); - if (global->sspi == NULL) { - wpa_printf(MSG_ERROR, "%s: Could not read security " - "interface - 0x%x", - __func__, (unsigned int) GetLastError()); - FreeLibrary(global->hsecurity); - global->hsecurity = NULL; - return -1; - } - - return 0; -} - - -void * tls_init(const struct tls_config *conf) -{ - struct tls_global *global; - - global = os_zalloc(sizeof(*global)); - if (global == NULL) - return NULL; - if (schannel_load_lib(global)) { - os_free(global); - return NULL; - } - return global; -} - - -void tls_deinit(void *ssl_ctx) -{ - struct tls_global *global = ssl_ctx; - - if (global->my_cert_store) - CertCloseStore(global->my_cert_store, 0); - FreeLibrary(global->hsecurity); - os_free(global); -} - - -int tls_get_errors(void *ssl_ctx) -{ - return 0; -} - - -struct tls_connection * tls_connection_init(void *ssl_ctx) -{ - struct tls_connection *conn; - - conn = os_zalloc(sizeof(*conn)); - if (conn == NULL) - return NULL; - conn->start = 1; - - return conn; -} - - -void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return; - - os_free(conn); -} - - -int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) -{ - return conn ? conn->established : 0; -} - - -int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) -{ - struct tls_global *global = ssl_ctx; - if (conn == NULL) - return -1; - - conn->eap_tls_prf_set = 0; - conn->established = conn->failed = 0; - conn->read_alerts = conn->write_alerts = 0; - global->sspi->DeleteSecurityContext(&conn->context); - /* FIX: what else needs to be reseted? */ - - return 0; -} - - -int tls_global_set_params(void *tls_ctx, - const struct tls_connection_params *params) -{ - return -1; -} - - -int tls_global_set_verify(void *ssl_ctx, int check_crl) -{ - return -1; -} - - -int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, - int verify_peer) -{ - return -1; -} - - -int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, - struct tls_keys *keys) -{ - /* Schannel does not export master secret or client/server random. */ - return -1; -} - - -int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, - const char *label, int server_random_first, - u8 *out, size_t out_len) -{ - /* - * Cannot get master_key from Schannel, but EapKeyBlock can be used to - * generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and - * EAP-TTLS cannot use this, though, since they are using different - * labels. The only option could be to implement TLSv1 completely here - * and just use Schannel or CryptoAPI for low-level crypto - * functionality.. - */ - - if (conn == NULL || !conn->eap_tls_prf_set || server_random_first || - os_strcmp(label, "client EAP encryption") != 0 || - out_len > sizeof(conn->eap_tls_prf)) - return -1; - - os_memcpy(out, conn->eap_tls_prf, out_len); - - return 0; -} - - -static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global, - struct tls_connection *conn) -{ - DWORD sspi_flags, sspi_flags_out; - SecBufferDesc outbuf; - SecBuffer outbufs[1]; - SECURITY_STATUS status; - TimeStamp ts_expiry; - - sspi_flags = ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONFIDENTIALITY | - ISC_RET_EXTENDED_ERROR | - ISC_REQ_ALLOCATE_MEMORY | - ISC_REQ_MANUAL_CRED_VALIDATION; - - wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__); - - outbufs[0].pvBuffer = NULL; - outbufs[0].BufferType = SECBUFFER_TOKEN; - outbufs[0].cbBuffer = 0; - - outbuf.cBuffers = 1; - outbuf.pBuffers = outbufs; - outbuf.ulVersion = SECBUFFER_VERSION; - -#ifdef UNICODE - status = global->sspi->InitializeSecurityContextW( - &conn->creds, NULL, NULL /* server name */, sspi_flags, 0, - SECURITY_NATIVE_DREP, NULL, 0, &conn->context, - &outbuf, &sspi_flags_out, &ts_expiry); -#else /* UNICODE */ - status = global->sspi->InitializeSecurityContextA( - &conn->creds, NULL, NULL /* server name */, sspi_flags, 0, - SECURITY_NATIVE_DREP, NULL, 0, &conn->context, - &outbuf, &sspi_flags_out, &ts_expiry); -#endif /* UNICODE */ - if (status != SEC_I_CONTINUE_NEEDED) { - wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA " - "failed - 0x%x", - __func__, (unsigned int) status); - return NULL; - } - - if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) { - struct wpabuf *buf; - wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello", - outbufs[0].pvBuffer, outbufs[0].cbBuffer); - conn->start = 0; - buf = wpabuf_alloc_copy(outbufs[0].pvBuffer, - outbufs[0].cbBuffer); - if (buf == NULL) - return NULL; - global->sspi->FreeContextBuffer(outbufs[0].pvBuffer); - return buf; - } - - wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello"); - - return NULL; -} - - -#ifndef SECPKG_ATTR_EAP_KEY_BLOCK -#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b - -typedef struct _SecPkgContext_EapKeyBlock { - BYTE rgbKeys[128]; - BYTE rgbIVs[64]; -} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock; -#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */ - -static int tls_get_eap(struct tls_global *global, struct tls_connection *conn) -{ - SECURITY_STATUS status; - SecPkgContext_EapKeyBlock kb; - - /* Note: Windows NT and Windows Me/98/95 do not support getting - * EapKeyBlock */ - - status = global->sspi->QueryContextAttributes( - &conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb); - if (status != SEC_E_OK) { - wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes(" - "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)", - __func__, (int) status); - return -1; - } - - wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys", - kb.rgbKeys, sizeof(kb.rgbKeys)); - wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs", - kb.rgbIVs, sizeof(kb.rgbIVs)); - - os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys)); - conn->eap_tls_prf_set = 1; - return 0; -} - - -struct wpabuf * tls_connection_handshake(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data) -{ - struct tls_global *global = tls_ctx; - DWORD sspi_flags, sspi_flags_out; - SecBufferDesc inbuf, outbuf; - SecBuffer inbufs[2], outbufs[1]; - SECURITY_STATUS status; - TimeStamp ts_expiry; - struct wpabuf *out_buf = NULL; - - if (appl_data) - *appl_data = NULL; - - if (conn->start) - return tls_conn_hs_clienthello(global, conn); - - wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process", - (int) wpabuf_len(in_data)); - - sspi_flags = ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONFIDENTIALITY | - ISC_RET_EXTENDED_ERROR | - ISC_REQ_ALLOCATE_MEMORY | - ISC_REQ_MANUAL_CRED_VALIDATION; - - /* Input buffer for Schannel */ - inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data); - inbufs[0].cbBuffer = wpabuf_len(in_data); - inbufs[0].BufferType = SECBUFFER_TOKEN; - - /* Place for leftover data from Schannel */ - inbufs[1].pvBuffer = NULL; - inbufs[1].cbBuffer = 0; - inbufs[1].BufferType = SECBUFFER_EMPTY; - - inbuf.cBuffers = 2; - inbuf.pBuffers = inbufs; - inbuf.ulVersion = SECBUFFER_VERSION; - - /* Output buffer for Schannel */ - outbufs[0].pvBuffer = NULL; - outbufs[0].cbBuffer = 0; - outbufs[0].BufferType = SECBUFFER_TOKEN; - - outbuf.cBuffers = 1; - outbuf.pBuffers = outbufs; - outbuf.ulVersion = SECBUFFER_VERSION; - -#ifdef UNICODE - status = global->sspi->InitializeSecurityContextW( - &conn->creds, &conn->context, NULL, sspi_flags, 0, - SECURITY_NATIVE_DREP, &inbuf, 0, NULL, - &outbuf, &sspi_flags_out, &ts_expiry); -#else /* UNICODE */ - status = global->sspi->InitializeSecurityContextA( - &conn->creds, &conn->context, NULL, sspi_flags, 0, - SECURITY_NATIVE_DREP, &inbuf, 0, NULL, - &outbuf, &sspi_flags_out, &ts_expiry); -#endif /* UNICODE */ - - wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> " - "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d " - "intype[1]=%d outlen[0]=%d", - (int) status, (int) inbufs[0].cbBuffer, - (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer, - (int) inbufs[1].BufferType, - (int) outbufs[0].cbBuffer); - if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED || - (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) { - if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) { - wpa_hexdump(MSG_MSGDUMP, "SChannel - output", - outbufs[0].pvBuffer, outbufs[0].cbBuffer); - out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer, - outbufs[0].cbBuffer); - global->sspi->FreeContextBuffer(outbufs[0].pvBuffer); - outbufs[0].pvBuffer = NULL; - if (out_buf == NULL) - return NULL; - } - } - - switch (status) { - case SEC_E_INCOMPLETE_MESSAGE: - wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE"); - break; - case SEC_I_CONTINUE_NEEDED: - wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED"); - break; - case SEC_E_OK: - /* TODO: verify server certificate chain */ - wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake " - "completed successfully"); - conn->established = 1; - tls_get_eap(global, conn); - - /* Need to return something to get final TLS ACK. */ - if (out_buf == NULL) - out_buf = wpabuf_alloc(0); - - if (inbufs[1].BufferType == SECBUFFER_EXTRA) { - wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted " - "application data", - inbufs[1].pvBuffer, inbufs[1].cbBuffer); - if (appl_data) { - *appl_data = wpabuf_alloc_copy( - outbufs[1].pvBuffer, - outbufs[1].cbBuffer); - } - global->sspi->FreeContextBuffer(inbufs[1].pvBuffer); - inbufs[1].pvBuffer = NULL; - } - break; - case SEC_I_INCOMPLETE_CREDENTIALS: - wpa_printf(MSG_DEBUG, - "Schannel: SEC_I_INCOMPLETE_CREDENTIALS"); - break; - case SEC_E_WRONG_PRINCIPAL: - wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL"); - break; - case SEC_E_INTERNAL_ERROR: - wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR"); - break; - } - - if (FAILED(status)) { - wpa_printf(MSG_DEBUG, "Schannel: Handshake failed " - "(out_buf=%p)", out_buf); - conn->failed++; - global->sspi->DeleteSecurityContext(&conn->context); - return out_buf; - } - - if (inbufs[1].BufferType == SECBUFFER_EXTRA) { - /* TODO: Can this happen? What to do with this data? */ - wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data", - inbufs[1].pvBuffer, inbufs[1].cbBuffer); - global->sspi->FreeContextBuffer(inbufs[1].pvBuffer); - inbufs[1].pvBuffer = NULL; - } - - return out_buf; -} - - -struct wpabuf * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data) -{ - return NULL; -} - - -struct wpabuf * tls_connection_encrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data) -{ - struct tls_global *global = tls_ctx; - SECURITY_STATUS status; - SecBufferDesc buf; - SecBuffer bufs[4]; - SecPkgContext_StreamSizes sizes; - int i; - struct wpabuf *out; - - status = global->sspi->QueryContextAttributes(&conn->context, - SECPKG_ATTR_STREAM_SIZES, - &sizes); - if (status != SEC_E_OK) { - wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed", - __func__); - return NULL; - } - wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u", - __func__, - (unsigned int) sizes.cbHeader, - (unsigned int) sizes.cbTrailer); - - out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) + - sizes.cbTrailer); - - os_memset(&bufs, 0, sizeof(bufs)); - bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader); - bufs[0].cbBuffer = sizes.cbHeader; - bufs[0].BufferType = SECBUFFER_STREAM_HEADER; - - bufs[1].pvBuffer = wpabuf_put(out, 0); - wpabuf_put_buf(out, in_data); - bufs[1].cbBuffer = wpabuf_len(in_data); - bufs[1].BufferType = SECBUFFER_DATA; - - bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer); - bufs[2].cbBuffer = sizes.cbTrailer; - bufs[2].BufferType = SECBUFFER_STREAM_TRAILER; - - buf.ulVersion = SECBUFFER_VERSION; - buf.cBuffers = 3; - buf.pBuffers = bufs; - - status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0); - - wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> " - "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d " - "len[2]=%d type[2]=%d", - (int) status, - (int) bufs[0].cbBuffer, (int) bufs[0].BufferType, - (int) bufs[1].cbBuffer, (int) bufs[1].BufferType, - (int) bufs[2].cbBuffer, (int) bufs[2].BufferType); - wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: " - "out_data=%p bufs %p %p %p", - wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer, - bufs[2].pvBuffer); - - for (i = 0; i < 3; i++) { - if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY) - { - wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs", - bufs[i].pvBuffer, bufs[i].cbBuffer); - } - } - - if (status == SEC_E_OK) { - wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__); - wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data " - "from EncryptMessage", out); - return out; - } - - wpa_printf(MSG_DEBUG, "%s: Failed - status=%d", - __func__, (int) status); - wpabuf_free(out); - return NULL; -} - - -struct wpabuf * tls_connection_decrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data) -{ - struct tls_global *global = tls_ctx; - SECURITY_STATUS status; - SecBufferDesc buf; - SecBuffer bufs[4]; - int i; - struct wpabuf *out, *tmp; - - wpa_hexdump_buf(MSG_MSGDUMP, - "Schannel: Encrypted data to DecryptMessage", in_data); - os_memset(&bufs, 0, sizeof(bufs)); - tmp = wpabuf_dup(in_data); - if (tmp == NULL) - return NULL; - bufs[0].pvBuffer = wpabuf_mhead(tmp); - bufs[0].cbBuffer = wpabuf_len(in_data); - bufs[0].BufferType = SECBUFFER_DATA; - - bufs[1].BufferType = SECBUFFER_EMPTY; - bufs[2].BufferType = SECBUFFER_EMPTY; - bufs[3].BufferType = SECBUFFER_EMPTY; - - buf.ulVersion = SECBUFFER_VERSION; - buf.cBuffers = 4; - buf.pBuffers = bufs; - - status = global->sspi->DecryptMessage(&conn->context, &buf, 0, - NULL); - wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> " - "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d " - "len[2]=%d type[2]=%d len[3]=%d type[3]=%d", - (int) status, - (int) bufs[0].cbBuffer, (int) bufs[0].BufferType, - (int) bufs[1].cbBuffer, (int) bufs[1].BufferType, - (int) bufs[2].cbBuffer, (int) bufs[2].BufferType, - (int) bufs[3].cbBuffer, (int) bufs[3].BufferType); - wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: " - "out_data=%p bufs %p %p %p %p", - wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer, - bufs[2].pvBuffer, bufs[3].pvBuffer); - - switch (status) { - case SEC_E_INCOMPLETE_MESSAGE: - wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE", - __func__); - break; - case SEC_E_OK: - wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__); - for (i = 0; i < 4; i++) { - if (bufs[i].BufferType == SECBUFFER_DATA) - break; - } - if (i == 4) { - wpa_printf(MSG_DEBUG, "%s: No output data from " - "DecryptMessage", __func__); - wpabuf_free(tmp); - return NULL; - } - wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from " - "DecryptMessage", - bufs[i].pvBuffer, bufs[i].cbBuffer); - out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer); - wpabuf_free(tmp); - return out; - } - - wpa_printf(MSG_DEBUG, "%s: Failed - status=%d", - __func__, (int) status); - wpabuf_free(tmp); - return NULL; -} - - -int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) -{ - return 0; -} - - -int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, - u8 *ciphers) -{ - return -1; -} - - -int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, - char *buf, size_t buflen) -{ - return -1; -} - - -int tls_connection_enable_workaround(void *ssl_ctx, - struct tls_connection *conn) -{ - return 0; -} - - -int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, - int ext_type, const u8 *data, - size_t data_len) -{ - return -1; -} - - -int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - return conn->failed; -} - - -int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - return conn->read_alerts; -} - - -int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - return conn->write_alerts; -} - - -int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, - const struct tls_connection_params *params) -{ - struct tls_global *global = tls_ctx; - ALG_ID algs[1]; - SECURITY_STATUS status; - TimeStamp ts_expiry; - - if (conn == NULL) - return -1; - - if (global->my_cert_store == NULL && - (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) == - NULL) { - wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x", - __func__, (unsigned int) GetLastError()); - return -1; - } - - os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred)); - conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; - conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1; - algs[0] = CALG_RSA_KEYX; - conn->schannel_cred.cSupportedAlgs = 1; - conn->schannel_cred.palgSupportedAlgs = algs; - conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS; -#ifdef UNICODE - status = global->sspi->AcquireCredentialsHandleW( - NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL, - &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry); -#else /* UNICODE */ - status = global->sspi->AcquireCredentialsHandleA( - NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, - &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry); -#endif /* UNICODE */ - if (status != SEC_E_OK) { - wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - " - "0x%x", __func__, (unsigned int) status); - return -1; - } - - return 0; -} - - -unsigned int tls_capabilities(void *tls_ctx) -{ - return 0; -} diff --git a/contrib/hostapd/src/drivers/android_drv.h b/contrib/hostapd/src/drivers/android_drv.h deleted file mode 100644 index 31d94408a9..0000000000 --- a/contrib/hostapd/src/drivers/android_drv.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Android driver interface - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef ANDROID_DRV_H -#define ANDROID_DRV_H - -#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE " - -#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/contrib/hostapd/src/drivers/driver.h b/contrib/hostapd/src/drivers/driver.h deleted file mode 100644 index 7ad857616c..0000000000 --- a/contrib/hostapd/src/drivers/driver.h +++ /dev/null @@ -1,3847 +0,0 @@ -/* - * Driver interface definition - * Copyright (c) 2003-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file defines a driver interface used by both %wpa_supplicant and - * hostapd. The first part of the file defines data structures used in various - * driver operations. This is followed by the struct wpa_driver_ops that each - * driver wrapper will beed to define with callback functions for requesting - * driver operations. After this, there are definitions for driver event - * reporting with wpa_supplicant_event() and some convenience helper functions - * that can be used to report events. - */ - -#ifndef DRIVER_H -#define DRIVER_H - -#define WPA_SUPPLICANT_DRIVER_VERSION 4 - -#include "common/defs.h" -#include "utils/list.h" - -#define HOSTAPD_CHAN_DISABLED 0x00000001 -#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002 -#define HOSTAPD_CHAN_NO_IBSS 0x00000004 -#define HOSTAPD_CHAN_RADAR 0x00000008 -#define HOSTAPD_CHAN_HT40PLUS 0x00000010 -#define HOSTAPD_CHAN_HT40MINUS 0x00000020 -#define HOSTAPD_CHAN_HT40 0x00000040 -#define HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED 0x00000080 - -#define HOSTAPD_CHAN_DFS_UNKNOWN 0x00000000 -#define HOSTAPD_CHAN_DFS_USABLE 0x00000100 -#define HOSTAPD_CHAN_DFS_UNAVAILABLE 0x00000200 -#define HOSTAPD_CHAN_DFS_AVAILABLE 0x00000300 -#define HOSTAPD_CHAN_DFS_MASK 0x00000300 - -#define HOSTAPD_CHAN_VHT_10_70 0x00000800 -#define HOSTAPD_CHAN_VHT_30_50 0x00001000 -#define HOSTAPD_CHAN_VHT_50_30 0x00002000 -#define HOSTAPD_CHAN_VHT_70_10 0x00004000 - -enum reg_change_initiator { - REGDOM_SET_BY_CORE, - REGDOM_SET_BY_USER, - REGDOM_SET_BY_DRIVER, - REGDOM_SET_BY_COUNTRY_IE, - REGDOM_BEACON_HINT, -}; - -/** - * struct hostapd_channel_data - Channel information - */ -struct hostapd_channel_data { - /** - * chan - Channel number (IEEE 802.11) - */ - short chan; - - /** - * freq - Frequency in MHz - */ - int freq; - - /** - * flag - Channel flags (HOSTAPD_CHAN_*) - */ - int flag; - - /** - * max_tx_power - Regulatory transmit power limit in dBm - */ - u8 max_tx_power; - - /* - * survey_list - Linked list of surveys - */ - struct dl_list survey_list; - - /** - * min_nf - Minimum observed noise floor, in dBm, based on all - * surveyed channel data - */ - s8 min_nf; - -#ifdef CONFIG_ACS - /** - * interference_factor - Computed interference factor on this - * channel (used internally in src/ap/acs.c; driver wrappers do not - * need to set this) - */ - long double interference_factor; -#endif /* CONFIG_ACS */ -}; - -#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0) -#define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1) - -/** - * struct hostapd_hw_modes - Supported hardware mode information - */ -struct hostapd_hw_modes { - /** - * mode - Hardware mode - */ - enum hostapd_hw_mode mode; - - /** - * num_channels - Number of entries in the channels array - */ - int num_channels; - - /** - * channels - Array of supported channels - */ - struct hostapd_channel_data *channels; - - /** - * num_rates - Number of entries in the rates array - */ - int num_rates; - - /** - * rates - Array of supported rates in 100 kbps units - */ - int *rates; - - /** - * ht_capab - HT (IEEE 802.11n) capabilities - */ - u16 ht_capab; - - /** - * mcs_set - MCS (IEEE 802.11n) rate parameters - */ - u8 mcs_set[16]; - - /** - * a_mpdu_params - A-MPDU (IEEE 802.11n) parameters - */ - u8 a_mpdu_params; - - /** - * vht_capab - VHT (IEEE 802.11ac) capabilities - */ - u32 vht_capab; - - /** - * vht_mcs_set - VHT MCS (IEEE 802.11ac) rate parameters - */ - u8 vht_mcs_set[8]; - - unsigned int flags; /* HOSTAPD_MODE_FLAG_* */ -}; - - -#define IEEE80211_MODE_INFRA 0 -#define IEEE80211_MODE_IBSS 1 -#define IEEE80211_MODE_AP 2 - -#define IEEE80211_CAP_ESS 0x0001 -#define IEEE80211_CAP_IBSS 0x0002 -#define IEEE80211_CAP_PRIVACY 0x0010 - -/* DMG (60 GHz) IEEE 802.11ad */ -/* type - bits 0..1 */ -#define IEEE80211_CAP_DMG_MASK 0x0003 -#define IEEE80211_CAP_DMG_IBSS 0x0001 /* Tx by: STA */ -#define IEEE80211_CAP_DMG_PBSS 0x0002 /* Tx by: PCP */ -#define IEEE80211_CAP_DMG_AP 0x0003 /* Tx by: AP */ - -#define WPA_SCAN_QUAL_INVALID BIT(0) -#define WPA_SCAN_NOISE_INVALID BIT(1) -#define WPA_SCAN_LEVEL_INVALID BIT(2) -#define WPA_SCAN_LEVEL_DBM BIT(3) -#define WPA_SCAN_AUTHENTICATED BIT(4) -#define WPA_SCAN_ASSOCIATED BIT(5) - -/** - * struct wpa_scan_res - Scan result for an BSS/IBSS - * @flags: information flags about the BSS/IBSS (WPA_SCAN_*) - * @bssid: BSSID - * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1) - * @beacon_int: beacon interval in TUs (host byte order) - * @caps: capability information field in host byte order - * @qual: signal quality - * @noise: noise level - * @level: signal level - * @tsf: Timestamp - * @age: Age of the information in milliseconds (i.e., how many milliseconds - * ago the last Beacon or Probe Response frame was received) - * @ie_len: length of the following IE field in octets - * @beacon_ie_len: length of the following Beacon IE field in octets - * - * This structure is used as a generic format for scan results from the - * driver. Each driver interface implementation is responsible for converting - * the driver or OS specific scan results into this format. - * - * If the driver does not support reporting all IEs, the IE data structure is - * constructed of the IEs that are available. This field will also need to - * include SSID in IE format. All drivers are encouraged to be extended to - * report all IEs to make it easier to support future additions. - */ -struct wpa_scan_res { - unsigned int flags; - u8 bssid[ETH_ALEN]; - int freq; - u16 beacon_int; - u16 caps; - int qual; - int noise; - int level; - u64 tsf; - unsigned int age; - size_t ie_len; - size_t beacon_ie_len; - /* - * Followed by ie_len octets of IEs from Probe Response frame (or if - * the driver does not indicate source of IEs, these may also be from - * Beacon frame). After the first set of IEs, another set of IEs may - * follow (with beacon_ie_len octets of data) if the driver provides - * both IE sets. - */ -}; - -/** - * struct wpa_scan_results - Scan results - * @res: Array of pointers to allocated variable length scan result entries - * @num: Number of entries in the scan result array - * @fetch_time: Time when the results were fetched from the driver - */ -struct wpa_scan_results { - struct wpa_scan_res **res; - size_t num; - struct os_reltime fetch_time; -}; - -/** - * struct wpa_interface_info - Network interface information - * @next: Pointer to the next interface or NULL if this is the last one - * @ifname: Interface name that can be used with init() or init2() - * @desc: Human readable adapter description (e.g., vendor/model) or NULL if - * not available - * @drv_name: struct wpa_driver_ops::name (note: unlike other strings, this one - * is not an allocated copy, i.e., get_interfaces() caller will not free - * this) - */ -struct wpa_interface_info { - struct wpa_interface_info *next; - char *ifname; - char *desc; - const char *drv_name; -}; - -#define WPAS_MAX_SCAN_SSIDS 16 - -/** - * struct wpa_driver_scan_params - Scan parameters - * Data for struct wpa_driver_ops::scan2(). - */ -struct wpa_driver_scan_params { - /** - * ssids - SSIDs to scan for - */ - struct wpa_driver_scan_ssid { - /** - * ssid - specific SSID to scan for (ProbeReq) - * %NULL or zero-length SSID is used to indicate active scan - * with wildcard SSID. - */ - const u8 *ssid; - /** - * ssid_len: Length of the SSID in octets - */ - size_t ssid_len; - } ssids[WPAS_MAX_SCAN_SSIDS]; - - /** - * num_ssids - Number of entries in ssids array - * Zero indicates a request for a passive scan. - */ - size_t num_ssids; - - /** - * extra_ies - Extra IE(s) to add into Probe Request or %NULL - */ - const u8 *extra_ies; - - /** - * extra_ies_len - Length of extra_ies in octets - */ - size_t extra_ies_len; - - /** - * freqs - Array of frequencies to scan or %NULL for all frequencies - * - * The frequency is set in MHz. The array is zero-terminated. - */ - int *freqs; - - /** - * filter_ssids - Filter for reporting SSIDs - * - * This optional parameter can be used to request the driver wrapper to - * filter scan results to include only the specified SSIDs. %NULL - * indicates that no filtering is to be done. This can be used to - * reduce memory needs for scan results in environments that have large - * number of APs with different SSIDs. - * - * The driver wrapper is allowed to take this allocated buffer into its - * own use by setting the pointer to %NULL. In that case, the driver - * wrapper is responsible for freeing the buffer with os_free() once it - * is not needed anymore. - */ - struct wpa_driver_scan_filter { - u8 ssid[32]; - size_t ssid_len; - } *filter_ssids; - - /** - * num_filter_ssids - Number of entries in filter_ssids array - */ - size_t num_filter_ssids; - - /** - * filter_rssi - Filter by RSSI - * - * The driver may filter scan results in firmware to reduce host - * wakeups and thereby save power. Specify the RSSI threshold in s32 - * dBm. - */ - s32 filter_rssi; - - /** - * 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; - - /** - * only_new_results - Request driver to report only new results - * - * This is used to request the driver to report only BSSes that have - * been detected after this scan request has been started, i.e., to - * flush old cached BSS entries. - */ - int only_new_results; - - /* - * NOTE: Whenever adding new parameters here, please make sure - * wpa_scan_clone_params() and wpa_scan_free_params() get updated with - * matching changes. - */ -}; - -/** - * struct wpa_driver_auth_params - Authentication parameters - * Data for struct wpa_driver_ops::authenticate(). - */ -struct wpa_driver_auth_params { - int freq; - const u8 *bssid; - const u8 *ssid; - size_t ssid_len; - int auth_alg; - const u8 *ie; - size_t ie_len; - const u8 *wep_key[4]; - size_t wep_key_len[4]; - int wep_tx_keyidx; - int local_state_change; - - /** - * p2p - Whether this connection is a P2P group - */ - int p2p; - - const u8 *sae_data; - size_t sae_data_len; - -}; - -enum wps_mode { - WPS_MODE_NONE /* no WPS provisioning being used */, - WPS_MODE_OPEN /* WPS provisioning with AP that is in open mode */, - WPS_MODE_PRIVACY /* WPS provisioning with AP that is using protection - */ -}; - -/** - * struct wpa_driver_associate_params - Association parameters - * Data for struct wpa_driver_ops::associate(). - */ -struct wpa_driver_associate_params { - /** - * bssid - BSSID of the selected AP - * This can be %NULL, if ap_scan=2 mode is used and the driver is - * responsible for selecting with which BSS to associate. */ - const u8 *bssid; - - /** - * ssid - The selected SSID - */ - const u8 *ssid; - - /** - * ssid_len - Length of the SSID (1..32) - */ - size_t ssid_len; - - /** - * freq - Frequency of the channel the selected AP is using - * Frequency that the selected AP is using (in MHz as - * reported in the scan results) - */ - int freq; - - /** - * bg_scan_period - Background scan period in seconds, 0 to disable - * background scan, or -1 to indicate no change to default driver - * configuration - */ - int bg_scan_period; - - /** - * wpa_ie - WPA information element for (Re)Association Request - * WPA information element to be included in (Re)Association - * Request (including information element id and length). Use - * of this WPA IE is optional. If the driver generates the WPA - * IE, it can use pairwise_suite, group_suite, and - * key_mgmt_suite to select proper algorithms. In this case, - * the driver has to notify wpa_supplicant about the used WPA - * IE by generating an event that the interface code will - * convert into EVENT_ASSOCINFO data (see below). - * - * When using WPA2/IEEE 802.11i, wpa_ie is used for RSN IE - * instead. The driver can determine which version is used by - * looking at the first byte of the IE (0xdd for WPA, 0x30 for - * WPA2/RSN). - * - * When using WPS, wpa_ie is used for WPS IE instead of WPA/RSN IE. - */ - const u8 *wpa_ie; - - /** - * wpa_ie_len - length of the wpa_ie - */ - 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 (WPA_CIPHER_*) - * - * This is usually ignored if @wpa_ie is used. - */ - unsigned int pairwise_suite; - - /** - * group_suite - Selected group cipher suite (WPA_CIPHER_*) - * - * This is usually ignored if @wpa_ie is used. - */ - unsigned int group_suite; - - /** - * key_mgmt_suite - Selected key management suite (WPA_KEY_MGMT_*) - * - * This is usually ignored if @wpa_ie is used. - */ - unsigned int key_mgmt_suite; - - /** - * auth_alg - Allowed authentication algorithms - * Bit field of WPA_AUTH_ALG_* - */ - int auth_alg; - - /** - * mode - Operation mode (infra/ibss) IEEE80211_MODE_* - */ - int mode; - - /** - * wep_key - WEP keys for static WEP configuration - */ - const u8 *wep_key[4]; - - /** - * wep_key_len - WEP key length for static WEP configuration - */ - size_t wep_key_len[4]; - - /** - * wep_tx_keyidx - WEP TX key index for static WEP configuration - */ - int wep_tx_keyidx; - - /** - * mgmt_frame_protection - IEEE 802.11w management frame protection - */ - enum mfp_options mgmt_frame_protection; - - /** - * ft_ies - IEEE 802.11r / FT information elements - * If the supplicant is using IEEE 802.11r (FT) and has the needed keys - * for fast transition, this parameter is set to include the IEs that - * are to be sent in the next FT Authentication Request message. - * update_ft_ies() handler is called to update the IEs for further - * FT messages in the sequence. - * - * The driver should use these IEs only if the target AP is advertising - * the same mobility domain as the one included in the MDIE here. - * - * In ap_scan=2 mode, the driver can use these IEs when moving to a new - * AP after the initial association. These IEs can only be used if the - * target AP is advertising support for FT and is using the same MDIE - * and SSID as the current AP. - * - * The driver is responsible for reporting the FT IEs received from the - * AP's response using wpa_supplicant_event() with EVENT_FT_RESPONSE - * type. update_ft_ies() handler will then be called with the FT IEs to - * include in the next frame in the authentication sequence. - */ - const u8 *ft_ies; - - /** - * ft_ies_len - Length of ft_ies in bytes - */ - size_t ft_ies_len; - - /** - * ft_md - FT Mobility domain (6 octets) (also included inside ft_ies) - * - * This value is provided to allow the driver interface easier access - * to the current mobility domain. This value is set to %NULL if no - * mobility domain is currently active. - */ - const u8 *ft_md; - - /** - * passphrase - RSN passphrase for PSK - * - * This value is made available only for WPA/WPA2-Personal (PSK) and - * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is - * the 8..63 character ASCII passphrase, if available. Please note that - * this can be %NULL if passphrase was not used to generate the PSK. In - * that case, the psk field must be used to fetch the PSK. - */ - const char *passphrase; - - /** - * psk - RSN PSK (alternative for passphrase for PSK) - * - * This value is made available only for WPA/WPA2-Personal (PSK) and - * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is - * the 32-octet (256-bit) PSK, if available. The driver wrapper should - * be prepared to handle %NULL value as an error. - */ - const u8 *psk; - - /** - * drop_unencrypted - Enable/disable unencrypted frame filtering - * - * Configure the driver to drop all non-EAPOL frames (both receive and - * transmit paths). Unencrypted EAPOL frames (ethertype 0x888e) must - * still be allowed for key negotiation. - */ - int drop_unencrypted; - - /** - * prev_bssid - Previously used BSSID in this ESS - * - * When not %NULL, this is a request to use reassociation instead of - * association. - */ - const u8 *prev_bssid; - - /** - * wps - WPS mode - * - * If the driver needs to do special configuration for WPS association, - * this variable provides more information on what type of association - * is being requested. Most drivers should not need ot use this. - */ - enum wps_mode wps; - - /** - * p2p - Whether this connection is a P2P group - */ - int p2p; - - /** - * uapsd - UAPSD parameters for the network - * -1 = do not change defaults - * AP mode: 1 = enabled, 0 = disabled - * STA mode: bits 0..3 UAPSD enabled for VO,VI,BK,BE - */ - int uapsd; - - /** - * fixed_bssid - Whether to force this BSSID in IBSS mode - * 1 = Fix this BSSID and prevent merges. - * 0 = Do not fix BSSID. - */ - int fixed_bssid; - - /** - * disable_ht - Disable HT (IEEE 802.11n) for this connection - */ - int disable_ht; - - /** - * HT Capabilities over-rides. Only bits set in the mask will be used, - * and not all values are used by the kernel anyway. Currently, MCS, - * MPDU and MSDU fields are used. - */ - const u8 *htcaps; /* struct ieee80211_ht_capabilities * */ - const u8 *htcaps_mask; /* struct ieee80211_ht_capabilities * */ - -#ifdef CONFIG_VHT_OVERRIDES - /** - * disable_vht - Disable VHT for this connection - */ - int disable_vht; - - /** - * VHT capability overrides. - */ - const struct ieee80211_vht_capabilities *vhtcaps; - const struct ieee80211_vht_capabilities *vhtcaps_mask; -#endif /* CONFIG_VHT_OVERRIDES */ -}; - -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 - */ - u8 *head; - - /** - * head_len - Length of the head buffer in octets - */ - size_t head_len; - - /** - * tail - Beacon tail following TIM IE - */ - 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. - */ - 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; - - /** - * ap_max_inactivity - Timeout in seconds to detect STA's inactivity - * - * This is used by driver which advertises this capability. - */ - int ap_max_inactivity; - - /** - * disable_dgaf - Whether group-addressed frames are disabled - */ - int disable_dgaf; -}; - -/** - * struct wpa_driver_capa - Driver capability information - */ -struct wpa_driver_capa { -#define WPA_DRIVER_CAPA_KEY_MGMT_WPA 0x00000001 -#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2 0x00000002 -#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK 0x00000004 -#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK 0x00000008 -#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE 0x00000010 -#define WPA_DRIVER_CAPA_KEY_MGMT_FT 0x00000020 -#define WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK 0x00000040 -#define WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK 0x00000080 - unsigned int key_mgmt; - -#define WPA_DRIVER_CAPA_ENC_WEP40 0x00000001 -#define WPA_DRIVER_CAPA_ENC_WEP104 0x00000002 -#define WPA_DRIVER_CAPA_ENC_TKIP 0x00000004 -#define WPA_DRIVER_CAPA_ENC_CCMP 0x00000008 -#define WPA_DRIVER_CAPA_ENC_WEP128 0x00000010 -#define WPA_DRIVER_CAPA_ENC_GCMP 0x00000020 -#define WPA_DRIVER_CAPA_ENC_GCMP_256 0x00000040 -#define WPA_DRIVER_CAPA_ENC_CCMP_256 0x00000080 -#define WPA_DRIVER_CAPA_ENC_BIP 0x00000100 -#define WPA_DRIVER_CAPA_ENC_BIP_GMAC_128 0x00000200 -#define WPA_DRIVER_CAPA_ENC_BIP_GMAC_256 0x00000400 -#define WPA_DRIVER_CAPA_ENC_BIP_CMAC_256 0x00000800 - unsigned int enc; - -#define WPA_DRIVER_AUTH_OPEN 0x00000001 -#define WPA_DRIVER_AUTH_SHARED 0x00000002 -#define WPA_DRIVER_AUTH_LEAP 0x00000004 - unsigned int auth; - -/* Driver generated WPA/RSN IE */ -#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 -/* 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 -#define WPA_DRIVER_FLAGS_WIRED 0x00000010 -/* Driver provides separate commands for authentication and association (SME in - * wpa_supplicant). */ -#define WPA_DRIVER_FLAGS_SME 0x00000020 -/* Driver supports AP mode */ -#define WPA_DRIVER_FLAGS_AP 0x00000040 -/* Driver needs static WEP key setup after association has been completed */ -#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE 0x00000080 -/* unused: 0x00000100 */ -/* Driver supports concurrent P2P operations */ -#define WPA_DRIVER_FLAGS_P2P_CONCURRENT 0x00000200 -/* - * Driver uses the initial interface as a dedicated management interface, i.e., - * it cannot be used for P2P group operations or non-P2P purposes. - */ -#define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE 0x00000400 -/* This interface is P2P capable (P2P GO or P2P Client) */ -#define WPA_DRIVER_FLAGS_P2P_CAPABLE 0x00000800 -/* unused: 0x00001000 */ -/* - * Driver uses the initial interface for P2P management interface and non-P2P - * purposes (e.g., connect to infra AP), but this interface cannot be used for - * P2P group operations. - */ -#define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P 0x00002000 -/* - * Driver is known to use sane error codes, i.e., when it indicates that - * something (e.g., association) fails, there was indeed a failure and the - * operation does not end up getting completed successfully later. - */ -#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES 0x00004000 -/* Driver supports off-channel TX */ -#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 -/* Driver supports inactivity timer in AP mode */ -#define WPA_DRIVER_FLAGS_INACTIVITY_TIMER 0x00800000 -/* Driver expects user space implementation of MLME in AP mode */ -#define WPA_DRIVER_FLAGS_AP_MLME 0x01000000 -/* Driver supports SAE with user space SME */ -#define WPA_DRIVER_FLAGS_SAE 0x02000000 -/* Driver makes use of OBSS scan mechanism in wpa_supplicant */ -#define WPA_DRIVER_FLAGS_OBSS_SCAN 0x04000000 -/* Driver supports IBSS (Ad-hoc) mode */ -#define WPA_DRIVER_FLAGS_IBSS 0x08000000 -/* Driver supports radar detection */ -#define WPA_DRIVER_FLAGS_RADAR 0x10000000 -/* Driver supports a dedicated interface for P2P Device */ -#define WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE 0x20000000 -/* Driver supports QoS Mapping */ -#define WPA_DRIVER_FLAGS_QOS_MAPPING 0x40000000 -/* Driver supports CSA in AP mode */ -#define WPA_DRIVER_FLAGS_AP_CSA 0x80000000 - 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 - */ - unsigned int max_remain_on_chan; - - /** - * max_stations - Maximum number of associated stations the driver - * 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; - - unsigned int max_acl_mac_addrs; - - /** - * Number of supported concurrent channels - */ - unsigned int num_multichan_concurrent; - - /** - * extended_capa - extended capabilities in driver/device - * - * Must be allocated and freed by driver and the pointers must be - * valid for the lifetime of the driver, i.e., freed in deinit() - */ - const u8 *extended_capa, *extended_capa_mask; - unsigned int extended_capa_len; -}; - - -struct hostapd_data; - -struct hostap_sta_driver_data { - unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes; - unsigned long current_tx_rate; - unsigned long inactive_msec; - unsigned long flags; - unsigned long num_ps_buf_frames; - unsigned long tx_retry_failed; - unsigned long tx_retry_count; - int last_rssi; - int last_ack_rssi; -}; - -struct hostapd_sta_add_params { - 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_capabilities; - const struct ieee80211_vht_capabilities *vht_capabilities; - u32 flags; /* bitmask of WPA_STA_* flags */ - int set; /* Set STA parameters instead of add */ - u8 qosinfo; - const u8 *ext_capab; - size_t ext_capab_len; - const u8 *supp_channels; - size_t supp_channels_len; - const u8 *supp_oper_classes; - size_t supp_oper_classes_len; -}; - -struct hostapd_freq_params { - int mode; - int freq; - int channel; - /* for HT */ - int ht_enabled; - int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled, - * secondary channel below primary, 1 = HT40 - * enabled, secondary channel above primary */ - - /* for VHT */ - int vht_enabled; - - /* valid for both HT and VHT, center_freq2 is non-zero - * only for bandwidth 80 and an 80+80 channel */ - int center_freq1, center_freq2; - int bandwidth; -}; - -struct mac_address { - u8 addr[ETH_ALEN]; -}; - -struct hostapd_acl_params { - u8 acl_policy; - unsigned int num_mac_acl; - struct mac_address mac_acl[0]; -}; - -enum wpa_driver_if_type { - /** - * WPA_IF_STATION - Station mode interface - */ - WPA_IF_STATION, - - /** - * WPA_IF_AP_VLAN - AP mode VLAN interface - * - * This interface shares its address and Beacon frame with the main - * BSS. - */ - WPA_IF_AP_VLAN, - - /** - * WPA_IF_AP_BSS - AP mode BSS interface - * - * This interface has its own address and Beacon frame. - */ - WPA_IF_AP_BSS, - - /** - * WPA_IF_P2P_GO - P2P Group Owner - */ - WPA_IF_P2P_GO, - - /** - * WPA_IF_P2P_CLIENT - P2P Client - */ - WPA_IF_P2P_CLIENT, - - /** - * WPA_IF_P2P_GROUP - P2P Group interface (will become either - * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known) - */ - WPA_IF_P2P_GROUP, - - /** - * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the - * abstracted P2P Device function in the driver - */ - WPA_IF_P2P_DEVICE -}; - -struct wpa_init_params { - void *global_priv; - const u8 *bssid; - const char *ifname; - const u8 *ssid; - size_t ssid_len; - const char *test_socket; - int use_pae_group_addr; - char **bridge; - size_t num_bridge; - - u8 *own_addr; /* buffer for writing own MAC address */ -}; - - -struct wpa_bss_params { - /** Interface name (for multi-SSID/VLAN support) */ - const char *ifname; - /** Whether IEEE 802.1X or WPA/WPA2 is enabled */ - int enabled; - - int wpa; - int ieee802_1x; - int wpa_group; - int wpa_pairwise; - int wpa_key_mgmt; - int rsn_preauth; - enum mfp_options ieee80211w; -}; - -#define WPA_STA_AUTHORIZED BIT(0) -#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) - -enum tdls_oper { - TDLS_DISCOVERY_REQ, - TDLS_SETUP, - TDLS_TEARDOWN, - TDLS_ENABLE_LINK, - TDLS_DISABLE_LINK, - TDLS_ENABLE, - TDLS_DISABLE -}; - -enum wnm_oper { - WNM_SLEEP_ENTER_CONFIRM, - WNM_SLEEP_ENTER_FAIL, - WNM_SLEEP_EXIT_CONFIRM, - WNM_SLEEP_EXIT_FAIL, - WNM_SLEEP_TFS_REQ_IE_ADD, /* STA requests driver to add TFS req IE */ - WNM_SLEEP_TFS_REQ_IE_NONE, /* STA requests empty TFS req IE */ - WNM_SLEEP_TFS_REQ_IE_SET, /* AP requests driver to set TFS req IE for - * a STA */ - WNM_SLEEP_TFS_RESP_IE_ADD, /* AP requests driver to add TFS resp IE - * for a STA */ - WNM_SLEEP_TFS_RESP_IE_NONE, /* AP requests empty TFS resp IE */ - WNM_SLEEP_TFS_RESP_IE_SET, /* AP requests driver to set TFS resp IE - * for a STA */ - WNM_SLEEP_TFS_IE_DEL /* AP delete the TFS IE */ -}; - -/* enum chan_width - Channel width definitions */ -enum chan_width { - CHAN_WIDTH_20_NOHT, - CHAN_WIDTH_20, - CHAN_WIDTH_40, - CHAN_WIDTH_80, - CHAN_WIDTH_80P80, - CHAN_WIDTH_160, - CHAN_WIDTH_UNKNOWN -}; - -/** - * struct wpa_signal_info - Information about channel signal quality - */ -struct wpa_signal_info { - u32 frequency; - int above_threshold; - int current_signal; - int avg_signal; - int current_noise; - int current_txrate; - enum chan_width chanwidth; - int center_frq1; - int center_frq2; -}; - -/** - * struct beacon_data - Beacon data - * @head: Head portion of Beacon frame (before TIM IE) - * @tail: Tail portion of Beacon frame (after TIM IE) - * @beacon_ies: Extra information element(s) to add into Beacon frames or %NULL - * @proberesp_ies: Extra information element(s) to add into Probe Response - * frames or %NULL - * @assocresp_ies: Extra information element(s) to add into (Re)Association - * Response frames or %NULL - * @probe_resp: Probe Response frame template - * @head_len: Length of @head - * @tail_len: Length of @tail - * @beacon_ies_len: Length of beacon_ies in octets - * @proberesp_ies_len: Length of proberesp_ies in octets - * @proberesp_ies_len: Length of proberesp_ies in octets - * @probe_resp_len: Length of probe response template (@probe_resp) - */ -struct beacon_data { - u8 *head, *tail; - u8 *beacon_ies; - u8 *proberesp_ies; - u8 *assocresp_ies; - u8 *probe_resp; - - size_t head_len, tail_len; - size_t beacon_ies_len; - size_t proberesp_ies_len; - size_t assocresp_ies_len; - size_t probe_resp_len; -}; - -/** - * struct csa_settings - Settings for channel switch command - * @cs_count: Count in Beacon frames (TBTT) to perform the switch - * @block_tx: 1 - block transmission for CSA period - * @freq_params: Next channel frequency parameter - * @beacon_csa: Beacon/probe resp/asooc resp info for CSA period - * @beacon_after: Next beacon/probe resp/asooc resp info - * @counter_offset_beacon: Offset to the count field in beacon's tail - * @counter_offset_presp: Offset to the count field in probe resp. - */ -struct csa_settings { - u8 cs_count; - u8 block_tx; - - struct hostapd_freq_params freq_params; - struct beacon_data beacon_csa; - struct beacon_data beacon_after; - - u16 counter_offset_beacon; - u16 counter_offset_presp; -}; - -/** - * struct wpa_driver_ops - Driver interface API definition - * - * This structure defines the API that each driver interface needs to implement - * for core wpa_supplicant code. All driver specific functionality is captured - * in this wrapper. - */ -struct wpa_driver_ops { - /** Name of the driver interface */ - const char *name; - /** One line description of the driver interface */ - const char *desc; - - /** - * get_bssid - Get the current BSSID - * @priv: private driver interface data - * @bssid: buffer for BSSID (ETH_ALEN = 6 bytes) - * - * Returns: 0 on success, -1 on failure - * - * Query kernel driver for the current BSSID and copy it to bssid. - * Setting bssid to 00:00:00:00:00:00 is recommended if the STA is not - * associated. - */ - int (*get_bssid)(void *priv, u8 *bssid); - - /** - * get_ssid - Get the current SSID - * @priv: private driver interface data - * @ssid: buffer for SSID (at least 32 bytes) - * - * Returns: Length of the SSID on success, -1 on failure - * - * Query kernel driver for the current SSID and copy it to ssid. - * Returning zero is recommended if the STA is not associated. - * - * Note: SSID is an array of octets, i.e., it is not nul terminated and - * can, at least in theory, contain control characters (including nul) - * and as such, should be processed as binary data, not a printable - * string. - */ - int (*get_ssid)(void *priv, u8 *ssid); - - /** - * set_key - Configure encryption key - * @ifname: Interface name (for multi-SSID/VLAN support) - * @priv: private driver interface data - * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, - * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK, - * %WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256, - * %WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256, - * %WPA_ALG_BIP_CMAC_256); - * %WPA_ALG_NONE clears the key. - * @addr: Address of the peer STA (BSSID of the current AP when setting - * pairwise key in station mode), ff:ff:ff:ff:ff:ff for - * broadcast keys, %NULL for default keys that are used both for - * broadcast and unicast; when clearing keys, %NULL is used to - * indicate that both the broadcast-only and default key of the - * specified key index is to be cleared - * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for - * IGTK - * @set_tx: configure this key as the default Tx key (only used when - * driver does not support separate unicast/individual key - * @seq: sequence number/packet number, seq_len octets, the next - * packet number to be used for in replay protection; configured - * for Rx keys (in most cases, this is only used with broadcast - * keys and set to zero for unicast keys); %NULL if not set - * @seq_len: length of the seq, depends on the algorithm: - * TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets - * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, - * 8-byte Rx Mic Key - * @key_len: length of the key buffer in octets (WEP: 5 or 13, - * TKIP: 32, CCMP/GCMP: 16, IGTK: 16) - * - * Returns: 0 on success, -1 on failure - * - * Configure the given key for the kernel driver. If the driver - * supports separate individual keys (4 default keys + 1 individual), - * addr can be used to determine whether the key is default or - * individual. If only 4 keys are supported, the default key with key - * index 0 is used as the individual key. STA must be configured to use - * it as the default Tx key (set_tx is set) and accept Rx for all the - * key indexes. In most cases, WPA uses only key indexes 1 and 2 for - * broadcast keys, so key index 0 is available for this kind of - * configuration. - * - * Please note that TKIP keys include separate TX and RX MIC keys and - * some drivers may expect them in different order than wpa_supplicant - * is using. If the TX/RX keys are swapped, all TKIP encrypted packets - * will trigger Michael MIC errors. This can be fixed by changing the - * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key - * in driver_*.c set_key() implementation, see driver_ndis.c for an - * example on how this can be done. - */ - int (*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); - - /** - * init - Initialize driver interface - * @ctx: context to be used when calling wpa_supplicant functions, - * e.g., wpa_supplicant_event() - * @ifname: interface name, e.g., wlan0 - * - * Returns: Pointer to private data, %NULL on failure - * - * Initialize driver interface, including event processing for kernel - * driver events (e.g., associated, scan results, Michael MIC failure). - * This function can allocate a private configuration data area for - * @ctx, file descriptor, interface name, etc. information that may be - * needed in future driver operations. If this is not used, non-NULL - * value will need to be returned because %NULL is used to indicate - * failure. The returned value will be used as 'void *priv' data for - * all other driver_ops functions. - * - * The main event loop (eloop.c) of wpa_supplicant can be used to - * register callback for read sockets (eloop_register_read_sock()). - * - * See below for more information about events and - * wpa_supplicant_event() function. - */ - void * (*init)(void *ctx, const char *ifname); - - /** - * deinit - Deinitialize driver interface - * @priv: private driver interface data from init() - * - * Shut down driver interface and processing of driver events. Free - * private data buffer if one was allocated in init() handler. - */ - void (*deinit)(void *priv); - - /** - * set_param - Set driver configuration parameters - * @priv: private driver interface data from init() - * @param: driver specific configuration parameters - * - * Returns: 0 on success, -1 on failure - * - * Optional handler for notifying driver interface about configuration - * parameters (driver_param). - */ - int (*set_param)(void *priv, const char *param); - - /** - * set_countermeasures - Enable/disable TKIP countermeasures - * @priv: private driver interface data - * @enabled: 1 = countermeasures enabled, 0 = disabled - * - * Returns: 0 on success, -1 on failure - * - * Configure TKIP countermeasures. When these are enabled, the driver - * should drop all received and queued frames that are using TKIP. - */ - int (*set_countermeasures)(void *priv, int enabled); - - /** - * deauthenticate - Request driver to deauthenticate - * @priv: private driver interface data - * @addr: peer address (BSSID of the AP) - * @reason_code: 16-bit reason code to be sent in the deauthentication - * frame - * - * Returns: 0 on success, -1 on failure - */ - int (*deauthenticate)(void *priv, const u8 *addr, int reason_code); - - /** - * associate - Request driver to associate - * @priv: private driver interface data - * @params: association parameters - * - * Returns: 0 on success, -1 on failure - */ - int (*associate)(void *priv, - struct wpa_driver_associate_params *params); - - /** - * add_pmkid - Add PMKSA cache entry to the driver - * @priv: private driver interface data - * @bssid: BSSID for the PMKSA cache entry - * @pmkid: PMKID for the PMKSA cache entry - * - * Returns: 0 on success, -1 on failure - * - * This function is called when a new PMK is received, as a result of - * either normal authentication or RSN pre-authentication. - * - * If the driver generates RSN IE, i.e., it does not use wpa_ie in - * associate(), add_pmkid() can be used to add new PMKSA cache entries - * in the driver. If the driver uses wpa_ie from wpa_supplicant, this - * driver_ops function does not need to be implemented. Likewise, if - * the driver does not support WPA, this function is not needed. - */ - int (*add_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid); - - /** - * remove_pmkid - Remove PMKSA cache entry to the driver - * @priv: private driver interface data - * @bssid: BSSID for the PMKSA cache entry - * @pmkid: PMKID for the PMKSA cache entry - * - * Returns: 0 on success, -1 on failure - * - * This function is called when the supplicant drops a PMKSA cache - * entry for any reason. - * - * If the driver generates RSN IE, i.e., it does not use wpa_ie in - * associate(), remove_pmkid() can be used to synchronize PMKSA caches - * between the driver and wpa_supplicant. If the driver uses wpa_ie - * from wpa_supplicant, this driver_ops function does not need to be - * implemented. Likewise, if the driver does not support WPA, this - * function is not needed. - */ - int (*remove_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid); - - /** - * flush_pmkid - Flush PMKSA cache - * @priv: private driver interface data - * - * Returns: 0 on success, -1 on failure - * - * This function is called when the supplicant drops all PMKSA cache - * entries for any reason. - * - * If the driver generates RSN IE, i.e., it does not use wpa_ie in - * associate(), remove_pmkid() can be used to synchronize PMKSA caches - * between the driver and wpa_supplicant. If the driver uses wpa_ie - * from wpa_supplicant, this driver_ops function does not need to be - * implemented. Likewise, if the driver does not support WPA, this - * function is not needed. - */ - int (*flush_pmkid)(void *priv); - - /** - * get_capa - Get driver capabilities - * @priv: private driver interface data - * - * Returns: 0 on success, -1 on failure - * - * Get driver/firmware/hardware capabilities. - */ - int (*get_capa)(void *priv, struct wpa_driver_capa *capa); - - /** - * poll - Poll driver for association information - * @priv: private driver interface data - * - * This is an option callback that can be used when the driver does not - * provide event mechanism for association events. This is called when - * receiving WPA EAPOL-Key messages that require association - * information. The driver interface is supposed to generate associnfo - * event before returning from this callback function. In addition, the - * driver interface should generate an association event after having - * sent out associnfo. - */ - void (*poll)(void *priv); - - /** - * get_ifname - Get interface name - * @priv: private driver interface data - * - * Returns: Pointer to the interface name. This can differ from the - * interface name used in init() call. Init() is called first. - * - * This optional function can be used to allow the driver interface to - * replace the interface name with something else, e.g., based on an - * interface mapping from a more descriptive name. - */ - const char * (*get_ifname)(void *priv); - - /** - * get_mac_addr - Get own MAC address - * @priv: private driver interface data - * - * Returns: Pointer to own MAC address or %NULL on failure - * - * This optional function can be used to get the own MAC address of the - * device from the driver interface code. This is only needed if the - * l2_packet implementation for the OS does not provide easy access to - * a MAC address. */ - const u8 * (*get_mac_addr)(void *priv); - - /** - * send_eapol - Optional function for sending EAPOL packets - * @priv: private driver interface data - * @dest: Destination MAC address - * @proto: Ethertype - * @data: EAPOL packet starting with IEEE 802.1X header - * @data_len: Size of the EAPOL packet - * - * Returns: 0 on success, -1 on failure - * - * This optional function can be used to override l2_packet operations - * with driver specific functionality. If this function pointer is set, - * l2_packet module is not used at all and the driver interface code is - * responsible for receiving and sending all EAPOL packets. The - * received EAPOL packets are sent to core code with EVENT_EAPOL_RX - * event. The driver interface is required to implement get_mac_addr() - * handler if send_eapol() is used. - */ - int (*send_eapol)(void *priv, const u8 *dest, u16 proto, - const u8 *data, size_t data_len); - - /** - * set_operstate - Sets device operating state to DORMANT or UP - * @priv: private driver interface data - * @state: 0 = dormant, 1 = up - * Returns: 0 on success, -1 on failure - * - * This is an optional function that can be used on operating systems - * that support a concept of controlling network device state from user - * space applications. This function, if set, gets called with - * state = 1 when authentication has been completed and with state = 0 - * when connection is lost. - */ - int (*set_operstate)(void *priv, int state); - - /** - * mlme_setprotection - MLME-SETPROTECTION.request primitive - * @priv: Private driver interface data - * @addr: Address of the station for which to set protection (may be - * %NULL for group keys) - * @protect_type: MLME_SETPROTECTION_PROTECT_TYPE_* - * @key_type: MLME_SETPROTECTION_KEY_TYPE_* - * Returns: 0 on success, -1 on failure - * - * This is an optional function that can be used to set the driver to - * require protection for Tx and/or Rx frames. This uses the layer - * interface defined in IEEE 802.11i-2004 clause 10.3.22.1 - * (MLME-SETPROTECTION.request). Many drivers do not use explicit - * set protection operation; instead, they set protection implicitly - * based on configured keys. - */ - int (*mlme_setprotection)(void *priv, const u8 *addr, int protect_type, - int key_type); - - /** - * get_hw_feature_data - Get hardware support data (channels and rates) - * @priv: Private driver interface data - * @num_modes: Variable for returning the number of returned modes - * 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. - */ - struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv, - u16 *num_modes, - u16 *flags); - - /** - * 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 - */ - int (*send_mlme)(void *priv, const u8 *data, size_t data_len, - int noack); - - /** - * update_ft_ies - Update FT (IEEE 802.11r) IEs - * @priv: Private driver interface data - * @md: Mobility domain (2 octets) (also included inside ies) - * @ies: FT IEs (MDIE, FTIE, ...) or %NULL to remove IEs - * @ies_len: Length of FT IEs in bytes - * Returns: 0 on success, -1 on failure - * - * The supplicant uses this callback to let the driver know that keying - * material for FT is available and that the driver can use the - * provided IEs in the next message in FT authentication sequence. - * - * This function is only needed for driver that support IEEE 802.11r - * (Fast BSS Transition). - */ - int (*update_ft_ies)(void *priv, const u8 *md, const u8 *ies, - size_t ies_len); - - /** - * send_ft_action - Send FT Action frame (IEEE 802.11r) - * @priv: Private driver interface data - * @action: Action field value - * @target_ap: Target AP address - * @ies: FT IEs (MDIE, FTIE, ...) (FT Request action frame body) - * @ies_len: Length of FT IEs in bytes - * Returns: 0 on success, -1 on failure - * - * The supplicant uses this callback to request the driver to transmit - * an FT Action frame (action category 6) for over-the-DS fast BSS - * transition. - */ - int (*send_ft_action)(void *priv, u8 action, const u8 *target_ap, - const u8 *ies, size_t ies_len); - - /** - * get_scan_results2 - Fetch the latest scan results - * @priv: private driver interface data - * - * Returns: Allocated buffer of scan results (caller is responsible for - * freeing the data structure) on success, NULL on failure - */ - struct wpa_scan_results * (*get_scan_results2)(void *priv); - - /** - * set_country - Set country - * @priv: Private driver interface data - * @alpha2: country to which to switch to - * Returns: 0 on success, -1 on failure - * - * This function is for drivers which support some form - * of setting a regulatory domain. - */ - int (*set_country)(void *priv, const char *alpha2); - - /** - * get_country - Get country - * @priv: Private driver interface data - * @alpha2: Buffer for returning country code (at least 3 octets) - * Returns: 0 on success, -1 on failure - */ - int (*get_country)(void *priv, char *alpha2); - - /** - * global_init - Global driver initialization - * Returns: Pointer to private data (global), %NULL on failure - * - * This optional function is called to initialize the driver wrapper - * for global data, i.e., data that applies to all interfaces. If this - * function is implemented, global_deinit() will also need to be - * implemented to free the private data. The driver will also likely - * use init2() function instead of init() to get the pointer to global - * data available to per-interface initializer. - */ - void * (*global_init)(void); - - /** - * global_deinit - Global driver deinitialization - * @priv: private driver global data from global_init() - * - * Terminate any global driver related functionality and free the - * global data structure. - */ - void (*global_deinit)(void *priv); - - /** - * init2 - Initialize driver interface (with global data) - * @ctx: context to be used when calling wpa_supplicant functions, - * e.g., wpa_supplicant_event() - * @ifname: interface name, e.g., wlan0 - * @global_priv: private driver global data from global_init() - * Returns: Pointer to private data, %NULL on failure - * - * This function can be used instead of init() if the driver wrapper - * uses global data. - */ - void * (*init2)(void *ctx, const char *ifname, void *global_priv); - - /** - * get_interfaces - Get information about available interfaces - * @global_priv: private driver global data from global_init() - * Returns: Allocated buffer of interface information (caller is - * responsible for freeing the data structure) on success, NULL on - * failure - */ - struct wpa_interface_info * (*get_interfaces)(void *global_priv); - - /** - * scan2 - Request the driver to initiate scan - * @priv: private driver interface data - * @params: Scan parameters - * - * Returns: 0 on success, -1 on failure - * - * Once the scan results are ready, the driver should report scan - * results event for wpa_supplicant which will eventually request the - * results with wpa_driver_get_scan_results2(). - */ - int (*scan2)(void *priv, struct wpa_driver_scan_params *params); - - /** - * authenticate - Request driver to authenticate - * @priv: private driver interface data - * @params: authentication parameters - * Returns: 0 on success, -1 on failure - * - * This is an optional function that can be used with drivers that - * support separate authentication and association steps, i.e., when - * wpa_supplicant can act as the SME. If not implemented, associate() - * function is expected to take care of IEEE 802.11 authentication, - * too. - */ - int (*authenticate)(void *priv, - struct wpa_driver_auth_params *params); - - /** - * set_ap - Set Beacon and Probe Response information for AP mode - * @priv: Private driver interface data - * @params: Parameters to use in AP mode - * - * 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. 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_ap)(void *priv, struct wpa_driver_ap_params *params); - - /** - * set_acl - Set ACL in AP mode - * @priv: Private driver interface data - * @params: Parameters to configure ACL - * Returns: 0 on success, -1 on failure - * - * This is used only for the drivers which support MAC address ACL. - */ - int (*set_acl)(void *priv, struct hostapd_acl_params *params); - - /** - * hapd_init - Initialize driver interface (hostapd only) - * @hapd: Pointer to hostapd context - * @params: Configuration for the driver wrapper - * Returns: Pointer to private data, %NULL on failure - * - * This function is used instead of init() or init2() when the driver - * wrapper is used with hostapd. - */ - void * (*hapd_init)(struct hostapd_data *hapd, - struct wpa_init_params *params); - - /** - * hapd_deinit - Deinitialize driver interface (hostapd only) - * @priv: Private driver interface data from hapd_init() - */ - void (*hapd_deinit)(void *priv); - - /** - * set_ieee8021x - Enable/disable IEEE 802.1X support (AP only) - * @priv: Private driver interface data - * @params: BSS parameters - * Returns: 0 on success, -1 on failure - * - * 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_ap() to set WPA/RSN IE - * for Beacon frames. - * - * DEPRECATED - use set_ap() instead - */ - int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params); - - /** - * set_privacy - Enable/disable privacy (AP only) - * @priv: Private driver interface data - * @enabled: 1 = privacy enabled, 0 = disabled - * Returns: 0 on success, -1 on failure - * - * 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_ap(). - * - * DEPRECATED - use set_ap() instead - */ - int (*set_privacy)(void *priv, int enabled); - - /** - * get_seqnum - Fetch the current TSC/packet number (AP only) - * @ifname: The interface name (main or virtual) - * @priv: Private driver interface data - * @addr: MAC address of the station or %NULL for group keys - * @idx: Key index - * @seq: Buffer for returning the latest used TSC/packet number - * Returns: 0 on success, -1 on failure - * - * This function is used to fetch the last used TSC/packet number for - * a TKIP, CCMP, GCMP, or BIP/IGTK key. It is mainly used with group - * keys, so there is no strict requirement on implementing support for - * unicast keys (i.e., addr != %NULL). - */ - int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr, - int idx, u8 *seq); - - /** - * flush - Flush all association stations (AP only) - * @priv: Private driver interface data - * Returns: 0 on success, -1 on failure - * - * This function requests the driver to disassociate all associated - * stations. This function does not need to be implemented if the - * driver does not process association frames internally. - */ - int (*flush)(void *priv); - - /** - * set_generic_elem - Add IEs into Beacon/Probe Response frames (AP) - * @priv: Private driver interface data - * @elem: Information elements - * @elem_len: Length of the elem buffer in octets - * Returns: 0 on success, -1 on failure - * - * 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_ap(). - * - * DEPRECATED - use set_ap() instead - */ - int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len); - - /** - * read_sta_data - Fetch station data - * @priv: Private driver interface data - * @data: Buffer for returning station information - * @addr: MAC address of the station - * Returns: 0 on success, -1 on failure - */ - int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data, - const u8 *addr); - - /** - * hapd_send_eapol - Send an EAPOL packet (AP only) - * @priv: private driver interface data - * @addr: Destination MAC address - * @data: EAPOL packet starting with IEEE 802.1X header - * @data_len: Length of the EAPOL packet in octets - * @encrypt: Whether the frame should be encrypted - * @own_addr: Source MAC address - * @flags: WPA_STA_* flags for the destination station - * - * Returns: 0 on success, -1 on failure - */ - int (*hapd_send_eapol)(void *priv, const u8 *addr, const u8 *data, - size_t data_len, int encrypt, - const u8 *own_addr, u32 flags); - - /** - * sta_deauth - Deauthenticate a station (AP only) - * @priv: Private driver interface data - * @own_addr: Source address and BSSID for the Deauthentication frame - * @addr: MAC address of the station to deauthenticate - * @reason: Reason code for the Deauthentiation frame - * Returns: 0 on success, -1 on failure - * - * This function requests a specific station to be deauthenticated and - * a Deauthentication frame to be sent to it. - */ - int (*sta_deauth)(void *priv, const u8 *own_addr, const u8 *addr, - int reason); - - /** - * sta_disassoc - Disassociate a station (AP only) - * @priv: Private driver interface data - * @own_addr: Source address and BSSID for the Disassociation frame - * @addr: MAC address of the station to disassociate - * @reason: Reason code for the Disassociation frame - * Returns: 0 on success, -1 on failure - * - * This function requests a specific station to be disassociated and - * a Disassociation frame to be sent to it. - */ - int (*sta_disassoc)(void *priv, const u8 *own_addr, const u8 *addr, - int reason); - - /** - * sta_remove - Remove a station entry (AP only) - * @priv: Private driver interface data - * @addr: MAC address of the station to be removed - * Returns: 0 on success, -1 on failure - */ - int (*sta_remove)(void *priv, const u8 *addr); - - /** - * hapd_get_ssid - Get the current SSID (AP only) - * @priv: Private driver interface data - * @buf: Buffer for returning the SSID - * @len: Maximum length of the buffer - * Returns: Length of the SSID on success, -1 on failure - * - * This function need not be implemented if the driver uses Beacon - * template from set_ap() and does not reply to Probe Request frames. - */ - int (*hapd_get_ssid)(void *priv, u8 *buf, int len); - - /** - * hapd_set_ssid - Set SSID (AP only) - * @priv: Private driver interface data - * @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); - - /** - * hapd_set_countermeasures - Enable/disable TKIP countermeasures (AP) - * @priv: Private driver interface data - * @enabled: 1 = countermeasures enabled, 0 = disabled - * Returns: 0 on success, -1 on failure - * - * This need not be implemented if the driver does not take care of - * association processing. - */ - int (*hapd_set_countermeasures)(void *priv, int enabled); - - /** - * sta_add - Add a station entry - * @priv: Private driver interface data - * @params: Station parameters - * Returns: 0 on success, -1 on failure - * - * 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); - - /** - * get_inact_sec - Get station inactivity duration (AP only) - * @priv: Private driver interface data - * @addr: Station address - * Returns: Number of seconds station has been inactive, -1 on failure - */ - int (*get_inact_sec)(void *priv, const u8 *addr); - - /** - * sta_clear_stats - Clear station statistics (AP only) - * @priv: Private driver interface data - * @addr: Station address - * Returns: 0 on success, -1 on failure - */ - int (*sta_clear_stats)(void *priv, const u8 *addr); - - /** - * set_freq - Set channel/frequency (AP only) - * @priv: Private driver interface data - * @freq: Channel parameters - * Returns: 0 on success, -1 on failure - */ - int (*set_freq)(void *priv, struct hostapd_freq_params *freq); - - /** - * set_rts - Set RTS threshold - * @priv: Private driver interface data - * @rts: RTS threshold in octets - * Returns: 0 on success, -1 on failure - */ - int (*set_rts)(void *priv, int rts); - - /** - * set_frag - Set fragmentation threshold - * @priv: Private driver interface data - * @frag: Fragmentation threshold in octets - * Returns: 0 on success, -1 on failure - */ - int (*set_frag)(void *priv, int frag); - - /** - * sta_set_flags - Set station flags (AP only) - * @priv: Private driver interface data - * @addr: Station address - * @total_flags: Bitmap of all WPA_STA_* flags currently set - * @flags_or: Bitmap of WPA_STA_* flags to add - * @flags_and: Bitmap of WPA_STA_* flags to us as a mask - * Returns: 0 on success, -1 on failure - */ - int (*sta_set_flags)(void *priv, const u8 *addr, - int total_flags, int flags_or, int flags_and); - - /** - * set_tx_queue_params - Set TX queue parameters - * @priv: Private driver interface data - * @queue: Queue number (0 = VO, 1 = VI, 2 = BE, 3 = BK) - * @aifs: AIFS - * @cw_min: cwMin - * @cw_max: cwMax - * @burst_time: Maximum length for bursting in 0.1 msec units - */ - int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min, - int cw_max, int burst_time); - - /** - * if_add - Add a virtual interface - * @priv: Private driver interface data - * @type: Interface type - * @ifname: Interface name for the new virtual interface - * @addr: Local address to use for the interface or %NULL to use the - * parent interface address - * @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces - * @drv_priv: Pointer for overwriting the driver context or %NULL if - * not allowed (applies only to %WPA_IF_AP_BSS type) - * @force_ifname: Buffer for returning an interface name that the - * driver ended up using if it differs from the requested ifname - * @if_addr: Buffer for returning the allocated interface address - * (this may differ from the requested addr if the driver cannot - * change interface address) - * @bridge: Bridge interface to use or %NULL if no bridge configured - * @use_existing: Whether to allow existing interface to be used - * Returns: 0 on success, -1 on failure - */ - int (*if_add)(void *priv, enum wpa_driver_if_type type, - const char *ifname, const u8 *addr, void *bss_ctx, - void **drv_priv, char *force_ifname, u8 *if_addr, - const char *bridge, int use_existing); - - /** - * if_remove - Remove a virtual interface - * @priv: Private driver interface data - * @type: Interface type - * @ifname: Interface name of the virtual interface to be removed - * Returns: 0 on success, -1 on failure - */ - int (*if_remove)(void *priv, enum wpa_driver_if_type type, - const char *ifname); - - /** - * set_sta_vlan - Bind a station into a specific interface (AP only) - * @priv: Private driver interface data - * @ifname: Interface (main or virtual BSS or VLAN) - * @addr: MAC address of the associated station - * @vlan_id: VLAN ID - * Returns: 0 on success, -1 on failure - * - * This function is used to bind a station to a specific virtual - * interface. It is only used if when virtual interfaces are supported, - * e.g., to assign stations to different VLAN interfaces based on - * information from a RADIUS server. This allows separate broadcast - * domains to be used with a single BSS. - */ - int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname, - int vlan_id); - - /** - * commit - Optional commit changes handler (AP only) - * @priv: driver private data - * Returns: 0 on success, -1 on failure - * - * This optional handler function can be registered if the driver - * interface implementation needs to commit changes (e.g., by setting - * network interface up) at the end of initial configuration. If set, - * this handler will be called after initial setup has been completed. - */ - int (*commit)(void *priv); - - /** - * send_ether - Send an ethernet packet (AP only) - * @priv: private driver interface data - * @dst: Destination MAC address - * @src: Source MAC address - * @proto: Ethertype - * @data: EAPOL packet starting with IEEE 802.1X header - * @data_len: Length of the EAPOL packet in octets - * Returns: 0 on success, -1 on failure - */ - int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto, - const u8 *data, size_t data_len); - - /** - * set_radius_acl_auth - Notification of RADIUS ACL change - * @priv: Private driver interface data - * @mac: MAC address of the station - * @accepted: Whether the station was accepted - * @session_timeout: Session timeout for the station - * Returns: 0 on success, -1 on failure - */ - int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted, - u32 session_timeout); - - /** - * set_radius_acl_expire - Notification of RADIUS ACL expiration - * @priv: Private driver interface data - * @mac: MAC address of the station - * Returns: 0 on success, -1 on failure - */ - int (*set_radius_acl_expire)(void *priv, const u8 *mac); - - /** - * 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) - * @proberesp: WPS IE(s) for Probe Response frames or %NULL to remove - * extra IE(s) - * @assocresp: WPS IE(s) for (Re)Association Response frames or %NULL - * to remove extra IE(s) - * Returns: 0 on success, -1 on failure - * - * 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_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 - * whenever a (Re)Association Request frame indicated use of WPS. - * - * This will also be used to add P2P IE(s) into Beacon/Probe Response - * frames when operating as a GO. The driver is responsible for adding - * timing related attributes (e.g., NoA) in addition to the IEs - * included here by appending them after these buffers. This call is - * 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, - const struct wpabuf *assocresp); - - /** - * set_supp_port - Set IEEE 802.1X Supplicant Port status - * @priv: Private driver interface data - * @authorized: Whether the port is authorized - * Returns: 0 on success, -1 on failure - */ - int (*set_supp_port)(void *priv, int authorized); - - /** - * set_wds_sta - Bind a station into a 4-address WDS (AP only) - * @priv: Private driver interface data - * @addr: MAC address of the associated station - * @aid: Association ID - * @val: 1 = bind to 4-address WDS; 0 = unbind - * @bridge_ifname: Bridge interface to use for the WDS station or %NULL - * to indicate that bridge is not to be used - * @ifname_wds: Buffer to return the interface name for the new WDS - * station or %NULL to indicate name is not returned. - * Returns: 0 on success, -1 on failure - */ - int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val, - const char *bridge_ifname, char *ifname_wds); - - /** - * send_action - Transmit an Action frame - * @priv: Private driver interface data - * @freq: Frequency (in MHz) of the channel - * @wait: Time to wait off-channel for a response (in ms), or zero - * @dst: Destination MAC address (Address 1) - * @src: Source MAC address (Address 2) - * @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 - * frame to the specified destination. - * - * If the %WPA_DRIVER_FLAGS_OFFCHANNEL_TX flag is set, the frame will - * be transmitted on the given channel and the device will wait for a - * response on that channel for the given wait time. - * - * If the flag is not set, the wait time will be ignored. In this case, - * if a remain-on-channel duration is in progress, the frame must be - * transmitted on that channel; alternatively the frame may be sent on - * the current operational channel (if in associated state in station - * mode or while operating as an AP.) - */ - 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, int no_cck); - - /** - * send_action_cancel_wait - Cancel action frame TX wait - * @priv: Private driver interface data - * - * This command cancels the wait time associated with sending an action - * frame. It is only available when %WPA_DRIVER_FLAGS_OFFCHANNEL_TX is - * set in the driver flags. - */ - void (*send_action_cancel_wait)(void *priv); - - /** - * remain_on_channel - Remain awake on a channel - * @priv: Private driver interface data - * @freq: Frequency (in MHz) of the channel - * @duration: Duration in milliseconds - * Returns: 0 on success, -1 on failure - * - * This command is used to request the driver to remain awake on the - * specified channel for the specified duration and report received - * Action frames with EVENT_RX_MGMT events. Optionally, received - * Probe Request frames may also be requested to be reported by calling - * probe_req_report(). These will be reported with EVENT_RX_PROBE_REQ. - * - * The driver may not be at the requested channel when this function - * returns, i.e., the return code is only indicating whether the - * request was accepted. The caller will need to wait until the - * EVENT_REMAIN_ON_CHANNEL event indicates that the driver has - * completed the channel change. This may take some time due to other - * need for the radio and the caller should be prepared to timing out - * its wait since there are no guarantees on when this request can be - * executed. - */ - int (*remain_on_channel)(void *priv, unsigned int freq, - unsigned int duration); - - /** - * cancel_remain_on_channel - Cancel remain-on-channel operation - * @priv: Private driver interface data - * - * This command can be used to cancel a remain-on-channel operation - * before its originally requested duration has passed. This could be - * used, e.g., when remain_on_channel() is used to request extra time - * to receive a response to an Action frame and the response is - * received when there is still unneeded time remaining on the - * remain-on-channel operation. - */ - int (*cancel_remain_on_channel)(void *priv); - - /** - * probe_req_report - Request Probe Request frames to be indicated - * @priv: Private driver interface data - * @report: Whether to report received Probe Request frames - * Returns: 0 on success, -1 on failure (or if not supported) - * - * This command can be used to request the driver to indicate when - * Probe Request frames are received with EVENT_RX_PROBE_REQ events. - * Since this operation may require extra resources, e.g., due to less - * optimal hardware/firmware RX filtering, many drivers may disable - * Probe Request reporting at least in station mode. This command is - * used to notify the driver when the Probe Request frames need to be - * reported, e.g., during remain-on-channel operations. - */ - int (*probe_req_report)(void *priv, int report); - - /** - * deinit_ap - Deinitialize AP mode - * @priv: Private driver interface data - * Returns: 0 on success, -1 on failure (or if not supported) - * - * This optional function can be used to disable AP mode related - * configuration. If the interface was not dynamically added, - * change the driver mode to station mode to allow normal station - * operations like scanning to be completed. - */ - int (*deinit_ap)(void *priv); - - /** - * deinit_p2p_cli - Deinitialize P2P client mode - * @priv: Private driver interface data - * Returns: 0 on success, -1 on failure (or if not supported) - * - * This optional function can be used to disable P2P client mode. If the - * interface was not dynamically added, change the interface type back - * to station mode. - */ - int (*deinit_p2p_cli)(void *priv); - - /** - * suspend - Notification on system suspend/hibernate event - * @priv: Private driver interface data - */ - void (*suspend)(void *priv); - - /** - * resume - Notification on system resume/thaw event - * @priv: Private driver interface data - */ - void (*resume)(void *priv); - - /** - * signal_monitor - Set signal monitoring parameters - * @priv: Private driver interface data - * @threshold: Threshold value for signal change events; 0 = disabled - * @hysteresis: Minimum change in signal strength before indicating a - * new event - * Returns: 0 on success, -1 on failure (or if not supported) - * - * This function can be used to configure monitoring of signal strength - * with the current AP. Whenever signal strength drops below the - * %threshold value or increases above it, EVENT_SIGNAL_CHANGE event - * should be generated assuming the signal strength has changed at - * least %hysteresis from the previously indicated signal change event. - */ - int (*signal_monitor)(void *priv, int threshold, int hysteresis); - - /** - * send_frame - Send IEEE 802.11 frame (testing use only) - * @priv: Private driver interface data - * @data: IEEE 802.11 frame with IEEE 802.11 header - * @data_len: Size of the frame - * @encrypt: Whether to encrypt the frame (if keys are set) - * Returns: 0 on success, -1 on failure - * - * This function is only used for debugging purposes and is not - * required to be implemented for normal operations. - */ - int (*send_frame)(void *priv, const u8 *data, size_t data_len, - int encrypt); - - /** - * shared_freq - Get operating frequency of shared interface(s) - * @priv: Private driver interface data - * Returns: Operating frequency in MHz, 0 if no shared operation in - * use, or -1 on failure - * - * This command can be used to request the current operating frequency - * of any virtual interface that shares the same radio to provide - * information for channel selection for other virtual interfaces. - */ - int (*shared_freq)(void *priv); - - /** - * get_noa - Get current Notice of Absence attribute payload - * @priv: Private driver interface data - * @buf: Buffer for returning NoA - * @buf_len: Buffer length in octets - * Returns: Number of octets used in buf, 0 to indicate no NoA is being - * advertized, or -1 on failure - * - * This function is used to fetch the current Notice of Absence - * attribute value from GO. - */ - int (*get_noa)(void *priv, u8 *buf, size_t buf_len); - - /** - * set_noa - Set Notice of Absence parameters for GO (testing) - * @priv: Private driver interface data - * @count: Count - * @start: Start time in ms from next TBTT - * @duration: Duration in ms - * Returns: 0 on success or -1 on failure - * - * This function is used to set Notice of Absence parameters for GO. It - * is used only for testing. To disable NoA, all parameters are set to - * 0. - */ - int (*set_noa)(void *priv, u8 count, int start, int duration); - - /** - * set_p2p_powersave - Set P2P power save options - * @priv: Private driver interface data - * @legacy_ps: 0 = disable, 1 = enable, 2 = maximum PS, -1 = no change - * @opp_ps: 0 = disable, 1 = enable, -1 = no change - * @ctwindow: 0.. = change (msec), -1 = no change - * Returns: 0 on success or -1 on failure - */ - int (*set_p2p_powersave)(void *priv, int legacy_ps, int opp_ps, - int ctwindow); - - /** - * ampdu - Enable/disable aggregation - * @priv: Private driver interface data - * @ampdu: 1/0 = enable/disable A-MPDU aggregation - * Returns: 0 on success or -1 on failure - */ - int (*ampdu)(void *priv, int ampdu); - - /** - * get_radio_name - Get physical radio name for the device - * @priv: Private driver interface data - * Returns: Radio name or %NULL if not known - * - * The returned data must not be modified by the caller. It is assumed - * that any interface that has the same radio name as another is - * sharing the same physical radio. This information can be used to - * share scan results etc. information between the virtual interfaces - * to speed up various operations. - */ - const char * (*get_radio_name)(void *priv); - - /** - * send_tdls_mgmt - for sending TDLS management packets - * @priv: private driver interface data - * @dst: Destination (peer) MAC address - * @action_code: TDLS action code for the mssage - * @dialog_token: Dialog Token to use in the message (if needed) - * @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, 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. - */ - int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code, - 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); - - /** - * wnm_oper - Notify driver of the WNM frame reception - * @priv: Private driver interface data - * @oper: WNM operation. See %enum wnm_oper - * @peer: Destination (peer) MAC address - * @buf: Buffer for the driver to fill in (for getting IE) - * @buf_len: Return the len of buf - * Returns: 0 on success, negative (<0) on failure - */ - int (*wnm_oper)(void *priv, enum wnm_oper oper, const u8 *peer, - u8 *buf, u16 *buf_len); - - /** - * set_qos_map - Set QoS Map - * @priv: Private driver interface data - * @qos_map_set: QoS Map - * @qos_map_set_len: Length of QoS Map - */ - int (*set_qos_map)(void *priv, const u8 *qos_map_set, - u8 qos_map_set_len); - - /** - * signal_poll - Get current connection information - * @priv: Private driver interface data - * @signal_info: Connection info structure - */ - int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info); - - /** - * set_authmode - Set authentication algorithm(s) for static WEP - * @priv: Private driver interface data - * @authmode: 1=Open System, 2=Shared Key, 3=both - * Returns: 0 on success, -1 on failure - * - * 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 - * @cmd: Command to execute - * @buf: Return buffer - * @buf_len: Buffer length - * Returns: 0 on success, -1 on failure - */ - int (*driver_cmd)(void *priv, char *cmd, char *buf, size_t buf_len); -#endif /* ANDROID */ - - /** - * 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); - - /** - * radio_disable - Disable/enable radio - * @priv: Private driver interface data - * @disabled: 1=disable 0=enable radio - * Returns: 0 on success, -1 on failure - * - * This optional command is for testing purposes. It can be used to - * disable the radio on a testbed device to simulate out-of-radio-range - * conditions. - */ - int (*radio_disable)(void *priv, int disabled); - - /** - * switch_channel - Announce channel switch and migrate the GO to the - * given frequency - * @priv: Private driver interface data - * @settings: Settings for CSA period and new channel - * Returns: 0 on success, -1 on failure - * - * This function is used to move the GO to the legacy STA channel to - * avoid frequency conflict in single channel concurrency. - */ - int (*switch_channel)(void *priv, struct csa_settings *settings); - - /** - * start_dfs_cac - Listen for radar interference on the channel - * @priv: Private driver interface data - * @freq: Channel parameters - * Returns: 0 on success, -1 on failure - */ - int (*start_dfs_cac)(void *priv, struct hostapd_freq_params *freq); - - /** - * stop_ap - Removes beacon from AP - * @priv: Private driver interface data - * Returns: 0 on success, -1 on failure (or if not supported) - * - * This optional function can be used to disable AP mode related - * configuration. Unlike deinit_ap, it does not change to station - * mode. - */ - int (*stop_ap)(void *priv); - - /** - * get_survey - Retrieve survey data - * @priv: Private driver interface data - * @freq: If set, survey data for the specified frequency is only - * being requested. If not set, all survey data is requested. - * Returns: 0 on success, -1 on failure - * - * Use this to retrieve: - * - * - the observed channel noise floor - * - the amount of time we have spent on the channel - * - the amount of time during which we have spent on the channel that - * the radio has determined the medium is busy and we cannot - * transmit - * - the amount of time we have spent receiving data - * - the amount of time we have spent transmitting data - * - * This data can be used for spectrum heuristics. One example is - * Automatic Channel Selection (ACS). The channel survey data is - * kept on a linked list on the channel data, one entry is added - * for each survey. The min_nf of the channel is updated for each - * survey. - */ - int (*get_survey)(void *priv, unsigned int freq); - - /** - * status - Get driver interface status information - * @priv: Private driver interface data - * @buf: Buffer for printing tou the status information - * @buflen: Maximum length of the buffer - * Returns: Length of written status information or -1 on failure - */ - int (*status)(void *priv, char *buf, size_t buflen); -}; - - -/** - * enum wpa_event_type - Event type for wpa_supplicant_event() calls - */ -enum wpa_event_type { - /** - * EVENT_ASSOC - Association completed - * - * This event needs to be delivered when the driver completes IEEE - * 802.11 association or reassociation successfully. - * wpa_driver_ops::get_bssid() is expected to provide the current BSSID - * after this event has been generated. In addition, optional - * EVENT_ASSOCINFO may be generated just before EVENT_ASSOC to provide - * more information about the association. If the driver interface gets - * both of these events at the same time, it can also include the - * assoc_info data in EVENT_ASSOC call. - */ - EVENT_ASSOC, - - /** - * EVENT_DISASSOC - Association lost - * - * This event should be called when association is lost either due to - * receiving deauthenticate or disassociate frame from the AP or when - * sending either of these frames to the current AP. If the driver - * supports separate deauthentication event, EVENT_DISASSOC should only - * be used for disassociation and EVENT_DEAUTH for deauthentication. - * In AP mode, union wpa_event_data::disassoc_info is required. - */ - EVENT_DISASSOC, - - /** - * EVENT_MICHAEL_MIC_FAILURE - Michael MIC (TKIP) detected - * - * This event must be delivered when a Michael MIC error is detected by - * the local driver. Additional data for event processing is - * provided with union wpa_event_data::michael_mic_failure. This - * information is used to request new encyption key and to initiate - * TKIP countermeasures if needed. - */ - EVENT_MICHAEL_MIC_FAILURE, - - /** - * EVENT_SCAN_RESULTS - Scan results available - * - * This event must be called whenever scan results are available to be - * fetched with struct wpa_driver_ops::get_scan_results(). This event - * is expected to be used some time after struct wpa_driver_ops::scan() - * is called. If the driver provides an unsolicited event when the scan - * has been completed, this event can be used to trigger - * EVENT_SCAN_RESULTS call. If such event is not available from the - * driver, the driver wrapper code is expected to use a registered - * timeout to generate EVENT_SCAN_RESULTS call after the time that the - * scan is expected to be completed. Optional information about - * completed scan can be provided with union wpa_event_data::scan_info. - */ - EVENT_SCAN_RESULTS, - - /** - * EVENT_ASSOCINFO - Report optional extra information for association - * - * This event can be used to report extra association information for - * EVENT_ASSOC processing. This extra information includes IEs from - * association frames and Beacon/Probe Response frames in union - * wpa_event_data::assoc_info. EVENT_ASSOCINFO must be send just before - * EVENT_ASSOC. Alternatively, the driver interface can include - * assoc_info data in the EVENT_ASSOC call if it has all the - * information available at the same point. - */ - EVENT_ASSOCINFO, - - /** - * EVENT_INTERFACE_STATUS - Report interface status changes - * - * This optional event can be used to report changes in interface - * status (interface added/removed) using union - * wpa_event_data::interface_status. This can be used to trigger - * wpa_supplicant to stop and re-start processing for the interface, - * e.g., when a cardbus card is ejected/inserted. - */ - EVENT_INTERFACE_STATUS, - - /** - * EVENT_PMKID_CANDIDATE - Report a candidate AP for pre-authentication - * - * This event can be used to inform wpa_supplicant about candidates for - * RSN (WPA2) pre-authentication. If wpa_supplicant is not responsible - * for scan request (ap_scan=2 mode), this event is required for - * pre-authentication. If wpa_supplicant is performing scan request - * (ap_scan=1), this event is optional since scan results can be used - * to add pre-authentication candidates. union - * wpa_event_data::pmkid_candidate is used to report the BSSID of the - * candidate and priority of the candidate, e.g., based on the signal - * strength, in order to try to pre-authenticate first with candidates - * that are most likely targets for re-association. - * - * EVENT_PMKID_CANDIDATE can be called whenever the driver has updates - * on the candidate list. In addition, it can be called for the current - * AP and APs that have existing PMKSA cache entries. wpa_supplicant - * will automatically skip pre-authentication in cases where a valid - * PMKSA exists. When more than one candidate exists, this event should - * be generated once for each candidate. - * - * Driver will be notified about successful pre-authentication with - * struct wpa_driver_ops::add_pmkid() calls. - */ - EVENT_PMKID_CANDIDATE, - - /** - * EVENT_STKSTART - Request STK handshake (MLME-STKSTART.request) - * - * This event can be used to inform wpa_supplicant about desire to set - * up secure direct link connection between two stations as defined in - * IEEE 802.11e with a new PeerKey mechanism that replaced the original - * STAKey negotiation. The caller will need to set peer address for the - * event. - */ - EVENT_STKSTART, - - /** - * EVENT_TDLS - Request TDLS operation - * - * This event can be used to request a TDLS operation to be performed. - */ - EVENT_TDLS, - - /** - * EVENT_FT_RESPONSE - Report FT (IEEE 802.11r) response IEs - * - * The driver is expected to report the received FT IEs from - * FT authentication sequence from the AP. The FT IEs are included in - * the extra information in union wpa_event_data::ft_ies. - */ - EVENT_FT_RESPONSE, - - /** - * EVENT_IBSS_RSN_START - Request RSN authentication in IBSS - * - * The driver can use this event to inform wpa_supplicant about a STA - * in an IBSS with which protected frames could be exchanged. This - * event starts RSN authentication with the other STA to authenticate - * the STA and set up encryption keys with it. - */ - EVENT_IBSS_RSN_START, - - /** - * EVENT_AUTH - Authentication result - * - * This event should be called when authentication attempt has been - * completed. This is only used if the driver supports separate - * authentication step (struct wpa_driver_ops::authenticate). - * Information about authentication result is included in - * union wpa_event_data::auth. - */ - EVENT_AUTH, - - /** - * EVENT_DEAUTH - Authentication lost - * - * This event should be called when authentication is lost either due - * to receiving deauthenticate frame from the AP or when sending that - * frame to the current AP. - * In AP mode, union wpa_event_data::deauth_info is required. - */ - EVENT_DEAUTH, - - /** - * EVENT_ASSOC_REJECT - Association rejected - * - * This event should be called when (re)association attempt has been - * rejected by the AP. Information about the association response is - * included in union wpa_event_data::assoc_reject. - */ - EVENT_ASSOC_REJECT, - - /** - * EVENT_AUTH_TIMED_OUT - Authentication timed out - */ - EVENT_AUTH_TIMED_OUT, - - /** - * EVENT_ASSOC_TIMED_OUT - Association timed out - */ - EVENT_ASSOC_TIMED_OUT, - - /** - * EVENT_FT_RRB_RX - FT (IEEE 802.11r) RRB frame received - */ - EVENT_FT_RRB_RX, - - /** - * EVENT_WPS_BUTTON_PUSHED - Report hardware push button press for WPS - */ - EVENT_WPS_BUTTON_PUSHED, - - /** - * EVENT_TX_STATUS - Report TX status - */ - EVENT_TX_STATUS, - - /** - * EVENT_RX_FROM_UNKNOWN - Report RX from unknown STA - */ - EVENT_RX_FROM_UNKNOWN, - - /** - * EVENT_RX_MGMT - Report RX of a management frame - */ - EVENT_RX_MGMT, - - /** - * EVENT_REMAIN_ON_CHANNEL - Remain-on-channel duration started - * - * This event is used to indicate when the driver has started the - * requested remain-on-channel duration. Information about the - * operation is included in union wpa_event_data::remain_on_channel. - */ - EVENT_REMAIN_ON_CHANNEL, - - /** - * EVENT_CANCEL_REMAIN_ON_CHANNEL - Remain-on-channel timed out - * - * This event is used to indicate when the driver has completed - * remain-on-channel duration, i.e., may noot be available on the - * requested channel anymore. Information about the - * operation is included in union wpa_event_data::remain_on_channel. - */ - EVENT_CANCEL_REMAIN_ON_CHANNEL, - - /** - * EVENT_MLME_RX - Report reception of frame for MLME (test use only) - * - * This event is used only by driver_test.c and userspace MLME. - */ - EVENT_MLME_RX, - - /** - * EVENT_RX_PROBE_REQ - Indicate received Probe Request frame - * - * This event is used to indicate when a Probe Request frame has been - * received. Information about the received frame is included in - * union wpa_event_data::rx_probe_req. The driver is required to report - * these events only after successfully completed probe_req_report() - * commands to request the events (i.e., report parameter is non-zero) - * in station mode. In AP mode, Probe Request frames should always be - * reported. - */ - EVENT_RX_PROBE_REQ, - - /** - * EVENT_NEW_STA - New wired device noticed - * - * This event is used to indicate that a new device has been detected - * in a network that does not use association-like functionality (i.e., - * mainly wired Ethernet). This can be used to start EAPOL - * authenticator when receiving a frame from a device. The address of - * the device is included in union wpa_event_data::new_sta. - */ - EVENT_NEW_STA, - - /** - * EVENT_EAPOL_RX - Report received EAPOL frame - * - * When in AP mode with hostapd, this event is required to be used to - * deliver the receive EAPOL frames from the driver. With - * %wpa_supplicant, this event is used only if the send_eapol() handler - * is used to override the use of l2_packet for EAPOL frame TX. - */ - EVENT_EAPOL_RX, - - /** - * EVENT_SIGNAL_CHANGE - Indicate change in signal strength - * - * This event is used to indicate changes in the signal strength - * observed in frames received from the current AP if signal strength - * monitoring has been enabled with signal_monitor(). - */ - EVENT_SIGNAL_CHANGE, - - /** - * EVENT_INTERFACE_ENABLED - Notify that interface was enabled - * - * This event is used to indicate that the interface was enabled after - * having been previously disabled, e.g., due to rfkill. - */ - EVENT_INTERFACE_ENABLED, - - /** - * EVENT_INTERFACE_DISABLED - Notify that interface was disabled - * - * This event is used to indicate that the interface was disabled, - * e.g., due to rfkill. - */ - EVENT_INTERFACE_DISABLED, - - /** - * EVENT_CHANNEL_LIST_CHANGED - Channel list changed - * - * This event is used to indicate that the channel list has changed, - * e.g., because of a regulatory domain change triggered by scan - * results including an AP advertising a country code. - */ - EVENT_CHANNEL_LIST_CHANGED, - - /** - * EVENT_INTERFACE_UNAVAILABLE - Notify that interface is unavailable - * - * This event is used to indicate that the driver cannot maintain this - * interface in its operation mode anymore. The most likely use for - * this is to indicate that AP mode operation is not available due to - * operating channel would need to be changed to a DFS channel when - * the driver does not support radar detection and another virtual - * interfaces caused the operating channel to change. Other similar - * resource conflicts could also trigger this for station mode - * interfaces. - */ - EVENT_INTERFACE_UNAVAILABLE, - - /** - * EVENT_BEST_CHANNEL - * - * Driver generates this event whenever it detects a better channel - * (e.g., based on RSSI or channel use). This information can be used - * to improve channel selection for a new AP/P2P group. - */ - EVENT_BEST_CHANNEL, - - /** - * EVENT_UNPROT_DEAUTH - Unprotected Deauthentication frame received - * - * This event should be called when a Deauthentication frame is dropped - * due to it not being protected (MFP/IEEE 802.11w). - * union wpa_event_data::unprot_deauth is required to provide more - * details of the frame. - */ - EVENT_UNPROT_DEAUTH, - - /** - * EVENT_UNPROT_DISASSOC - Unprotected Disassociation frame received - * - * This event should be called when a Disassociation frame is dropped - * due to it not being protected (MFP/IEEE 802.11w). - * union wpa_event_data::unprot_disassoc is required to provide more - * details of the frame. - */ - EVENT_UNPROT_DISASSOC, - - /** - * EVENT_STATION_LOW_ACK - * - * Driver generates this event whenever it detected that a particular - * station was lost. Detection can be through massive transmission - * failures for example. - */ - EVENT_STATION_LOW_ACK, - - /** - * EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore - */ - 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, - - /** - * EVENT_CH_SWITCH - AP or GO decided to switch channels - * - * Described in wpa_event_data.ch_switch - * */ - EVENT_CH_SWITCH, - - /** - * EVENT_WNM - Request WNM operation - * - * This event can be used to request a WNM operation to be performed. - */ - EVENT_WNM, - - /** - * EVENT_CONNECT_FAILED_REASON - Connection failure reason in AP mode - * - * This event indicates that the driver reported a connection failure - * with the specified client (for example, max client reached, etc.) in - * AP mode. - */ - EVENT_CONNECT_FAILED_REASON, - - /** - * EVENT_RADAR_DETECTED - Notify of radar detection - * - * A radar has been detected on the supplied frequency, hostapd should - * react accordingly (e.g., change channel). - */ - EVENT_DFS_RADAR_DETECTED, - - /** - * EVENT_CAC_FINISHED - Notify that channel availability check has been completed - * - * After a successful CAC, the channel can be marked clear and used. - */ - EVENT_DFS_CAC_FINISHED, - - /** - * EVENT_CAC_ABORTED - Notify that channel availability check has been aborted - * - * The CAC was not successful, and the channel remains in the previous - * state. This may happen due to a radar beeing detected or other - * external influences. - */ - EVENT_DFS_CAC_ABORTED, - - /** - * EVENT_DFS_CAC_NOP_FINISHED - Notify that non-occupancy period is over - * - * The channel which was previously unavailable is now available again. - */ - EVENT_DFS_NOP_FINISHED, - - /** - * EVENT_SURVEY - Received survey data - * - * This event gets triggered when a driver query is issued for survey - * data and the requested data becomes available. The returned data is - * stored in struct survey_results. The results provide at most one - * survey entry for each frequency and at minimum will provide one - * survey entry for one frequency. The survey data can be os_malloc()'d - * and then os_free()'d, so the event callback must only copy data. - */ - EVENT_SURVEY, - - /** - * EVENT_SCAN_STARTED - Scan started - * - * This indicates that driver has started a scan operation either based - * on a request from wpa_supplicant/hostapd or from another application. - * EVENT_SCAN_RESULTS is used to indicate when the scan has been - * completed (either successfully or by getting cancelled). - */ - EVENT_SCAN_STARTED, - - /** - * EVENT_AVOID_FREQUENCIES - Received avoid frequency range - * - * This event indicates a set of frequency ranges that should be avoided - * to reduce issues due to interference or internal co-existence - * information in the driver. - */ - EVENT_AVOID_FREQUENCIES -}; - - -/** - * struct freq_survey - Channel survey info - * - * @ifidx: Interface index in which this survey was observed - * @freq: Center of frequency of the surveyed channel - * @nf: Channel noise floor in dBm - * @channel_time: Amount of time in ms the radio spent on the channel - * @channel_time_busy: Amount of time in ms the radio detected some signal - * that indicated to the radio the channel was not clear - * @channel_time_rx: Amount of time the radio spent receiving data - * @channel_time_tx: Amount of time the radio spent transmitting data - * @filled: bitmask indicating which fields have been reported, see - * SURVEY_HAS_* defines. - * @list: Internal list pointers - */ -struct freq_survey { - u32 ifidx; - unsigned int freq; - s8 nf; - u64 channel_time; - u64 channel_time_busy; - u64 channel_time_rx; - u64 channel_time_tx; - unsigned int filled; - struct dl_list list; -}; - -#define SURVEY_HAS_NF BIT(0) -#define SURVEY_HAS_CHAN_TIME BIT(1) -#define SURVEY_HAS_CHAN_TIME_BUSY BIT(2) -#define SURVEY_HAS_CHAN_TIME_RX BIT(3) -#define SURVEY_HAS_CHAN_TIME_TX BIT(4) - - -/** - * union wpa_event_data - Additional data for wpa_supplicant_event() calls - */ -union wpa_event_data { - /** - * struct assoc_info - Data for EVENT_ASSOC and EVENT_ASSOCINFO events - * - * This structure is optional for EVENT_ASSOC calls and required for - * EVENT_ASSOCINFO calls. By using EVENT_ASSOC with this data, the - * driver interface does not need to generate separate EVENT_ASSOCINFO - * calls. - */ - struct assoc_info { - /** - * reassoc - Flag to indicate association or reassociation - */ - int reassoc; - - /** - * req_ies - (Re)Association Request IEs - * - * If the driver generates WPA/RSN IE, this event data must be - * returned for WPA handshake to have needed information. If - * wpa_supplicant-generated WPA/RSN IE is used, this - * information event is optional. - * - * This should start with the first IE (fixed fields before IEs - * are not included). - */ - const u8 *req_ies; - - /** - * req_ies_len - Length of req_ies in bytes - */ - size_t req_ies_len; - - /** - * resp_ies - (Re)Association Response IEs - * - * Optional association data from the driver. This data is not - * required WPA, but may be useful for some protocols and as - * such, should be reported if this is available to the driver - * interface. - * - * This should start with the first IE (fixed fields before IEs - * are not included). - */ - const u8 *resp_ies; - - /** - * resp_ies_len - Length of resp_ies in bytes - */ - size_t resp_ies_len; - - /** - * beacon_ies - Beacon or Probe Response IEs - * - * Optional Beacon/ProbeResp data: IEs included in Beacon or - * Probe Response frames from the current AP (i.e., the one - * that the client just associated with). This information is - * used to update WPA/RSN IE for the AP. If this field is not - * set, the results from previous scan will be used. If no - * data for the new AP is found, scan results will be requested - * again (without scan request). At this point, the driver is - * expected to provide WPA/RSN IE for the AP (if WPA/WPA2 is - * used). - * - * This should start with the first IE (fixed fields before IEs - * are not included). - */ - const u8 *beacon_ies; - - /** - * beacon_ies_len - Length of beacon_ies */ - size_t beacon_ies_len; - - /** - * freq - Frequency of the operational channel in MHz - */ - unsigned int freq; - - /** - * addr - Station address (for AP mode) - */ - const u8 *addr; - } assoc_info; - - /** - * struct disassoc_info - Data for EVENT_DISASSOC events - */ - struct disassoc_info { - /** - * addr - Station address (for AP mode) - */ - const u8 *addr; - - /** - * reason_code - Reason Code (host byte order) used in - * Deauthentication frame - */ - u16 reason_code; - - /** - * ie - Optional IE(s) in Disassociation frame - */ - const u8 *ie; - - /** - * ie_len - Length of ie buffer in octets - */ - size_t ie_len; - - /** - * locally_generated - Whether the frame was locally generated - */ - int locally_generated; - } disassoc_info; - - /** - * struct deauth_info - Data for EVENT_DEAUTH events - */ - struct deauth_info { - /** - * addr - Station address (for AP mode) - */ - const u8 *addr; - - /** - * reason_code - Reason Code (host byte order) used in - * Deauthentication frame - */ - u16 reason_code; - - /** - * ie - Optional IE(s) in Deauthentication frame - */ - const u8 *ie; - - /** - * ie_len - Length of ie buffer in octets - */ - size_t ie_len; - - /** - * locally_generated - Whether the frame was locally generated - */ - int locally_generated; - } deauth_info; - - /** - * struct michael_mic_failure - Data for EVENT_MICHAEL_MIC_FAILURE - */ - struct michael_mic_failure { - int unicast; - const u8 *src; - } michael_mic_failure; - - /** - * struct interface_status - Data for EVENT_INTERFACE_STATUS - */ - struct interface_status { - char ifname[100]; - enum { - EVENT_INTERFACE_ADDED, EVENT_INTERFACE_REMOVED - } ievent; - } interface_status; - - /** - * struct pmkid_candidate - Data for EVENT_PMKID_CANDIDATE - */ - struct pmkid_candidate { - /** BSSID of the PMKID candidate */ - u8 bssid[ETH_ALEN]; - /** Smaller the index, higher the priority */ - int index; - /** Whether RSN IE includes pre-authenticate flag */ - int preauth; - } pmkid_candidate; - - /** - * struct stkstart - Data for EVENT_STKSTART - */ - struct stkstart { - u8 peer[ETH_ALEN]; - } stkstart; - - /** - * struct tdls - Data for EVENT_TDLS - */ - struct tdls { - u8 peer[ETH_ALEN]; - enum { - TDLS_REQUEST_SETUP, - TDLS_REQUEST_TEARDOWN - } oper; - u16 reason_code; /* for teardown */ - } tdls; - - /** - * struct wnm - Data for EVENT_WNM - */ - struct wnm { - u8 addr[ETH_ALEN]; - enum { - WNM_OPER_SLEEP, - } oper; - enum { - WNM_SLEEP_ENTER, - WNM_SLEEP_EXIT - } sleep_action; - int sleep_intval; - u16 reason_code; - u8 *buf; - u16 buf_len; - } wnm; - - /** - * struct ft_ies - FT information elements (EVENT_FT_RESPONSE) - * - * During FT (IEEE 802.11r) authentication sequence, the driver is - * expected to use this event to report received FT IEs (MDIE, FTIE, - * RSN IE, TIE, possible resource request) to the supplicant. The FT - * IEs for the next message will be delivered through the - * struct wpa_driver_ops::update_ft_ies() callback. - */ - struct ft_ies { - const u8 *ies; - size_t ies_len; - int ft_action; - u8 target_ap[ETH_ALEN]; - /** Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request */ - const u8 *ric_ies; - /** Length of ric_ies buffer in octets */ - size_t ric_ies_len; - } ft_ies; - - /** - * struct ibss_rsn_start - Data for EVENT_IBSS_RSN_START - */ - struct ibss_rsn_start { - u8 peer[ETH_ALEN]; - } ibss_rsn_start; - - /** - * struct auth_info - Data for EVENT_AUTH events - */ - 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; - } auth; - - /** - * struct assoc_reject - Data for EVENT_ASSOC_REJECT events - */ - struct assoc_reject { - /** - * bssid - BSSID of the AP that rejected association - */ - const u8 *bssid; - - /** - * resp_ies - (Re)Association Response IEs - * - * Optional association data from the driver. This data is not - * required WPA, but may be useful for some protocols and as - * such, should be reported if this is available to the driver - * interface. - * - * This should start with the first IE (fixed fields before IEs - * are not included). - */ - const u8 *resp_ies; - - /** - * resp_ies_len - Length of resp_ies in bytes - */ - size_t resp_ies_len; - - /** - * status_code - Status Code from (Re)association Response - */ - u16 status_code; - } assoc_reject; - - struct timeout_event { - u8 addr[ETH_ALEN]; - } timeout_event; - - /** - * struct ft_rrb_rx - Data for EVENT_FT_RRB_RX events - */ - struct ft_rrb_rx { - const u8 *src; - const u8 *data; - size_t data_len; - } ft_rrb_rx; - - /** - * struct tx_status - Data for EVENT_TX_STATUS events - */ - struct tx_status { - u16 type; - u16 stype; - const u8 *dst; - const u8 *data; - size_t data_len; - int ack; - } tx_status; - - /** - * struct rx_from_unknown - Data for EVENT_RX_FROM_UNKNOWN events - */ - struct rx_from_unknown { - const u8 *bssid; - const u8 *addr; - int wds; - } rx_from_unknown; - - /** - * struct rx_mgmt - Data for EVENT_RX_MGMT events - */ - struct rx_mgmt { - const u8 *frame; - size_t frame_len; - u32 datarate; - - /** - * freq - Frequency (in MHz) on which the frame was received - */ - int freq; - - /** - * ssi_signal - Signal strength in dBm (or 0 if not available) - */ - int ssi_signal; - } rx_mgmt; - - /** - * struct remain_on_channel - Data for EVENT_REMAIN_ON_CHANNEL events - * - * This is also used with EVENT_CANCEL_REMAIN_ON_CHANNEL events. - */ - struct remain_on_channel { - /** - * freq - Channel frequency in MHz - */ - unsigned int freq; - - /** - * duration - Duration to remain on the channel in milliseconds - */ - unsigned int duration; - } remain_on_channel; - - /** - * struct scan_info - Optional data for EVENT_SCAN_RESULTS events - * @aborted: Whether the scan was aborted - * @freqs: Scanned frequencies in MHz (%NULL = all channels scanned) - * @num_freqs: Number of entries in freqs array - * @ssids: Scanned SSIDs (%NULL or zero-length SSID indicates wildcard - * SSID) - * @num_ssids: Number of entries in ssids array - */ - struct scan_info { - int aborted; - const int *freqs; - size_t num_freqs; - struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS]; - size_t num_ssids; - } scan_info; - - /** - * struct mlme_rx - Data for EVENT_MLME_RX events - */ - struct mlme_rx { - const u8 *buf; - size_t len; - int freq; - int channel; - int ssi; - } mlme_rx; - - /** - * struct rx_probe_req - Data for EVENT_RX_PROBE_REQ events - */ - struct rx_probe_req { - /** - * sa - Source address of the received Probe Request frame - */ - 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; - - /** - * ie_len - Length of ie buffer in octets - */ - size_t ie_len; - - /** - * signal - signal strength in dBm (or 0 if not available) - */ - int ssi_signal; - } rx_probe_req; - - /** - * struct new_sta - Data for EVENT_NEW_STA events - */ - struct new_sta { - const u8 *addr; - } new_sta; - - /** - * struct eapol_rx - Data for EVENT_EAPOL_RX events - */ - struct eapol_rx { - const u8 *src; - const u8 *data; - size_t data_len; - } eapol_rx; - - /** - * signal_change - Data for EVENT_SIGNAL_CHANGE events - */ - struct wpa_signal_info signal_change; - - /** - * struct best_channel - Data for EVENT_BEST_CHANNEL events - * @freq_24: Best 2.4 GHz band channel frequency in MHz - * @freq_5: Best 5 GHz band channel frequency in MHz - * @freq_overall: Best channel frequency in MHz - * - * 0 can be used to indicate no preference in either band. - */ - struct best_channel { - int freq_24; - int freq_5; - int freq_overall; - } best_chan; - - struct unprot_deauth { - const u8 *sa; - const u8 *da; - u16 reason_code; - } unprot_deauth; - - struct unprot_disassoc { - const u8 *sa; - const u8 *da; - u16 reason_code; - } unprot_disassoc; - - /** - * struct low_ack - Data for EVENT_STATION_LOW_ACK events - * @addr: station address - */ - struct low_ack { - u8 addr[ETH_ALEN]; - } low_ack; - - /** - * struct ibss_peer_lost - Data for EVENT_IBSS_PEER_LOST - */ - 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; - - /** - * struct ch_switch - * @freq: Frequency of new channel in MHz - * @ht_enabled: Whether this is an HT channel - * @ch_offset: Secondary channel offset - * @ch_width: Channel width - * @cf1: Center frequency 1 - * @cf2: Center frequency 2 - */ - struct ch_switch { - int freq; - int ht_enabled; - int ch_offset; - enum chan_width ch_width; - int cf1; - int cf2; - } ch_switch; - - /** - * struct connect_failed - Data for EVENT_CONNECT_FAILED_REASON - * @addr: Remote client address - * @code: Reason code for connection failure - */ - struct connect_failed_reason { - u8 addr[ETH_ALEN]; - enum { - MAX_CLIENT_REACHED, - BLOCKED_CLIENT - } code; - } connect_failed_reason; - - /** - * struct dfs_event - Data for radar detected events - * @freq: Frequency of the channel in MHz - */ - struct dfs_event { - int freq; - int ht_enabled; - int chan_offset; - enum chan_width chan_width; - int cf1; - int cf2; - } dfs_event; - - /** - * survey_results - Survey result data for EVENT_SURVEY - * @freq_filter: Requested frequency survey filter, 0 if request - * was for all survey data - * @survey_list: Linked list of survey data - */ - struct survey_results { - unsigned int freq_filter; - struct dl_list survey_list; /* struct freq_survey */ - } survey_results; - - /** - * channel_list_changed - Data for EVENT_CHANNEL_LIST_CHANGED - * @initiator: Initiator of the regulatory change - */ - struct channel_list_changed { - enum reg_change_initiator initiator; - } channel_list_changed; - - /** - * freq_range - List of frequency ranges - * - * This is used as the data with EVENT_AVOID_FREQUENCIES. - */ - struct wpa_freq_range_list freq_range; -}; - -/** - * wpa_supplicant_event - Report a driver event for wpa_supplicant - * @ctx: Context pointer (wpa_s); this is the ctx variable registered - * with struct wpa_driver_ops::init() - * @event: event type (defined above) - * @data: possible extra data for the event - * - * Driver wrapper code should call this function whenever an event is received - * from the driver. - */ -void wpa_supplicant_event(void *ctx, enum wpa_event_type event, - union wpa_event_data *data); - - -/* - * The following inline functions are provided for convenience to simplify - * event indication for some of the common events. - */ - -static inline void drv_event_assoc(void *ctx, const u8 *addr, const u8 *ie, - size_t ielen, int reassoc) -{ - union wpa_event_data event; - os_memset(&event, 0, sizeof(event)); - event.assoc_info.reassoc = reassoc; - event.assoc_info.req_ies = ie; - event.assoc_info.req_ies_len = ielen; - event.assoc_info.addr = addr; - wpa_supplicant_event(ctx, EVENT_ASSOC, &event); -} - -static inline void drv_event_disassoc(void *ctx, const u8 *addr) -{ - union wpa_event_data event; - os_memset(&event, 0, sizeof(event)); - event.disassoc_info.addr = addr; - wpa_supplicant_event(ctx, EVENT_DISASSOC, &event); -} - -static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data, - size_t data_len) -{ - union wpa_event_data event; - os_memset(&event, 0, sizeof(event)); - event.eapol_rx.src = src; - event.eapol_rx.data = data; - event.eapol_rx.data_len = data_len; - 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); - -/* NULL terminated array of linked in driver wrappers */ -extern struct wpa_driver_ops *wpa_drivers[]; - -#endif /* DRIVER_H */ diff --git a/contrib/hostapd/src/drivers/driver_atheros.c b/contrib/hostapd/src/drivers/driver_atheros.c deleted file mode 100644 index 23a4e2b95e..0000000000 --- a/contrib/hostapd/src/drivers/driver_atheros.c +++ /dev/null @@ -1,2193 +0,0 @@ -/* - * hostapd / Driver interaction with Atheros driver - * Copyright (c) 2004, Sam Leffler - * Copyright (c) 2004, Video54 Technologies - * Copyright (c) 2005-2007, Jouni Malinen - * Copyright (c) 2009, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include -#include - -#include "common.h" -#include "eloop.h" -#include "common/ieee802_11_defs.h" -#include "l2_packet/l2_packet.h" -#include "p2p/p2p.h" - -#include "common.h" -#ifndef _BYTE_ORDER -#ifdef WORDS_BIGENDIAN -#define _BYTE_ORDER _BIG_ENDIAN -#else -#define _BYTE_ORDER _LITTLE_ENDIAN -#endif -#endif /* _BYTE_ORDER */ - -/* - * Note, the ATH_WPS_IE setting must match with the driver build.. If the - * driver does not include this, the IEEE80211_IOCTL_GETWPAIE ioctl will fail. - */ -#define ATH_WPS_IE - -#include "ieee80211_external.h" - - -#ifdef CONFIG_WPS -#include -#endif /* CONFIG_WPS */ - -#ifndef ETH_P_80211_RAW -#define ETH_P_80211_RAW 0x0019 -#endif - -#include "linux_wext.h" - -#include "driver.h" -#include "eloop.h" -#include "priv_netlink.h" -#include "l2_packet/l2_packet.h" -#include "common/ieee802_11_defs.h" -#include "netlink.h" -#include "linux_ioctl.h" - - -struct atheros_driver_data { - struct hostapd_data *hapd; /* back pointer */ - - char iface[IFNAMSIZ + 1]; - int ifindex; - struct l2_packet_data *sock_xmit; /* raw packet xmit socket */ - struct l2_packet_data *sock_recv; /* raw packet recv socket */ - int ioctl_sock; /* socket for ioctl() use */ - struct netlink_data *netlink; - int we_version; - u8 acct_mac[ETH_ALEN]; - struct hostap_sta_driver_data acct_data; - - struct l2_packet_data *sock_raw; /* raw 802.11 management frames */ - struct wpabuf *wpa_ie; - struct wpabuf *wps_beacon_ie; - struct wpabuf *wps_probe_resp_ie; - u8 own_addr[ETH_ALEN]; -}; - -static int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, - int reason_code); -static int atheros_set_privacy(void *priv, int enabled); - -static const char * athr_get_ioctl_name(int op) -{ - switch (op) { - case IEEE80211_IOCTL_SETPARAM: - return "SETPARAM"; - case IEEE80211_IOCTL_GETPARAM: - return "GETPARAM"; - case IEEE80211_IOCTL_SETKEY: - return "SETKEY"; - case IEEE80211_IOCTL_SETWMMPARAMS: - return "SETWMMPARAMS"; - case IEEE80211_IOCTL_DELKEY: - return "DELKEY"; - case IEEE80211_IOCTL_GETWMMPARAMS: - return "GETWMMPARAMS"; - case IEEE80211_IOCTL_SETMLME: - return "SETMLME"; - case IEEE80211_IOCTL_GETCHANINFO: - return "GETCHANINFO"; - case IEEE80211_IOCTL_SETOPTIE: - return "SETOPTIE"; - case IEEE80211_IOCTL_GETOPTIE: - return "GETOPTIE"; - case IEEE80211_IOCTL_ADDMAC: - return "ADDMAC"; - case IEEE80211_IOCTL_DELMAC: - return "DELMAC"; - case IEEE80211_IOCTL_GETCHANLIST: - return "GETCHANLIST"; - case IEEE80211_IOCTL_SETCHANLIST: - return "SETCHANLIST"; - case IEEE80211_IOCTL_KICKMAC: - return "KICKMAC"; - case IEEE80211_IOCTL_CHANSWITCH: - return "CHANSWITCH"; - case IEEE80211_IOCTL_GETMODE: - return "GETMODE"; - case IEEE80211_IOCTL_SETMODE: - return "SETMODE"; - case IEEE80211_IOCTL_GET_APPIEBUF: - return "GET_APPIEBUF"; - case IEEE80211_IOCTL_SET_APPIEBUF: - return "SET_APPIEBUF"; - case IEEE80211_IOCTL_SET_ACPARAMS: - return "SET_ACPARAMS"; - case IEEE80211_IOCTL_FILTERFRAME: - return "FILTERFRAME"; - case IEEE80211_IOCTL_SET_RTPARAMS: - return "SET_RTPARAMS"; - case IEEE80211_IOCTL_SET_MEDENYENTRY: - return "SET_MEDENYENTRY"; - case IEEE80211_IOCTL_GET_MACADDR: - return "GET_MACADDR"; - case IEEE80211_IOCTL_SET_HBRPARAMS: - return "SET_HBRPARAMS"; - case IEEE80211_IOCTL_SET_RXTIMEOUT: - return "SET_RXTIMEOUT"; - case IEEE80211_IOCTL_STA_STATS: - return "STA_STATS"; - case IEEE80211_IOCTL_GETWPAIE: - return "GETWPAIE"; - default: - return "??"; - } -} - - -static const char * athr_get_param_name(int op) -{ - switch (op) { - case IEEE80211_IOC_MCASTCIPHER: - return "MCASTCIPHER"; - case IEEE80211_PARAM_MCASTKEYLEN: - return "MCASTKEYLEN"; - case IEEE80211_PARAM_UCASTCIPHERS: - return "UCASTCIPHERS"; - case IEEE80211_PARAM_KEYMGTALGS: - return "KEYMGTALGS"; - case IEEE80211_PARAM_RSNCAPS: - return "RSNCAPS"; - case IEEE80211_PARAM_WPA: - return "WPA"; - case IEEE80211_PARAM_AUTHMODE: - return "AUTHMODE"; - case IEEE80211_PARAM_PRIVACY: - return "PRIVACY"; - case IEEE80211_PARAM_COUNTERMEASURES: - return "COUNTERMEASURES"; - default: - return "??"; - } -} - - -static int -set80211priv(struct atheros_driver_data *drv, int op, void *data, int len) -{ - struct iwreq iwr; - int do_inline = len < IFNAMSIZ; - - /* Certain ioctls must use the non-inlined method */ - if (op == IEEE80211_IOCTL_SET_APPIEBUF || - op == IEEE80211_IOCTL_FILTERFRAME) - do_inline = 0; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - if (do_inline) { - /* - * Argument data fits inline; put it there. - */ - 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->ioctl_sock, op, &iwr) < 0) { - wpa_printf(MSG_DEBUG, "atheros: %s: %s: ioctl op=0x%x " - "(%s) len=%d failed: %d (%s)", - __func__, drv->iface, op, - athr_get_ioctl_name(op), - len, errno, strerror(errno)); - return -1; - } - return 0; -} - -static int -set80211param(struct atheros_driver_data *drv, int op, int arg) -{ - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.mode = op; - memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg)); - - if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { - perror("ioctl[IEEE80211_IOCTL_SETPARAM]"); - wpa_printf(MSG_DEBUG, "%s: %s: Failed to set parameter (op %d " - "(%s) arg %d)", __func__, drv->iface, op, - athr_get_param_name(op), arg); - return -1; - } - return 0; -} - -#ifndef CONFIG_NO_STDOUT_DEBUG -static const char * -ether_sprintf(const u8 *addr) -{ - static char buf[sizeof(MACSTR)]; - - if (addr != NULL) - snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); - else - snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); - return buf; -} -#endif /* CONFIG_NO_STDOUT_DEBUG */ - -/* - * Configure WPA parameters. - */ -static int -atheros_configure_wpa(struct atheros_driver_data *drv, - struct wpa_bss_params *params) -{ - int v; - - switch (params->wpa_group) { - case WPA_CIPHER_CCMP: - v = IEEE80211_CIPHER_AES_CCM; - break; - case WPA_CIPHER_TKIP: - v = IEEE80211_CIPHER_TKIP; - break; - case WPA_CIPHER_WEP104: - v = IEEE80211_CIPHER_WEP; - break; - case WPA_CIPHER_WEP40: - v = IEEE80211_CIPHER_WEP; - break; - case WPA_CIPHER_NONE: - v = IEEE80211_CIPHER_NONE; - break; - default: - wpa_printf(MSG_ERROR, "Unknown group key cipher %u", - params->wpa_group); - return -1; - } - wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v); - if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) { - printf("Unable to set group key cipher to %u\n", v); - return -1; - } - if (v == IEEE80211_CIPHER_WEP) { - /* key length is done only for specific ciphers */ - v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); - if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) { - printf("Unable to set group key length to %u\n", v); - return -1; - } - } - - v = 0; - if (params->wpa_pairwise & WPA_CIPHER_CCMP) - v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) - v |= 1<wpa_pairwise & WPA_CIPHER_NONE) - v |= 1<wpa_key_mgmt); - if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, - params->wpa_key_mgmt)) { - printf("Unable to set key management algorithms to 0x%x\n", - params->wpa_key_mgmt); - return -1; - } - - v = 0; - if (params->rsn_preauth) - v |= BIT(0); -#ifdef CONFIG_IEEE80211W - if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) { - v |= BIT(7); - if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) - v |= BIT(6); - } -#endif /* CONFIG_IEEE80211W */ - - wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v); - if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) { - printf("Unable to set RSN capabilities to 0x%x\n", v); - return -1; - } - - wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa); - if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) { - printf("Unable to set WPA to %u\n", params->wpa); - return -1; - } - return 0; -} - -static int -atheros_set_ieee8021x(void *priv, struct wpa_bss_params *params) -{ - struct atheros_driver_data *drv = priv; - - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); - - if (!params->enabled) { - /* XXX restore state */ - if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, - IEEE80211_AUTH_AUTO) < 0) - return -1; - /* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */ - return atheros_set_privacy(drv, 0); - } - if (!params->wpa && !params->ieee802_1x) { - wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!"); - return -1; - } - if (params->wpa && atheros_configure_wpa(drv, params) != 0) { - wpa_printf(MSG_WARNING, "Error configuring WPA state!"); - return -1; - } - if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, - (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { - wpa_printf(MSG_WARNING, "Error enabling WPA/802.1X!"); - return -1; - } - - return 0; -} - -static int -atheros_set_privacy(void *priv, int enabled) -{ - struct atheros_driver_data *drv = priv; - - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - - return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled); -} - -static int -atheros_set_sta_authorized(void *priv, const u8 *addr, int authorized) -{ - struct atheros_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d", - __func__, ether_sprintf(addr), authorized); - - if (authorized) - mlme.im_op = IEEE80211_MLME_AUTHORIZE; - else - mlme.im_op = IEEE80211_MLME_UNAUTHORIZE; - mlme.im_reason = 0; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR, - __func__, authorized ? "" : "un", MAC2STR(addr)); - } - - return ret; -} - -static int -atheros_sta_set_flags(void *priv, const u8 *addr, - int total_flags, int flags_or, int flags_and) -{ - /* For now, only support setting Authorized flag */ - if (flags_or & WPA_STA_AUTHORIZED) - return atheros_set_sta_authorized(priv, addr, 1); - if (!(flags_and & WPA_STA_AUTHORIZED)) - return atheros_set_sta_authorized(priv, addr, 0); - return 0; -} - -static int -atheros_del_key(void *priv, const u8 *addr, int key_idx) -{ - struct atheros_driver_data *drv = priv; - struct ieee80211req_del_key wk; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d", - __func__, ether_sprintf(addr), key_idx); - - memset(&wk, 0, sizeof(wk)); - if (addr != NULL) { - memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); - wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE; - } else { - wk.idk_keyix = key_idx; - } - - ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s" - " key_idx %d)", __func__, ether_sprintf(addr), - key_idx); - } - - return ret; -} - -static int -atheros_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 atheros_driver_data *drv = priv; - struct ieee80211req_key wk; - u_int8_t cipher; - int ret; - - if (alg == WPA_ALG_NONE) - return atheros_del_key(drv, addr, key_idx); - - wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d", - __func__, alg, ether_sprintf(addr), key_idx); - - switch (alg) { - case WPA_ALG_WEP: - cipher = IEEE80211_CIPHER_WEP; - break; - case WPA_ALG_TKIP: - cipher = IEEE80211_CIPHER_TKIP; - break; - case WPA_ALG_CCMP: - cipher = IEEE80211_CIPHER_AES_CCM; - break; -#ifdef CONFIG_IEEE80211W - case WPA_ALG_IGTK: - cipher = IEEE80211_CIPHER_AES_CMAC; - break; -#endif /* CONFIG_IEEE80211W */ - default: - printf("%s: unknown/unsupported algorithm %d\n", - __func__, alg); - return -1; - } - - if (key_len > sizeof(wk.ik_keydata)) { - printf("%s: key length %lu too big\n", __func__, - (unsigned long) key_len); - return -3; - } - - memset(&wk, 0, sizeof(wk)); - wk.ik_type = cipher; - wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; - if (addr == NULL || is_broadcast_ether_addr(addr)) { - memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); - wk.ik_keyix = key_idx; - if (set_tx) - wk.ik_flags |= IEEE80211_KEY_DEFAULT; - } else { - memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); - wk.ik_keyix = IEEE80211_KEYIX_NONE; - } - wk.ik_keylen = key_len; - memcpy(wk.ik_keydata, key, key_len); - - ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s" - " key_idx %d alg %d key_len %lu set_tx %d)", - __func__, ether_sprintf(wk.ik_macaddr), key_idx, - alg, (unsigned long) key_len, set_tx); - } - - return ret; -} - - -static int -atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, - u8 *seq) -{ - struct atheros_driver_data *drv = priv; - struct ieee80211req_key wk; - - wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", - __func__, ether_sprintf(addr), idx); - - memset(&wk, 0, sizeof(wk)); - if (addr == NULL) - memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); - else - memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); - wk.ik_keyix = idx; - - if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) { - wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data " - "(addr " MACSTR " key_idx %d)", - __func__, MAC2STR(wk.ik_macaddr), idx); - return -1; - } - -#ifdef WORDS_BIGENDIAN - { - /* - * wk.ik_keytsc is in host byte order (big endian), need to - * swap it to match with the byte order used in WPA. - */ - int i; -#ifndef WPA_KEY_RSC_LEN -#define WPA_KEY_RSC_LEN 8 -#endif - u8 tmp[WPA_KEY_RSC_LEN]; - memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); - for (i = 0; i < WPA_KEY_RSC_LEN; i++) { - seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; - } - } -#else /* WORDS_BIGENDIAN */ - memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); -#endif /* WORDS_BIGENDIAN */ - return 0; -} - - -static int -atheros_flush(void *priv) -{ - u8 allsta[IEEE80211_ADDR_LEN]; - memset(allsta, 0xff, IEEE80211_ADDR_LEN); - return atheros_sta_deauth(priv, NULL, allsta, - IEEE80211_REASON_AUTH_LEAVE); -} - - -static int -atheros_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, - const u8 *addr) -{ - struct atheros_driver_data *drv = priv; - struct ieee80211req_sta_stats stats; - - memset(data, 0, sizeof(*data)); - - /* - * Fetch statistics for station from the system. - */ - memset(&stats, 0, sizeof(stats)); - memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); - if (set80211priv(drv, IEEE80211_IOCTL_STA_STATS, - &stats, sizeof(stats))) { - wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr " - MACSTR ")", __func__, MAC2STR(addr)); - if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { - memcpy(data, &drv->acct_data, sizeof(*data)); - return 0; - } - - printf("Failed to get station stats information element.\n"); - return -1; - } - - data->rx_packets = stats.is_stats.ns_rx_data; - data->rx_bytes = stats.is_stats.ns_rx_bytes; - data->tx_packets = stats.is_stats.ns_tx_data; - data->tx_bytes = stats.is_stats.ns_tx_bytes; - return 0; -} - - -static int -atheros_sta_clear_stats(void *priv, const u8 *addr) -{ - struct atheros_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr)); - - mlme.im_op = IEEE80211_MLME_CLEAR_STATS; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, - sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr " - MACSTR ")", __func__, MAC2STR(addr)); - } - - return ret; -} - - -static int -atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) -{ - struct atheros_driver_data *drv = priv; - u8 buf[512]; - struct ieee80211req_getset_appiebuf *app_ie; - - 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); - - app_ie = (struct ieee80211req_getset_appiebuf *) buf; - os_memcpy(&(app_ie->app_buf[0]), ie, ie_len); - app_ie->app_buflen = ie_len; - - app_ie->app_frmtype = IEEE80211_APPIE_FRAME_BEACON; - - /* append WPS IE for Beacon */ - if (drv->wps_beacon_ie != NULL) { - os_memcpy(&(app_ie->app_buf[ie_len]), - wpabuf_head(drv->wps_beacon_ie), - 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); - - /* append WPS IE for Probe Response */ - app_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_RESP; - if (drv->wps_probe_resp_ie != NULL) { - os_memcpy(&(app_ie->app_buf[ie_len]), - wpabuf_head(drv->wps_probe_resp_ie), - wpabuf_len(drv->wps_probe_resp_ie)); - app_ie->app_buflen = 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); - return 0; -} - -static int -atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, - int reason_code) -{ - struct atheros_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", - __func__, ether_sprintf(addr), reason_code); - - mlme.im_op = IEEE80211_MLME_DEAUTH; - mlme.im_reason = reason_code; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR - " reason %d)", - __func__, MAC2STR(addr), reason_code); - } - - return ret; -} - -static int -atheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, - int reason_code) -{ - struct atheros_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", - __func__, ether_sprintf(addr), reason_code); - - mlme.im_op = IEEE80211_MLME_DISASSOC; - mlme.im_reason = reason_code; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr " - MACSTR " reason %d)", - __func__, MAC2STR(addr), reason_code); - } - - return ret; -} - -#ifdef CONFIG_WPS -static void atheros_raw_recv_wps(void *ctx, const u8 *src_addr, const u8 *buf, - size_t len) -{ - struct atheros_driver_data *drv = ctx; - const struct ieee80211_mgmt *mgmt; - u16 fc; - union wpa_event_data event; - - /* Send Probe Request information to WPS processing */ - - if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) - return; - mgmt = (const struct ieee80211_mgmt *) buf; - - fc = le_to_host16(mgmt->frame_control); - if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || - WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ) - return; - - 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)); - wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event); -} -#endif /* CONFIG_WPS */ - -#ifdef CONFIG_IEEE80211R -static void atheros_raw_recv_11r(void *ctx, const u8 *src_addr, const u8 *buf, - size_t len) -{ - struct atheros_driver_data *drv = ctx; - union wpa_event_data event; - const struct ieee80211_mgmt *mgmt; - u16 fc; - u16 stype; - int ielen; - const u8 *iebuf; - - /* Do 11R processing for ASSOC/AUTH/FT ACTION frames */ - if (len < IEEE80211_HDRLEN) - return; - mgmt = (const struct ieee80211_mgmt *) buf; - - fc = le_to_host16(mgmt->frame_control); - - if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) - return; - stype = WLAN_FC_GET_STYPE(fc); - - wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype, - (int) len); - - if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore", - __func__); - return; - } - switch (stype) { - case WLAN_FC_STYPE_ASSOC_REQ: - if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.assoc_req)) - break; - ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)); - iebuf = mgmt->u.assoc_req.variable; - drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0); - break; - case WLAN_FC_STYPE_REASSOC_REQ: - if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.reassoc_req)) - break; - ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)); - iebuf = mgmt->u.reassoc_req.variable; - drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1); - break; - case WLAN_FC_STYPE_ACTION: - os_memset(&event, 0, sizeof(event)); - event.rx_mgmt.frame = buf; - event.rx_mgmt.frame_len = len; - wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); - break; - case WLAN_FC_STYPE_AUTH: - if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.auth)) - break; - os_memset(&event, 0, sizeof(event)); - os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN); - os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN); - event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg); - event.auth.status_code = - le_to_host16(mgmt->u.auth.status_code); - event.auth.auth_transaction = - le_to_host16(mgmt->u.auth.auth_transaction); - event.auth.ies = mgmt->u.auth.variable; - event.auth.ies_len = len - IEEE80211_HDRLEN - - sizeof(mgmt->u.auth); - wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event); - break; - default: - break; - } -} -#endif /* CONFIG_IEEE80211R */ - -#ifdef CONFIG_HS20 -static void atheros_raw_recv_hs20(void *ctx, const u8 *src_addr, const u8 *buf, - size_t len) -{ - struct atheros_driver_data *drv = ctx; - const struct ieee80211_mgmt *mgmt; - u16 fc; - union wpa_event_data event; - - /* Send the Action frame for HS20 processing */ - - if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.action.category) + - sizeof(mgmt->u.action.u.public_action)) - return; - - mgmt = (const struct ieee80211_mgmt *) buf; - - fc = le_to_host16(mgmt->frame_control); - if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || - WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION || - mgmt->u.action.category != WLAN_ACTION_PUBLIC) - return; - - wpa_printf(MSG_DEBUG, "%s:Received Public Action frame", __func__); - - os_memset(&event, 0, sizeof(event)); - event.rx_mgmt.frame = (const u8 *) mgmt; - event.rx_mgmt.frame_len = len; - wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); -} - -#endif /* CONFIG_HS20 */ - - -static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set, - u8 qos_map_set_len) -{ -#ifdef CONFIG_ATHEROS_QOS_MAP - struct atheros_driver_data *drv = ctx; - struct ieee80211req_athdbg req; - struct ieee80211_qos_map *qos_map = &req.data.qos_map; - struct iwreq iwr; - int i, up_start; - - if (qos_map_set_len < 16 || qos_map_set_len > 58 || - qos_map_set_len & 1) { - wpa_printf(MSG_ERROR, "Invalid QoS Map"); - return -1; - } else { - memset(&req, 0, sizeof(struct ieee80211req_athdbg)); - req.cmd = IEEE80211_DBGREQ_SETQOSMAPCONF; - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, sizeof(iwr.ifr_name)); - iwr.u.data.pointer = (void *) &req; - iwr.u.data.length = sizeof(struct ieee80211req_athdbg); - } - - qos_map->valid = 1; - qos_map->num_dscp_except = (qos_map_set_len - 16) / 2; - if (qos_map->num_dscp_except) { - for (i = 0; i < qos_map->num_dscp_except; i++) { - qos_map->dscp_exception[i].dscp = qos_map_set[i * 2]; - qos_map->dscp_exception[i].up = qos_map_set[i * 2 + 1]; - } - } - - up_start = qos_map_set_len - 16; - for (i = 0; i < IEEE80211_MAX_QOS_UP_RANGE; i++) { - qos_map->up[i].low = qos_map_set[up_start + (i * 2)]; - qos_map->up[i].high = qos_map_set[up_start + (i * 2) + 1]; - } - - if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_DBGREQ, &iwr) < 0) { - perror("ioctl[IEEE80211_IOCTL_DBGREQ]"); - wpa_printf(MSG_DEBUG, "%s: %s: Failed to set QoS Map", - __func__, drv->iface); - return -1; - } -#endif /* CONFIG_ATHEROS_QOS_MAP */ - - return 0; -} - -#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R) -static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf, - size_t len) -{ - struct atheros_driver_data *drv = ctx; - union wpa_event_data event; - const struct ieee80211_mgmt *mgmt; - u16 fc; - u16 stype; - - /* Do 11R processing for WNM ACTION frames */ - if (len < IEEE80211_HDRLEN) - return; - mgmt = (const struct ieee80211_mgmt *) buf; - - fc = le_to_host16(mgmt->frame_control); - - if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) - return; - stype = WLAN_FC_GET_STYPE(fc); - - wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype, - (int) len); - - if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore", - __func__); - return; - } - - switch (stype) { - case WLAN_FC_STYPE_ACTION: - os_memset(&event, 0, sizeof(event)); - event.rx_mgmt.frame = buf; - event.rx_mgmt.frame_len = len; - wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); - break; - default: - break; - } -} -#endif /* CONFIG_WNM */ - -#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WNM) -static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, - size_t len) -{ -#ifdef CONFIG_WPS - atheros_raw_recv_wps(ctx, src_addr, buf, len); -#endif /* CONFIG_WPS */ -#ifdef CONFIG_IEEE80211R - atheros_raw_recv_11r(ctx, src_addr, buf, len); -#endif /* CONFIG_IEEE80211R */ -#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R) - atheros_raw_recv_11v(ctx, src_addr, buf, len); -#endif /* CONFIG_WNM */ -#ifdef CONFIG_HS20 - atheros_raw_recv_hs20(ctx, src_addr, buf, len); -#endif /* CONFIG_HS20 */ -} -#endif /* CONFIG_WPS || CONFIG_IEEE80211R */ - -static int atheros_receive_pkt(struct atheros_driver_data *drv) -{ - int ret = 0; - struct ieee80211req_set_filter filt; - - wpa_printf(MSG_DEBUG, "%s Enter", __func__); - filt.app_filterype = 0; -#ifdef CONFIG_WPS - filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ; -#endif /* CONFIG_WPS */ -#ifdef CONFIG_IEEE80211R - filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ | - IEEE80211_FILTER_TYPE_AUTH | - IEEE80211_FILTER_TYPE_ACTION); -#endif -#ifdef CONFIG_WNM - filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION; -#endif /* CONFIG_WNM */ -#ifdef CONFIG_HS20 - filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION; -#endif /* CONFIG_HS20 */ - if (filt.app_filterype) { - ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, - sizeof(struct ieee80211req_set_filter)); - if (ret) - return ret; - } - -#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) - drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW, - atheros_raw_receive, drv, 1); - if (drv->sock_raw == NULL) - return -1; -#endif /* CONFIG_WPS || CONFIG_IEEE80211R */ - return ret; -} - -static int atheros_reset_appfilter(struct atheros_driver_data *drv) -{ - struct ieee80211req_set_filter filt; - filt.app_filterype = 0; - return set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, - sizeof(struct ieee80211req_set_filter)); -} - -#ifdef CONFIG_WPS -static int -atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) -{ - struct atheros_driver_data *drv = priv; - u8 buf[512]; - struct ieee80211req_getset_appiebuf *beac_ie; - - 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; - beac_ie->app_buflen = len; - os_memcpy(&(beac_ie->app_buf[0]), ie, len); - - /* append the WPA/RSN IE if it is set already */ - 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); -} - -static int -atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, - const struct wpabuf *proberesp, - const struct wpabuf *assocresp) -{ - 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); - drv->wps_probe_resp_ie = proberesp ? wpabuf_dup(proberesp) : NULL; - - atheros_set_wps_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL, - assocresp ? wpabuf_len(assocresp) : 0, - IEEE80211_APPIE_FRAME_ASSOC_RESP); - if (atheros_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL, - beacon ? wpabuf_len(beacon) : 0, - IEEE80211_APPIE_FRAME_BEACON)) - return -1; - return atheros_set_wps_ie(priv, - proberesp ? wpabuf_head(proberesp) : NULL, - proberesp ? wpabuf_len(proberesp): 0, - IEEE80211_APPIE_FRAME_PROBE_RESP); -} -#else /* CONFIG_WPS */ -#define atheros_set_ap_wps_ie NULL -#endif /* CONFIG_WPS */ - -#ifdef CONFIG_IEEE80211R -static int -atheros_sta_auth(void *priv, const u8 *own_addr, const u8 *addr, u16 seq, - u16 status_code, const u8 *ie, size_t len) -{ - struct atheros_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d", - __func__, ether_sprintf(addr), status_code); - - mlme.im_op = IEEE80211_MLME_AUTH; - mlme.im_reason = status_code; - mlme.im_seq = seq; - os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - mlme.im_optie_len = len; - if (len) { - if (len < IEEE80211_MAX_OPT_IE) { - os_memcpy(mlme.im_optie, ie, len); - } else { - wpa_printf(MSG_DEBUG, "%s: Not enough space to copy " - "opt_ie STA (addr " MACSTR " reason %d, " - "ie_len %d)", - __func__, MAC2STR(addr), status_code, - (int) len); - return -1; - } - } - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to auth STA (addr " MACSTR - " reason %d)", - __func__, MAC2STR(addr), status_code); - } - return ret; -} - -static int -atheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr, - int reassoc, u16 status_code, const u8 *ie, size_t len) -{ - struct atheros_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d reassoc %d", - __func__, ether_sprintf(addr), status_code, reassoc); - - if (reassoc) - mlme.im_op = IEEE80211_MLME_REASSOC; - else - mlme.im_op = IEEE80211_MLME_ASSOC; - mlme.im_reason = status_code; - os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - mlme.im_optie_len = len; - if (len) { - if (len < IEEE80211_MAX_OPT_IE) { - os_memcpy(mlme.im_optie, ie, len); - } else { - wpa_printf(MSG_DEBUG, "%s: Not enough space to copy " - "opt_ie STA (addr " MACSTR " reason %d, " - "ie_len %d)", - __func__, MAC2STR(addr), status_code, - (int) len); - return -1; - } - } - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to assoc STA (addr " MACSTR - " reason %d)", - __func__, MAC2STR(addr), status_code); - } - return ret; -} -#endif /* CONFIG_IEEE80211R */ - -static void -atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) -{ - struct hostapd_data *hapd = drv->hapd; - struct ieee80211req_wpaie ie; - int ielen = 0; - u8 *iebuf = NULL; - - /* - * Fetch negotiated WPA/RSN parameters from the system. - */ - memset(&ie, 0, sizeof(ie)); - memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); - if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { - /* - * See ATH_WPS_IE comment in the beginning of the file for a - * possible cause for the failure.. - */ - wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s", - __func__, strerror(errno)); - goto no_ie; - } - wpa_hexdump(MSG_MSGDUMP, "atheros req WPA IE", - ie.wpa_ie, IEEE80211_MAX_OPT_IE); - wpa_hexdump(MSG_MSGDUMP, "atheros req RSN IE", - ie.rsn_ie, IEEE80211_MAX_OPT_IE); -#ifdef ATH_WPS_IE - wpa_hexdump(MSG_MSGDUMP, "atheros req WPS IE", - ie.wps_ie, IEEE80211_MAX_OPT_IE); -#endif /* ATH_WPS_IE */ - iebuf = ie.wpa_ie; - /* atheros seems to return some random data if WPA/RSN IE is not set. - * Assume the IE was not included if the IE type is unknown. */ - if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) - iebuf[1] = 0; - if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { - /* atheros-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not - * set. This is needed for WPA2. */ - iebuf = ie.rsn_ie; - if (iebuf[0] != WLAN_EID_RSN) - iebuf[1] = 0; - } - - ielen = iebuf[1]; - -#ifdef ATH_WPS_IE - /* if WPS IE is present, preference is given to WPS */ - if (ie.wps_ie && - (ie.wps_ie[1] > 0 && (ie.wps_ie[0] == WLAN_EID_VENDOR_SPECIFIC))) { - iebuf = ie.wps_ie; - ielen = ie.wps_ie[1]; - } -#endif /* ATH_WPS_IE */ - - if (ielen == 0) - iebuf = NULL; - else - ielen += 2; - -no_ie: - drv_event_assoc(hapd, addr, iebuf, ielen, 0); - - if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { - /* Cached accounting data is not valid anymore. */ - memset(drv->acct_mac, 0, ETH_ALEN); - memset(&drv->acct_data, 0, sizeof(drv->acct_data)); - } -} - -static void -atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, - char *custom, char *end) -{ - wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); - - if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { - char *pos; - u8 addr[ETH_ALEN]; - pos = strstr(custom, "addr="); - if (pos == NULL) { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "without sender address ignored"); - return; - } - pos += 5; - if (hwaddr_aton(pos, addr) == 0) { - union wpa_event_data data; - os_memset(&data, 0, sizeof(data)); - data.michael_mic_failure.unicast = 1; - data.michael_mic_failure.src = addr; - wpa_supplicant_event(drv->hapd, - EVENT_MICHAEL_MIC_FAILURE, &data); - } else { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "with invalid MAC address"); - } - } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) { - char *key, *value; - u32 val; - key = custom; - while ((key = strchr(key, '\n')) != NULL) { - key++; - value = strchr(key, '='); - if (value == NULL) - continue; - *value++ = '\0'; - val = strtoul(value, NULL, 10); - if (strcmp(key, "mac") == 0) - hwaddr_aton(value, drv->acct_mac); - else if (strcmp(key, "rx_packets") == 0) - drv->acct_data.rx_packets = val; - else if (strcmp(key, "tx_packets") == 0) - drv->acct_data.tx_packets = val; - else if (strcmp(key, "rx_bytes") == 0) - drv->acct_data.rx_bytes = val; - else if (strcmp(key, "tx_bytes") == 0) - drv->acct_data.tx_bytes = val; - key = value; - } -#ifdef CONFIG_WPS - } else if (strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) { - /* Some atheros kernels send push button as a wireless event */ - /* PROBLEM! this event is received for ALL BSSs ... - * so all are enabled for WPS... ugh. - */ - wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL); -#endif /* CONFIG_WPS */ -#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) -#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */ - } else if (strncmp(custom, "Manage.prob_req ", 16) == 0) { - /* - * Atheros driver uses a hack to pass Probe Request frames as a - * binary data in the custom wireless event. The old way (using - * packet sniffing) didn't work when bridging. - * Format: "Manage.prob_req " | zero padding | frame - */ - int len = atoi(custom + 16); - if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) { - wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event " - "length %d", len); - return; - } - atheros_raw_receive(drv, NULL, - (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); - } else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) { - /* Format: "Manage.assoc_req " | zero padding | - * frame */ - int len = atoi(custom + 17); - if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) { - wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/" - "assoc_req/auth event length %d", len); - return; - } - atheros_raw_receive(drv, NULL, - (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); - } else if (strncmp(custom, "Manage.action ", 14) == 0) { - /* Format: "Manage.assoc_req " | zero padding | - * frame */ - int len = atoi(custom + 14); - if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) { - wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/" - "assoc_req/auth event length %d", len); - return; - } - atheros_raw_receive(drv, NULL, - (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); - } else if (strncmp(custom, "Manage.auth ", 12) == 0) { - /* Format: "Manage.auth " | zero padding | frame - */ - int len = atoi(custom + 12); - if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) { - wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/" - "assoc_req/auth event length %d", len); - return; - } - atheros_raw_receive(drv, NULL, - (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); -#endif /* CONFIG_WPS or CONFIG_IEEE80211R */ - } -} - -/* -* Handle size of data problem. WEXT only allows data of 256 bytes for custom -* events, and p2p data can be much bigger. So the athr driver sends a small -* event telling me to collect the big data with an ioctl. -* On the first event, send all pending events to supplicant. -*/ -static void fetch_pending_big_events(struct atheros_driver_data *drv) -{ - union wpa_event_data event; - const struct ieee80211_mgmt *mgmt; - u8 tbuf[IW_PRIV_SIZE_MASK]; /* max size is 2047 bytes */ - u16 fc, stype; - struct iwreq iwr; - size_t data_len; - u32 freq, frame_type; - - while (1) { - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - - iwr.u.data.pointer = (void *) tbuf; - iwr.u.data.length = sizeof(tbuf); - iwr.u.data.flags = IEEE80211_IOC_P2P_FETCH_FRAME; - - if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) - < 0) { - if (errno == ENOSPC) { - wpa_printf(MSG_DEBUG, "%s:%d exit", - __func__, __LINE__); - return; - } - wpa_printf(MSG_DEBUG, "athr: %s: P2P_BIG_PARAM[" - "P2P_FETCH_FRAME] failed: %s", - __func__, strerror(errno)); - return; - } - data_len = iwr.u.data.length; - wpa_hexdump(MSG_DEBUG, "athr: P2P_FETCH_FRAME data", - (u8 *) tbuf, data_len); - if (data_len < sizeof(freq) + sizeof(frame_type) + 24) { - wpa_printf(MSG_DEBUG, "athr: frame too short"); - continue; - } - os_memcpy(&freq, tbuf, sizeof(freq)); - os_memcpy(&frame_type, &tbuf[sizeof(freq)], - sizeof(frame_type)); - mgmt = (void *) &tbuf[sizeof(freq) + sizeof(frame_type)]; - data_len -= sizeof(freq) + sizeof(frame_type); - - if (frame_type == IEEE80211_EV_RX_MGMT) { - fc = le_to_host16(mgmt->frame_control); - stype = WLAN_FC_GET_STYPE(fc); - - wpa_printf(MSG_DEBUG, "athr: EV_RX_MGMT stype=%u " - "freq=%u len=%u", stype, freq, (int) data_len); - - if (stype == WLAN_FC_STYPE_ACTION) { - os_memset(&event, 0, sizeof(event)); - event.rx_mgmt.frame = (const u8 *) mgmt; - event.rx_mgmt.frame_len = data_len; - wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, - &event); - continue; - } - } else { - wpa_printf(MSG_DEBUG, "athr: %s unknown type %d", - __func__, frame_type); - continue; - } - } -} - -static void -atheros_wireless_event_atheros_custom(struct atheros_driver_data *drv, - int opcode, char *buf, int len) -{ - switch (opcode) { - case IEEE80211_EV_RX_MGMT: - wpa_printf(MSG_DEBUG, "WEXT: EV_RX_MGMT"); - fetch_pending_big_events(drv); - break; - default: - break; - } -} - -static void -atheros_wireless_event_wireless(struct atheros_driver_data *drv, - char *data, int len) -{ - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end, *custom, *buf; - - 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. */ - memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); - wpa_printf(MSG_MSGDUMP, "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 > 18 && - (iwe->cmd == IWEVMICHAELMICFAILURE || - iwe->cmd == IWEVASSOCREQIE || - 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; - memcpy(dpos, pos + IW_EV_LCP_LEN, - sizeof(struct iw_event) - dlen); - } else { - memcpy(&iwe_buf, pos, sizeof(struct iw_event)); - custom += IW_EV_POINT_OFF; - } - - switch (iwe->cmd) { - case IWEVEXPIRED: - drv_event_disassoc(drv->hapd, - (u8 *) iwe->u.addr.sa_data); - break; - case IWEVREGISTERED: - atheros_new_sta(drv, (u8 *) iwe->u.addr.sa_data); - break; - case IWEVASSOCREQIE: - /* Driver hack.. Use IWEVASSOCREQIE to bypass - * IWEVCUSTOM size limitations. Need to handle this - * just like IWEVCUSTOM. - */ - case IWEVCUSTOM: - if (custom + iwe->u.data.length > end) - return; - buf = malloc(iwe->u.data.length + 1); - if (buf == NULL) - return; /* XXX */ - memcpy(buf, custom, iwe->u.data.length); - buf[iwe->u.data.length] = '\0'; - - if (iwe->u.data.flags != 0) { - atheros_wireless_event_atheros_custom( - drv, (int) iwe->u.data.flags, - buf, len); - } else { - atheros_wireless_event_wireless_custom( - drv, buf, buf + iwe->u.data.length); - } - free(buf); - break; - } - - pos += iwe->len; - } -} - - -static void -atheros_wireless_event_rtm_newlink(void *ctx, - struct ifinfomsg *ifi, u8 *buf, size_t len) -{ - struct atheros_driver_data *drv = ctx; - int attrlen, rta_len; - struct rtattr *attr; - - if (ifi->ifi_index != drv->ifindex) - return; - - attrlen = len; - attr = (struct rtattr *) buf; - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_WIRELESS) { - atheros_wireless_event_wireless( - drv, ((char *) attr) + rta_len, - attr->rta_len - rta_len); - } - attr = RTA_NEXT(attr, attrlen); - } -} - - -static int -atheros_get_we_version(struct atheros_driver_data *drv) -{ - struct iw_range *range; - struct iwreq iwr; - int minlen; - size_t buflen; - - drv->we_version = 0; - - /* - * Use larger buffer than struct iw_range in order to allow the - * structure to grow in the future. - */ - buflen = sizeof(struct iw_range) + 500; - range = os_zalloc(buflen); - if (range == NULL) - return -1; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) range; - iwr.u.data.length = buflen; - - minlen = ((char *) &range->enc_capa) - (char *) range + - sizeof(range->enc_capa); - - if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { - perror("ioctl[SIOCGIWRANGE]"); - free(range); - return -1; - } else if (iwr.u.data.length >= minlen && - range->we_version_compiled >= 18) { - wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " - "WE(source)=%d enc_capa=0x%x", - range->we_version_compiled, - range->we_version_source, - range->enc_capa); - drv->we_version = range->we_version_compiled; - } - - os_free(range); - return 0; -} - - -static int -atheros_wireless_event_init(struct atheros_driver_data *drv) -{ - struct netlink_config *cfg; - - atheros_get_we_version(drv); - - cfg = os_zalloc(sizeof(*cfg)); - if (cfg == NULL) - return -1; - cfg->ctx = drv; - cfg->newlink_cb = atheros_wireless_event_rtm_newlink; - drv->netlink = netlink_init(cfg); - if (drv->netlink == NULL) { - os_free(cfg); - return -1; - } - - return 0; -} - - -static int -atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, - int encrypt, const u8 *own_addr, u32 flags) -{ - struct atheros_driver_data *drv = priv; - unsigned char buf[3000]; - unsigned char *bp = buf; - struct l2_ethhdr *eth; - size_t len; - int status; - - /* - * Prepend the Ethernet header. If the caller left us - * space at the front we could just insert it but since - * we don't know we copy to a local buffer. Given the frequency - * and size of frames this probably doesn't matter. - */ - len = data_len + sizeof(struct l2_ethhdr); - if (len > sizeof(buf)) { - bp = malloc(len); - if (bp == NULL) { - printf("EAPOL frame discarded, cannot malloc temp " - "buffer of size %lu!\n", (unsigned long) len); - return -1; - } - } - eth = (struct l2_ethhdr *) bp; - memcpy(eth->h_dest, addr, ETH_ALEN); - memcpy(eth->h_source, own_addr, ETH_ALEN); - eth->h_proto = host_to_be16(ETH_P_EAPOL); - memcpy(eth+1, data, data_len); - - wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); - - status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len); - - if (bp != buf) - free(bp); - return status; -} - -static void -handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) -{ - struct atheros_driver_data *drv = ctx; - drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr), - len - sizeof(struct l2_ethhdr)); -} - -static void * -atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params) -{ - struct atheros_driver_data *drv; - struct ifreq ifr; - struct iwreq iwr; - char brname[IFNAMSIZ]; - - drv = os_zalloc(sizeof(struct atheros_driver_data)); - if (drv == NULL) { - printf("Could not allocate memory for atheros driver data\n"); - return NULL; - } - - drv->hapd = hapd; - drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->ioctl_sock < 0) { - perror("socket[PF_INET,SOCK_DGRAM]"); - goto bad; - } - memcpy(drv->iface, params->ifname, sizeof(drv->iface)); - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); - if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) { - perror("ioctl(SIOCGIFINDEX)"); - goto bad; - } - drv->ifindex = ifr.ifr_ifindex; - - drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, - handle_read, drv, 1); - if (drv->sock_xmit == NULL) - goto bad; - if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) - goto bad; - os_memcpy(drv->own_addr, params->own_addr, ETH_ALEN); - if (params->bridge[0]) { - wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.", - params->bridge[0]); - drv->sock_recv = l2_packet_init(params->bridge[0], NULL, - ETH_P_EAPOL, handle_read, drv, - 1); - if (drv->sock_recv == NULL) - goto bad; - } else if (linux_br_get(brname, drv->iface) == 0) { - wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for " - "EAPOL receive", brname); - drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL, - handle_read, drv, 1); - if (drv->sock_recv == NULL) - goto bad; - } else - drv->sock_recv = drv->sock_xmit; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - - iwr.u.mode = IW_MODE_MASTER; - - if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { - perror("ioctl[SIOCSIWMODE]"); - printf("Could not set interface to master mode!\n"); - goto bad; - } - - /* mark down during setup */ - linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); - atheros_set_privacy(drv, 0); /* default to no privacy */ - - if (atheros_receive_pkt(drv)) - goto bad; - - if (atheros_wireless_event_init(drv)) - goto bad; - - return drv; -bad: - atheros_reset_appfilter(drv); - if (drv->sock_raw) - l2_packet_deinit(drv->sock_raw); - if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) - l2_packet_deinit(drv->sock_recv); - if (drv->sock_xmit != NULL) - l2_packet_deinit(drv->sock_xmit); - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - if (drv != NULL) - free(drv); - return NULL; -} - - -static void -atheros_deinit(void *priv) -{ - struct atheros_driver_data *drv = priv; - - atheros_reset_appfilter(drv); - netlink_deinit(drv->netlink); - (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) - l2_packet_deinit(drv->sock_recv); - if (drv->sock_xmit != NULL) - l2_packet_deinit(drv->sock_xmit); - if (drv->sock_raw) - l2_packet_deinit(drv->sock_raw); - wpabuf_free(drv->wpa_ie); - wpabuf_free(drv->wps_beacon_ie); - wpabuf_free(drv->wps_probe_resp_ie); - free(drv); -} - -static int -atheros_set_ssid(void *priv, const u8 *buf, int len) -{ - struct atheros_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.essid.flags = 1; /* SSID active */ - iwr.u.essid.pointer = (caddr_t) buf; - iwr.u.essid.length = len + 1; - - if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { - perror("ioctl[SIOCSIWESSID]"); - printf("len=%d\n", len); - return -1; - } - return 0; -} - -static int -atheros_get_ssid(void *priv, u8 *buf, int len) -{ - struct atheros_driver_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.essid.pointer = (caddr_t) buf; - iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ? - IW_ESSID_MAX_SIZE : len; - - if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { - perror("ioctl[SIOCGIWESSID]"); - ret = -1; - } else - ret = iwr.u.essid.length; - - return ret; -} - -static int -atheros_set_countermeasures(void *priv, int enabled) -{ - struct atheros_driver_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); - return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled); -} - -static int -atheros_commit(void *priv) -{ - struct atheros_driver_data *drv = priv; - return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1); -} - -static int atheros_set_authmode(void *priv, int auth_algs) -{ - int authmode; - - if ((auth_algs & WPA_AUTH_ALG_OPEN) && - (auth_algs & WPA_AUTH_ALG_SHARED)) - authmode = IEEE80211_AUTH_AUTO; - else if (auth_algs & WPA_AUTH_ALG_OPEN) - authmode = IEEE80211_AUTH_OPEN; - else if (auth_algs & WPA_AUTH_ALG_SHARED) - authmode = IEEE80211_AUTH_SHARED; - else - return -1; - - 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; -} - - -#ifdef CONFIG_IEEE80211R - -static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len, - int noack) -{ - struct atheros_driver_data *drv = priv; - u8 buf[1510]; - const struct ieee80211_mgmt *mgmt; - struct ieee80211req_mgmtbuf *mgmt_frm; - - mgmt = (const struct ieee80211_mgmt *) frm; - wpa_printf(MSG_DEBUG, "%s frmlen = %lu " MACSTR, __func__, - (unsigned long) data_len, MAC2STR(mgmt->da)); - mgmt_frm = (struct ieee80211req_mgmtbuf *) buf; - memcpy(mgmt_frm->macaddr, (u8 *)mgmt->da, IEEE80211_ADDR_LEN); - mgmt_frm->buflen = data_len; - if (&mgmt_frm->buf[0] + data_len > buf + sizeof(buf)) { - wpa_printf(MSG_INFO, "atheros: Too long frame for " - "atheros_send_mgmt (%u)", (unsigned int) data_len); - return -1; - } - os_memcpy(&mgmt_frm->buf[0], frm, data_len); - return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm, - sizeof(struct ieee80211req_mgmtbuf) + data_len); -} - - -static int atheros_add_tspec(void *priv, const u8 *addr, u8 *tspec_ie, - size_t tspec_ielen) -{ - struct atheros_driver_data *drv = priv; - int retv; - struct ieee80211req_res req; - struct ieee80211req_res_addts *addts = &req.u.addts; - - wpa_printf(MSG_DEBUG, "%s", __func__); - req.type = IEEE80211_RESREQ_ADDTS; - os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN); - os_memcpy(addts->tspecie, tspec_ie, tspec_ielen); - retv = set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req, - sizeof(struct ieee80211req_res)); - if (retv < 0) { - wpa_printf(MSG_DEBUG, "%s IEEE80211_IOCTL_RES_REQ FAILED " - "retv = %d", __func__, retv); - return -1; - } - os_memcpy(tspec_ie, addts->tspecie, tspec_ielen); - return addts->status; -} - - -static int atheros_add_sta_node(void *priv, const u8 *addr, u16 auth_alg) -{ - struct atheros_driver_data *drv = priv; - struct ieee80211req_res req; - struct ieee80211req_res_addnode *addnode = &req.u.addnode; - - wpa_printf(MSG_DEBUG, "%s", __func__); - req.type = IEEE80211_RESREQ_ADDNODE; - os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN); - addnode->auth_alg = auth_alg; - return set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req, - sizeof(struct ieee80211req_res)); -} - -#endif /* CONFIG_IEEE80211R */ - - -/* Use only to set a big param, get will not work. */ -static int -set80211big(struct atheros_driver_data *drv, int op, const void *data, int len) -{ - struct iwreq iwr; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - - iwr.u.data.pointer = (void *) data; - iwr.u.data.length = len; - iwr.u.data.flags = op; - wpa_printf(MSG_DEBUG, "%s: op=0x%x=%d (%s) len=0x%x", - __func__, op, op, athr_get_param_name(op), len); - - if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) < 0) { - wpa_printf(MSG_DEBUG, "%s: op=0x%x (%s) subop=0x%x=%d " - "value=0x%x,0x%x failed: %d (%s)", - __func__, op, athr_get_ioctl_name(op), iwr.u.mode, - iwr.u.mode, iwr.u.data.length, - iwr.u.data.flags, errno, strerror(errno)); - return -1; - } - return 0; -} - - -static int atheros_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, int no_cck) -{ - struct atheros_driver_data *drv = priv; - struct ieee80211_p2p_send_action *act; - int res; - - act = os_zalloc(sizeof(*act) + data_len); - if (act == NULL) - return -1; - act->freq = freq; - os_memcpy(act->dst_addr, dst, ETH_ALEN); - os_memcpy(act->src_addr, src, ETH_ALEN); - os_memcpy(act->bssid, bssid, ETH_ALEN); - os_memcpy(act + 1, data, data_len); - wpa_printf(MSG_DEBUG, "%s: freq=%d, wait=%u, dst=" MACSTR ", src=" - MACSTR ", bssid=" MACSTR, - __func__, act->freq, wait, MAC2STR(act->dst_addr), - MAC2STR(act->src_addr), MAC2STR(act->bssid)); - wpa_hexdump(MSG_MSGDUMP, "athr: act", (u8 *) act, sizeof(*act)); - wpa_hexdump(MSG_MSGDUMP, "athr: data", data, data_len); - - res = set80211big(drv, IEEE80211_IOC_P2P_SEND_ACTION, - act, sizeof(*act) + data_len); - os_free(act); - return res; -} - - -#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM) -static int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer, - u8 *ie, u16 *len, enum wnm_oper oper) -{ -#define IEEE80211_APPIE_MAX 1024 /* max appie buffer size */ - u8 buf[IEEE80211_APPIE_MAX]; - struct ieee80211req_getset_appiebuf *tfs_ie; - u16 val; - - wpa_printf(MSG_DEBUG, "atheros: ifname=%s, WNM TFS IE oper=%d " MACSTR, - drv->iface, oper, MAC2STR(peer)); - - switch (oper) { - case WNM_SLEEP_TFS_REQ_IE_SET: - if (*len > IEEE80211_APPIE_MAX - - sizeof(struct ieee80211req_getset_appiebuf)) { - wpa_printf(MSG_DEBUG, "TFS Req IE(s) too large"); - return -1; - } - tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; - tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; - tfs_ie->app_buflen = ETH_ALEN + 2 + 2 + *len; - - /* Command header for driver */ - os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); - val = oper; - os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); - val = *len; - os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); - - /* copy the ie */ - os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2 + 2, ie, *len); - - if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie, - IEEE80211_APPIE_MAX)) { - wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: " - "%s", __func__, strerror(errno)); - return -1; - } - break; - case WNM_SLEEP_TFS_RESP_IE_ADD: - tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; - tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; - tfs_ie->app_buflen = IEEE80211_APPIE_MAX - - sizeof(struct ieee80211req_getset_appiebuf); - /* Command header for driver */ - os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); - val = oper; - os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); - val = 0; - os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); - - if (set80211priv(drv, IEEE80211_IOCTL_GET_APPIEBUF, tfs_ie, - IEEE80211_APPIE_MAX)) { - wpa_printf(MSG_DEBUG, "%s: Failed to get WNM TFS IE: " - "%s", __func__, strerror(errno)); - return -1; - } - - *len = tfs_ie->app_buflen; - os_memcpy(ie, &(tfs_ie->app_buf[0]), *len); - wpa_printf(MSG_DEBUG, "atheros: %c len=%d", tfs_ie->app_buf[0], - *len); - break; - case WNM_SLEEP_TFS_RESP_IE_NONE: - *len = 0; - break; - case WNM_SLEEP_TFS_IE_DEL: - tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; - tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; - tfs_ie->app_buflen = IEEE80211_APPIE_MAX - - sizeof(struct ieee80211req_getset_appiebuf); - /* Command header for driver */ - os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); - val = oper; - os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); - val = 0; - os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); - - if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie, - IEEE80211_APPIE_MAX)) { - wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: " - "%s", __func__, strerror(errno)); - return -1; - } - break; - default: - wpa_printf(MSG_DEBUG, "Unsupported TFS oper %d", oper); - break; - } - - return 0; -} - - -static int atheros_wnm_sleep(struct atheros_driver_data *drv, - const u8 *peer, enum wnm_oper oper) -{ - u8 *data, *pos; - size_t dlen; - int ret; - u16 val; - - wpa_printf(MSG_DEBUG, "atheros: WNM-Sleep Oper %d, " MACSTR, - oper, MAC2STR(peer)); - - dlen = ETH_ALEN + 2 + 2; - data = os_malloc(dlen); - if (data == NULL) - return -1; - - /* Command header for driver */ - pos = data; - os_memcpy(pos, peer, ETH_ALEN); - pos += ETH_ALEN; - - val = oper; - os_memcpy(pos, &val, 2); - pos += 2; - - val = 0; - os_memcpy(pos, &val, 2); - - ret = atheros_set_wps_ie(drv, data, dlen, IEEE80211_APPIE_FRAME_WNM); - - os_free(data); - - return ret; -} - - -static int atheros_wnm_oper(void *priv, enum wnm_oper oper, const u8 *peer, - u8 *buf, u16 *buf_len) -{ - struct atheros_driver_data *drv = priv; - - switch (oper) { - case WNM_SLEEP_ENTER_CONFIRM: - case WNM_SLEEP_ENTER_FAIL: - case WNM_SLEEP_EXIT_CONFIRM: - case WNM_SLEEP_EXIT_FAIL: - return atheros_wnm_sleep(drv, peer, oper); - case WNM_SLEEP_TFS_REQ_IE_SET: - case WNM_SLEEP_TFS_RESP_IE_ADD: - case WNM_SLEEP_TFS_RESP_IE_NONE: - case WNM_SLEEP_TFS_IE_DEL: - return athr_wnm_tfs(drv, peer, buf, buf_len, oper); - default: - wpa_printf(MSG_DEBUG, "atheros: Unsupported WNM operation %d", - oper); - return -1; - } -} -#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */ - - -const struct wpa_driver_ops wpa_driver_atheros_ops = { - .name = "atheros", - .hapd_init = atheros_init, - .hapd_deinit = atheros_deinit, - .set_ieee8021x = atheros_set_ieee8021x, - .set_privacy = atheros_set_privacy, - .set_key = atheros_set_key, - .get_seqnum = atheros_get_seqnum, - .flush = atheros_flush, - .set_generic_elem = atheros_set_opt_ie, - .sta_set_flags = atheros_sta_set_flags, - .read_sta_data = atheros_read_sta_driver_data, - .hapd_send_eapol = atheros_send_eapol, - .sta_disassoc = atheros_sta_disassoc, - .sta_deauth = atheros_sta_deauth, - .hapd_set_ssid = atheros_set_ssid, - .hapd_get_ssid = atheros_get_ssid, - .set_countermeasures = atheros_set_countermeasures, - .sta_clear_stats = atheros_sta_clear_stats, - .commit = atheros_commit, - .set_ap_wps_ie = atheros_set_ap_wps_ie, - .set_authmode = atheros_set_authmode, - .set_ap = atheros_set_ap, -#ifdef CONFIG_IEEE80211R - .sta_assoc = atheros_sta_assoc, - .sta_auth = atheros_sta_auth, - .send_mlme = atheros_send_mgmt, - .add_tspec = atheros_add_tspec, - .add_sta_node = atheros_add_sta_node, -#endif /* CONFIG_IEEE80211R */ - .send_action = atheros_send_action, -#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM) - .wnm_oper = atheros_wnm_oper, -#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */ - .set_qos_map = atheros_set_qos_map, -}; diff --git a/contrib/hostapd/src/drivers/driver_bsd.c b/contrib/hostapd/src/drivers/driver_bsd.c deleted file mode 100644 index 4b3b11ad0c..0000000000 --- a/contrib/hostapd/src/drivers/driver_bsd.c +++ /dev/null @@ -1,1631 +0,0 @@ -/* - * WPA Supplicant - driver interaction with BSD net80211 layer - * Copyright (c) 2004, Sam Leffler - * Copyright (c) 2004, 2Wire, Inc - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include -#include - -#include "common.h" -#include "driver.h" -#include "eloop.h" -#include "common/ieee802_11_defs.h" -#include "common/wpa_common.h" - -#include -#include - -#ifdef __NetBSD__ -#include -#else -#include -#endif -#include - -#ifdef __DragonFly__ -#include -#include -#else /* __DragonFly__ */ -#ifdef __GLIBC__ -#include -#endif /* __GLIBC__ */ -#include -#include -#include -#endif /* __DragonFly__ || __GLIBC__ */ -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -#include -#endif -#if __NetBSD__ -#include -#endif - -#include "l2_packet/l2_packet.h" - -struct bsd_driver_data { - struct hostapd_data *hapd; /* back pointer */ - - int sock; /* open socket for 802.11 ioctls */ - struct l2_packet_data *sock_xmit;/* raw packet xmit socket */ - int route; /* routing socket for events */ - char ifname[IFNAMSIZ+1]; /* interface name */ - unsigned int ifindex; /* interface index */ - void *ctx; - struct wpa_driver_capa capa; /* driver capability */ - int is_ap; /* Access point mode */ - int prev_roaming; /* roaming state to restore on deinit */ - int prev_privacy; /* privacy state to restore on deinit */ - int prev_wpa; /* wpa state to restore on deinit */ - enum ieee80211_opmode opmode; /* operation mode */ - char *event_buf; - size_t event_buf_len; -}; - -/* Generic functions for hostapd and wpa_supplicant */ - -static int -bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len) -{ - struct bsd_driver_data *drv = priv; - struct ieee80211req ireq; - - os_memset(&ireq, 0, sizeof(ireq)); - os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name)); - ireq.i_type = op; - ireq.i_val = val; - ireq.i_data = (void *) arg; - ireq.i_len = arg_len; - - if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) { - wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, " - "arg_len=%u]: %s", op, val, arg_len, - strerror(errno)); - return -1; - } - return 0; -} - -static int -bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg, - int arg_len) -{ - struct bsd_driver_data *drv = priv; - - os_memset(ireq, 0, sizeof(*ireq)); - os_strlcpy(ireq->i_name, drv->ifname, sizeof(ireq->i_name)); - ireq->i_type = op; - ireq->i_len = arg_len; - ireq->i_data = arg; - - if (ioctl(drv->sock, SIOCG80211, ireq) < 0) { - wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, " - "arg_len=%u]: %s", op, arg_len, strerror(errno)); - return -1; - } - return 0; -} - -static int -get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len) -{ - struct ieee80211req ireq; - - if (bsd_get80211(drv, &ireq, op, arg, arg_len) < 0) - return -1; - return ireq.i_len; -} - -static int -set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len) -{ - return bsd_set80211(drv, op, 0, arg, arg_len); -} - -static int -set80211param(struct bsd_driver_data *drv, int op, int arg) -{ - return bsd_set80211(drv, op, arg, NULL, 0); -} - -static int -bsd_get_ssid(void *priv, u8 *ssid, int len) -{ - struct bsd_driver_data *drv = priv; -#ifdef SIOCG80211NWID - struct ieee80211_nwid nwid; - struct ifreq ifr; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); - ifr.ifr_data = (void *)&nwid; - if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 || - nwid.i_len > IEEE80211_NWID_LEN) - return -1; - os_memcpy(ssid, nwid.i_nwid, nwid.i_len); - return nwid.i_len; -#else - return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN); -#endif -} - -static int -bsd_set_ssid(void *priv, const u8 *ssid, int ssid_len) -{ - struct bsd_driver_data *drv = priv; -#ifdef SIOCS80211NWID - struct ieee80211_nwid nwid; - struct ifreq ifr; - - os_memcpy(nwid.i_nwid, ssid, ssid_len); - nwid.i_len = ssid_len; - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); - ifr.ifr_data = (void *)&nwid; - return ioctl(drv->sock, SIOCS80211NWID, &ifr); -#else - return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len); -#endif -} - -static int -bsd_get_if_media(void *priv) -{ - struct bsd_driver_data *drv = priv; - struct ifmediareq ifmr; - - os_memset(&ifmr, 0, sizeof(ifmr)); - os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name)); - - if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) { - wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__, - strerror(errno)); - return -1; - } - - return ifmr.ifm_current; -} - -static int -bsd_set_if_media(void *priv, int media) -{ - struct bsd_driver_data *drv = priv; - struct ifreq ifr; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); - ifr.ifr_media = media; - - if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) { - wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__, - strerror(errno)); - return -1; - } - - return 0; -} - -static int -bsd_set_mediaopt(void *priv, uint32_t mask, uint32_t mode) -{ - int media = bsd_get_if_media(priv); - - if (media < 0) - return -1; - media &= ~mask; - media |= mode; - if (bsd_set_if_media(priv, media) < 0) - return -1; - return 0; -} - -static int -bsd_del_key(void *priv, const u8 *addr, int key_idx) -{ - struct ieee80211req_del_key wk; - - os_memset(&wk, 0, sizeof(wk)); - if (addr == NULL) { - wpa_printf(MSG_DEBUG, "%s: key_idx=%d", __func__, key_idx); - wk.idk_keyix = key_idx; - } else { - wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, - MAC2STR(addr)); - os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); - wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */ - } - - return set80211var(priv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk)); -} - -static int -bsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr) -{ - struct ieee80211req_mlme mlme; - - os_memset(&mlme, 0, sizeof(mlme)); - mlme.im_op = op; - mlme.im_reason = reason; - os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - return set80211var(priv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); -} - -static int -bsd_ctrl_iface(void *priv, int enable) -{ - struct bsd_driver_data *drv = priv; - struct ifreq ifr; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); - - if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) { - perror("ioctl[SIOCGIFFLAGS]"); - return -1; - } - - if (enable) { - if (ifr.ifr_flags & IFF_UP) - return 0; - ifr.ifr_flags |= IFF_UP; - } else { - if (!(ifr.ifr_flags & IFF_UP)) - return 0; - ifr.ifr_flags &= ~IFF_UP; - } - - if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) { - perror("ioctl[SIOCSIFFLAGS]"); - return -1; - } - - return 0; -} - -static int -bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg, - const unsigned char *addr, int key_idx, int set_tx, const u8 *seq, - size_t seq_len, const u8 *key, size_t key_len) -{ - struct ieee80211req_key wk; -#ifdef IEEE80211_KEY_NOREPLAY - struct bsd_driver_data *drv = priv; -#endif /* IEEE80211_KEY_NOREPLAY */ - - wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d " - "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx, - set_tx, seq_len, key_len); - - if (alg == WPA_ALG_NONE) { -#ifndef HOSTAPD - if (addr == NULL || is_broadcast_ether_addr(addr)) - return bsd_del_key(priv, NULL, key_idx); - else -#endif /* HOSTAPD */ - return bsd_del_key(priv, addr, key_idx); - } - - os_memset(&wk, 0, sizeof(wk)); - switch (alg) { - case WPA_ALG_WEP: - wk.ik_type = IEEE80211_CIPHER_WEP; - break; - case WPA_ALG_TKIP: - wk.ik_type = IEEE80211_CIPHER_TKIP; - break; - case WPA_ALG_CCMP: - wk.ik_type = IEEE80211_CIPHER_AES_CCM; - break; - default: - wpa_printf(MSG_ERROR, "%s: unknown alg=%d", __func__, alg); - return -1; - } - - wk.ik_flags = IEEE80211_KEY_RECV; - if (set_tx) - wk.ik_flags |= IEEE80211_KEY_XMIT; - - if (addr == NULL) { - os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); - wk.ik_keyix = key_idx; - } else { - os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); - /* - * Deduce whether group/global or unicast key by checking - * the address (yech). Note also that we can only mark global - * keys default; doing this for a unicast key is an error. - */ - if (is_broadcast_ether_addr(addr)) { - wk.ik_flags |= IEEE80211_KEY_GROUP; - wk.ik_keyix = key_idx; - } else { - wk.ik_keyix = key_idx == 0 ? IEEE80211_KEYIX_NONE : - key_idx; - } - } - if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx) - wk.ik_flags |= IEEE80211_KEY_DEFAULT; -#ifndef HOSTAPD -#ifdef IEEE80211_KEY_NOREPLAY - /* - * Ignore replay failures in IBSS and AHDEMO mode. - */ - if (drv->opmode == IEEE80211_M_IBSS || - drv->opmode == IEEE80211_M_AHDEMO) - wk.ik_flags |= IEEE80211_KEY_NOREPLAY; -#endif /* IEEE80211_KEY_NOREPLAY */ -#endif /* HOSTAPD */ - wk.ik_keylen = key_len; - if (seq) { -#ifdef WORDS_BIGENDIAN - /* - * wk.ik_keyrsc is in host byte order (big endian), need to - * swap it to match with the byte order used in WPA. - */ - int i; - u8 *keyrsc = (u8 *) &wk.ik_keyrsc; - for (i = 0; i < seq_len; i++) - keyrsc[WPA_KEY_RSC_LEN - i - 1] = seq[i]; -#else /* WORDS_BIGENDIAN */ - os_memcpy(&wk.ik_keyrsc, seq, seq_len); -#endif /* WORDS_BIGENDIAN */ - } - os_memcpy(wk.ik_keydata, key, key_len); - - return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)); -} - -static int -bsd_configure_wpa(void *priv, struct wpa_bss_params *params) -{ -#ifndef IEEE80211_IOC_APPIE - static const char *ciphernames[] = - { "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" }; - int v; - - switch (params->wpa_group) { - case WPA_CIPHER_CCMP: - v = IEEE80211_CIPHER_AES_CCM; - break; - case WPA_CIPHER_TKIP: - v = IEEE80211_CIPHER_TKIP; - break; - case WPA_CIPHER_WEP104: - v = IEEE80211_CIPHER_WEP; - break; - case WPA_CIPHER_WEP40: - v = IEEE80211_CIPHER_WEP; - break; - case WPA_CIPHER_NONE: - v = IEEE80211_CIPHER_NONE; - break; - default: - printf("Unknown group key cipher %u\n", - params->wpa_group); - return -1; - } - wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)", - __func__, ciphernames[v], v); - if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) { - printf("Unable to set group key cipher to %u (%s)\n", - v, ciphernames[v]); - return -1; - } - if (v == IEEE80211_CIPHER_WEP) { - /* key length is done only for specific ciphers */ - v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); - if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) { - printf("Unable to set group key length to %u\n", v); - return -1; - } - } - - v = 0; - if (params->wpa_pairwise & WPA_CIPHER_CCMP) - v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) - v |= 1<wpa_pairwise & WPA_CIPHER_NONE) - v |= 1<wpa_key_mgmt); - if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS, - params->wpa_key_mgmt)) { - printf("Unable to set key management algorithms to 0x%x\n", - params->wpa_key_mgmt); - return -1; - } - - v = 0; - if (params->rsn_preauth) - v |= BIT(0); - wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", - __func__, params->rsn_preauth); - if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) { - printf("Unable to set RSN capabilities to 0x%x\n", v); - return -1; - } -#endif /* IEEE80211_IOC_APPIE */ - - wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa); - if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) { - printf("Unable to set WPA to %u\n", params->wpa); - return -1; - } - return 0; -} - -static int -bsd_set_ieee8021x(void *priv, struct wpa_bss_params *params) -{ - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); - - if (!params->enabled) { - /* XXX restore state */ - return set80211param(priv, IEEE80211_IOC_AUTHMODE, - IEEE80211_AUTH_AUTO); - } - if (!params->wpa && !params->ieee802_1x) { - wpa_printf(MSG_ERROR, "%s: No 802.1X or WPA enabled", - __func__); - return -1; - } - if (params->wpa && bsd_configure_wpa(priv, params) != 0) { - wpa_printf(MSG_ERROR, "%s: Failed to configure WPA state", - __func__); - return -1; - } - if (set80211param(priv, IEEE80211_IOC_AUTHMODE, - (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { - wpa_printf(MSG_ERROR, "%s: Failed to enable WPA/802.1X", - __func__); - return -1; - } - return bsd_ctrl_iface(priv, 1); -} - -static void -bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN]) -{ - struct ieee80211req_wpaie ie; - int ielen = 0; - u8 *iebuf = NULL; - - /* - * Fetch and validate any negotiated WPA/RSN parameters. - */ - memset(&ie, 0, sizeof(ie)); - memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); - if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { - printf("Failed to get WPA/RSN information element.\n"); - goto no_ie; - } - iebuf = ie.wpa_ie; - ielen = ie.wpa_ie[1]; - if (ielen == 0) - iebuf = NULL; - else - ielen += 2; - -no_ie: - drv_event_assoc(ctx, addr, iebuf, ielen, 0); -} - -static int -bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, - int encrypt, const u8 *own_addr, u32 flags) -{ - struct bsd_driver_data *drv = priv; - - wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", data, data_len); - - return l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, data, - data_len); -} - -static int -bsd_set_freq(void *priv, struct hostapd_freq_params *freq) -{ - struct bsd_driver_data *drv = priv; -#ifdef SIOCS80211CHANNEL - struct ieee80211chanreq creq; -#endif /* SIOCS80211CHANNEL */ - u32 mode; - int channel = freq->channel; - - if (channel < 14) { - mode = -#ifdef CONFIG_IEEE80211N - freq->ht_enabled ? IFM_IEEE80211_11NG : -#endif /* CONFIG_IEEE80211N */ - IFM_IEEE80211_11G; - } else if (channel == 14) { - mode = IFM_IEEE80211_11B; - } else { - mode = -#ifdef CONFIG_IEEE80211N - freq->ht_enabled ? IFM_IEEE80211_11NA : -#endif /* CONFIG_IEEE80211N */ - IFM_IEEE80211_11A; - } - if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) { - wpa_printf(MSG_ERROR, "%s: failed to set modulation mode", - __func__); - return -1; - } - -#ifdef SIOCS80211CHANNEL - os_memset(&creq, 0, sizeof(creq)); - os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name)); - creq.i_channel = (u_int16_t)channel; - return ioctl(drv->sock, SIOCS80211CHANNEL, &creq); -#else /* SIOCS80211CHANNEL */ - return set80211param(priv, IEEE80211_IOC_CHANNEL, channel); -#endif /* SIOCS80211CHANNEL */ -} - -static int -bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) -{ -#ifdef IEEE80211_IOC_APPIE - wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__, - (unsigned long)ie_len); - return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA, - ie, ie_len); -#endif /* IEEE80211_IOC_APPIE */ - return 0; -} - -static size_t -rtbuf_len(void) -{ - size_t len; - - int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0}; - - if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { - wpa_printf(MSG_WARNING, "%s failed: %s\n", __func__, - strerror(errno)); - len = 2048; - } - - return len; -} - -#ifdef HOSTAPD - -/* - * Avoid conflicts with hostapd definitions by undefining couple of defines - * from net80211 header files. - */ -#undef RSN_VERSION -#undef WPA_VERSION -#undef WPA_OUI_TYPE - -static int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, - int reason_code); - -const char * -ether_sprintf(const u8 *addr) -{ - static char buf[sizeof(MACSTR)]; - - if (addr != NULL) - snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); - else - snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); - return buf; -} - -static int -bsd_set_privacy(void *priv, int enabled) -{ - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - - return set80211param(priv, IEEE80211_IOC_PRIVACY, enabled); -} - -static int -bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, - u8 *seq) -{ - struct ieee80211req_key wk; - - wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", - __func__, ether_sprintf(addr), idx); - - memset(&wk, 0, sizeof(wk)); - if (addr == NULL) - memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); - else - memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); - wk.ik_keyix = idx; - - if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) { - printf("Failed to get encryption.\n"); - return -1; - } - -#ifdef WORDS_BIGENDIAN - { - /* - * wk.ik_keytsc is in host byte order (big endian), need to - * swap it to match with the byte order used in WPA. - */ - int i; - u8 tmp[WPA_KEY_RSC_LEN]; - memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); - for (i = 0; i < WPA_KEY_RSC_LEN; i++) { - seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; - } - } -#else /* WORDS_BIGENDIAN */ - memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); -#endif /* WORDS_BIGENDIAN */ - return 0; -} - - -static int -bsd_flush(void *priv) -{ - u8 allsta[IEEE80211_ADDR_LEN]; - - memset(allsta, 0xff, IEEE80211_ADDR_LEN); - return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE); -} - - -static int -bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, - const u8 *addr) -{ - struct ieee80211req_sta_stats stats; - - memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); - if (get80211var(priv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) - > 0) { - /* XXX? do packets counts include non-data frames? */ - data->rx_packets = stats.is_stats.ns_rx_data; - data->rx_bytes = stats.is_stats.ns_rx_bytes; - data->tx_packets = stats.is_stats.ns_tx_data; - data->tx_bytes = stats.is_stats.ns_tx_bytes; - } - return 0; -} - -static int -bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code) -{ - return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, - addr); -} - -static int -bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, - int reason_code) -{ - return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code, - addr); -} - -static void -bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) -{ - struct bsd_driver_data *drv = ctx; - struct if_announcemsghdr *ifan; - struct rt_msghdr *rtm; - struct ieee80211_michael_event *mic; - struct ieee80211_join_event *join; - struct ieee80211_leave_event *leave; - int n; - union wpa_event_data data; - - n = read(sock, drv->event_buf, drv->event_buf_len); - if (n < 0) { - if (errno != EINTR && errno != EAGAIN) - wpa_printf(MSG_ERROR, "%s read() failed: %s\n", - __func__, strerror(errno)); - return; - } - - rtm = (struct rt_msghdr *) drv->event_buf; - if (rtm->rtm_version != RTM_VERSION) { - wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", - rtm->rtm_version); - return; - } - ifan = (struct if_announcemsghdr *) rtm; - switch (rtm->rtm_type) { - case RTM_IEEE80211: - switch (ifan->ifan_what) { - case RTM_IEEE80211_ASSOC: - case RTM_IEEE80211_REASSOC: - case RTM_IEEE80211_DISASSOC: - case RTM_IEEE80211_SCAN: - break; - case RTM_IEEE80211_LEAVE: - leave = (struct ieee80211_leave_event *) &ifan[1]; - drv_event_disassoc(drv->hapd, leave->iev_addr); - break; - case RTM_IEEE80211_JOIN: -#ifdef RTM_IEEE80211_REJOIN - case RTM_IEEE80211_REJOIN: -#endif - join = (struct ieee80211_join_event *) &ifan[1]; - bsd_new_sta(drv, drv->hapd, join->iev_addr); - break; - case RTM_IEEE80211_REPLAY: - /* ignore */ - break; - case RTM_IEEE80211_MICHAEL: - mic = (struct ieee80211_michael_event *) &ifan[1]; - wpa_printf(MSG_DEBUG, - "Michael MIC failure wireless event: " - "keyix=%u src_addr=" MACSTR, mic->iev_keyix, - MAC2STR(mic->iev_src)); - os_memset(&data, 0, sizeof(data)); - data.michael_mic_failure.unicast = 1; - data.michael_mic_failure.src = mic->iev_src; - wpa_supplicant_event(drv->hapd, - EVENT_MICHAEL_MIC_FAILURE, &data); - break; - } - break; - } -} - -static void -handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) -{ - struct bsd_driver_data *drv = ctx; - drv_event_eapol_rx(drv->hapd, src_addr, buf, len); -} - -static void * -bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) -{ - struct bsd_driver_data *drv; - - drv = os_zalloc(sizeof(struct bsd_driver_data)); - if (drv == NULL) { - wpa_printf(MSG_ERROR, "Could not allocate memory for bsd driver data"); - return NULL; - } - - drv->event_buf_len = rtbuf_len(); - - drv->event_buf = os_malloc(drv->event_buf_len); - if (drv->event_buf == NULL) { - wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__); - goto bad; - } - - drv->hapd = hapd; - drv->sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->sock < 0) { - perror("socket[PF_INET,SOCK_DGRAM]"); - goto bad; - } - os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); - - drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, - handle_read, drv, 0); - if (drv->sock_xmit == NULL) - goto bad; - if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) - goto bad; - - /* mark down during setup */ - if (bsd_ctrl_iface(drv, 0) < 0) - goto bad; - - drv->route = socket(PF_ROUTE, SOCK_RAW, 0); - if (drv->route < 0) { - perror("socket(PF_ROUTE,SOCK_RAW)"); - goto bad; - } - eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv, - NULL); - - if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) { - wpa_printf(MSG_ERROR, "%s: failed to set operation mode", - __func__); - goto bad; - } - - return drv; -bad: - if (drv->sock_xmit != NULL) - l2_packet_deinit(drv->sock_xmit); - if (drv->sock >= 0) - close(drv->sock); - os_free(drv->event_buf); - if (drv != NULL) - os_free(drv); - return NULL; -} - - -static void -bsd_deinit(void *priv) -{ - struct bsd_driver_data *drv = priv; - - if (drv->route >= 0) { - eloop_unregister_read_sock(drv->route); - close(drv->route); - } - bsd_ctrl_iface(drv, 0); - if (drv->sock >= 0) - close(drv->sock); - if (drv->sock_xmit != NULL) - l2_packet_deinit(drv->sock_xmit); - os_free(drv->event_buf); - os_free(drv); -} - - -static int -bsd_commit(void *priv) -{ - return bsd_ctrl_iface(priv, 1); -} - - -static int -bsd_set_sta_authorized(void *priv, const u8 *addr, - int total_flags, int flags_or, int flags_and) -{ - int authorized = -1; - - /* For now, only support setting Authorized flag */ - if (flags_or & WPA_STA_AUTHORIZED) - authorized = 1; - if (!(flags_and & WPA_STA_AUTHORIZED)) - authorized = 0; - - if (authorized < 0) - return 0; - - return bsd_send_mlme_param(priv, authorized ? - IEEE80211_MLME_AUTHORIZE : - IEEE80211_MLME_UNAUTHORIZE, 0, addr); -} -#else /* HOSTAPD */ - -static int -get80211param(struct bsd_driver_data *drv, int op) -{ - struct ieee80211req ireq; - - if (bsd_get80211(drv, &ireq, op, NULL, 0) < 0) - return -1; - return ireq.i_val; -} - -static int -wpa_driver_bsd_get_bssid(void *priv, u8 *bssid) -{ - struct bsd_driver_data *drv = priv; -#ifdef SIOCG80211BSSID - struct ieee80211_bssid bs; - - os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name)); - if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0) - return -1; - os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid)); - return 0; -#else - return get80211var(drv, IEEE80211_IOC_BSSID, - bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0; -#endif -} - -static int -wpa_driver_bsd_get_ssid(void *priv, u8 *ssid) -{ - struct bsd_driver_data *drv = priv; - return bsd_get_ssid(drv, ssid, 0); -} - -static int -wpa_driver_bsd_set_wpa_ie(struct bsd_driver_data *drv, const u8 *wpa_ie, - size_t wpa_ie_len) -{ -#ifdef IEEE80211_IOC_APPIE - return bsd_set_opt_ie(drv, wpa_ie, wpa_ie_len); -#else /* IEEE80211_IOC_APPIE */ - return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len); -#endif /* IEEE80211_IOC_APPIE */ -} - -static int -wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy) -{ - int ret = 0; - - wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d", - __FUNCTION__, wpa, privacy); - - if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0) - ret = -1; - if (set80211param(priv, IEEE80211_IOC_PRIVACY, privacy) < 0) - ret = -1; - if (set80211param(priv, IEEE80211_IOC_WPA, wpa) < 0) - ret = -1; - - return ret; -} - -static int -wpa_driver_bsd_set_wpa(void *priv, int enabled) -{ - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); - - return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled); -} - -static int -wpa_driver_bsd_set_countermeasures(void *priv, int enabled) -{ - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - return set80211param(priv, IEEE80211_IOC_COUNTERMEASURES, enabled); -} - - -static int -wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled) -{ - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - return set80211param(priv, IEEE80211_IOC_DROPUNENCRYPTED, enabled); -} - -static int -wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code) -{ - return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, - addr); -} - -static int -wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg) -{ - 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(priv, IEEE80211_IOC_AUTHMODE, authmode); -} - -static void -handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) -{ - struct bsd_driver_data *drv = ctx; - - drv_event_eapol_rx(drv->ctx, src_addr, buf, len); -} - -static int -wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params) -{ - struct bsd_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - u32 mode; - int privacy; - int ret = 0; - - wpa_printf(MSG_DEBUG, - "%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u" - , __func__ - , (unsigned int) params->ssid_len, params->ssid - , (unsigned int) params->wpa_ie_len - , params->pairwise_suite - , params->group_suite - , params->key_mgmt_suite - ); - - switch (params->mode) { - case IEEE80211_MODE_INFRA: - mode = 0 /* STA */; - break; - case IEEE80211_MODE_IBSS: - mode = IFM_IEEE80211_IBSS; - break; - case IEEE80211_MODE_AP: - mode = IFM_IEEE80211_HOSTAP; - break; - default: - wpa_printf(MSG_ERROR, "%s: unknown operation mode", __func__); - return -1; - } - if (bsd_set_mediaopt(drv, IFM_OMASK, mode) < 0) { - wpa_printf(MSG_ERROR, "%s: failed to set operation mode", - __func__); - return -1; - } - - if (params->mode == IEEE80211_MODE_AP) { - drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, - handle_read, drv, 0); - if (drv->sock_xmit == NULL) - return -1; - drv->is_ap = 1; - return 0; - } - - if (wpa_driver_bsd_set_drop_unencrypted(drv, params->drop_unencrypted) - < 0) - ret = -1; - if (wpa_driver_bsd_set_auth_alg(drv, params->auth_alg) < 0) - ret = -1; - /* XXX error handling is wrong but unclear what to do... */ - if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0) - return -1; - - privacy = !(params->pairwise_suite == WPA_CIPHER_NONE && - params->group_suite == WPA_CIPHER_NONE && - params->key_mgmt_suite == WPA_KEY_MGMT_NONE && - params->wpa_ie_len == 0); - wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy); - - if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0) - return -1; - - if (params->wpa_ie_len && - set80211param(drv, IEEE80211_IOC_WPA, - params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0) - return -1; - - os_memset(&mlme, 0, sizeof(mlme)); - mlme.im_op = IEEE80211_MLME_ASSOC; - if (params->ssid != NULL) - os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len); - mlme.im_ssid_len = params->ssid_len; - if (params->bssid != NULL) - os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN); - if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0) - return -1; - return ret; -} - -static int -wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params) -{ - struct bsd_driver_data *drv = priv; -#ifdef IEEE80211_IOC_SCAN_MAX_SSID - struct ieee80211_scan_req sr; - int i; -#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ - - if (bsd_set_mediaopt(drv, IFM_OMASK, 0 /* STA */) < 0) { - wpa_printf(MSG_ERROR, "%s: failed to set operation mode", - __func__); - return -1; - } - - if (set80211param(drv, IEEE80211_IOC_ROAMING, - IEEE80211_ROAMING_MANUAL) < 0) { - wpa_printf(MSG_ERROR, "%s: failed to set " - "wpa_supplicant-based roaming: %s", __func__, - strerror(errno)); - return -1; - } - - if (wpa_driver_bsd_set_wpa(drv, 1) < 0) { - wpa_printf(MSG_ERROR, "%s: failed to set wpa: %s", __func__, - strerror(errno)); - return -1; - } - - /* NB: interface must be marked UP to do a scan */ - if (bsd_ctrl_iface(drv, 1) < 0) - return -1; - -#ifdef IEEE80211_IOC_SCAN_MAX_SSID - os_memset(&sr, 0, sizeof(sr)); - sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE | - IEEE80211_IOC_SCAN_NOJOIN; - sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; - if (params->num_ssids > 0) { - sr.sr_nssid = params->num_ssids; -#if 0 - /* Boundary check is done by upper layer */ - if (sr.sr_nssid > IEEE80211_IOC_SCAN_MAX_SSID) - sr.sr_nssid = IEEE80211_IOC_SCAN_MAX_SSID; -#endif - - /* NB: check scan cache first */ - sr.sr_flags |= IEEE80211_IOC_SCAN_CHECK; - } - for (i = 0; i < sr.sr_nssid; i++) { - sr.sr_ssid[i].len = params->ssids[i].ssid_len; - os_memcpy(sr.sr_ssid[i].ssid, params->ssids[i].ssid, - sr.sr_ssid[i].len); - } - - /* NB: net80211 delivers a scan complete event so no need to poll */ - return set80211var(drv, IEEE80211_IOC_SCAN_REQ, &sr, sizeof(sr)); -#else /* IEEE80211_IOC_SCAN_MAX_SSID */ - /* set desired ssid before scan */ - if (bsd_set_ssid(drv, params->ssids[0].ssid, - params->ssids[0].ssid_len) < 0) - return -1; - - /* NB: net80211 delivers a scan complete event so no need to poll */ - return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0); -#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ -} - -static void -wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) -{ - struct bsd_driver_data *drv = sock_ctx; - struct if_announcemsghdr *ifan; - struct if_msghdr *ifm; - struct rt_msghdr *rtm; - union wpa_event_data event; - struct ieee80211_michael_event *mic; - struct ieee80211_leave_event *leave; - struct ieee80211_join_event *join; - int n; - - n = read(sock, drv->event_buf, drv->event_buf_len); - if (n < 0) { - if (errno != EINTR && errno != EAGAIN) - wpa_printf(MSG_ERROR, "%s read() failed: %s\n", - __func__, strerror(errno)); - return; - } - - rtm = (struct rt_msghdr *) drv->event_buf; - if (rtm->rtm_version != RTM_VERSION) { - wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", - rtm->rtm_version); - return; - } - os_memset(&event, 0, sizeof(event)); - switch (rtm->rtm_type) { - case RTM_IFANNOUNCE: - ifan = (struct if_announcemsghdr *) rtm; - if (ifan->ifan_index != drv->ifindex) - break; - os_strlcpy(event.interface_status.ifname, drv->ifname, - sizeof(event.interface_status.ifname)); - switch (ifan->ifan_what) { - case IFAN_DEPARTURE: - event.interface_status.ievent = EVENT_INTERFACE_REMOVED; - default: - return; - } - wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s", - event.interface_status.ifname, - ifan->ifan_what == IFAN_DEPARTURE ? - "removed" : "added"); - wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); - break; - case RTM_IEEE80211: - ifan = (struct if_announcemsghdr *) rtm; - if (ifan->ifan_index != drv->ifindex) - break; - switch (ifan->ifan_what) { - case RTM_IEEE80211_ASSOC: - case RTM_IEEE80211_REASSOC: - if (drv->is_ap) - break; - wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); - break; - case RTM_IEEE80211_DISASSOC: - if (drv->is_ap) - break; - wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL); - break; - case RTM_IEEE80211_SCAN: - if (drv->is_ap) - break; - wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL); - break; - case RTM_IEEE80211_LEAVE: - leave = (struct ieee80211_leave_event *) &ifan[1]; - drv_event_disassoc(ctx, leave->iev_addr); - break; - case RTM_IEEE80211_JOIN: -#ifdef RTM_IEEE80211_REJOIN - case RTM_IEEE80211_REJOIN: -#endif - join = (struct ieee80211_join_event *) &ifan[1]; - bsd_new_sta(drv, ctx, join->iev_addr); - break; - case RTM_IEEE80211_REPLAY: - /* ignore */ - break; - case RTM_IEEE80211_MICHAEL: - mic = (struct ieee80211_michael_event *) &ifan[1]; - wpa_printf(MSG_DEBUG, - "Michael MIC failure wireless event: " - "keyix=%u src_addr=" MACSTR, mic->iev_keyix, - MAC2STR(mic->iev_src)); - - os_memset(&event, 0, sizeof(event)); - event.michael_mic_failure.unicast = - !IEEE80211_IS_MULTICAST(mic->iev_dst); - wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, - &event); - break; - } - break; - case RTM_IFINFO: - ifm = (struct if_msghdr *) rtm; - if (ifm->ifm_index != drv->ifindex) - break; - if ((rtm->rtm_flags & RTF_UP) == 0) { - os_strlcpy(event.interface_status.ifname, drv->ifname, - sizeof(event.interface_status.ifname)); - event.interface_status.ievent = EVENT_INTERFACE_REMOVED; - wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", - event.interface_status.ifname); - wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); - } - break; - } -} - -static void -wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res, - struct ieee80211req_scan_result *sr) -{ - struct wpa_scan_res *result, **tmp; - size_t extra_len; - u8 *pos; - - extra_len = 2 + sr->isr_ssid_len; - extra_len += 2 + sr->isr_nrates; - extra_len += 3; /* ERP IE */ - extra_len += sr->isr_ie_len; - - result = os_zalloc(sizeof(*result) + extra_len); - if (result == NULL) - return; - os_memcpy(result->bssid, sr->isr_bssid, ETH_ALEN); - result->freq = sr->isr_freq; - result->beacon_int = sr->isr_intval; - result->caps = sr->isr_capinfo; - result->qual = sr->isr_rssi; - result->noise = sr->isr_noise; - /* - * the rssi value reported by the kernel is in 0.5dB steps relative to - * the reported noise floor. see ieee80211_node.h for details. - */ - result->level = sr->isr_rssi / 2 + sr->isr_noise; - - pos = (u8 *)(result + 1); - - *pos++ = WLAN_EID_SSID; - *pos++ = sr->isr_ssid_len; - os_memcpy(pos, sr + 1, sr->isr_ssid_len); - pos += sr->isr_ssid_len; - - /* - * Deal all rates as supported rate. - * Because net80211 doesn't report extended supported rate or not. - */ - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = sr->isr_nrates; - os_memcpy(pos, sr->isr_rates, sr->isr_nrates); - pos += sr->isr_nrates; - - *pos++ = WLAN_EID_ERP_INFO; - *pos++ = 1; - *pos++ = sr->isr_erp; - - os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len); - pos += sr->isr_ie_len; - - result->ie_len = pos - (u8 *)(result + 1); - - tmp = os_realloc_array(res->res, res->num + 1, - sizeof(struct wpa_scan_res *)); - if (tmp == NULL) { - os_free(result); - return; - } - tmp[res->num++] = result; - res->res = tmp; -} - -struct wpa_scan_results * -wpa_driver_bsd_get_scan_results2(void *priv) -{ - struct ieee80211req_scan_result *sr; - struct wpa_scan_results *res; - int len, rest; - uint8_t buf[24*1024], *pos; - - len = get80211var(priv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024); - if (len < 0) - return NULL; - - res = os_zalloc(sizeof(*res)); - if (res == NULL) - return NULL; - - pos = buf; - rest = len; - while (rest >= sizeof(struct ieee80211req_scan_result)) { - sr = (struct ieee80211req_scan_result *)pos; - wpa_driver_bsd_add_scan_entry(res, sr); - pos += sr->isr_len; - rest -= sr->isr_len; - } - - wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)", - len, (unsigned long)res->num); - - return res; -} - -static int wpa_driver_bsd_capa(struct bsd_driver_data *drv) -{ -#ifdef IEEE80211_IOC_DEVCAPS -/* kernel definitions copied from net80211/ieee80211_var.h */ -#define IEEE80211_CIPHER_WEP 0 -#define IEEE80211_CIPHER_TKIP 1 -#define IEEE80211_CIPHER_AES_CCM 3 -#define IEEE80211_CRYPTO_WEP (1<capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | - WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; - if (devcaps.dc_drivercaps & IEEE80211_C_WPA2) - drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; - - if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP) - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | - WPA_DRIVER_CAPA_ENC_WEP104; - if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_TKIP) - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; - if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM) - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; - - if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP) - drv->capa.flags |= WPA_DRIVER_FLAGS_AP; -#undef IEEE80211_CIPHER_WEP -#undef IEEE80211_CIPHER_TKIP -#undef IEEE80211_CIPHER_AES_CCM -#undef IEEE80211_CRYPTO_WEP -#undef IEEE80211_CRYPTO_TKIP -#undef IEEE80211_CRYPTO_AES_CCM -#undef IEEE80211_C_HOSTAP -#undef IEEE80211_C_WPA1 -#undef IEEE80211_C_WPA2 -#else /* IEEE80211_IOC_DEVCAPS */ - /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ - drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | - WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; - drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | - WPA_DRIVER_CAPA_ENC_WEP104 | - WPA_DRIVER_CAPA_ENC_TKIP | - WPA_DRIVER_CAPA_ENC_CCMP; - drv->capa.flags |= WPA_DRIVER_FLAGS_AP; -#endif /* IEEE80211_IOC_DEVCAPS */ -#ifdef IEEE80211_IOC_SCAN_MAX_SSID - drv->capa.max_scan_ssids = IEEE80211_IOC_SCAN_MAX_SSID; -#else /* IEEE80211_IOC_SCAN_MAX_SSID */ - drv->capa.max_scan_ssids = 1; -#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ - drv->capa.auth = WPA_DRIVER_AUTH_OPEN | - WPA_DRIVER_AUTH_SHARED | - WPA_DRIVER_AUTH_LEAP; - return 0; -} - -static enum ieee80211_opmode -get80211opmode(struct bsd_driver_data *drv) -{ - struct ifmediareq ifmr; - - (void) memset(&ifmr, 0, sizeof(ifmr)); - (void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name)); - - if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { - if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) { - if (ifmr.ifm_current & IFM_FLAG0) - return IEEE80211_M_AHDEMO; - else - return IEEE80211_M_IBSS; - } - if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) - return IEEE80211_M_HOSTAP; - if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) - return IEEE80211_M_MONITOR; -#ifdef IEEE80211_M_MBSS - if (ifmr.ifm_current & IFM_IEEE80211_MBSS) - return IEEE80211_M_MBSS; -#endif /* IEEE80211_M_MBSS */ - } - return IEEE80211_M_STA; -} - -static void * -wpa_driver_bsd_init(void *ctx, const char *ifname) -{ -#define GETPARAM(drv, param, v) \ - (((v) = get80211param(drv, param)) != -1) - struct bsd_driver_data *drv; - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - - drv->event_buf_len = rtbuf_len(); - - drv->event_buf = os_malloc(drv->event_buf_len); - if (drv->event_buf == NULL) { - wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__); - goto fail1; - } - - /* - * NB: We require the interface name be mappable to an index. - * This implies we do not support having wpa_supplicant - * wait for an interface to appear. This seems ok; that - * doesn't belong here; it's really the job of devd. - */ - drv->ifindex = if_nametoindex(ifname); - if (drv->ifindex == 0) { - wpa_printf(MSG_DEBUG, "%s: interface %s does not exist", - __func__, ifname); - goto fail1; - } - drv->sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->sock < 0) - goto fail1; - - os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); - /* Down interface during setup. */ - if (bsd_ctrl_iface(drv, 0) < 0) - goto fail; - - drv->route = socket(PF_ROUTE, SOCK_RAW, 0); - if (drv->route < 0) - goto fail; - eloop_register_read_sock(drv->route, - wpa_driver_bsd_event_receive, ctx, drv); - - drv->ctx = ctx; - - if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) { - wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s", - __func__, strerror(errno)); - goto fail; - } - if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) { - wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s", - __func__, strerror(errno)); - goto fail; - } - if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) { - wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s", - __func__, strerror(errno)); - goto fail; - } - - if (wpa_driver_bsd_capa(drv)) - goto fail; - - drv->opmode = get80211opmode(drv); - - return drv; -fail: - close(drv->sock); -fail1: - os_free(drv->event_buf); - os_free(drv); - return NULL; -#undef GETPARAM -} - -static void -wpa_driver_bsd_deinit(void *priv) -{ - struct bsd_driver_data *drv = priv; - - wpa_driver_bsd_set_wpa(drv, 0); - eloop_unregister_read_sock(drv->route); - - /* NB: mark interface down */ - bsd_ctrl_iface(drv, 0); - - wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy); - if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0) - wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state", - __func__); - - if (drv->sock_xmit != NULL) - l2_packet_deinit(drv->sock_xmit); - (void) close(drv->route); /* ioctl socket */ - (void) close(drv->sock); /* event socket */ - os_free(drv->event_buf); - os_free(drv); -} - -static int -wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa) -{ - struct bsd_driver_data *drv = priv; - - os_memcpy(capa, &drv->capa, sizeof(*capa)); - return 0; -} -#endif /* HOSTAPD */ - - -const struct wpa_driver_ops wpa_driver_bsd_ops = { - .name = "bsd", - .desc = "BSD 802.11 support", -#ifdef HOSTAPD - .hapd_init = bsd_init, - .hapd_deinit = bsd_deinit, - .set_privacy = bsd_set_privacy, - .get_seqnum = bsd_get_seqnum, - .flush = bsd_flush, - .read_sta_data = bsd_read_sta_driver_data, - .sta_disassoc = bsd_sta_disassoc, - .sta_deauth = bsd_sta_deauth, - .sta_set_flags = bsd_set_sta_authorized, - .commit = bsd_commit, -#else /* HOSTAPD */ - .init = wpa_driver_bsd_init, - .deinit = wpa_driver_bsd_deinit, - .get_bssid = wpa_driver_bsd_get_bssid, - .get_ssid = wpa_driver_bsd_get_ssid, - .set_countermeasures = wpa_driver_bsd_set_countermeasures, - .scan2 = wpa_driver_bsd_scan, - .get_scan_results2 = wpa_driver_bsd_get_scan_results2, - .deauthenticate = wpa_driver_bsd_deauthenticate, - .associate = wpa_driver_bsd_associate, - .get_capa = wpa_driver_bsd_get_capa, -#endif /* HOSTAPD */ - .set_freq = bsd_set_freq, - .set_key = bsd_set_key, - .set_ieee8021x = bsd_set_ieee8021x, - .hapd_set_ssid = bsd_set_ssid, - .hapd_get_ssid = bsd_get_ssid, - .hapd_send_eapol = bsd_send_eapol, - .set_generic_elem = bsd_set_opt_ie, -}; diff --git a/contrib/hostapd/src/drivers/driver_common.c b/contrib/hostapd/src/drivers/driver_common.c deleted file mode 100644 index 3058cd57dd..0000000000 --- a/contrib/hostapd/src/drivers/driver_common.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Common driver-related functions - * Copyright (c) 2003-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include "utils/common.h" -#include "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(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(IBSS_PEER_LOST); - E2S(DRIVER_GTK_REKEY); - E2S(SCHED_SCAN_STOPPED); - E2S(DRIVER_CLIENT_POLL_OK); - E2S(EAPOL_TX_STATUS); - E2S(CH_SWITCH); - E2S(WNM); - E2S(CONNECT_FAILED_REASON); - E2S(DFS_RADAR_DETECTED); - E2S(DFS_CAC_FINISHED); - E2S(DFS_CAC_ABORTED); - E2S(DFS_NOP_FINISHED); - E2S(SURVEY); - E2S(SCAN_STARTED); - E2S(AVOID_FREQUENCIES); - } - - return "UNKNOWN"; -#undef E2S -} diff --git a/contrib/hostapd/src/drivers/driver_hostap.c b/contrib/hostapd/src/drivers/driver_hostap.c deleted file mode 100644 index 16f5563af9..0000000000 --- a/contrib/hostapd/src/drivers/driver_hostap.c +++ /dev/null @@ -1,1193 +0,0 @@ -/* - * Driver interaction with Linux Host AP driver - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "linux_wext.h" -#include "common.h" -#include "driver.h" -#include "driver_wext.h" -#include "eloop.h" -#include "driver_hostap.h" - - -#include -#include - -#include "priv_netlink.h" -#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 - * frames that might be longer than normal default MTU and they are not - * fragmented */ -#define HOSTAPD_MTU 2290 - -static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; - -struct hostap_driver_data { - struct hostapd_data *hapd; - - char iface[IFNAMSIZ + 1]; - int sock; /* raw packet socket for driver access */ - int ioctl_sock; /* socket for ioctl() use */ - struct netlink_data *netlink; - - int we_version; - - u8 *generic_ie; - size_t generic_ie_len; - u8 *wps_ie; - size_t wps_ie_len; -}; - - -static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param, - int len); -static int hostap_set_iface_flags(void *priv, int dev_up); - -static void handle_data(struct hostap_driver_data *drv, u8 *buf, size_t len, - u16 stype) -{ - struct ieee80211_hdr *hdr; - u16 fc, ethertype; - u8 *pos, *sa; - size_t left; - union wpa_event_data event; - - if (len < sizeof(struct ieee80211_hdr)) - return; - - hdr = (struct ieee80211_hdr *) buf; - fc = le_to_host16(hdr->frame_control); - - if ((fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) != WLAN_FC_TODS) { - printf("Not ToDS data frame (fc=0x%04x)\n", fc); - return; - } - - sa = hdr->addr2; - os_memset(&event, 0, sizeof(event)); - 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); - left = len - sizeof(*hdr); - - if (left < sizeof(rfc1042_header)) { - printf("Too short data frame\n"); - return; - } - - if (memcmp(pos, rfc1042_header, sizeof(rfc1042_header)) != 0) { - printf("Data frame with no RFC1042 header\n"); - return; - } - pos += sizeof(rfc1042_header); - left -= sizeof(rfc1042_header); - - if (left < 2) { - printf("No ethertype in data frame\n"); - return; - } - - ethertype = WPA_GET_BE16(pos); - pos += 2; - left -= 2; - switch (ethertype) { - case ETH_P_PAE: - drv_event_eapol_rx(drv->hapd, sa, pos, left); - break; - - default: - printf("Unknown ethertype 0x%04x in data frame\n", ethertype); - break; - } -} - - -static void handle_tx_callback(struct hostap_driver_data *drv, u8 *buf, - size_t len, int ok) -{ - struct ieee80211_hdr *hdr; - u16 fc; - union wpa_event_data event; - - hdr = (struct ieee80211_hdr *) buf; - fc = le_to_host16(hdr->frame_control); - - os_memset(&event, 0, sizeof(event)); - event.tx_status.type = WLAN_FC_GET_TYPE(fc); - event.tx_status.stype = WLAN_FC_GET_STYPE(fc); - event.tx_status.dst = hdr->addr1; - event.tx_status.data = buf; - event.tx_status.data_len = len; - event.tx_status.ack = ok; - wpa_supplicant_event(drv->hapd, EVENT_TX_STATUS, &event); -} - - -static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len) -{ - struct ieee80211_hdr *hdr; - u16 fc, extra_len, type, stype; - size_t data_len = len; - int ver; - union wpa_event_data event; - - /* PSPOLL is only 16 bytes, but driver does not (at least yet) pass - * these to user space */ - if (len < 24) { - wpa_printf(MSG_MSGDUMP, "handle_frame: too short (%lu)", - (unsigned long) len); - return; - } - - hdr = (struct ieee80211_hdr *) buf; - fc = le_to_host16(hdr->frame_control); - type = WLAN_FC_GET_TYPE(fc); - stype = WLAN_FC_GET_STYPE(fc); - - if (type != WLAN_FC_TYPE_MGMT || stype != WLAN_FC_STYPE_BEACON) { - wpa_hexdump(MSG_MSGDUMP, "Received management frame", - buf, len); - } - - ver = fc & WLAN_FC_PVER; - - /* protocol version 3 is reserved for indicating extra data after the - * payload, version 2 for indicating ACKed frame (TX callbacks), and - * version 1 for indicating failed frame (no ACK, TX callbacks) */ - if (ver == 3) { - u8 *pos = buf + len - 2; - extra_len = WPA_GET_LE16(pos); - printf("extra data in frame (elen=%d)\n", extra_len); - if ((size_t) extra_len + 2 > len) { - printf(" extra data overflow\n"); - return; - } - len -= extra_len + 2; - } else if (ver == 1 || ver == 2) { - handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0); - return; - } else if (ver != 0) { - printf("unknown protocol version %d\n", ver); - return; - } - - switch (type) { - case WLAN_FC_TYPE_MGMT: - os_memset(&event, 0, sizeof(event)); - event.rx_mgmt.frame = buf; - event.rx_mgmt.frame_len = data_len; - wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); - break; - case WLAN_FC_TYPE_CTRL: - wpa_printf(MSG_DEBUG, "CTRL"); - break; - case WLAN_FC_TYPE_DATA: - wpa_printf(MSG_DEBUG, "DATA"); - handle_data(drv, buf, data_len, stype); - break; - default: - wpa_printf(MSG_DEBUG, "unknown frame type %d", type); - break; - } -} - - -static void handle_read(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct hostap_driver_data *drv = eloop_ctx; - int len; - unsigned char buf[3000]; - - len = recv(sock, buf, sizeof(buf), 0); - if (len < 0) { - perror("recv"); - return; - } - - handle_frame(drv, buf, len); -} - - -static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr) -{ - struct ifreq ifr; - struct sockaddr_ll addr; - - drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (drv->sock < 0) { - perror("socket[PF_PACKET,SOCK_RAW]"); - return -1; - } - - if (eloop_register_read_sock(drv->sock, handle_read, drv, NULL)) { - printf("Could not register read socket\n"); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface); - if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { - perror("ioctl(SIOCGIFINDEX)"); - return -1; - } - - if (hostap_set_iface_flags(drv, 1)) { - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sll_family = AF_PACKET; - addr.sll_ifindex = ifr.ifr_ifindex; - wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", - addr.sll_ifindex); - - if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("bind"); - return -1; - } - - return linux_get_ifhwaddr(drv->sock, drv->iface, own_addr); -} - - -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; - int res; - - /* Request TX callback */ - hdr->frame_control |= host_to_le16(BIT(1)); - res = send(drv->sock, msg, len, 0); - hdr->frame_control &= ~host_to_le16(BIT(1)); - - return res; -} - - -static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data, - size_t data_len, int encrypt, const u8 *own_addr, - u32 flags) -{ - struct hostap_driver_data *drv = priv; - struct ieee80211_hdr *hdr; - size_t len; - u8 *pos; - int res; - - len = sizeof(*hdr) + sizeof(rfc1042_header) + 2 + data_len; - hdr = os_zalloc(len); - if (hdr == NULL) { - printf("malloc() failed for hostapd_send_data(len=%lu)\n", - (unsigned long) len); - return -1; - } - - hdr->frame_control = - IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); - hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); - if (encrypt) - hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); - memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); - memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); - memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); - - pos = (u8 *) (hdr + 1); - memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); - pos += sizeof(rfc1042_header); - *((u16 *) pos) = htons(ETH_P_PAE); - pos += 2; - memcpy(pos, data, data_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)", - (unsigned long) len, errno, strerror(errno)); - } - free(hdr); - - return res; -} - - -static int hostap_sta_set_flags(void *priv, const u8 *addr, - int total_flags, int flags_or, int flags_and) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param param; - - if (flags_or & WPA_STA_AUTHORIZED) - flags_or = BIT(5); /* WLAN_STA_AUTHORIZED */ - if (!(flags_and & WPA_STA_AUTHORIZED)) - flags_and = ~BIT(5); - else - flags_and = ~0; - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA; - memcpy(param.sta_addr, addr, ETH_ALEN); - param.u.set_flags_sta.flags_or = flags_or; - param.u.set_flags_sta.flags_and = flags_and; - return hostapd_ioctl(drv, ¶m, sizeof(param)); -} - - -static int hostap_set_iface_flags(void *priv, int dev_up) -{ - struct hostap_driver_data *drv = priv; - struct ifreq ifr; - char ifname[IFNAMSIZ]; - - os_snprintf(ifname, IFNAMSIZ, "%sap", drv->iface); - if (linux_set_iface_flags(drv->ioctl_sock, ifname, dev_up) < 0) - return -1; - - if (dev_up) { - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - ifr.ifr_mtu = HOSTAPD_MTU; - if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) { - perror("ioctl[SIOCSIFMTU]"); - printf("Setting MTU failed - trying to survive with " - "current value\n"); - } - } - - return 0; -} - - -static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param, - int len) -{ - struct hostap_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) param; - iwr.u.data.length = len; - - if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) { - perror("ioctl[PRISM2_IOCTL_HOSTAPD]"); - return -1; - } - - return 0; -} - - -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 hostap_driver_data *drv = priv; - struct prism2_hostapd_param *param; - u8 *buf; - size_t blen; - int ret = 0; - - 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; - if (addr == NULL) - memset(param->sta_addr, 0xff, ETH_ALEN); - else - memcpy(param->sta_addr, addr, ETH_ALEN); - switch (alg) { - case WPA_ALG_NONE: - os_strlcpy((char *) param->u.crypt.alg, "NONE", - HOSTAP_CRYPT_ALG_NAME_LEN); - break; - case WPA_ALG_WEP: - os_strlcpy((char *) param->u.crypt.alg, "WEP", - HOSTAP_CRYPT_ALG_NAME_LEN); - break; - case WPA_ALG_TKIP: - os_strlcpy((char *) param->u.crypt.alg, "TKIP", - HOSTAP_CRYPT_ALG_NAME_LEN); - break; - case WPA_ALG_CCMP: - os_strlcpy((char *) param->u.crypt.alg, "CCMP", - HOSTAP_CRYPT_ALG_NAME_LEN); - break; - default: - os_free(buf); - return -1; - } - param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; - param->u.crypt.idx = key_idx; - param->u.crypt.key_len = key_len; - memcpy((u8 *) (param + 1), key, key_len); - - if (hostapd_ioctl(drv, param, blen)) { - printf("Failed to set encryption.\n"); - ret = -1; - } - free(buf); - - return ret; -} - - -static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr, - int idx, u8 *seq) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param *param; - u8 *buf; - size_t blen; - int ret = 0; - - blen = sizeof(*param) + 32; - buf = os_zalloc(blen); - if (buf == NULL) - return -1; - - param = (struct prism2_hostapd_param *) buf; - param->cmd = PRISM2_GET_ENCRYPTION; - if (addr == NULL) - memset(param->sta_addr, 0xff, ETH_ALEN); - else - memcpy(param->sta_addr, addr, ETH_ALEN); - param->u.crypt.idx = idx; - - if (hostapd_ioctl(drv, param, blen)) { - printf("Failed to get encryption.\n"); - ret = -1; - } else { - memcpy(seq, param->u.crypt.seq, 8); - } - free(buf); - - return ret; -} - - -static int hostap_ioctl_prism2param(void *priv, int param, int value) -{ - struct hostap_driver_data *drv = priv; - struct iwreq iwr; - int *i; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - i = (int *) iwr.u.name; - *i++ = param; - *i++ = value; - - if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) { - perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]"); - return -1; - } - - return 0; -} - - -static int hostap_set_ieee8021x(void *priv, struct wpa_bss_params *params) -{ - struct hostap_driver_data *drv = priv; - int enabled = params->enabled; - - /* enable kernel driver support for IEEE 802.1X */ - if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_IEEE_802_1X, enabled)) { - printf("Could not setup IEEE 802.1X support in kernel driver." - "\n"); - return -1; - } - - if (!enabled) - return 0; - - /* use host driver implementation of encryption to allow - * individual keys and passing plaintext EAPOL frames */ - if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_DECRYPT, 1) || - hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_ENCRYPT, 1)) { - printf("Could not setup host-based encryption in kernel " - "driver.\n"); - return -1; - } - - return 0; -} - - -static int hostap_set_privacy(void *priv, int enabled) -{ - struct hostap_drvier_data *drv = priv; - - return hostap_ioctl_prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED, - enabled); -} - - -static int hostap_set_ssid(void *priv, const u8 *buf, int len) -{ - struct hostap_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.essid.flags = 1; /* SSID active */ - iwr.u.essid.pointer = (caddr_t) buf; - iwr.u.essid.length = len + 1; - - if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { - perror("ioctl[SIOCSIWESSID]"); - printf("len=%d\n", len); - return -1; - } - - return 0; -} - - -static int hostap_flush(void *priv) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param param; - - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_FLUSH; - return hostapd_ioctl(drv, ¶m, sizeof(param)); -} - - -static int hostap_read_sta_data(void *priv, - struct hostap_sta_driver_data *data, - const u8 *addr) -{ - struct hostap_driver_data *drv = priv; - char buf[1024], line[128], *pos; - FILE *f; - unsigned long val; - - memset(data, 0, sizeof(*data)); - snprintf(buf, sizeof(buf), "/proc/net/hostap/%s/" MACSTR, - drv->iface, MAC2STR(addr)); - - f = fopen(buf, "r"); - if (!f) - return -1; - /* Need to read proc file with in one piece, so use large enough - * buffer. */ - setbuffer(f, buf, sizeof(buf)); - - while (fgets(line, sizeof(line), f)) { - pos = strchr(line, '='); - if (!pos) - continue; - *pos++ = '\0'; - val = strtoul(pos, NULL, 10); - if (strcmp(line, "rx_packets") == 0) - data->rx_packets = val; - else if (strcmp(line, "tx_packets") == 0) - data->tx_packets = val; - else if (strcmp(line, "rx_bytes") == 0) - data->rx_bytes = val; - else if (strcmp(line, "tx_bytes") == 0) - data->tx_bytes = val; - } - - fclose(f); - - return 0; -} - - -static int hostap_sta_add(void *priv, struct hostapd_sta_add_params *params) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param param; - int tx_supp_rates = 0; - size_t i; - -#define WLAN_RATE_1M BIT(0) -#define WLAN_RATE_2M BIT(1) -#define WLAN_RATE_5M5 BIT(2) -#define WLAN_RATE_11M BIT(3) - - for (i = 0; i < params->supp_rates_len; i++) { - if ((params->supp_rates[i] & 0x7f) == 2) - tx_supp_rates |= WLAN_RATE_1M; - if ((params->supp_rates[i] & 0x7f) == 4) - tx_supp_rates |= WLAN_RATE_2M; - if ((params->supp_rates[i] & 0x7f) == 11) - tx_supp_rates |= WLAN_RATE_5M5; - if ((params->supp_rates[i] & 0x7f) == 22) - tx_supp_rates |= WLAN_RATE_11M; - } - - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_ADD_STA; - memcpy(param.sta_addr, params->addr, ETH_ALEN); - param.u.add_sta.aid = params->aid; - param.u.add_sta.capability = params->capability; - param.u.add_sta.tx_supp_rates = tx_supp_rates; - return hostapd_ioctl(drv, ¶m, sizeof(param)); -} - - -static int hostap_sta_remove(void *priv, const u8 *addr) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param param; - - hostap_sta_set_flags(drv, addr, 0, 0, ~WPA_STA_AUTHORIZED); - - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_REMOVE_STA; - memcpy(param.sta_addr, addr, ETH_ALEN); - if (hostapd_ioctl(drv, ¶m, sizeof(param))) { - printf("Could not remove station from kernel driver.\n"); - return -1; - } - return 0; -} - - -static int hostap_get_inact_sec(void *priv, const u8 *addr) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param param; - - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_GET_INFO_STA; - memcpy(param.sta_addr, addr, ETH_ALEN); - if (hostapd_ioctl(drv, ¶m, sizeof(param))) { - return -1; - } - - return param.u.get_info_sta.inactive_sec; -} - - -static int hostap_sta_clear_stats(void *priv, const u8 *addr) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param param; - - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_STA_CLEAR_STATS; - memcpy(param.sta_addr, addr, ETH_ALEN); - if (hostapd_ioctl(drv, ¶m, sizeof(param))) { - return -1; - } - - return 0; -} - - -static int hostapd_ioctl_set_generic_elem(struct hostap_driver_data *drv) -{ - struct prism2_hostapd_param *param; - int res; - size_t blen, elem_len; - - elem_len = drv->generic_ie_len + drv->wps_ie_len; - blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + elem_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 = elem_len; - if (drv->generic_ie) { - os_memcpy(param->u.generic_elem.data, drv->generic_ie, - drv->generic_ie_len); - } - if (drv->wps_ie) { - os_memcpy(¶m->u.generic_elem.data[drv->generic_ie_len], - drv->wps_ie, drv->wps_ie_len); - } - wpa_hexdump(MSG_DEBUG, "hostap: Set generic IE", - param->u.generic_elem.data, elem_len); - res = hostapd_ioctl(drv, param, blen); - - os_free(param); - - return res; -} - - -static int hostap_set_generic_elem(void *priv, - const u8 *elem, size_t elem_len) -{ - struct hostap_driver_data *drv = priv; - - os_free(drv->generic_ie); - drv->generic_ie = NULL; - drv->generic_ie_len = 0; - if (elem) { - drv->generic_ie = os_malloc(elem_len); - if (drv->generic_ie == NULL) - return -1; - os_memcpy(drv->generic_ie, elem, elem_len); - drv->generic_ie_len = elem_len; - } - - return hostapd_ioctl_set_generic_elem(drv); -} - - -static int hostap_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, - const struct wpabuf *proberesp, - const struct wpabuf *assocresp) -{ - struct hostap_driver_data *drv = priv; - - /* - * Host AP driver supports only one set of extra IEs, so we need to - * use the Probe Response IEs also for Beacon frames since they include - * more information. - */ - - os_free(drv->wps_ie); - drv->wps_ie = NULL; - drv->wps_ie_len = 0; - if (proberesp) { - drv->wps_ie = os_malloc(wpabuf_len(proberesp)); - if (drv->wps_ie == NULL) - return -1; - os_memcpy(drv->wps_ie, wpabuf_head(proberesp), - wpabuf_len(proberesp)); - drv->wps_ie_len = wpabuf_len(proberesp); - } - - return hostapd_ioctl_set_generic_elem(drv); -} - - -static void -hostapd_wireless_event_wireless_custom(struct hostap_driver_data *drv, - char *custom) -{ - wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); - - if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { - char *pos; - u8 addr[ETH_ALEN]; - pos = strstr(custom, "addr="); - if (pos == NULL) { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "without sender address ignored"); - return; - } - pos += 5; - if (hwaddr_aton(pos, addr) == 0) { - union wpa_event_data data; - os_memset(&data, 0, sizeof(data)); - data.michael_mic_failure.unicast = 1; - data.michael_mic_failure.src = addr; - wpa_supplicant_event(drv->hapd, - EVENT_MICHAEL_MIC_FAILURE, &data); - } else { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "with invalid MAC address"); - } - } -} - - -static void hostapd_wireless_event_wireless(struct hostap_driver_data *drv, - char *data, int len) -{ - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end, *custom, *buf; - - 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. */ - 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 > 18 && - (iwe->cmd == IWEVMICHAELMICFAILURE || - 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; - memcpy(dpos, pos + IW_EV_LCP_LEN, - sizeof(struct iw_event) - dlen); - } else { - 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 = malloc(iwe->u.data.length + 1); - if (buf == NULL) - return; - memcpy(buf, custom, iwe->u.data.length); - buf[iwe->u.data.length] = '\0'; - hostapd_wireless_event_wireless_custom(drv, buf); - free(buf); - break; - } - - pos += iwe->len; - } -} - - -static void hostapd_wireless_event_rtm_newlink(void *ctx, - struct ifinfomsg *ifi, - u8 *buf, size_t len) -{ - struct hostap_driver_data *drv = ctx; - int attrlen, rta_len; - struct rtattr *attr; - - /* TODO: use ifi->ifi_index to filter out wireless events from other - * interfaces */ - - attrlen = len; - attr = (struct rtattr *) buf; - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_WIRELESS) { - hostapd_wireless_event_wireless( - drv, ((char *) attr) + rta_len, - attr->rta_len - rta_len); - } - attr = RTA_NEXT(attr, attrlen); - } -} - - -static int hostap_get_we_version(struct hostap_driver_data *drv) -{ - struct iw_range *range; - struct iwreq iwr; - int minlen; - size_t buflen; - - drv->we_version = 0; - - /* - * Use larger buffer than struct iw_range in order to allow the - * structure to grow in the future. - */ - buflen = sizeof(struct iw_range) + 500; - range = os_zalloc(buflen); - if (range == NULL) - return -1; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) range; - iwr.u.data.length = buflen; - - minlen = ((char *) &range->enc_capa) - (char *) range + - sizeof(range->enc_capa); - - if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { - perror("ioctl[SIOCGIWRANGE]"); - free(range); - return -1; - } else if (iwr.u.data.length >= minlen && - range->we_version_compiled >= 18) { - wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " - "WE(source)=%d enc_capa=0x%x", - range->we_version_compiled, - range->we_version_source, - range->enc_capa); - drv->we_version = range->we_version_compiled; - } - - free(range); - return 0; -} - - -static int hostap_wireless_event_init(struct hostap_driver_data *drv) -{ - struct netlink_config *cfg; - - hostap_get_we_version(drv); - - cfg = os_zalloc(sizeof(*cfg)); - if (cfg == NULL) - return -1; - cfg->ctx = drv; - cfg->newlink_cb = hostapd_wireless_event_rtm_newlink; - drv->netlink = netlink_init(cfg); - if (drv->netlink == NULL) { - os_free(cfg); - return -1; - } - - return 0; -} - - -static void * hostap_init(struct hostapd_data *hapd, - struct wpa_init_params *params) -{ - struct hostap_driver_data *drv; - - drv = os_zalloc(sizeof(struct hostap_driver_data)); - if (drv == NULL) { - printf("Could not allocate memory for hostapd driver data\n"); - return NULL; - } - - drv->hapd = hapd; - drv->ioctl_sock = drv->sock = -1; - memcpy(drv->iface, params->ifname, sizeof(drv->iface)); - - drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->ioctl_sock < 0) { - perror("socket[PF_INET,SOCK_DGRAM]"); - free(drv); - return NULL; - } - - if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 1)) { - printf("Could not enable hostapd mode for interface %s\n", - drv->iface); - close(drv->ioctl_sock); - free(drv); - return NULL; - } - - if (hostap_init_sockets(drv, params->own_addr) || - hostap_wireless_event_init(drv)) { - close(drv->ioctl_sock); - free(drv); - return NULL; - } - - return drv; -} - - -static void hostap_driver_deinit(void *priv) -{ - struct hostap_driver_data *drv = priv; - - netlink_deinit(drv->netlink); - (void) hostap_set_iface_flags(drv, 0); - (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 0); - (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD_STA, 0); - - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - - if (drv->sock >= 0) - close(drv->sock); - - os_free(drv->generic_ie); - os_free(drv->wps_ie); - - free(drv); -} - - -static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, - int reason) -{ - struct hostap_driver_data *drv = priv; - struct ieee80211_mgmt mgmt; - - if (is_broadcast_ether_addr(addr)) { - /* - * New Prism2.5/3 STA firmware versions seem to have issues - * with this broadcast deauth frame. This gets the firmware in - * odd state where nothing works correctly, so let's skip - * sending this for the hostap driver. - */ - return 0; - } - - memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DEAUTH); - memcpy(mgmt.da, addr, ETH_ALEN); - memcpy(mgmt.sa, own_addr, ETH_ALEN); - 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), 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; -} - - -static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, - int reason) -{ - struct hostap_driver_data *drv = priv; - struct ieee80211_mgmt mgmt; - - memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DISASSOC); - memcpy(mgmt.da, addr, ETH_ALEN); - memcpy(mgmt.sa, own_addr, ETH_ALEN); - 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), 0); -} - - -static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv, - u16 *num_modes, - u16 *flags) -{ - struct hostapd_hw_modes *mode; - int i, clen, rlen; - const short chan2freq[14] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 - }; - - mode = os_zalloc(sizeof(struct hostapd_hw_modes)); - if (mode == NULL) - return NULL; - - *num_modes = 1; - *flags = 0; - - mode->mode = HOSTAPD_MODE_IEEE80211B; - mode->num_channels = 14; - mode->num_rates = 4; - - clen = mode->num_channels * sizeof(struct hostapd_channel_data); - rlen = mode->num_rates * sizeof(int); - - mode->channels = os_zalloc(clen); - mode->rates = os_zalloc(rlen); - if (mode->channels == NULL || mode->rates == NULL) { - os_free(mode->channels); - os_free(mode->rates); - os_free(mode); - return NULL; - } - - for (i = 0; i < 14; i++) { - mode->channels[i].chan = i + 1; - mode->channels[i].freq = chan2freq[i]; - /* TODO: Get allowed channel list from the driver */ - if (i >= 11) - mode->channels[i].flag = HOSTAPD_CHAN_DISABLED; - } - - mode->rates[0] = 10; - mode->rates[1] = 20; - mode->rates[2] = 55; - mode->rates[3] = 110; - - return mode; -} - - -static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr, - const u8 *addr, int qos) -{ - struct ieee80211_hdr hdr; - - os_memset(&hdr, 0, sizeof(hdr)); - - /* - * 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); - - hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0); -} - - -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, - .hapd_init = hostap_init, - .hapd_deinit = hostap_driver_deinit, - .set_ieee8021x = hostap_set_ieee8021x, - .set_privacy = hostap_set_privacy, - .get_seqnum = hostap_get_seqnum, - .flush = hostap_flush, - .set_generic_elem = hostap_set_generic_elem, - .read_sta_data = hostap_read_sta_data, - .hapd_send_eapol = hostap_send_eapol, - .sta_set_flags = hostap_sta_set_flags, - .sta_deauth = hostap_sta_deauth, - .sta_disassoc = hostap_sta_disassoc, - .sta_remove = hostap_sta_remove, - .hapd_set_ssid = hostap_set_ssid, - .send_mlme = hostap_send_mlme, - .sta_add = hostap_sta_add, - .get_inact_sec = hostap_get_inact_sec, - .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, - .set_freq = hostap_set_freq, - .poll_client = wpa_driver_hostap_poll_client, -}; diff --git a/contrib/hostapd/src/drivers/driver_hostap.h b/contrib/hostapd/src/drivers/driver_hostap.h deleted file mode 100644 index a9d3e76cbe..0000000000 --- a/contrib/hostapd/src/drivers/driver_hostap.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Driver interaction with Linux Host AP driver - * Copyright (c) 2002-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef HOSTAP_DRIVER_H -#define HOSTAP_DRIVER_H - -/* netdevice private ioctls (used, e.g., with iwpriv from user space) */ - -/* New wireless extensions API - SET/GET convention (even ioctl numbers are - * root only) - */ -#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0) -#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1) -#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2) -#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3) -#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4) -#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6) -#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8) -#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10) -#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12) -#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14) -#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16) -#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18) -#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20) -#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22) - -/* following are not in SIOCGIWPRIV list; check permission in the driver code - */ -#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13) -#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14) - - -/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */ -enum { - /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */ - PRISM2_PARAM_TXRATECTRL = 2, - PRISM2_PARAM_BEACON_INT = 3, - PRISM2_PARAM_PSEUDO_IBSS = 4, - PRISM2_PARAM_ALC = 5, - /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */ - PRISM2_PARAM_DUMP = 7, - PRISM2_PARAM_OTHER_AP_POLICY = 8, - PRISM2_PARAM_AP_MAX_INACTIVITY = 9, - PRISM2_PARAM_AP_BRIDGE_PACKETS = 10, - PRISM2_PARAM_DTIM_PERIOD = 11, - PRISM2_PARAM_AP_NULLFUNC_ACK = 12, - PRISM2_PARAM_MAX_WDS = 13, - PRISM2_PARAM_AP_AUTOM_AP_WDS = 14, - PRISM2_PARAM_AP_AUTH_ALGS = 15, - PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16, - PRISM2_PARAM_HOST_ENCRYPT = 17, - PRISM2_PARAM_HOST_DECRYPT = 18, - PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, - PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, - PRISM2_PARAM_HOST_ROAMING = 21, - PRISM2_PARAM_BCRX_STA_KEY = 22, - PRISM2_PARAM_IEEE_802_1X = 23, - PRISM2_PARAM_ANTSEL_TX = 24, - PRISM2_PARAM_ANTSEL_RX = 25, - PRISM2_PARAM_MONITOR_TYPE = 26, - PRISM2_PARAM_WDS_TYPE = 27, - PRISM2_PARAM_HOSTSCAN = 28, - PRISM2_PARAM_AP_SCAN = 29, - PRISM2_PARAM_ENH_SEC = 30, - PRISM2_PARAM_IO_DEBUG = 31, - PRISM2_PARAM_BASIC_RATES = 32, - PRISM2_PARAM_OPER_RATES = 33, - PRISM2_PARAM_HOSTAPD = 34, - PRISM2_PARAM_HOSTAPD_STA = 35, - PRISM2_PARAM_WPA = 36, - PRISM2_PARAM_PRIVACY_INVOKED = 37, - PRISM2_PARAM_TKIP_COUNTERMEASURES = 38, - PRISM2_PARAM_DROP_UNENCRYPTED = 39, - PRISM2_PARAM_SCAN_CHANNEL_MASK = 40, -}; - -enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1, - HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 }; - - -/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */ -enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1, - AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3, - AP_MAC_CMD_KICKALL = 4 }; - - -/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */ -enum { - PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */, - /* Note! Old versions of prism2_srec have a fatal error in CRC-16 - * calculation, which will corrupt all non-volatile downloads. - * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to - * prevent use of old versions of prism2_srec for non-volatile - * download. */ - PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */, - PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */, - /* Persistent versions of volatile download commands (keep firmware - * data in memory and automatically re-download after hw_reset */ - PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5, - PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6, -}; - -struct prism2_download_param { - u32 dl_cmd; - u32 start_addr; - u32 num_areas; - struct prism2_download_area { - u32 addr; /* wlan card address */ - u32 len; - caddr_t ptr; /* pointer to data in user space */ - } data[0]; -}; - -#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072 -#define PRISM2_MAX_DOWNLOAD_LEN 262144 - - -/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */ -enum { - PRISM2_HOSTAPD_FLUSH = 1, - PRISM2_HOSTAPD_ADD_STA = 2, - PRISM2_HOSTAPD_REMOVE_STA = 3, - PRISM2_HOSTAPD_GET_INFO_STA = 4, - /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ - PRISM2_SET_ENCRYPTION = 6, - PRISM2_GET_ENCRYPTION = 7, - PRISM2_HOSTAPD_SET_FLAGS_STA = 8, - PRISM2_HOSTAPD_GET_RID = 9, - PRISM2_HOSTAPD_SET_RID = 10, - PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11, - PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, - PRISM2_HOSTAPD_MLME = 13, - PRISM2_HOSTAPD_SCAN_REQ = 14, - PRISM2_HOSTAPD_STA_CLEAR_STATS = 15, -}; - -#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 -#define PRISM2_HOSTAPD_RID_HDR_LEN \ -((size_t) (&((struct prism2_hostapd_param *) 0)->u.rid.data)) -#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ -((size_t) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data)) - -/* Maximum length for algorithm names (-1 for nul termination) used in ioctl() - */ -#define HOSTAP_CRYPT_ALG_NAME_LEN 16 - - -struct prism2_hostapd_param { - u32 cmd; - u8 sta_addr[ETH_ALEN]; - union { - struct { - u16 aid; - u16 capability; - u8 tx_supp_rates; - } add_sta; - struct { - u32 inactive_sec; - } get_info_sta; - struct { - u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; - u32 flags; - u32 err; - u8 idx; - u8 seq[8]; /* sequence counter (set: RX, get: TX) */ - u16 key_len; - u8 key[0]; - } crypt; - struct { - u32 flags_and; - u32 flags_or; - } set_flags_sta; - struct { - u16 rid; - u16 len; - u8 data[0]; - } rid; - struct { - u8 len; - u8 data[0]; - } generic_elem; - struct { -#define MLME_STA_DEAUTH 0 -#define MLME_STA_DISASSOC 1 - u16 cmd; - u16 reason_code; - } mlme; - struct { - u8 ssid_len; - u8 ssid[32]; - } scan_req; - } u; -}; - -#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0) -#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1) - -#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2 -#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3 -#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4 -#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5 -#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6 -#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7 - -#endif /* HOSTAP_DRIVER_H */ diff --git a/contrib/hostapd/src/drivers/driver_madwifi.c b/contrib/hostapd/src/drivers/driver_madwifi.c deleted file mode 100644 index 1635c1fbb5..0000000000 --- a/contrib/hostapd/src/drivers/driver_madwifi.c +++ /dev/null @@ -1,1309 +0,0 @@ -/* - * hostapd - driver interaction with MADWIFI 802.11 driver - * Copyright (c) 2004, Sam Leffler - * Copyright (c) 2004, Video54 Technologies - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This driver wrapper is only for hostapd AP mode functionality. Station - * (wpa_supplicant) operations with madwifi are supported by the driver_wext.c - * wrapper. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "driver.h" -#include "driver_wext.h" -#include "eloop.h" -#include "common/ieee802_11_defs.h" -#include "linux_wext.h" - -/* - * Avoid conflicts with wpa_supplicant definitions by undefining a definition. - */ -#undef WME_OUI_TYPE - -#include -#include -#ifdef WME_NUM_AC -/* Assume this is built against BSD branch of madwifi driver. */ -#define MADWIFI_BSD -#include -#endif /* WME_NUM_AC */ -#include -#include - -#ifdef CONFIG_WPS -#ifdef IEEE80211_IOCTL_FILTERFRAME -#include - -#ifndef ETH_P_80211_RAW -#define ETH_P_80211_RAW 0x0019 -#endif -#endif /* IEEE80211_IOCTL_FILTERFRAME */ -#endif /* CONFIG_WPS */ - -/* - * Avoid conflicts with hostapd definitions by undefining couple of defines - * from madwifi header files. - */ -#undef RSN_VERSION -#undef WPA_VERSION -#undef WPA_OUI_TYPE -#undef WME_OUI_TYPE - - -#ifdef IEEE80211_IOCTL_SETWMMPARAMS -/* Assume this is built against madwifi-ng */ -#define MADWIFI_NG -#endif /* IEEE80211_IOCTL_SETWMMPARAMS */ - -#define WPA_KEY_RSC_LEN 8 - -#include "priv_netlink.h" -#include "netlink.h" -#include "linux_ioctl.h" -#include "l2_packet/l2_packet.h" - - -struct madwifi_driver_data { - struct hostapd_data *hapd; /* back pointer */ - - char iface[IFNAMSIZ + 1]; - int ifindex; - struct l2_packet_data *sock_xmit; /* raw packet xmit socket */ - struct l2_packet_data *sock_recv; /* raw packet recv socket */ - int ioctl_sock; /* socket for ioctl() use */ - struct netlink_data *netlink; - int we_version; - u8 acct_mac[ETH_ALEN]; - struct hostap_sta_driver_data acct_data; - - struct l2_packet_data *sock_raw; /* raw 802.11 management frames */ -}; - -static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, - int reason_code); - -static int -set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len) -{ - struct iwreq iwr; - int do_inline = len < IFNAMSIZ; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -#ifdef IEEE80211_IOCTL_FILTERFRAME - /* FILTERFRAME must be NOT inline, regardless of size. */ - if (op == IEEE80211_IOCTL_FILTERFRAME) - do_inline = 0; -#endif /* IEEE80211_IOCTL_FILTERFRAME */ - if (op == IEEE80211_IOCTL_SET_APPIEBUF) - do_inline = 0; - if (do_inline) { - /* - * Argument data fits inline; put it there. - */ - 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->ioctl_sock, op, &iwr) < 0) { -#ifdef MADWIFI_NG - int first = IEEE80211_IOCTL_SETPARAM; - 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]", - "ioctl[IEEE80211_IOCTL_GET_APPIEBUF]", - "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]", - "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]", - "ioctl[IEEE80211_IOCTL_FILTERFRAME]", - "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; - static const char *opnames[] = { - "ioctl[IEEE80211_IOCTL_SETPARAM]", - "ioctl[IEEE80211_IOCTL_GETPARAM]", - "ioctl[IEEE80211_IOCTL_SETKEY]", - "ioctl[SIOCIWFIRSTPRIV+3]", - "ioctl[IEEE80211_IOCTL_DELKEY]", - "ioctl[SIOCIWFIRSTPRIV+5]", - "ioctl[IEEE80211_IOCTL_SETMLME]", - "ioctl[SIOCIWFIRSTPRIV+7]", - "ioctl[IEEE80211_IOCTL_SETOPTIE]", - "ioctl[IEEE80211_IOCTL_GETOPTIE]", - "ioctl[IEEE80211_IOCTL_ADDMAC]", - "ioctl[SIOCIWFIRSTPRIV+11]", - "ioctl[IEEE80211_IOCTL_DELMAC]", - "ioctl[SIOCIWFIRSTPRIV+13]", - "ioctl[IEEE80211_IOCTL_CHANLIST]", - "ioctl[SIOCIWFIRSTPRIV+15]", - "ioctl[IEEE80211_IOCTL_GETRSN]", - "ioctl[SIOCIWFIRSTPRIV+17]", - "ioctl[IEEE80211_IOCTL_GETKEY]", - }; -#endif /* MADWIFI_NG */ - int idx = op - first; - if (first <= op && - idx < (int) ARRAY_SIZE(opnames) && - opnames[idx]) - perror(opnames[idx]); - else - perror("ioctl[unknown???]"); - return -1; - } - return 0; -} - -static int -set80211param(struct madwifi_driver_data *drv, int op, int arg) -{ - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.mode = op; - memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg)); - - if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { - perror("ioctl[IEEE80211_IOCTL_SETPARAM]"); - wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d " - "arg %d)", __func__, op, arg); - return -1; - } - return 0; -} - -#ifndef CONFIG_NO_STDOUT_DEBUG -static const char * -ether_sprintf(const u8 *addr) -{ - static char buf[sizeof(MACSTR)]; - - if (addr != NULL) - snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); - else - snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); - return buf; -} -#endif /* CONFIG_NO_STDOUT_DEBUG */ - -/* - * Configure WPA parameters. - */ -static int -madwifi_configure_wpa(struct madwifi_driver_data *drv, - struct wpa_bss_params *params) -{ - int v; - - switch (params->wpa_group) { - case WPA_CIPHER_CCMP: - v = IEEE80211_CIPHER_AES_CCM; - break; - case WPA_CIPHER_TKIP: - v = IEEE80211_CIPHER_TKIP; - break; - case WPA_CIPHER_WEP104: - v = IEEE80211_CIPHER_WEP; - break; - case WPA_CIPHER_WEP40: - v = IEEE80211_CIPHER_WEP; - break; - case WPA_CIPHER_NONE: - v = IEEE80211_CIPHER_NONE; - break; - default: - wpa_printf(MSG_ERROR, "Unknown group key cipher %u", - params->wpa_group); - return -1; - } - wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v); - if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) { - printf("Unable to set group key cipher to %u\n", v); - return -1; - } - if (v == IEEE80211_CIPHER_WEP) { - /* key length is done only for specific ciphers */ - v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); - if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) { - printf("Unable to set group key length to %u\n", v); - return -1; - } - } - - v = 0; - if (params->wpa_pairwise & WPA_CIPHER_CCMP) - v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) - v |= 1<wpa_pairwise & WPA_CIPHER_NONE) - v |= 1<wpa_key_mgmt); - if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, - params->wpa_key_mgmt)) { - printf("Unable to set key management algorithms to 0x%x\n", - params->wpa_key_mgmt); - return -1; - } - - v = 0; - if (params->rsn_preauth) - v |= BIT(0); - wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", - __func__, params->rsn_preauth); - if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) { - printf("Unable to set RSN capabilities to 0x%x\n", v); - return -1; - } - - wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa); - if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) { - printf("Unable to set WPA to %u\n", params->wpa); - return -1; - } - return 0; -} - -static int -madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params) -{ - struct madwifi_driver_data *drv = priv; - - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); - - if (!params->enabled) { - /* XXX restore state */ - return set80211param(priv, IEEE80211_PARAM_AUTHMODE, - IEEE80211_AUTH_AUTO); - } - if (!params->wpa && !params->ieee802_1x) { - wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!"); - return -1; - } - if (params->wpa && madwifi_configure_wpa(drv, params) != 0) { - wpa_printf(MSG_WARNING, "Error configuring WPA state!"); - return -1; - } - if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, - (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { - wpa_printf(MSG_WARNING, "Error enabling WPA/802.1X!"); - return -1; - } - - return 0; -} - -static int -madwifi_set_privacy(void *priv, int enabled) -{ - struct madwifi_driver_data *drv = priv; - - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - - return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled); -} - -static int -madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized) -{ - struct madwifi_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d", - __func__, ether_sprintf(addr), authorized); - - if (authorized) - mlme.im_op = IEEE80211_MLME_AUTHORIZE; - else - mlme.im_op = IEEE80211_MLME_UNAUTHORIZE; - mlme.im_reason = 0; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR, - __func__, authorized ? "" : "un", MAC2STR(addr)); - } - - return ret; -} - -static int -madwifi_sta_set_flags(void *priv, const u8 *addr, - int total_flags, int flags_or, int flags_and) -{ - /* For now, only support setting Authorized flag */ - if (flags_or & WPA_STA_AUTHORIZED) - return madwifi_set_sta_authorized(priv, addr, 1); - if (!(flags_and & WPA_STA_AUTHORIZED)) - return madwifi_set_sta_authorized(priv, addr, 0); - return 0; -} - -static int -madwifi_del_key(void *priv, const u8 *addr, int key_idx) -{ - struct madwifi_driver_data *drv = priv; - struct ieee80211req_del_key wk; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d", - __func__, ether_sprintf(addr), key_idx); - - memset(&wk, 0, sizeof(wk)); - if (addr != NULL) { - memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); - wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE; - } else { - wk.idk_keyix = key_idx; - } - - ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s" - " key_idx %d)", __func__, ether_sprintf(addr), - key_idx); - } - - return ret; -} - -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 madwifi_driver_data *drv = priv; - struct ieee80211req_key wk; - u_int8_t cipher; - int ret; - - if (alg == WPA_ALG_NONE) - return madwifi_del_key(drv, addr, key_idx); - - wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d", - __func__, alg, ether_sprintf(addr), key_idx); - - if (alg == WPA_ALG_WEP) - cipher = IEEE80211_CIPHER_WEP; - else if (alg == WPA_ALG_TKIP) - cipher = IEEE80211_CIPHER_TKIP; - else if (alg == WPA_ALG_CCMP) - cipher = IEEE80211_CIPHER_AES_CCM; - else { - printf("%s: unknown/unsupported algorithm %d\n", - __func__, alg); - return -1; - } - - if (key_len > sizeof(wk.ik_keydata)) { - printf("%s: key length %lu too big\n", __func__, - (unsigned long) key_len); - return -3; - } - - memset(&wk, 0, sizeof(wk)); - wk.ik_type = cipher; - wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; - if (addr == NULL || is_broadcast_ether_addr(addr)) { - memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); - wk.ik_keyix = key_idx; - wk.ik_flags |= IEEE80211_KEY_DEFAULT; - } else { - memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); - wk.ik_keyix = IEEE80211_KEYIX_NONE; - } - wk.ik_keylen = key_len; - memcpy(wk.ik_keydata, key, key_len); - - ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s" - " key_idx %d alg %d key_len %lu set_tx %d)", - __func__, ether_sprintf(wk.ik_macaddr), key_idx, - alg, (unsigned long) key_len, set_tx); - } - - return ret; -} - - -static int -madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, - u8 *seq) -{ - struct madwifi_driver_data *drv = priv; - struct ieee80211req_key wk; - - wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", - __func__, ether_sprintf(addr), idx); - - memset(&wk, 0, sizeof(wk)); - if (addr == NULL) - memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); - else - memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); - wk.ik_keyix = idx; - - if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) { - wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data " - "(addr " MACSTR " key_idx %d)", - __func__, MAC2STR(wk.ik_macaddr), idx); - return -1; - } - -#ifdef WORDS_BIGENDIAN - { - /* - * wk.ik_keytsc is in host byte order (big endian), need to - * swap it to match with the byte order used in WPA. - */ - int i; - u8 tmp[WPA_KEY_RSC_LEN]; - memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); - for (i = 0; i < WPA_KEY_RSC_LEN; i++) { - seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; - } - } -#else /* WORDS_BIGENDIAN */ - memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); -#endif /* WORDS_BIGENDIAN */ - return 0; -} - - -static int -madwifi_flush(void *priv) -{ -#ifdef MADWIFI_BSD - u8 allsta[IEEE80211_ADDR_LEN]; - memset(allsta, 0xff, IEEE80211_ADDR_LEN); - return madwifi_sta_deauth(priv, NULL, allsta, - IEEE80211_REASON_AUTH_LEAVE); -#else /* MADWIFI_BSD */ - return 0; /* XXX */ -#endif /* MADWIFI_BSD */ -} - - -static int -madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, - const u8 *addr) -{ - struct madwifi_driver_data *drv = priv; - -#ifdef MADWIFI_BSD - struct ieee80211req_sta_stats stats; - - memset(data, 0, sizeof(*data)); - - /* - * Fetch statistics for station from the system. - */ - memset(&stats, 0, sizeof(stats)); - memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); - if (set80211priv(drv, -#ifdef MADWIFI_NG - IEEE80211_IOCTL_STA_STATS, -#else /* MADWIFI_NG */ - IEEE80211_IOCTL_GETSTASTATS, -#endif /* MADWIFI_NG */ - &stats, sizeof(stats))) { - wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr " - MACSTR ")", __func__, MAC2STR(addr)); - if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { - memcpy(data, &drv->acct_data, sizeof(*data)); - return 0; - } - - printf("Failed to get station stats information element.\n"); - return -1; - } - - data->rx_packets = stats.is_stats.ns_rx_data; - data->rx_bytes = stats.is_stats.ns_rx_bytes; - data->tx_packets = stats.is_stats.ns_tx_data; - data->tx_bytes = stats.is_stats.ns_tx_bytes; - return 0; - -#else /* MADWIFI_BSD */ - - char buf[1024], line[128], *pos; - FILE *f; - unsigned long val; - - memset(data, 0, sizeof(*data)); - snprintf(buf, sizeof(buf), "/proc/net/madwifi/%s/" MACSTR, - drv->iface, MAC2STR(addr)); - - f = fopen(buf, "r"); - if (!f) { - if (memcmp(addr, drv->acct_mac, ETH_ALEN) != 0) - return -1; - memcpy(data, &drv->acct_data, sizeof(*data)); - return 0; - } - /* Need to read proc file with in one piece, so use large enough - * buffer. */ - setbuffer(f, buf, sizeof(buf)); - - while (fgets(line, sizeof(line), f)) { - pos = strchr(line, '='); - if (!pos) - continue; - *pos++ = '\0'; - val = strtoul(pos, NULL, 10); - if (strcmp(line, "rx_packets") == 0) - data->rx_packets = val; - else if (strcmp(line, "tx_packets") == 0) - data->tx_packets = val; - else if (strcmp(line, "rx_bytes") == 0) - data->rx_bytes = val; - else if (strcmp(line, "tx_bytes") == 0) - data->tx_bytes = val; - } - - fclose(f); - - return 0; -#endif /* MADWIFI_BSD */ -} - - -static int -madwifi_sta_clear_stats(void *priv, const u8 *addr) -{ -#if defined(MADWIFI_BSD) && defined(IEEE80211_MLME_CLEAR_STATS) - struct madwifi_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr)); - - mlme.im_op = IEEE80211_MLME_CLEAR_STATS; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, - sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr " - MACSTR ")", __func__, MAC2STR(addr)); - } - - return ret; -#else /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */ - return 0; /* FIX */ -#endif /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */ -} - - -static int -madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) -{ - /* - * Do nothing; we setup parameters at startup that define the - * contents of the beacon information element. - */ - return 0; -} - -static int -madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, - int reason_code) -{ - struct madwifi_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", - __func__, ether_sprintf(addr), reason_code); - - mlme.im_op = IEEE80211_MLME_DEAUTH; - mlme.im_reason = reason_code; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR - " reason %d)", - __func__, MAC2STR(addr), reason_code); - } - - return ret; -} - -static int -madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, - int reason_code) -{ - struct madwifi_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", - __func__, ether_sprintf(addr), reason_code); - - mlme.im_op = IEEE80211_MLME_DISASSOC; - mlme.im_reason = reason_code; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr " - MACSTR " reason %d)", - __func__, MAC2STR(addr), reason_code); - } - - return ret; -} - -#ifdef CONFIG_WPS -#ifdef IEEE80211_IOCTL_FILTERFRAME -static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, - size_t len) -{ - struct madwifi_driver_data *drv = ctx; - const struct ieee80211_mgmt *mgmt; - u16 fc; - union wpa_event_data event; - - /* Send Probe Request information to WPS processing */ - - if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) - return; - mgmt = (const struct ieee80211_mgmt *) buf; - - fc = le_to_host16(mgmt->frame_control); - if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || - WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ) - return; - - 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)); - wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event); -} -#endif /* IEEE80211_IOCTL_FILTERFRAME */ -#endif /* CONFIG_WPS */ - -static int madwifi_receive_probe_req(struct madwifi_driver_data *drv) -{ - int ret = 0; -#ifdef CONFIG_WPS -#ifdef IEEE80211_IOCTL_FILTERFRAME - struct ieee80211req_set_filter filt; - - wpa_printf(MSG_DEBUG, "%s Enter", __func__); - filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ; - - ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, - sizeof(struct ieee80211req_set_filter)); - if (ret) - return ret; - - drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW, - madwifi_raw_receive, drv, 1); - if (drv->sock_raw == NULL) - return -1; -#endif /* IEEE80211_IOCTL_FILTERFRAME */ -#endif /* CONFIG_WPS */ - return ret; -} - -#ifdef CONFIG_WPS -static int -madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) -{ - struct madwifi_driver_data *drv = priv; - u8 buf[256]; - struct ieee80211req_getset_appiebuf *beac_ie; - - wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, - (unsigned long) len); - - beac_ie = (struct ieee80211req_getset_appiebuf *) buf; - beac_ie->app_frmtype = frametype; - beac_ie->app_buflen = len; - memcpy(&(beac_ie->app_buf[0]), ie, len); - - return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie, - sizeof(struct ieee80211req_getset_appiebuf) + len); -} - -static int -madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, - const struct wpabuf *proberesp, - const struct wpabuf *assocresp) -{ - if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL, - beacon ? wpabuf_len(beacon) : 0, - IEEE80211_APPIE_FRAME_BEACON) < 0) - return -1; - return madwifi_set_wps_ie(priv, - proberesp ? wpabuf_head(proberesp) : NULL, - proberesp ? wpabuf_len(proberesp) : 0, - IEEE80211_APPIE_FRAME_PROBE_RESP); -} -#else /* CONFIG_WPS */ -#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]) -{ - struct hostapd_data *hapd = drv->hapd; - struct ieee80211req_wpaie ie; - int ielen = 0; - u8 *iebuf = NULL; - - /* - * Fetch negotiated WPA/RSN parameters from the system. - */ - memset(&ie, 0, sizeof(ie)); - memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); - if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { - wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE", - __func__); - goto no_ie; - } - wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE", - ie.wpa_ie, IEEE80211_MAX_OPT_IE); - iebuf = ie.wpa_ie; - /* madwifi seems to return some random data if WPA/RSN IE is not set. - * Assume the IE was not included if the IE type is unknown. */ - if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) - iebuf[1] = 0; -#ifdef MADWIFI_NG - wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE", - ie.rsn_ie, IEEE80211_MAX_OPT_IE); - if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { - /* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not - * set. This is needed for WPA2. */ - iebuf = ie.rsn_ie; - if (iebuf[0] != WLAN_EID_RSN) - iebuf[1] = 0; - } -#endif /* MADWIFI_NG */ - - ielen = iebuf[1]; - if (ielen == 0) - iebuf = NULL; - else - ielen += 2; - -no_ie: - drv_event_assoc(hapd, addr, iebuf, ielen, 0); - - if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { - /* Cached accounting data is not valid anymore. */ - memset(drv->acct_mac, 0, ETH_ALEN); - memset(&drv->acct_data, 0, sizeof(drv->acct_data)); - } -} - -static void -madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv, - char *custom) -{ - wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); - - if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { - char *pos; - u8 addr[ETH_ALEN]; - pos = strstr(custom, "addr="); - if (pos == NULL) { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "without sender address ignored"); - return; - } - pos += 5; - if (hwaddr_aton(pos, addr) == 0) { - union wpa_event_data data; - os_memset(&data, 0, sizeof(data)); - data.michael_mic_failure.unicast = 1; - data.michael_mic_failure.src = addr; - wpa_supplicant_event(drv->hapd, - EVENT_MICHAEL_MIC_FAILURE, &data); - } else { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "with invalid MAC address"); - } - } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) { - char *key, *value; - u32 val; - key = custom; - while ((key = strchr(key, '\n')) != NULL) { - key++; - value = strchr(key, '='); - if (value == NULL) - continue; - *value++ = '\0'; - val = strtoul(value, NULL, 10); - if (strcmp(key, "mac") == 0) - hwaddr_aton(value, drv->acct_mac); - else if (strcmp(key, "rx_packets") == 0) - drv->acct_data.rx_packets = val; - else if (strcmp(key, "tx_packets") == 0) - drv->acct_data.tx_packets = val; - else if (strcmp(key, "rx_bytes") == 0) - drv->acct_data.rx_bytes = val; - else if (strcmp(key, "tx_bytes") == 0) - drv->acct_data.tx_bytes = val; - key = value; - } - } -} - -static void -madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, - char *data, int len) -{ - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end, *custom, *buf; - - 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. */ - memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); - wpa_printf(MSG_MSGDUMP, "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 > 18 && - (iwe->cmd == IWEVMICHAELMICFAILURE || - 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; - memcpy(dpos, pos + IW_EV_LCP_LEN, - sizeof(struct iw_event) - dlen); - } else { - memcpy(&iwe_buf, pos, sizeof(struct iw_event)); - custom += IW_EV_POINT_OFF; - } - - switch (iwe->cmd) { - case IWEVEXPIRED: - drv_event_disassoc(drv->hapd, - (u8 *) iwe->u.addr.sa_data); - break; - case IWEVREGISTERED: - madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data); - break; - case IWEVCUSTOM: - if (custom + iwe->u.data.length > end) - return; - buf = malloc(iwe->u.data.length + 1); - if (buf == NULL) - return; /* XXX */ - memcpy(buf, custom, iwe->u.data.length); - buf[iwe->u.data.length] = '\0'; - madwifi_wireless_event_wireless_custom(drv, buf); - free(buf); - break; - } - - pos += iwe->len; - } -} - - -static void -madwifi_wireless_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, - u8 *buf, size_t len) -{ - struct madwifi_driver_data *drv = ctx; - int attrlen, rta_len; - struct rtattr *attr; - - if (ifi->ifi_index != drv->ifindex) - return; - - attrlen = len; - attr = (struct rtattr *) buf; - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_WIRELESS) { - madwifi_wireless_event_wireless( - drv, ((char *) attr) + rta_len, - attr->rta_len - rta_len); - } - attr = RTA_NEXT(attr, attrlen); - } -} - - -static int -madwifi_get_we_version(struct madwifi_driver_data *drv) -{ - struct iw_range *range; - struct iwreq iwr; - int minlen; - size_t buflen; - - drv->we_version = 0; - - /* - * Use larger buffer than struct iw_range in order to allow the - * structure to grow in the future. - */ - buflen = sizeof(struct iw_range) + 500; - range = os_zalloc(buflen); - if (range == NULL) - return -1; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) range; - iwr.u.data.length = buflen; - - minlen = ((char *) &range->enc_capa) - (char *) range + - sizeof(range->enc_capa); - - if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { - perror("ioctl[SIOCGIWRANGE]"); - free(range); - return -1; - } else if (iwr.u.data.length >= minlen && - range->we_version_compiled >= 18) { - wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " - "WE(source)=%d enc_capa=0x%x", - range->we_version_compiled, - range->we_version_source, - range->enc_capa); - drv->we_version = range->we_version_compiled; - } - - free(range); - return 0; -} - - -static int -madwifi_wireless_event_init(struct madwifi_driver_data *drv) -{ - struct netlink_config *cfg; - - madwifi_get_we_version(drv); - - cfg = os_zalloc(sizeof(*cfg)); - if (cfg == NULL) - return -1; - cfg->ctx = drv; - cfg->newlink_cb = madwifi_wireless_event_rtm_newlink; - drv->netlink = netlink_init(cfg); - if (drv->netlink == NULL) { - os_free(cfg); - return -1; - } - - return 0; -} - - -static int -madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, - int encrypt, const u8 *own_addr, u32 flags) -{ - struct madwifi_driver_data *drv = priv; - unsigned char buf[3000]; - unsigned char *bp = buf; - struct l2_ethhdr *eth; - size_t len; - int status; - - /* - * Prepend the Ethernet header. If the caller left us - * space at the front we could just insert it but since - * we don't know we copy to a local buffer. Given the frequency - * and size of frames this probably doesn't matter. - */ - len = data_len + sizeof(struct l2_ethhdr); - if (len > sizeof(buf)) { - bp = malloc(len); - if (bp == NULL) { - printf("EAPOL frame discarded, cannot malloc temp " - "buffer of size %lu!\n", (unsigned long) len); - return -1; - } - } - eth = (struct l2_ethhdr *) bp; - memcpy(eth->h_dest, addr, ETH_ALEN); - memcpy(eth->h_source, own_addr, ETH_ALEN); - eth->h_proto = host_to_be16(ETH_P_EAPOL); - memcpy(eth+1, data, data_len); - - wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); - - status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len); - - if (bp != buf) - free(bp); - return status; -} - -static void -handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) -{ - struct madwifi_driver_data *drv = ctx; - drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr), - len - sizeof(struct l2_ethhdr)); -} - -static void * -madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params) -{ - struct madwifi_driver_data *drv; - struct ifreq ifr; - struct iwreq iwr; - char brname[IFNAMSIZ]; - - drv = os_zalloc(sizeof(struct madwifi_driver_data)); - if (drv == NULL) { - printf("Could not allocate memory for madwifi driver data\n"); - return NULL; - } - - drv->hapd = hapd; - drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->ioctl_sock < 0) { - perror("socket[PF_INET,SOCK_DGRAM]"); - goto bad; - } - memcpy(drv->iface, params->ifname, sizeof(drv->iface)); - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); - if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) { - perror("ioctl(SIOCGIFINDEX)"); - goto bad; - } - drv->ifindex = ifr.ifr_ifindex; - - drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, - handle_read, drv, 1); - if (drv->sock_xmit == NULL) - goto bad; - if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) - goto bad; - if (params->bridge[0]) { - wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.", - params->bridge[0]); - drv->sock_recv = l2_packet_init(params->bridge[0], NULL, - ETH_P_EAPOL, handle_read, drv, - 1); - if (drv->sock_recv == NULL) - goto bad; - } else if (linux_br_get(brname, drv->iface) == 0) { - wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for " - "EAPOL receive", brname); - drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL, - handle_read, drv, 1); - if (drv->sock_recv == NULL) - goto bad; - } else - drv->sock_recv = drv->sock_xmit; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - - iwr.u.mode = IW_MODE_MASTER; - - if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { - perror("ioctl[SIOCSIWMODE]"); - printf("Could not set interface to master mode!\n"); - goto bad; - } - - /* mark down during setup */ - linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); - madwifi_set_privacy(drv, 0); /* default to no privacy */ - - madwifi_receive_probe_req(drv); - - if (madwifi_wireless_event_init(drv)) - goto bad; - - return drv; -bad: - if (drv->sock_xmit != NULL) - l2_packet_deinit(drv->sock_xmit); - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - if (drv != NULL) - free(drv); - return NULL; -} - - -static void -madwifi_deinit(void *priv) -{ - struct madwifi_driver_data *drv = priv; - - netlink_deinit(drv->netlink); - (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) - l2_packet_deinit(drv->sock_recv); - if (drv->sock_xmit != NULL) - l2_packet_deinit(drv->sock_xmit); - if (drv->sock_raw) - l2_packet_deinit(drv->sock_raw); - free(drv); -} - -static int -madwifi_set_ssid(void *priv, const u8 *buf, int len) -{ - struct madwifi_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.essid.flags = 1; /* SSID active */ - iwr.u.essid.pointer = (caddr_t) buf; - iwr.u.essid.length = len + 1; - - if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { - perror("ioctl[SIOCSIWESSID]"); - printf("len=%d\n", len); - return -1; - } - return 0; -} - -static int -madwifi_get_ssid(void *priv, u8 *buf, int len) -{ - struct madwifi_driver_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.essid.pointer = (caddr_t) buf; - iwr.u.essid.length = len; - - if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { - perror("ioctl[SIOCGIWESSID]"); - ret = -1; - } else - ret = iwr.u.essid.length; - - return ret; -} - -static int -madwifi_set_countermeasures(void *priv, int enabled) -{ - struct madwifi_driver_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); - return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled); -} - -static int -madwifi_commit(void *priv) -{ - struct madwifi_driver_data *drv = priv; - return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1); -} - - -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, - .hapd_init = madwifi_init, - .hapd_deinit = madwifi_deinit, - .set_ieee8021x = madwifi_set_ieee8021x, - .set_privacy = madwifi_set_privacy, - .get_seqnum = madwifi_get_seqnum, - .flush = madwifi_flush, - .set_generic_elem = madwifi_set_opt_ie, - .sta_set_flags = madwifi_sta_set_flags, - .read_sta_data = madwifi_read_sta_driver_data, - .hapd_send_eapol = madwifi_send_eapol, - .sta_disassoc = madwifi_sta_disassoc, - .sta_deauth = madwifi_sta_deauth, - .hapd_set_ssid = madwifi_set_ssid, - .hapd_get_ssid = madwifi_get_ssid, - .hapd_set_countermeasures = madwifi_set_countermeasures, - .sta_clear_stats = madwifi_sta_clear_stats, - .commit = madwifi_commit, - .set_ap_wps_ie = madwifi_set_ap_wps_ie, - .set_freq = madwifi_set_freq, -}; diff --git a/contrib/hostapd/src/drivers/driver_ndis.c b/contrib/hostapd/src/drivers/driver_ndis.c deleted file mode 100644 index 4953af6a16..0000000000 --- a/contrib/hostapd/src/drivers/driver_ndis.c +++ /dev/null @@ -1,3218 +0,0 @@ -/* - * WPA Supplicant - Windows/NDIS driver interface - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifdef __CYGWIN__ -/* Avoid some header file conflicts by not including standard headers for - * cygwin builds when Packet32.h is included. */ -#include "build_config.h" -int close(int fd); -#else /* __CYGWIN__ */ -#include "includes.h" -#endif /* __CYGWIN__ */ -#ifdef CONFIG_USE_NDISUIO -#include -#else /* CONFIG_USE_NDISUIO */ -#include -#endif /* CONFIG_USE_NDISUIO */ -#ifdef __MINGW32_VERSION -#include -#else /* __MINGW32_VERSION */ -#include -#endif /* __MINGW32_VERSION */ - -#ifdef _WIN32_WCE -#include -#include -#include -#endif /* _WIN32_WCE */ - -#include "common.h" -#include "driver.h" -#include "eloop.h" -#include "common/ieee802_11_defs.h" -#include "driver_ndis.h" - -int wpa_driver_register_event_cb(struct wpa_driver_ndis_data *drv); -#ifdef CONFIG_NDIS_EVENTS_INTEGRATED -void wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data); -#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */ - -static void wpa_driver_ndis_deinit(void *priv); -static void wpa_driver_ndis_poll(void *drv); -static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx); -static int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv); -static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv); -static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv); - - -static const u8 pae_group_addr[ETH_ALEN] = -{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; - - -/* FIX: to be removed once this can be compiled with the complete NDIS - * header files */ -#ifndef OID_802_11_BSSID -#define OID_802_11_BSSID 0x0d010101 -#define OID_802_11_SSID 0x0d010102 -#define OID_802_11_INFRASTRUCTURE_MODE 0x0d010108 -#define OID_802_11_ADD_WEP 0x0D010113 -#define OID_802_11_REMOVE_WEP 0x0D010114 -#define OID_802_11_DISASSOCIATE 0x0D010115 -#define OID_802_11_BSSID_LIST 0x0d010217 -#define OID_802_11_AUTHENTICATION_MODE 0x0d010118 -#define OID_802_11_PRIVACY_FILTER 0x0d010119 -#define OID_802_11_BSSID_LIST_SCAN 0x0d01011A -#define OID_802_11_WEP_STATUS 0x0d01011B -#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS -#define OID_802_11_ADD_KEY 0x0d01011D -#define OID_802_11_REMOVE_KEY 0x0d01011E -#define OID_802_11_ASSOCIATION_INFORMATION 0x0d01011F -#define OID_802_11_TEST 0x0d010120 -#define OID_802_11_CAPABILITY 0x0d010122 -#define OID_802_11_PMKID 0x0d010123 - -#define NDIS_802_11_LENGTH_SSID 32 -#define NDIS_802_11_LENGTH_RATES 8 -#define NDIS_802_11_LENGTH_RATES_EX 16 - -typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; - -typedef struct NDIS_802_11_SSID { - ULONG SsidLength; - UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; -} NDIS_802_11_SSID; - -typedef LONG NDIS_802_11_RSSI; - -typedef enum NDIS_802_11_NETWORK_TYPE { - Ndis802_11FH, - Ndis802_11DS, - Ndis802_11OFDM5, - Ndis802_11OFDM24, - Ndis802_11NetworkTypeMax -} NDIS_802_11_NETWORK_TYPE; - -typedef struct NDIS_802_11_CONFIGURATION_FH { - ULONG Length; - ULONG HopPattern; - ULONG HopSet; - ULONG DwellTime; -} NDIS_802_11_CONFIGURATION_FH; - -typedef struct NDIS_802_11_CONFIGURATION { - ULONG Length; - ULONG BeaconPeriod; - ULONG ATIMWindow; - ULONG DSConfig; - NDIS_802_11_CONFIGURATION_FH FHConfig; -} NDIS_802_11_CONFIGURATION; - -typedef enum NDIS_802_11_NETWORK_INFRASTRUCTURE { - Ndis802_11IBSS, - Ndis802_11Infrastructure, - Ndis802_11AutoUnknown, - Ndis802_11InfrastructureMax -} NDIS_802_11_NETWORK_INFRASTRUCTURE; - -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 -} NDIS_802_11_AUTHENTICATION_MODE; - -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, NDIS_802_11_ENCRYPTION_STATUS; - -typedef enum NDIS_802_11_PRIVACY_FILTER { - Ndis802_11PrivFilterAcceptAll, - Ndis802_11PrivFilter8021xWEP -} NDIS_802_11_PRIVACY_FILTER; - -typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; -typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; - -typedef struct NDIS_WLAN_BSSID_EX { - ULONG Length; - NDIS_802_11_MAC_ADDRESS MacAddress; /* BSSID */ - UCHAR Reserved[2]; - NDIS_802_11_SSID Ssid; - ULONG Privacy; - NDIS_802_11_RSSI Rssi; - 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; - -typedef struct NDIS_802_11_BSSID_LIST_EX { - ULONG NumberOfItems; - NDIS_WLAN_BSSID_EX Bssid[1]; -} NDIS_802_11_BSSID_LIST_EX; - -typedef struct NDIS_802_11_FIXED_IEs { - UCHAR Timestamp[8]; - USHORT BeaconInterval; - USHORT Capabilities; -} NDIS_802_11_FIXED_IEs; - -typedef struct NDIS_802_11_WEP { - ULONG Length; - ULONG KeyIndex; - ULONG KeyLength; - UCHAR KeyMaterial[1]; -} NDIS_802_11_WEP; - -typedef ULONG NDIS_802_11_KEY_INDEX; -typedef ULONGLONG NDIS_802_11_KEY_RSC; - -typedef struct NDIS_802_11_KEY { - ULONG Length; - ULONG KeyIndex; - ULONG KeyLength; - NDIS_802_11_MAC_ADDRESS BSSID; - NDIS_802_11_KEY_RSC KeyRSC; - UCHAR KeyMaterial[1]; -} NDIS_802_11_KEY; - -typedef struct NDIS_802_11_REMOVE_KEY { - ULONG Length; - ULONG KeyIndex; - NDIS_802_11_MAC_ADDRESS BSSID; -} NDIS_802_11_REMOVE_KEY; - -typedef struct NDIS_802_11_AI_REQFI { - USHORT Capabilities; - USHORT ListenInterval; - NDIS_802_11_MAC_ADDRESS CurrentAPAddress; -} NDIS_802_11_AI_REQFI; - -typedef struct NDIS_802_11_AI_RESFI { - USHORT Capabilities; - USHORT StatusCode; - USHORT AssociationId; -} NDIS_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; - -typedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION { - NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported; - NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported; -} NDIS_802_11_AUTHENTICATION_ENCRYPTION; - -typedef struct NDIS_802_11_CAPABILITY { - ULONG Length; - ULONG Version; - ULONG NoOfPMKIDs; - ULONG NoOfAuthEncryptPairsSupported; - NDIS_802_11_AUTHENTICATION_ENCRYPTION - AuthenticationEncryptionSupported[1]; -} NDIS_802_11_CAPABILITY; - -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; - -typedef struct NDIS_802_11_PMKID { - ULONG Length; - ULONG BSSIDInfoCount; - BSSID_INFO BSSIDInfo[1]; -} NDIS_802_11_PMKID; - -typedef enum NDIS_802_11_STATUS_TYPE { - Ndis802_11StatusType_Authentication, - Ndis802_11StatusType_PMKID_CandidateList = 2, - Ndis802_11StatusTypeMax -} NDIS_802_11_STATUS_TYPE; - -typedef struct NDIS_802_11_STATUS_INDICATION { - NDIS_802_11_STATUS_TYPE StatusType; -} NDIS_802_11_STATUS_INDICATION; - -typedef struct PMKID_CANDIDATE { - NDIS_802_11_MAC_ADDRESS BSSID; - ULONG Flags; -} PMKID_CANDIDATE; - -#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 - -typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST { - ULONG Version; - ULONG NumCandidates; - PMKID_CANDIDATE CandidateList[1]; -} NDIS_802_11_PMKID_CANDIDATE_LIST; - -typedef struct NDIS_802_11_AUTHENTICATION_REQUEST { - ULONG Length; - NDIS_802_11_MAC_ADDRESS Bssid; - ULONG Flags; -} NDIS_802_11_AUTHENTICATION_REQUEST; - -#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 - -#endif /* OID_802_11_BSSID */ - - -#ifndef OID_802_11_PMKID -/* Platform SDK for XP did not include WPA2, so add needed definitions */ - -#define OID_802_11_CAPABILITY 0x0d010122 -#define OID_802_11_PMKID 0x0d010123 - -#define Ndis802_11AuthModeWPA2 6 -#define Ndis802_11AuthModeWPA2PSK 7 - -#define Ndis802_11StatusType_PMKID_CandidateList 2 - -typedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION { - NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported; - NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported; -} NDIS_802_11_AUTHENTICATION_ENCRYPTION; - -typedef struct NDIS_802_11_CAPABILITY { - ULONG Length; - ULONG Version; - ULONG NoOfPMKIDs; - ULONG NoOfAuthEncryptPairsSupported; - NDIS_802_11_AUTHENTICATION_ENCRYPTION - AuthenticationEncryptionSupported[1]; -} NDIS_802_11_CAPABILITY; - -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; - -typedef struct NDIS_802_11_PMKID { - ULONG Length; - ULONG BSSIDInfoCount; - BSSID_INFO BSSIDInfo[1]; -} NDIS_802_11_PMKID; - -typedef struct PMKID_CANDIDATE { - NDIS_802_11_MAC_ADDRESS BSSID; - ULONG Flags; -} PMKID_CANDIDATE; - -#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 - -typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST { - ULONG Version; - ULONG NumCandidates; - PMKID_CANDIDATE CandidateList[1]; -} NDIS_802_11_PMKID_CANDIDATE_LIST; - -#endif /* OID_802_11_CAPABILITY */ - - -#ifndef OID_DOT11_CURRENT_OPERATION_MODE -/* Native 802.11 OIDs */ -#define OID_DOT11_NDIS_START 0x0D010300 -#define OID_DOT11_CURRENT_OPERATION_MODE (OID_DOT11_NDIS_START + 8) -#define OID_DOT11_SCAN_REQUEST (OID_DOT11_NDIS_START + 11) - -typedef enum _DOT11_BSS_TYPE { - dot11_BSS_type_infrastructure = 1, - dot11_BSS_type_independent = 2, - dot11_BSS_type_any = 3 -} DOT11_BSS_TYPE, * PDOT11_BSS_TYPE; - -typedef UCHAR DOT11_MAC_ADDRESS[6]; -typedef DOT11_MAC_ADDRESS * PDOT11_MAC_ADDRESS; - -typedef enum _DOT11_SCAN_TYPE { - dot11_scan_type_active = 1, - dot11_scan_type_passive = 2, - dot11_scan_type_auto = 3, - dot11_scan_type_forced = 0x80000000 -} DOT11_SCAN_TYPE, * PDOT11_SCAN_TYPE; - -typedef struct _DOT11_SCAN_REQUEST_V2 { - DOT11_BSS_TYPE dot11BSSType; - DOT11_MAC_ADDRESS dot11BSSID; - DOT11_SCAN_TYPE dot11ScanType; - BOOLEAN bRestrictedScan; - ULONG udot11SSIDsOffset; - ULONG uNumOfdot11SSIDs; - BOOLEAN bUseRequestIE; - ULONG uRequestIDsOffset; - ULONG uNumOfRequestIDs; - ULONG uPhyTypeInfosOffset; - ULONG uNumOfPhyTypeInfos; - ULONG uIEsOffset; - ULONG uIEsLength; - UCHAR ucBuffer[1]; -} DOT11_SCAN_REQUEST_V2, * PDOT11_SCAN_REQUEST_V2; - -#endif /* OID_DOT11_CURRENT_OPERATION_MODE */ - -#ifdef CONFIG_USE_NDISUIO -#ifndef _WIN32_WCE -#ifdef __MINGW32_VERSION -typedef ULONG NDIS_OID; -#endif /* __MINGW32_VERSION */ -/* from nuiouser.h */ -#define FSCTL_NDISUIO_BASE FILE_DEVICE_NETWORK - -#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \ - CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access) - -#define IOCTL_NDISUIO_OPEN_DEVICE \ - _NDISUIO_CTL_CODE(0x200, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_NDISUIO_QUERY_OID_VALUE \ - _NDISUIO_CTL_CODE(0x201, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_NDISUIO_SET_OID_VALUE \ - _NDISUIO_CTL_CODE(0x205, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_NDISUIO_SET_ETHER_TYPE \ - _NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_NDISUIO_QUERY_BINDING \ - _NDISUIO_CTL_CODE(0x203, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_NDISUIO_BIND_WAIT \ - _NDISUIO_CTL_CODE(0x204, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -typedef struct _NDISUIO_QUERY_OID -{ - NDIS_OID Oid; - UCHAR Data[sizeof(ULONG)]; -} NDISUIO_QUERY_OID, *PNDISUIO_QUERY_OID; - -typedef struct _NDISUIO_SET_OID -{ - NDIS_OID Oid; - UCHAR Data[sizeof(ULONG)]; -} NDISUIO_SET_OID, *PNDISUIO_SET_OID; - -typedef struct _NDISUIO_QUERY_BINDING -{ - ULONG BindingIndex; - ULONG DeviceNameOffset; - ULONG DeviceNameLength; - ULONG DeviceDescrOffset; - ULONG DeviceDescrLength; -} NDISUIO_QUERY_BINDING, *PNDISUIO_QUERY_BINDING; -#endif /* _WIN32_WCE */ -#endif /* CONFIG_USE_NDISUIO */ - - -static int ndis_get_oid(struct wpa_driver_ndis_data *drv, unsigned int oid, - char *data, size_t len) -{ -#ifdef CONFIG_USE_NDISUIO - NDISUIO_QUERY_OID *o; - size_t buflen = sizeof(*o) + len; - DWORD written; - int ret; - size_t hdrlen; - - o = os_zalloc(buflen); - if (o == NULL) - return -1; - o->Oid = oid; -#ifdef _WIN32_WCE - o->ptcDeviceName = drv->adapter_name; -#endif /* _WIN32_WCE */ - if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_OID_VALUE, - o, sizeof(NDISUIO_QUERY_OID), o, buflen, &written, - NULL)) { - wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_QUERY_OID_VALUE " - "failed (oid=%08x): %d", oid, (int) GetLastError()); - os_free(o); - return -1; - } - hdrlen = sizeof(NDISUIO_QUERY_OID) - sizeof(o->Data); - if (written < hdrlen) { - wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d); " - "too short", oid, (unsigned int) written); - os_free(o); - return -1; - } - written -= hdrlen; - if (written > len) { - wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d) > " - "len (%d)",oid, (unsigned int) written, len); - os_free(o); - return -1; - } - os_memcpy(data, o->Data, written); - ret = written; - os_free(o); - return ret; -#else /* CONFIG_USE_NDISUIO */ - char *buf; - PACKET_OID_DATA *o; - int ret; - - buf = os_zalloc(sizeof(*o) + len); - if (buf == NULL) - return -1; - o = (PACKET_OID_DATA *) buf; - o->Oid = oid; - o->Length = len; - - if (!PacketRequest(drv->adapter, FALSE, o)) { - wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed", - __func__, oid, len); - os_free(buf); - return -1; - } - if (o->Length > len) { - wpa_printf(MSG_DEBUG, "%s: oid=0x%x Length (%d) > len (%d)", - __func__, oid, (unsigned int) o->Length, len); - os_free(buf); - return -1; - } - os_memcpy(data, o->Data, o->Length); - ret = o->Length; - os_free(buf); - return ret; -#endif /* CONFIG_USE_NDISUIO */ -} - - -static int ndis_set_oid(struct wpa_driver_ndis_data *drv, unsigned int oid, - const char *data, size_t len) -{ -#ifdef CONFIG_USE_NDISUIO - NDISUIO_SET_OID *o; - size_t buflen, reallen; - DWORD written; - char txt[50]; - - os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid); - wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len); - - buflen = sizeof(*o) + len; - reallen = buflen - sizeof(o->Data); - o = os_zalloc(buflen); - if (o == NULL) - return -1; - o->Oid = oid; -#ifdef _WIN32_WCE - o->ptcDeviceName = drv->adapter_name; -#endif /* _WIN32_WCE */ - if (data) - os_memcpy(o->Data, data, len); - if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_SET_OID_VALUE, - o, reallen, NULL, 0, &written, NULL)) { - wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_SET_OID_VALUE " - "(oid=%08x) failed: %d", oid, (int) GetLastError()); - os_free(o); - return -1; - } - os_free(o); - return 0; -#else /* CONFIG_USE_NDISUIO */ - char *buf; - PACKET_OID_DATA *o; - char txt[50]; - - os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid); - wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len); - - buf = os_zalloc(sizeof(*o) + len); - if (buf == NULL) - return -1; - o = (PACKET_OID_DATA *) buf; - o->Oid = oid; - o->Length = len; - if (data) - os_memcpy(o->Data, data, len); - - if (!PacketRequest(drv->adapter, TRUE, o)) { - wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed", - __func__, oid, len); - os_free(buf); - return -1; - } - os_free(buf); - return 0; -#endif /* CONFIG_USE_NDISUIO */ -} - - -static int ndis_set_auth_mode(struct wpa_driver_ndis_data *drv, int mode) -{ - u32 auth_mode = mode; - if (ndis_set_oid(drv, OID_802_11_AUTHENTICATION_MODE, - (char *) &auth_mode, sizeof(auth_mode)) < 0) { - wpa_printf(MSG_DEBUG, "NDIS: Failed to set " - "OID_802_11_AUTHENTICATION_MODE (%d)", - (int) auth_mode); - return -1; - } - return 0; -} - - -static int ndis_get_auth_mode(struct wpa_driver_ndis_data *drv) -{ - u32 auth_mode; - int res; - res = ndis_get_oid(drv, OID_802_11_AUTHENTICATION_MODE, - (char *) &auth_mode, sizeof(auth_mode)); - if (res != sizeof(auth_mode)) { - wpa_printf(MSG_DEBUG, "NDIS: Failed to get " - "OID_802_11_AUTHENTICATION_MODE"); - return -1; - } - return auth_mode; -} - - -static int ndis_set_encr_status(struct wpa_driver_ndis_data *drv, int encr) -{ - u32 encr_status = encr; - if (ndis_set_oid(drv, OID_802_11_ENCRYPTION_STATUS, - (char *) &encr_status, sizeof(encr_status)) < 0) { - wpa_printf(MSG_DEBUG, "NDIS: Failed to set " - "OID_802_11_ENCRYPTION_STATUS (%d)", encr); - return -1; - } - return 0; -} - - -static int ndis_get_encr_status(struct wpa_driver_ndis_data *drv) -{ - u32 encr; - int res; - res = ndis_get_oid(drv, OID_802_11_ENCRYPTION_STATUS, - (char *) &encr, sizeof(encr)); - if (res != sizeof(encr)) { - wpa_printf(MSG_DEBUG, "NDIS: Failed to get " - "OID_802_11_ENCRYPTION_STATUS"); - return -1; - } - return encr; -} - - -static int wpa_driver_ndis_get_bssid(void *priv, u8 *bssid) -{ - struct wpa_driver_ndis_data *drv = priv; - - if (drv->wired) { - /* - * Report PAE group address as the "BSSID" for wired - * connection. - */ - os_memcpy(bssid, pae_group_addr, ETH_ALEN); - return 0; - } - - return ndis_get_oid(drv, OID_802_11_BSSID, (char *) bssid, ETH_ALEN) < - 0 ? -1 : 0; -} - - -static int wpa_driver_ndis_get_ssid(void *priv, u8 *ssid) -{ - struct wpa_driver_ndis_data *drv = priv; - NDIS_802_11_SSID buf; - int res; - - res = ndis_get_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf)); - if (res < 4) { - wpa_printf(MSG_DEBUG, "NDIS: Failed to get SSID"); - if (drv->wired) { - wpa_printf(MSG_DEBUG, "NDIS: Allow get_ssid failure " - "with a wired interface"); - return 0; - } - return -1; - } - os_memcpy(ssid, buf.Ssid, buf.SsidLength); - return buf.SsidLength; -} - - -static int wpa_driver_ndis_set_ssid(struct wpa_driver_ndis_data *drv, - const u8 *ssid, size_t ssid_len) -{ - NDIS_802_11_SSID buf; - - os_memset(&buf, 0, sizeof(buf)); - buf.SsidLength = ssid_len; - os_memcpy(buf.Ssid, ssid, ssid_len); - /* - * Make sure radio is marked enabled here so that scan request will not - * force SSID to be changed to a random one in order to enable radio at - * that point. - */ - drv->radio_enabled = 1; - return ndis_set_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf)); -} - - -/* Disconnect using OID_802_11_DISASSOCIATE. This will also turn the radio off. - */ -static int wpa_driver_ndis_radio_off(struct wpa_driver_ndis_data *drv) -{ - drv->radio_enabled = 0; - return ndis_set_oid(drv, OID_802_11_DISASSOCIATE, " ", 4); -} - - -/* Disconnect by setting SSID to random (i.e., likely not used). */ -static int wpa_driver_ndis_disconnect(struct wpa_driver_ndis_data *drv) -{ - char ssid[32]; - int i; - for (i = 0; i < 32; i++) - ssid[i] = rand() & 0xff; - return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, 32); -} - - -static int wpa_driver_ndis_deauthenticate(void *priv, const u8 *addr, - int reason_code) -{ - struct wpa_driver_ndis_data *drv = priv; - return wpa_driver_ndis_disconnect(drv); -} - - -static void wpa_driver_ndis_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_ndis_scan_native80211( - struct wpa_driver_ndis_data *drv, - struct wpa_driver_scan_params *params) -{ - DOT11_SCAN_REQUEST_V2 req; - int res; - - os_memset(&req, 0, sizeof(req)); - req.dot11BSSType = dot11_BSS_type_any; - os_memset(req.dot11BSSID, 0xff, ETH_ALEN); - req.dot11ScanType = dot11_scan_type_auto; - res = ndis_set_oid(drv, OID_DOT11_SCAN_REQUEST, (char *) &req, - sizeof(req)); - eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx); - eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv, - drv->ctx); - return res; -} - - -static int wpa_driver_ndis_scan(void *priv, - struct wpa_driver_scan_params *params) -{ - struct wpa_driver_ndis_data *drv = priv; - int res; - - if (drv->native80211) - return wpa_driver_ndis_scan_native80211(drv, params); - - if (!drv->radio_enabled) { - wpa_printf(MSG_DEBUG, "NDIS: turning radio on before the first" - " scan"); - if (wpa_driver_ndis_disconnect(drv) < 0) { - wpa_printf(MSG_DEBUG, "NDIS: failed to enable radio"); - } - drv->radio_enabled = 1; - } - - res = ndis_set_oid(drv, OID_802_11_BSSID_LIST_SCAN, " ", 4); - eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx); - eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv, - drv->ctx); - return res; -} - - -static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) -{ - const u8 *end, *pos; - - pos = (const u8 *) (res + 1); - end = pos + res->ie_len; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == ie) - return pos; - pos += 2 + pos[1]; - } - - return NULL; -} - - -static struct wpa_scan_res * wpa_driver_ndis_add_scan_ssid( - struct wpa_scan_res *r, NDIS_802_11_SSID *ssid) -{ - struct wpa_scan_res *nr; - u8 *pos; - - if (wpa_scan_get_ie(r, WLAN_EID_SSID)) - return r; /* SSID IE already present */ - - if (ssid->SsidLength == 0 || ssid->SsidLength > 32) - return r; /* No valid SSID inside scan data */ - - nr = os_realloc(r, sizeof(*r) + r->ie_len + 2 + ssid->SsidLength); - if (nr == NULL) - return r; - - pos = ((u8 *) (nr + 1)) + nr->ie_len; - *pos++ = WLAN_EID_SSID; - *pos++ = ssid->SsidLength; - os_memcpy(pos, ssid->Ssid, ssid->SsidLength); - nr->ie_len += 2 + ssid->SsidLength; - - return nr; -} - - -static struct wpa_scan_results * wpa_driver_ndis_get_scan_results(void *priv) -{ - struct wpa_driver_ndis_data *drv = priv; - NDIS_802_11_BSSID_LIST_EX *b; - size_t blen, count, i; - int len; - char *pos; - struct wpa_scan_results *results; - struct wpa_scan_res *r; - - blen = 65535; - b = os_zalloc(blen); - if (b == NULL) - return NULL; - len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen); - if (len < 0) { - wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results"); - os_free(b); - return NULL; - } - count = b->NumberOfItems; - - results = os_zalloc(sizeof(*results)); - if (results == NULL) { - os_free(b); - return NULL; - } - results->res = os_calloc(count, sizeof(struct wpa_scan_res *)); - if (results->res == NULL) { - os_free(results); - os_free(b); - return NULL; - } - - pos = (char *) &b->Bssid[0]; - for (i = 0; i < count; i++) { - NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos; - NDIS_802_11_FIXED_IEs *fixed; - - if (bss->IELength < sizeof(NDIS_802_11_FIXED_IEs)) { - wpa_printf(MSG_DEBUG, "NDIS: too small IELength=%d", - (int) bss->IELength); - break; - } - if (((char *) bss->IEs) + bss->IELength > (char *) b + blen) { - /* - * Some NDIS drivers have been reported to include an - * entry with an invalid IELength in scan results and - * this has crashed wpa_supplicant, so validate the - * returned value before using it. - */ - wpa_printf(MSG_DEBUG, "NDIS: skipped invalid scan " - "result IE (BSSID=" MACSTR ") IELength=%d", - MAC2STR(bss->MacAddress), - (int) bss->IELength); - break; - } - - r = os_zalloc(sizeof(*r) + bss->IELength - - sizeof(NDIS_802_11_FIXED_IEs)); - if (r == NULL) - break; - - os_memcpy(r->bssid, bss->MacAddress, ETH_ALEN); - r->level = (int) bss->Rssi; - r->freq = bss->Configuration.DSConfig / 1000; - fixed = (NDIS_802_11_FIXED_IEs *) bss->IEs; - r->beacon_int = WPA_GET_LE16((u8 *) &fixed->BeaconInterval); - r->caps = WPA_GET_LE16((u8 *) &fixed->Capabilities); - r->tsf = WPA_GET_LE64(fixed->Timestamp); - os_memcpy(r + 1, bss->IEs + sizeof(NDIS_802_11_FIXED_IEs), - bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)); - r->ie_len = bss->IELength - sizeof(NDIS_802_11_FIXED_IEs); - r = wpa_driver_ndis_add_scan_ssid(r, &bss->Ssid); - - results->res[results->num++] = r; - - pos += bss->Length; - if (pos > (char *) b + blen) - break; - } - - os_free(b); - - return results; -} - - -static int wpa_driver_ndis_remove_key(struct wpa_driver_ndis_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; - - 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 = ndis_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey, - sizeof(rkey)); - if (!pairwise) { - index = key_idx; - res2 = ndis_set_oid(drv, OID_802_11_REMOVE_WEP, - (char *) &index, sizeof(index)); - } else - res2 = 0; - - if (res < 0 && res2 < 0) - return -1; - return 0; -} - - -static int wpa_driver_ndis_add_wep(struct wpa_driver_ndis_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; - - 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 |= 1 << 31; -#if 0 /* Setting bit30 does not seem to work with some NDIS drivers */ - if (pairwise) - wep->KeyIndex |= 1 << 30; -#endif - wep->KeyLength = key_len; - os_memcpy(wep->KeyMaterial, key, key_len); - - wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_WEP", - (u8 *) wep, len); - res = ndis_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len); - - os_free(wep); - - return res; -} - - -static int wpa_driver_ndis_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_ndis_data *drv = priv; - size_t len, i; - NDIS_802_11_KEY *nkey; - int res, pairwise; - u8 bssid[ETH_ALEN]; - - if (addr == NULL || is_broadcast_ether_addr(addr)) { - /* Group Key */ - pairwise = 0; - if (wpa_driver_ndis_get_bssid(drv, bssid) < 0) - os_memset(bssid, 0xff, ETH_ALEN); - } else { - /* Pairwise Key */ - pairwise = 1; - os_memcpy(bssid, addr, ETH_ALEN); - } - - if (alg == WPA_ALG_NONE || key_len == 0) { - return wpa_driver_ndis_remove_key(drv, key_idx, addr, bssid, - pairwise); - } - - if (alg == WPA_ALG_WEP) { - return wpa_driver_ndis_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 |= (ULONGLONG) 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_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_KEY", - (u8 *) nkey, len); - res = ndis_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len); - os_free(nkey); - - return res; -} - - -static int -wpa_driver_ndis_associate(void *priv, - struct wpa_driver_associate_params *params) -{ - struct wpa_driver_ndis_data *drv = priv; - u32 auth_mode, encr, priv_mode, mode; - u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - drv->mode = params->mode; - - /* Note: Setting OID_802_11_INFRASTRUCTURE_MODE clears current keys, - * so static WEP keys needs to be set again after this. */ - if (params->mode == IEEE80211_MODE_IBSS) { - mode = Ndis802_11IBSS; - /* Need to make sure that BSSID polling is enabled for - * IBSS mode. */ - eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL); - eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, - drv, NULL); - } else - mode = Ndis802_11Infrastructure; - if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE, - (char *) &mode, sizeof(mode)) < 0) { - wpa_printf(MSG_DEBUG, "NDIS: Failed to set " - "OID_802_11_INFRASTRUCTURE_MODE (%d)", - (int) mode); - /* Try to continue anyway */ - } - - if (params->key_mgmt_suite == WPA_KEY_MGMT_NONE || - params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { - /* Re-set WEP keys if static WEP configuration is used. */ - int i; - for (i = 0; i < 4; i++) { - if (!params->wep_key[i]) - continue; - wpa_printf(MSG_DEBUG, "NDIS: Re-setting static WEP " - "key %d", i); - wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP, - bcast, i, - i == params->wep_tx_keyidx, - NULL, 0, params->wep_key[i], - params->wep_key_len[i]); - } - } - - 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; - priv_mode = Ndis802_11PrivFilterAcceptAll; - } else if (params->wpa_ie[0] == WLAN_EID_RSN) { - priv_mode = Ndis802_11PrivFilter8021xWEP; - if (params->key_mgmt_suite == WPA_KEY_MGMT_PSK) - auth_mode = Ndis802_11AuthModeWPA2PSK; - else - auth_mode = Ndis802_11AuthModeWPA2; -#ifdef CONFIG_WPS - } else if (params->key_mgmt_suite == WPA_KEY_MGMT_WPS) { - auth_mode = Ndis802_11AuthModeOpen; - priv_mode = Ndis802_11PrivFilterAcceptAll; - if (params->wps == WPS_MODE_PRIVACY) { - u8 dummy_key[5] = { 0x11, 0x22, 0x33, 0x44, 0x55 }; - /* - * Some NDIS drivers refuse to associate in open mode - * configuration due to Privacy field mismatch, so use - * a workaround to make the configuration look like - * matching one for WPS provisioning. - */ - wpa_printf(MSG_DEBUG, "NDIS: Set dummy WEP key as a " - "workaround to allow driver to associate " - "for WPS"); - wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP, - bcast, 0, 1, - NULL, 0, dummy_key, - sizeof(dummy_key)); - } -#endif /* CONFIG_WPS */ - } else { - priv_mode = Ndis802_11PrivFilter8021xWEP; - if (params->key_mgmt_suite == WPA_KEY_MGMT_WPA_NONE) - auth_mode = Ndis802_11AuthModeWPANone; - else if (params->key_mgmt_suite == WPA_KEY_MGMT_PSK) - auth_mode = Ndis802_11AuthModeWPAPSK; - else - auth_mode = Ndis802_11AuthModeWPA; - } - - switch (params->pairwise_suite) { - case WPA_CIPHER_CCMP: - encr = Ndis802_11Encryption3Enabled; - break; - case WPA_CIPHER_TKIP: - encr = Ndis802_11Encryption2Enabled; - break; - case WPA_CIPHER_WEP40: - case WPA_CIPHER_WEP104: - encr = Ndis802_11Encryption1Enabled; - break; - case WPA_CIPHER_NONE: -#ifdef CONFIG_WPS - if (params->wps == WPS_MODE_PRIVACY) { - encr = Ndis802_11Encryption1Enabled; - break; - } -#endif /* CONFIG_WPS */ - if (params->group_suite == WPA_CIPHER_CCMP) - encr = Ndis802_11Encryption3Enabled; - else if (params->group_suite == WPA_CIPHER_TKIP) - encr = Ndis802_11Encryption2Enabled; - else - encr = Ndis802_11EncryptionDisabled; - break; - default: -#ifdef CONFIG_WPS - if (params->wps == WPS_MODE_PRIVACY) { - encr = Ndis802_11Encryption1Enabled; - break; - } -#endif /* CONFIG_WPS */ - encr = Ndis802_11EncryptionDisabled; - break; - }; - - if (ndis_set_oid(drv, OID_802_11_PRIVACY_FILTER, - (char *) &priv_mode, sizeof(priv_mode)) < 0) { - wpa_printf(MSG_DEBUG, "NDIS: Failed to set " - "OID_802_11_PRIVACY_FILTER (%d)", - (int) priv_mode); - /* Try to continue anyway */ - } - - ndis_set_auth_mode(drv, auth_mode); - ndis_set_encr_status(drv, encr); - - if (params->bssid) { - ndis_set_oid(drv, OID_802_11_BSSID, (char *) params->bssid, - ETH_ALEN); - drv->oid_bssid_set = 1; - } else if (drv->oid_bssid_set) { - ndis_set_oid(drv, OID_802_11_BSSID, "\xff\xff\xff\xff\xff\xff", - ETH_ALEN); - drv->oid_bssid_set = 0; - } - - return wpa_driver_ndis_set_ssid(drv, params->ssid, params->ssid_len); -} - - -static int wpa_driver_ndis_set_pmkid(struct wpa_driver_ndis_data *drv) -{ - int len, count, i, ret; - struct ndis_pmkid_entry *entry; - NDIS_802_11_PMKID *p; - - 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", (u8 *) p, len); - ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) p, len); - os_free(p); - return ret; -} - - -static int wpa_driver_ndis_add_pmkid(void *priv, const u8 *bssid, - const u8 *pmkid) -{ - struct wpa_driver_ndis_data *drv = priv; - struct ndis_pmkid_entry *entry, *prev; - - 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_ndis_set_pmkid(drv); -} - - -static int wpa_driver_ndis_remove_pmkid(void *priv, const u8 *bssid, - const u8 *pmkid) -{ - struct wpa_driver_ndis_data *drv = priv; - struct ndis_pmkid_entry *entry, *prev; - - if (drv->no_of_pmkid == 0) - return 0; - - entry = drv->pmkid; - prev = 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_ndis_set_pmkid(drv); -} - - -static int wpa_driver_ndis_flush_pmkid(void *priv) -{ - struct wpa_driver_ndis_data *drv = priv; - NDIS_802_11_PMKID p; - struct ndis_pmkid_entry *pmkid, *prev; - int prev_authmode, ret; - - if (drv->no_of_pmkid == 0) - return 0; - - pmkid = drv->pmkid; - drv->pmkid = NULL; - while (pmkid) { - prev = pmkid; - pmkid = pmkid->next; - os_free(prev); - } - - /* - * Some drivers may refuse OID_802_11_PMKID if authMode is not set to - * WPA2, so change authMode temporarily, if needed. - */ - prev_authmode = ndis_get_auth_mode(drv); - if (prev_authmode != Ndis802_11AuthModeWPA2) - ndis_set_auth_mode(drv, Ndis802_11AuthModeWPA2); - - os_memset(&p, 0, sizeof(p)); - p.Length = 8; - p.BSSIDInfoCount = 0; - wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)", - (u8 *) &p, 8); - ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8); - - if (prev_authmode != Ndis802_11AuthModeWPA2) - ndis_set_auth_mode(drv, prev_authmode); - - return ret; -} - - -static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv) -{ - char buf[512], *pos; - NDIS_802_11_ASSOCIATION_INFORMATION *ai; - int len; - union wpa_event_data data; - NDIS_802_11_BSSID_LIST_EX *b; - size_t blen, i; - - len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION, buf, - sizeof(buf)); - if (len < 0) { - wpa_printf(MSG_DEBUG, "NDIS: failed to get association " - "information"); - return -1; - } - if (len > sizeof(buf)) { - /* Some drivers seem to be producing incorrect length for this - * data. Limit the length to the current buffer size to avoid - * crashing in hexdump. The data seems to be otherwise valid, - * so better try to use it. */ - wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association " - "information length %d", len); - len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION, - buf, sizeof(buf)); - if (len < -1) { - wpa_printf(MSG_DEBUG, "NDIS: re-reading association " - "information failed"); - return -1; - } - if (len > sizeof(buf)) { - wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association" - " information length %d (re-read)", len); - len = sizeof(buf); - } - } - wpa_hexdump(MSG_MSGDUMP, "NDIS: association information", - (u8 *) buf, len); - if (len < sizeof(*ai)) { - wpa_printf(MSG_DEBUG, "NDIS: too short association " - "information"); - return -1; - } - ai = (NDIS_802_11_ASSOCIATION_INFORMATION *) buf; - wpa_printf(MSG_DEBUG, "NDIS: ReqFixed=0x%x RespFixed=0x%x off_req=%d " - "off_resp=%d len_req=%d len_resp=%d", - ai->AvailableRequestFixedIEs, ai->AvailableResponseFixedIEs, - (int) ai->OffsetRequestIEs, (int) ai->OffsetResponseIEs, - (int) ai->RequestIELength, (int) ai->ResponseIELength); - - if (ai->OffsetRequestIEs + ai->RequestIELength > (unsigned) len || - ai->OffsetResponseIEs + ai->ResponseIELength > (unsigned) len) { - wpa_printf(MSG_DEBUG, "NDIS: association information - " - "IE overflow"); - return -1; - } - - wpa_hexdump(MSG_MSGDUMP, "NDIS: Request IEs", - (u8 *) buf + ai->OffsetRequestIEs, ai->RequestIELength); - wpa_hexdump(MSG_MSGDUMP, "NDIS: Response IEs", - (u8 *) buf + ai->OffsetResponseIEs, ai->ResponseIELength); - - os_memset(&data, 0, sizeof(data)); - data.assoc_info.req_ies = (u8 *) buf + ai->OffsetRequestIEs; - data.assoc_info.req_ies_len = ai->RequestIELength; - data.assoc_info.resp_ies = (u8 *) buf + ai->OffsetResponseIEs; - data.assoc_info.resp_ies_len = ai->ResponseIELength; - - blen = 65535; - b = os_zalloc(blen); - if (b == NULL) - goto skip_scan_results; - len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen); - if (len < 0) { - wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results"); - os_free(b); - b = NULL; - goto skip_scan_results; - } - wpa_printf(MSG_DEBUG, "NDIS: %d BSSID items to process for AssocInfo", - (unsigned int) b->NumberOfItems); - - pos = (char *) &b->Bssid[0]; - for (i = 0; i < b->NumberOfItems; i++) { - NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos; - if (os_memcmp(drv->bssid, bss->MacAddress, ETH_ALEN) == 0 && - bss->IELength > sizeof(NDIS_802_11_FIXED_IEs)) { - data.assoc_info.beacon_ies = - ((u8 *) bss->IEs) + - sizeof(NDIS_802_11_FIXED_IEs); - data.assoc_info.beacon_ies_len = - bss->IELength - sizeof(NDIS_802_11_FIXED_IEs); - wpa_hexdump(MSG_MSGDUMP, "NDIS: Beacon IEs", - data.assoc_info.beacon_ies, - data.assoc_info.beacon_ies_len); - break; - } - pos += bss->Length; - if (pos > (char *) b + blen) - break; - } - -skip_scan_results: - wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data); - - os_free(b); - - return 0; -} - - -static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_driver_ndis_data *drv = eloop_ctx; - u8 bssid[ETH_ALEN]; - int poll; - - if (drv->wired) - return; - - if (wpa_driver_ndis_get_bssid(drv, bssid)) { - /* Disconnected */ - if (!is_zero_ether_addr(drv->bssid)) { - os_memset(drv->bssid, 0, ETH_ALEN); - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); - } - } else { - /* Connected */ - if (os_memcmp(drv->bssid, bssid, ETH_ALEN) != 0) { - os_memcpy(drv->bssid, bssid, ETH_ALEN); - wpa_driver_ndis_get_associnfo(drv); - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); - } - } - - /* When using integrated NDIS event receiver, we can skip BSSID - * polling when using infrastructure network. However, when using - * IBSS mode, many driver do not seem to generate connection event, - * so we need to enable BSSID polling to figure out when IBSS network - * has been formed. - */ - poll = drv->mode == IEEE80211_MODE_IBSS; -#ifndef CONFIG_NDIS_EVENTS_INTEGRATED -#ifndef _WIN32_WCE - poll = 1; -#endif /* _WIN32_WCE */ -#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */ - - if (poll) { - eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, - drv, NULL); - } -} - - -static void wpa_driver_ndis_poll(void *priv) -{ - struct wpa_driver_ndis_data *drv = priv; - eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL); - wpa_driver_ndis_poll_timeout(drv, NULL); -} - - -/* Called when driver generates Media Connect Event by calling - * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_CONNECT */ -void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv) -{ - wpa_printf(MSG_DEBUG, "NDIS: Media Connect Event"); - if (wpa_driver_ndis_get_bssid(drv, drv->bssid) == 0) { - wpa_driver_ndis_get_associnfo(drv); - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); - } -} - - -/* Called when driver generates Media Disconnect Event by calling - * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_DISCONNECT */ -void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv) -{ - wpa_printf(MSG_DEBUG, "NDIS: Media Disconnect Event"); - os_memset(drv->bssid, 0, ETH_ALEN); - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); -} - - -static void wpa_driver_ndis_event_auth(struct wpa_driver_ndis_data *drv, - const u8 *data, size_t data_len) -{ - NDIS_802_11_AUTHENTICATION_REQUEST *req; - int pairwise = 0, group = 0; - union wpa_event_data event; - - if (data_len < sizeof(*req)) { - wpa_printf(MSG_DEBUG, "NDIS: Too short Authentication Request " - "Event (len=%d)", data_len); - return; - } - req = (NDIS_802_11_AUTHENTICATION_REQUEST *) data; - - wpa_printf(MSG_DEBUG, "NDIS: Authentication Request Event: " - "Bssid " MACSTR " Flags 0x%x", - MAC2STR(req->Bssid), (int) req->Flags); - - if ((req->Flags & NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR) == - NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR) - pairwise = 1; - else if ((req->Flags & NDIS_802_11_AUTH_REQUEST_GROUP_ERROR) == - NDIS_802_11_AUTH_REQUEST_GROUP_ERROR) - group = 1; - - if (pairwise || group) { - os_memset(&event, 0, sizeof(event)); - event.michael_mic_failure.unicast = pairwise; - wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, - &event); - } -} - - -static void wpa_driver_ndis_event_pmkid(struct wpa_driver_ndis_data *drv, - const u8 *data, size_t data_len) -{ - NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid; - size_t i; - union wpa_event_data event; - - if (data_len < 8) { - wpa_printf(MSG_DEBUG, "NDIS: Too short PMKID Candidate List " - "Event (len=%d)", data_len); - return; - } - pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data; - wpa_printf(MSG_DEBUG, "NDIS: PMKID Candidate List Event - Version %d " - "NumCandidates %d", - (int) pmkid->Version, (int) pmkid->NumCandidates); - - if (pmkid->Version != 1) { - wpa_printf(MSG_DEBUG, "NDIS: Unsupported PMKID Candidate List " - "Version %d", (int) pmkid->Version); - return; - } - - if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) { - wpa_printf(MSG_DEBUG, "NDIS: 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, "NDIS: %d: " MACSTR " Flags 0x%x", - 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); - } -} - - -/* Called when driver calls NdisMIndicateStatus() with - * NDIS_STATUS_MEDIA_SPECIFIC_INDICATION */ -void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv, - const u8 *data, size_t data_len) -{ - NDIS_802_11_STATUS_INDICATION *status; - - if (data == NULL || data_len < sizeof(*status)) - return; - - wpa_hexdump(MSG_DEBUG, "NDIS: Media Specific Indication", - data, data_len); - - status = (NDIS_802_11_STATUS_INDICATION *) data; - data += sizeof(status); - data_len -= sizeof(status); - - switch (status->StatusType) { - case Ndis802_11StatusType_Authentication: - wpa_driver_ndis_event_auth(drv, data, data_len); - break; - case Ndis802_11StatusType_PMKID_CandidateList: - wpa_driver_ndis_event_pmkid(drv, data, data_len); - break; - default: - wpa_printf(MSG_DEBUG, "NDIS: Unknown StatusType %d", - (int) status->StatusType); - break; - } -} - - -/* Called when an adapter is added */ -void wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv) -{ - union wpa_event_data event; - int i; - - wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Arrival"); - - for (i = 0; i < 30; i++) { - /* Re-open Packet32/NDISUIO connection */ - wpa_driver_ndis_adapter_close(drv); - if (wpa_driver_ndis_adapter_init(drv) < 0 || - wpa_driver_ndis_adapter_open(drv) < 0) { - wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialization " - "(%d) failed", i); - os_sleep(1, 0); - } else { - wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialized"); - break; - } - } - - os_memset(&event, 0, sizeof(event)); - os_strlcpy(event.interface_status.ifname, drv->ifname, - sizeof(event.interface_status.ifname)); - event.interface_status.ievent = EVENT_INTERFACE_ADDED; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); -} - - -/* Called when an adapter is removed */ -void wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv) -{ - union wpa_event_data event; - - wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Removal"); - os_memset(&event, 0, sizeof(event)); - os_strlcpy(event.interface_status.ifname, drv->ifname, - sizeof(event.interface_status.ifname)); - event.interface_status.ievent = EVENT_INTERFACE_REMOVED; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); -} - - -static void -wpa_driver_ndis_get_wpa_capability(struct wpa_driver_ndis_data *drv) -{ - wpa_printf(MSG_DEBUG, "NDIS: verifying driver WPA capability"); - - if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPA) == 0 && - ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPA) { - wpa_printf(MSG_DEBUG, "NDIS: WPA key management supported"); - drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA; - } - - if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPAPSK) == 0 && - ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPAPSK) { - wpa_printf(MSG_DEBUG, "NDIS: WPA-PSK key management " - "supported"); - drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; - } - - if (ndis_set_encr_status(drv, Ndis802_11Encryption3Enabled) == 0 && - ndis_get_encr_status(drv) == Ndis802_11Encryption3KeyAbsent) { - wpa_printf(MSG_DEBUG, "NDIS: CCMP encryption supported"); - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; - } - - if (ndis_set_encr_status(drv, Ndis802_11Encryption2Enabled) == 0 && - ndis_get_encr_status(drv) == Ndis802_11Encryption2KeyAbsent) { - wpa_printf(MSG_DEBUG, "NDIS: TKIP encryption supported"); - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; - } - - if (ndis_set_encr_status(drv, Ndis802_11Encryption1Enabled) == 0 && - ndis_get_encr_status(drv) == Ndis802_11Encryption1KeyAbsent) { - wpa_printf(MSG_DEBUG, "NDIS: WEP encryption supported"); - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | - WPA_DRIVER_CAPA_ENC_WEP104; - } - - if (ndis_set_auth_mode(drv, Ndis802_11AuthModeShared) == 0 && - ndis_get_auth_mode(drv) == Ndis802_11AuthModeShared) { - drv->capa.auth |= WPA_DRIVER_AUTH_SHARED; - } - - if (ndis_set_auth_mode(drv, Ndis802_11AuthModeOpen) == 0 && - ndis_get_auth_mode(drv) == Ndis802_11AuthModeOpen) { - drv->capa.auth |= WPA_DRIVER_AUTH_OPEN; - } - - ndis_set_encr_status(drv, Ndis802_11EncryptionDisabled); - - /* Could also verify OID_802_11_ADD_KEY error reporting and - * support for OID_802_11_ASSOCIATION_INFORMATION. */ - - if (drv->capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA && - drv->capa.enc & (WPA_DRIVER_CAPA_ENC_TKIP | - WPA_DRIVER_CAPA_ENC_CCMP)) { - wpa_printf(MSG_DEBUG, "NDIS: driver supports WPA"); - drv->has_capability = 1; - } else { - wpa_printf(MSG_DEBUG, "NDIS: no WPA support found"); - } - - wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x " - "enc 0x%x auth 0x%x", - drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth); -} - - -static void wpa_driver_ndis_get_capability(struct wpa_driver_ndis_data *drv) -{ - char buf[512]; - int len; - size_t i; - NDIS_802_11_CAPABILITY *c; - - drv->capa.flags = WPA_DRIVER_FLAGS_DRIVER_IE; - - len = ndis_get_oid(drv, OID_802_11_CAPABILITY, buf, sizeof(buf)); - if (len < 0) { - wpa_driver_ndis_get_wpa_capability(drv); - return; - } - - wpa_hexdump(MSG_MSGDUMP, "OID_802_11_CAPABILITY", (u8 *) buf, len); - c = (NDIS_802_11_CAPABILITY *) buf; - if (len < sizeof(*c) || c->Version != 2) { - wpa_printf(MSG_DEBUG, "NDIS: unsupported " - "OID_802_11_CAPABILITY data"); - return; - } - wpa_printf(MSG_DEBUG, "NDIS: Driver supports OID_802_11_CAPABILITY - " - "NoOfPMKIDs %d NoOfAuthEncrPairs %d", - (int) c->NoOfPMKIDs, - (int) c->NoOfAuthEncryptPairsSupported); - drv->has_capability = 1; - drv->no_of_pmkid = c->NoOfPMKIDs; - for (i = 0; i < c->NoOfAuthEncryptPairsSupported; i++) { - NDIS_802_11_AUTHENTICATION_ENCRYPTION *ae; - ae = &c->AuthenticationEncryptionSupported[i]; - if ((char *) (ae + 1) > buf + len) { - wpa_printf(MSG_DEBUG, "NDIS: auth/encr pair list " - "overflow"); - break; - } - wpa_printf(MSG_MSGDUMP, "NDIS: %d - auth %d encr %d", - i, (int) ae->AuthModeSupported, - (int) ae->EncryptStatusSupported); - switch (ae->AuthModeSupported) { - case Ndis802_11AuthModeOpen: - drv->capa.auth |= WPA_DRIVER_AUTH_OPEN; - break; - case Ndis802_11AuthModeShared: - drv->capa.auth |= WPA_DRIVER_AUTH_SHARED; - break; - case Ndis802_11AuthModeWPA: - drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA; - break; - case Ndis802_11AuthModeWPAPSK: - drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; - break; - case Ndis802_11AuthModeWPA2: - drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2; - break; - case Ndis802_11AuthModeWPA2PSK: - drv->capa.key_mgmt |= - WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; - break; - case Ndis802_11AuthModeWPANone: - drv->capa.key_mgmt |= - WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE; - break; - default: - break; - } - switch (ae->EncryptStatusSupported) { - case Ndis802_11Encryption1Enabled: - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40; - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP104; - break; - case Ndis802_11Encryption2Enabled: - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; - break; - case Ndis802_11Encryption3Enabled: - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; - break; - default: - break; - } - } - - wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x " - "enc 0x%x auth 0x%x", - drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth); -} - - -static int wpa_driver_ndis_get_capa(void *priv, struct wpa_driver_capa *capa) -{ - struct wpa_driver_ndis_data *drv = priv; - if (!drv->has_capability) - return -1; - os_memcpy(capa, &drv->capa, sizeof(*capa)); - return 0; -} - - -static const char * wpa_driver_ndis_get_ifname(void *priv) -{ - struct wpa_driver_ndis_data *drv = priv; - return drv->ifname; -} - - -static const u8 * wpa_driver_ndis_get_mac_addr(void *priv) -{ - struct wpa_driver_ndis_data *drv = priv; - return drv->own_addr; -} - - -#ifdef _WIN32_WCE - -#define NDISUIO_MSG_SIZE (sizeof(NDISUIO_DEVICE_NOTIFICATION) + 512) - -static void ndisuio_notification_receive(void *eloop_data, void *user_ctx) -{ - struct wpa_driver_ndis_data *drv = eloop_data; - NDISUIO_DEVICE_NOTIFICATION *hdr; - u8 buf[NDISUIO_MSG_SIZE]; - DWORD len, flags; - - if (!ReadMsgQueue(drv->event_queue, buf, NDISUIO_MSG_SIZE, &len, 0, - &flags)) { - wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: " - "ReadMsgQueue failed: %d", (int) GetLastError()); - return; - } - - if (len < sizeof(NDISUIO_DEVICE_NOTIFICATION)) { - wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: " - "Too short message (len=%d)", (int) len); - return; - } - - hdr = (NDISUIO_DEVICE_NOTIFICATION *) buf; - wpa_printf(MSG_DEBUG, "NDIS: Notification received: len=%d type=0x%x", - (int) len, hdr->dwNotificationType); - - switch (hdr->dwNotificationType) { -#ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL - case NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL: - wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_ARRIVAL"); - wpa_driver_ndis_event_adapter_arrival(drv); - break; -#endif -#ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL - case NDISUIO_NOTIFICATION_ADAPTER_REMOVAL: - wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_REMOVAL"); - wpa_driver_ndis_event_adapter_removal(drv); - break; -#endif - case NDISUIO_NOTIFICATION_MEDIA_CONNECT: - wpa_printf(MSG_DEBUG, "NDIS: MEDIA_CONNECT"); - SetEvent(drv->connected_event); - wpa_driver_ndis_event_connect(drv); - break; - case NDISUIO_NOTIFICATION_MEDIA_DISCONNECT: - ResetEvent(drv->connected_event); - wpa_printf(MSG_DEBUG, "NDIS: MEDIA_DISCONNECT"); - wpa_driver_ndis_event_disconnect(drv); - break; - case NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION: - wpa_printf(MSG_DEBUG, "NDIS: MEDIA_SPECIFIC_NOTIFICATION"); -#if _WIN32_WCE == 420 || _WIN32_WCE == 0x420 - wpa_driver_ndis_event_media_specific( - drv, hdr->pvStatusBuffer, hdr->uiStatusBufferSize); -#else - wpa_driver_ndis_event_media_specific( - drv, ((const u8 *) hdr) + hdr->uiOffsetToStatusBuffer, - (size_t) hdr->uiStatusBufferSize); -#endif - break; - default: - wpa_printf(MSG_DEBUG, "NDIS: Unknown notification type 0x%x", - hdr->dwNotificationType); - break; - } -} - - -static void ndisuio_notification_deinit(struct wpa_driver_ndis_data *drv) -{ - NDISUIO_REQUEST_NOTIFICATION req; - - memset(&req, 0, sizeof(req)); - req.hMsgQueue = drv->event_queue; - req.dwNotificationTypes = 0; - - if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION, - &req, sizeof(req), NULL, 0, NULL, NULL)) { - wpa_printf(MSG_INFO, "ndisuio_notification_deinit: " - "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d", - (int) GetLastError()); - } - - if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_CANCEL_NOTIFICATION, - NULL, 0, NULL, 0, NULL, NULL)) { - wpa_printf(MSG_INFO, "ndisuio_notification_deinit: " - "IOCTL_NDISUIO_CANCEL_NOTIFICATION failed: %d", - (int) GetLastError()); - } - - if (drv->event_queue) { - eloop_unregister_event(drv->event_queue, - sizeof(drv->event_queue)); - CloseHandle(drv->event_queue); - drv->event_queue = NULL; - } - - if (drv->connected_event) { - CloseHandle(drv->connected_event); - drv->connected_event = NULL; - } -} - - -static int ndisuio_notification_init(struct wpa_driver_ndis_data *drv) -{ - MSGQUEUEOPTIONS opt; - NDISUIO_REQUEST_NOTIFICATION req; - - drv->connected_event = - CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected")); - if (drv->connected_event == NULL) { - wpa_printf(MSG_INFO, "ndisuio_notification_init: " - "CreateEvent failed: %d", - (int) GetLastError()); - return -1; - } - - memset(&opt, 0, sizeof(opt)); - opt.dwSize = sizeof(opt); - opt.dwMaxMessages = 5; - opt.cbMaxMessage = NDISUIO_MSG_SIZE; - opt.bReadAccess = TRUE; - - drv->event_queue = CreateMsgQueue(NULL, &opt); - if (drv->event_queue == NULL) { - wpa_printf(MSG_INFO, "ndisuio_notification_init: " - "CreateMsgQueue failed: %d", - (int) GetLastError()); - ndisuio_notification_deinit(drv); - return -1; - } - - memset(&req, 0, sizeof(req)); - req.hMsgQueue = drv->event_queue; - req.dwNotificationTypes = -#ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL - NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL | -#endif -#ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL - NDISUIO_NOTIFICATION_ADAPTER_REMOVAL | -#endif - NDISUIO_NOTIFICATION_MEDIA_CONNECT | - NDISUIO_NOTIFICATION_MEDIA_DISCONNECT | - NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION; - - if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION, - &req, sizeof(req), NULL, 0, NULL, NULL)) { - wpa_printf(MSG_INFO, "ndisuio_notification_init: " - "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d", - (int) GetLastError()); - ndisuio_notification_deinit(drv); - return -1; - } - - eloop_register_event(drv->event_queue, sizeof(drv->event_queue), - ndisuio_notification_receive, drv, NULL); - - return 0; -} -#endif /* _WIN32_WCE */ - - -static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv) -{ -#ifdef CONFIG_USE_NDISUIO - NDISUIO_QUERY_BINDING *b; - size_t blen = sizeof(*b) + 1024; - int i, error, found = 0; - DWORD written; - char name[256], desc[256], *dpos; - WCHAR *pos; - size_t j, len, dlen; - - b = os_malloc(blen); - if (b == NULL) - return -1; - - for (i = 0; ; i++) { - os_memset(b, 0, blen); - b->BindingIndex = i; - if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_BINDING, - b, sizeof(NDISUIO_QUERY_BINDING), b, blen, - &written, NULL)) { - error = (int) GetLastError(); - if (error == ERROR_NO_MORE_ITEMS) - break; - wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING " - "failed: %d", error); - break; - } - - pos = (WCHAR *) ((char *) b + b->DeviceNameOffset); - len = b->DeviceNameLength; - if (len >= sizeof(name)) - len = sizeof(name) - 1; - for (j = 0; j < len; j++) - name[j] = (char) pos[j]; - name[len] = '\0'; - - pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset); - len = b->DeviceDescrLength; - if (len >= sizeof(desc)) - len = sizeof(desc) - 1; - for (j = 0; j < len; j++) - desc[j] = (char) pos[j]; - desc[len] = '\0'; - - wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc); - - if (os_strstr(name, drv->ifname)) { - wpa_printf(MSG_DEBUG, "NDIS: Interface name match"); - found = 1; - break; - } - - if (os_strncmp(desc, drv->ifname, os_strlen(drv->ifname)) == 0) - { - wpa_printf(MSG_DEBUG, "NDIS: Interface description " - "match"); - found = 1; - break; - } - } - - if (!found) { - wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'", - drv->ifname); - os_free(b); - return -1; - } - - os_strlcpy(drv->ifname, - os_strncmp(name, "\\DEVICE\\", 8) == 0 ? name + 8 : name, - sizeof(drv->ifname)); -#ifdef _WIN32_WCE - drv->adapter_name = wpa_strdup_tchar(drv->ifname); - if (drv->adapter_name == NULL) { - wpa_printf(MSG_ERROR, "NDIS: Failed to allocate memory for " - "adapter name"); - os_free(b); - return -1; - } -#endif /* _WIN32_WCE */ - - dpos = os_strstr(desc, " - "); - if (dpos) - dlen = dpos - desc; - else - dlen = os_strlen(desc); - drv->adapter_desc = dup_binstr(desc, dlen); - os_free(b); - if (drv->adapter_desc == NULL) - return -1; - - wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'", - drv->adapter_desc); - - return 0; -#else /* CONFIG_USE_NDISUIO */ - PTSTR _names; - char *names, *pos, *pos2; - ULONG len; - BOOLEAN res; -#define MAX_ADAPTERS 32 - char *name[MAX_ADAPTERS]; - char *desc[MAX_ADAPTERS]; - int num_name, num_desc, i, found_name, found_desc; - size_t dlen; - - wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s", - PacketGetVersion()); - - len = 8192; - _names = os_zalloc(len); - if (_names == NULL) - return -1; - - res = PacketGetAdapterNames(_names, &len); - if (!res && len > 8192) { - os_free(_names); - _names = os_zalloc(len); - if (_names == NULL) - return -1; - res = PacketGetAdapterNames(_names, &len); - } - - if (!res) { - wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list " - "(PacketGetAdapterNames)"); - os_free(_names); - return -1; - } - - names = (char *) _names; - if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') { - wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in " - "UNICODE"); - /* Convert to ASCII */ - pos2 = pos = names; - while (pos2 < names + len) { - if (pos2[0] == '\0' && pos2[1] == '\0' && - pos2[2] == '\0' && pos2[3] == '\0') { - pos2 += 4; - break; - } - *pos++ = pos2[0]; - pos2 += 2; - } - os_memcpy(pos + 2, names, pos - names); - pos += 2; - } else - pos = names; - - num_name = 0; - while (pos < names + len) { - name[num_name] = pos; - while (*pos && pos < names + len) - pos++; - if (pos + 1 >= names + len) { - os_free(names); - return -1; - } - pos++; - num_name++; - if (num_name >= MAX_ADAPTERS) { - wpa_printf(MSG_DEBUG, "NDIS: Too many adapters"); - os_free(names); - return -1; - } - if (*pos == '\0') { - wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found", - num_name); - pos++; - break; - } - } - - num_desc = 0; - while (pos < names + len) { - desc[num_desc] = pos; - while (*pos && pos < names + len) - pos++; - if (pos + 1 >= names + len) { - os_free(names); - return -1; - } - pos++; - num_desc++; - if (num_desc >= MAX_ADAPTERS) { - wpa_printf(MSG_DEBUG, "NDIS: Too many adapter " - "descriptions"); - os_free(names); - return -1; - } - if (*pos == '\0') { - wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions " - "found", num_name); - pos++; - break; - } - } - - /* - * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter - * descriptions. Fill in dummy descriptors to work around this. - */ - while (num_desc < num_name) - desc[num_desc++] = "dummy description"; - - if (num_name != num_desc) { - wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and " - "description counts (%d != %d)", - num_name, num_desc); - os_free(names); - return -1; - } - - found_name = found_desc = -1; - for (i = 0; i < num_name; i++) { - wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", - i, name[i], desc[i]); - if (found_name == -1 && os_strstr(name[i], drv->ifname)) - found_name = i; - if (found_desc == -1 && - os_strncmp(desc[i], drv->ifname, os_strlen(drv->ifname)) == - 0) - found_desc = i; - } - - if (found_name < 0 && found_desc >= 0) { - wpa_printf(MSG_DEBUG, "NDIS: Matched interface '%s' based on " - "description '%s'", - name[found_desc], desc[found_desc]); - found_name = found_desc; - os_strlcpy(drv->ifname, - os_strncmp(name[found_desc], "\\Device\\NPF_", 12) - == 0 ? name[found_desc] + 12 : name[found_desc], - sizeof(drv->ifname)); - } - - if (found_name < 0) { - wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'", - drv->ifname); - os_free(names); - return -1; - } - - i = found_name; - pos = os_strrchr(desc[i], '('); - if (pos) { - dlen = pos - desc[i]; - pos--; - if (pos > desc[i] && *pos == ' ') - dlen--; - } else { - dlen = os_strlen(desc[i]); - } - drv->adapter_desc = dup_binstr(desc[i], dlen); - os_free(names); - if (drv->adapter_desc == NULL) - return -1; - - wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'", - drv->adapter_desc); - - return 0; -#endif /* CONFIG_USE_NDISUIO */ -} - - -#if defined(CONFIG_NATIVE_WINDOWS) || defined(__CYGWIN__) -#ifndef _WIN32_WCE -/* - * These structures are undocumented for WinXP; only WinCE version is - * documented. These would be included wzcsapi.h if it were available. Some - * changes here have been needed to make the structures match with WinXP SP2. - * It is unclear whether these work with any other version. - */ - -typedef struct { - LPWSTR wszGuid; -} INTF_KEY_ENTRY, *PINTF_KEY_ENTRY; - -typedef struct { - DWORD dwNumIntfs; - PINTF_KEY_ENTRY pIntfs; -} INTFS_KEY_TABLE, *PINTFS_KEY_TABLE; - -typedef struct { - DWORD dwDataLen; - LPBYTE pData; -} RAW_DATA, *PRAW_DATA; - -typedef struct { - LPWSTR wszGuid; - LPWSTR wszDescr; - ULONG ulMediaState; - ULONG ulMediaType; - ULONG ulPhysicalMediaType; - INT nInfraMode; - INT nAuthMode; - INT nWepStatus; -#ifndef _WIN32_WCE - u8 pad[2]; /* why is this needed? */ -#endif /* _WIN32_WCE */ - DWORD dwCtlFlags; - DWORD dwCapabilities; /* something added for WinXP SP2(?) */ - RAW_DATA rdSSID; - RAW_DATA rdBSSID; - RAW_DATA rdBSSIDList; - RAW_DATA rdStSSIDList; - RAW_DATA rdCtrlData; -#ifdef UNDER_CE - BOOL bInitialized; -#endif - DWORD nWPAMCastCipher; - /* add some extra buffer for later additions since this interface is - * far from stable */ - u8 later_additions[100]; -} INTF_ENTRY, *PINTF_ENTRY; - -#define INTF_ALL 0xffffffff -#define INTF_ALL_FLAGS 0x0000ffff -#define INTF_CTLFLAGS 0x00000010 -#define INTFCTL_ENABLED 0x8000 -#endif /* _WIN32_WCE */ - - -#ifdef _WIN32_WCE -static int wpa_driver_ndis_rebind_adapter(struct wpa_driver_ndis_data *drv) -{ - HANDLE ndis; - TCHAR multi[100]; - int len; - - len = _tcslen(drv->adapter_name); - if (len > 80) - return -1; - - ndis = CreateFile(DD_NDIS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); - if (ndis == INVALID_HANDLE_VALUE) { - wpa_printf(MSG_DEBUG, "NDIS: Failed to open file to NDIS " - "device: %d", (int) GetLastError()); - return -1; - } - - len++; - memcpy(multi, drv->adapter_name, len * sizeof(TCHAR)); - memcpy(&multi[len], TEXT("NDISUIO\0"), 9 * sizeof(TCHAR)); - len += 9; - - if (!DeviceIoControl(ndis, IOCTL_NDIS_REBIND_ADAPTER, - multi, len * sizeof(TCHAR), NULL, 0, NULL, NULL)) - { - wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDIS_REBIND_ADAPTER " - "failed: 0x%x", (int) GetLastError()); - wpa_hexdump_ascii(MSG_DEBUG, "NDIS: rebind multi_sz", - (u8 *) multi, len * sizeof(TCHAR)); - CloseHandle(ndis); - return -1; - } - - CloseHandle(ndis); - - wpa_printf(MSG_DEBUG, "NDIS: Requested NDIS rebind of NDISUIO " - "protocol"); - - return 0; -} -#endif /* _WIN32_WCE */ - - -static int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv, - int enable) -{ -#ifdef _WIN32_WCE - HKEY hk, hk2; - LONG ret; - DWORD i, hnd, len; - TCHAR keyname[256], devname[256]; - -#define WZC_DRIVER TEXT("Drivers\\BuiltIn\\ZeroConfig") - - if (enable) { - HANDLE h; - h = ActivateDeviceEx(WZC_DRIVER, NULL, 0, NULL); - if (h == INVALID_HANDLE_VALUE || h == 0) { - wpa_printf(MSG_DEBUG, "NDIS: Failed to re-enable WZC " - "- ActivateDeviceEx failed: %d", - (int) GetLastError()); - return -1; - } - - wpa_printf(MSG_DEBUG, "NDIS: WZC re-enabled"); - return wpa_driver_ndis_rebind_adapter(drv); - } - - /* - * Unfortunately, just disabling the WZC for an interface is not enough - * to free NDISUIO for us, so need to disable and unload WZC completely - * for now when using WinCE with NDISUIO. In addition, must request - * NDISUIO protocol to be rebound to the adapter in order to free the - * NDISUIO binding that WZC hold before us. - */ - - /* Enumerate HKLM\Drivers\Active\* to find a handle to WZC. */ - ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, DEVLOAD_ACTIVE_KEY, 0, 0, &hk); - if (ret != ERROR_SUCCESS) { - wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(DEVLOAD_ACTIVE_KEY) " - "failed: %d %d", (int) ret, (int) GetLastError()); - return -1; - } - - for (i = 0; ; i++) { - len = sizeof(keyname); - ret = RegEnumKeyEx(hk, i, keyname, &len, NULL, NULL, NULL, - NULL); - if (ret != ERROR_SUCCESS) { - wpa_printf(MSG_DEBUG, "NDIS: Could not find active " - "WZC - assuming it is not running."); - RegCloseKey(hk); - return -1; - } - - ret = RegOpenKeyEx(hk, keyname, 0, 0, &hk2); - if (ret != ERROR_SUCCESS) { - wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(active dev) " - "failed: %d %d", - (int) ret, (int) GetLastError()); - continue; - } - - len = sizeof(devname); - ret = RegQueryValueEx(hk2, DEVLOAD_DEVKEY_VALNAME, NULL, NULL, - (LPBYTE) devname, &len); - if (ret != ERROR_SUCCESS) { - wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx(" - "DEVKEY_VALNAME) failed: %d %d", - (int) ret, (int) GetLastError()); - RegCloseKey(hk2); - continue; - } - - if (_tcscmp(devname, WZC_DRIVER) == 0) - break; - - RegCloseKey(hk2); - } - - RegCloseKey(hk); - - /* Found WZC - get handle to it. */ - len = sizeof(hnd); - ret = RegQueryValueEx(hk2, DEVLOAD_HANDLE_VALNAME, NULL, NULL, - (PUCHAR) &hnd, &len); - if (ret != ERROR_SUCCESS) { - wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx(HANDLE_VALNAME) " - "failed: %d %d", (int) ret, (int) GetLastError()); - RegCloseKey(hk2); - return -1; - } - - RegCloseKey(hk2); - - /* Deactivate WZC */ - if (!DeactivateDevice((HANDLE) hnd)) { - wpa_printf(MSG_DEBUG, "NDIS: DeactivateDevice failed: %d", - (int) GetLastError()); - return -1; - } - - wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily"); - drv->wzc_disabled = 1; - return wpa_driver_ndis_rebind_adapter(drv); - -#else /* _WIN32_WCE */ - - HMODULE hm; - DWORD (WINAPI *wzc_enum_interf)(LPWSTR pSrvAddr, - PINTFS_KEY_TABLE pIntfs); - DWORD (WINAPI *wzc_query_interf)(LPWSTR pSrvAddr, DWORD dwInFlags, - PINTF_ENTRY pIntf, - LPDWORD pdwOutFlags); - DWORD (WINAPI *wzc_set_interf)(LPWSTR pSrvAddr, DWORD dwInFlags, - PINTF_ENTRY pIntf, LPDWORD pdwOutFlags); - int ret = -1, j; - DWORD res; - INTFS_KEY_TABLE guids; - INTF_ENTRY intf; - char guid[128]; - WCHAR *pos; - DWORD flags, i; - - hm = LoadLibrary(TEXT("wzcsapi.dll")); - if (hm == NULL) { - wpa_printf(MSG_DEBUG, "NDIS: Failed to load wzcsapi.dll (%u) " - "- WZC probably not running", - (unsigned int) GetLastError()); - return -1; - } - -#ifdef _WIN32_WCE - wzc_enum_interf = (void *) GetProcAddressA(hm, "WZCEnumInterfaces"); - wzc_query_interf = (void *) GetProcAddressA(hm, "WZCQueryInterface"); - wzc_set_interf = (void *) GetProcAddressA(hm, "WZCSetInterface"); -#else /* _WIN32_WCE */ - wzc_enum_interf = (void *) GetProcAddress(hm, "WZCEnumInterfaces"); - wzc_query_interf = (void *) GetProcAddress(hm, "WZCQueryInterface"); - wzc_set_interf = (void *) GetProcAddress(hm, "WZCSetInterface"); -#endif /* _WIN32_WCE */ - - if (wzc_enum_interf == NULL || wzc_query_interf == NULL || - wzc_set_interf == NULL) { - wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces, " - "WZCQueryInterface, or WZCSetInterface not found " - "in wzcsapi.dll"); - goto fail; - } - - os_memset(&guids, 0, sizeof(guids)); - res = wzc_enum_interf(NULL, &guids); - if (res != 0) { - wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces failed: %d; " - "WZC service is apparently not running", - (int) res); - goto fail; - } - - wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces: %d interfaces", - (int) guids.dwNumIntfs); - - for (i = 0; i < guids.dwNumIntfs; i++) { - pos = guids.pIntfs[i].wszGuid; - for (j = 0; j < sizeof(guid); j++) { - guid[j] = (char) *pos; - if (*pos == 0) - break; - pos++; - } - guid[sizeof(guid) - 1] = '\0'; - wpa_printf(MSG_DEBUG, "NDIS: intfs %d GUID '%s'", - (int) i, guid); - if (os_strstr(drv->ifname, guid) == NULL) - continue; - - wpa_printf(MSG_DEBUG, "NDIS: Current interface found from " - "WZC"); - break; - } - - if (i >= guids.dwNumIntfs) { - wpa_printf(MSG_DEBUG, "NDIS: Current interface not found from " - "WZC"); - goto fail; - } - - os_memset(&intf, 0, sizeof(intf)); - intf.wszGuid = guids.pIntfs[i].wszGuid; - /* Set flags to verify that the structure has not changed. */ - intf.dwCtlFlags = -1; - flags = 0; - res = wzc_query_interf(NULL, INTFCTL_ENABLED, &intf, &flags); - if (res != 0) { - wpa_printf(MSG_DEBUG, "NDIS: Could not query flags for the " - "WZC interface: %d (0x%x)", - (int) res, (int) res); - wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u", - (unsigned int) GetLastError()); - goto fail; - } - - wpa_printf(MSG_DEBUG, "NDIS: WZC interface flags 0x%x dwCtlFlags 0x%x", - (int) flags, (int) intf.dwCtlFlags); - - if (intf.dwCtlFlags == -1) { - wpa_printf(MSG_DEBUG, "NDIS: Looks like wzcsapi has changed " - "again - could not disable WZC"); - wpa_hexdump(MSG_MSGDUMP, "NDIS: intf", - (u8 *) &intf, sizeof(intf)); - goto fail; - } - - if (enable) { - if (!(intf.dwCtlFlags & INTFCTL_ENABLED)) { - wpa_printf(MSG_DEBUG, "NDIS: Enabling WZC for this " - "interface"); - intf.dwCtlFlags |= INTFCTL_ENABLED; - res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf, - &flags); - if (res != 0) { - wpa_printf(MSG_DEBUG, "NDIS: Failed to enable " - "WZC: %d (0x%x)", - (int) res, (int) res); - wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u", - (unsigned int) GetLastError()); - goto fail; - } - wpa_printf(MSG_DEBUG, "NDIS: Re-enabled WZC for this " - "interface"); - drv->wzc_disabled = 0; - } - } else { - if (intf.dwCtlFlags & INTFCTL_ENABLED) { - wpa_printf(MSG_DEBUG, "NDIS: Disabling WZC for this " - "interface"); - intf.dwCtlFlags &= ~INTFCTL_ENABLED; - res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf, - &flags); - if (res != 0) { - wpa_printf(MSG_DEBUG, "NDIS: Failed to " - "disable WZC: %d (0x%x)", - (int) res, (int) res); - wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u", - (unsigned int) GetLastError()); - goto fail; - } - wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily " - "for this interface"); - drv->wzc_disabled = 1; - } else { - wpa_printf(MSG_DEBUG, "NDIS: WZC was not enabled for " - "this interface"); - } - } - - ret = 0; - -fail: - FreeLibrary(hm); - - return ret; -#endif /* _WIN32_WCE */ -} - -#else /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */ - -static int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv, - int enable) -{ - return 0; -} - -#endif /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */ - - -#ifdef CONFIG_USE_NDISUIO -/* - * l2_packet_ndis.c is sharing the same handle to NDISUIO, so we must be able - * to export this handle. This is somewhat ugly, but there is no better - * mechanism available to pass data from driver interface to l2_packet wrapper. - */ -static HANDLE driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE; - -HANDLE driver_ndis_get_ndisuio_handle(void) -{ - return driver_ndis_ndisuio_handle; -} -#endif /* CONFIG_USE_NDISUIO */ - - -static int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv) -{ -#ifdef CONFIG_USE_NDISUIO -#ifndef _WIN32_WCE -#define NDISUIO_DEVICE_NAME TEXT("\\\\.\\\\Ndisuio") - DWORD written; -#endif /* _WIN32_WCE */ - drv->ndisuio = CreateFile(NDISUIO_DEVICE_NAME, - GENERIC_READ | GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, - INVALID_HANDLE_VALUE); - if (drv->ndisuio == INVALID_HANDLE_VALUE) { - wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to " - "NDISUIO: %d", (int) GetLastError()); - return -1; - } - driver_ndis_ndisuio_handle = drv->ndisuio; - -#ifndef _WIN32_WCE - if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0, - NULL, 0, &written, NULL)) { - wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: " - "%d", (int) GetLastError()); - CloseHandle(drv->ndisuio); - drv->ndisuio = INVALID_HANDLE_VALUE; - return -1; - } -#endif /* _WIN32_WCE */ - - return 0; -#else /* CONFIG_USE_NDISUIO */ - return 0; -#endif /* CONFIG_USE_NDISUIO */ -} - - -static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv) -{ -#ifdef CONFIG_USE_NDISUIO - DWORD written; -#define MAX_NDIS_DEVICE_NAME_LEN 256 - WCHAR ifname[MAX_NDIS_DEVICE_NAME_LEN]; - size_t len, i, pos; - const char *prefix = "\\DEVICE\\"; - -#ifdef _WIN32_WCE - pos = 0; -#else /* _WIN32_WCE */ - pos = 8; -#endif /* _WIN32_WCE */ - len = pos + os_strlen(drv->ifname); - if (len >= MAX_NDIS_DEVICE_NAME_LEN) - return -1; - for (i = 0; i < pos; i++) - ifname[i] = (WCHAR) prefix[i]; - for (i = pos; i < len; i++) - ifname[i] = (WCHAR) drv->ifname[i - pos]; - ifname[i] = L'\0'; - - if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_OPEN_DEVICE, - ifname, len * sizeof(WCHAR), NULL, 0, &written, - NULL)) { - wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_OPEN_DEVICE " - "failed: %d", (int) GetLastError()); - wpa_hexdump_ascii(MSG_DEBUG, "NDIS: ifname", - (const u8 *) ifname, len * sizeof(WCHAR)); - CloseHandle(drv->ndisuio); - drv->ndisuio = INVALID_HANDLE_VALUE; - return -1; - } - - wpa_printf(MSG_DEBUG, "NDIS: Opened NDISUIO device successfully"); - - return 0; -#else /* CONFIG_USE_NDISUIO */ - char ifname[128]; - os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", drv->ifname); - drv->adapter = PacketOpenAdapter(ifname); - if (drv->adapter == NULL) { - wpa_printf(MSG_DEBUG, "NDIS: PacketOpenAdapter failed for " - "'%s'", ifname); - return -1; - } - return 0; -#endif /* CONFIG_USE_NDISUIO */ -} - - -static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv) -{ -#ifdef CONFIG_USE_NDISUIO - driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE; - if (drv->ndisuio != INVALID_HANDLE_VALUE) - CloseHandle(drv->ndisuio); -#else /* CONFIG_USE_NDISUIO */ - if (drv->adapter) - PacketCloseAdapter(drv->adapter); -#endif /* CONFIG_USE_NDISUIO */ -} - - -static int ndis_add_multicast(struct wpa_driver_ndis_data *drv) -{ - if (ndis_set_oid(drv, OID_802_3_MULTICAST_LIST, - (const char *) pae_group_addr, ETH_ALEN) < 0) { - wpa_printf(MSG_DEBUG, "NDIS: Failed to add PAE group address " - "to the multicast list"); - return -1; - } - - return 0; -} - - -static void * wpa_driver_ndis_init(void *ctx, const char *ifname) -{ - struct wpa_driver_ndis_data *drv; - u32 mode; - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - drv->ctx = ctx; - /* - * Compatibility code to strip possible prefix from the GUID. Previous - * versions include \Device\NPF_ prefix for all names, but the internal - * interface name is now only the GUI. Both Packet32 and NDISUIO - * prefixes are supported. - */ - if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0) - ifname += 12; - else if (os_strncmp(ifname, "\\DEVICE\\", 8) == 0) - ifname += 8; - os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); - - if (wpa_driver_ndis_adapter_init(drv) < 0) { - os_free(drv); - return NULL; - } - - if (wpa_driver_ndis_get_names(drv) < 0) { - wpa_driver_ndis_adapter_close(drv); - os_free(drv); - return NULL; - } - - wpa_driver_ndis_set_wzc(drv, 0); - - if (wpa_driver_ndis_adapter_open(drv) < 0) { - wpa_driver_ndis_adapter_close(drv); - os_free(drv); - return NULL; - } - - if (ndis_get_oid(drv, OID_802_3_CURRENT_ADDRESS, - (char *) drv->own_addr, ETH_ALEN) < 0) { - wpa_printf(MSG_DEBUG, "NDIS: Get OID_802_3_CURRENT_ADDRESS " - "failed"); - wpa_driver_ndis_adapter_close(drv); - os_free(drv); - return NULL; - } - wpa_driver_ndis_get_capability(drv); - - /* Make sure that the driver does not have any obsolete PMKID entries. - */ - wpa_driver_ndis_flush_pmkid(drv); - - /* - * Disconnect to make sure that driver re-associates if it was - * connected. - */ - wpa_driver_ndis_disconnect(drv); - - eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, drv, NULL); - -#ifdef CONFIG_NDIS_EVENTS_INTEGRATED - drv->events = ndis_events_init(&drv->events_pipe, &drv->event_avail, - drv->ifname, drv->adapter_desc); - if (drv->events == NULL) { - wpa_driver_ndis_deinit(drv); - return NULL; - } - eloop_register_event(drv->event_avail, sizeof(drv->event_avail), - wpa_driver_ndis_event_pipe_cb, drv, NULL); -#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */ - -#ifdef _WIN32_WCE - if (ndisuio_notification_init(drv) < 0) { - wpa_driver_ndis_deinit(drv); - return NULL; - } -#endif /* _WIN32_WCE */ - - /* Set mode here in case card was configured for ad-hoc mode - * previously. */ - mode = Ndis802_11Infrastructure; - if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE, - (char *) &mode, sizeof(mode)) < 0) { - char buf[8]; - int res; - wpa_printf(MSG_DEBUG, "NDIS: Failed to set " - "OID_802_11_INFRASTRUCTURE_MODE (%d)", - (int) mode); - /* Try to continue anyway */ - - res = ndis_get_oid(drv, OID_DOT11_CURRENT_OPERATION_MODE, buf, - sizeof(buf)); - if (res > 0) { - wpa_printf(MSG_INFO, "NDIS: The driver seems to use " - "Native 802.11 OIDs. These are not yet " - "fully supported."); - drv->native80211 = 1; - } else if (!drv->has_capability || drv->capa.enc == 0) { - /* - * Note: This will also happen with NDIS 6 drivers with - * Vista. - */ - wpa_printf(MSG_DEBUG, "NDIS: Driver did not provide " - "any wireless capabilities - assume it is " - "a wired interface"); - drv->wired = 1; - drv->capa.flags |= WPA_DRIVER_FLAGS_WIRED; - drv->has_capability = 1; - ndis_add_multicast(drv); - } - } - - return drv; -} - - -static void wpa_driver_ndis_deinit(void *priv) -{ - struct wpa_driver_ndis_data *drv = priv; - -#ifdef CONFIG_NDIS_EVENTS_INTEGRATED - if (drv->events) { - eloop_unregister_event(drv->event_avail, - sizeof(drv->event_avail)); - ndis_events_deinit(drv->events); - } -#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */ - -#ifdef _WIN32_WCE - ndisuio_notification_deinit(drv); -#endif /* _WIN32_WCE */ - - eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx); - eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL); - wpa_driver_ndis_flush_pmkid(drv); - wpa_driver_ndis_disconnect(drv); - if (wpa_driver_ndis_radio_off(drv) < 0) { - wpa_printf(MSG_DEBUG, "NDIS: failed to disassociate and turn " - "radio off"); - } - - wpa_driver_ndis_adapter_close(drv); - - if (drv->wzc_disabled) - wpa_driver_ndis_set_wzc(drv, 1); - -#ifdef _WIN32_WCE - os_free(drv->adapter_name); -#endif /* _WIN32_WCE */ - os_free(drv->adapter_desc); - os_free(drv); -} - - -static struct wpa_interface_info * -wpa_driver_ndis_get_interfaces(void *global_priv) -{ - struct wpa_interface_info *iface = NULL, *niface; - -#ifdef CONFIG_USE_NDISUIO - NDISUIO_QUERY_BINDING *b; - size_t blen = sizeof(*b) + 1024; - int i, error; - DWORD written; - char name[256], desc[256]; - WCHAR *pos; - size_t j, len; - HANDLE ndisuio; - - ndisuio = CreateFile(NDISUIO_DEVICE_NAME, - GENERIC_READ | GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, - INVALID_HANDLE_VALUE); - if (ndisuio == INVALID_HANDLE_VALUE) { - wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to " - "NDISUIO: %d", (int) GetLastError()); - return NULL; - } - -#ifndef _WIN32_WCE - if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0, - NULL, 0, &written, NULL)) { - wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: " - "%d", (int) GetLastError()); - CloseHandle(ndisuio); - return NULL; - } -#endif /* _WIN32_WCE */ - - b = os_malloc(blen); - if (b == NULL) { - CloseHandle(ndisuio); - return NULL; - } - - for (i = 0; ; i++) { - os_memset(b, 0, blen); - b->BindingIndex = i; - if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_QUERY_BINDING, - b, sizeof(NDISUIO_QUERY_BINDING), b, blen, - &written, NULL)) { - error = (int) GetLastError(); - if (error == ERROR_NO_MORE_ITEMS) - break; - wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING " - "failed: %d", error); - break; - } - - pos = (WCHAR *) ((char *) b + b->DeviceNameOffset); - len = b->DeviceNameLength; - if (len >= sizeof(name)) - len = sizeof(name) - 1; - for (j = 0; j < len; j++) - name[j] = (char) pos[j]; - name[len] = '\0'; - - pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset); - len = b->DeviceDescrLength; - if (len >= sizeof(desc)) - len = sizeof(desc) - 1; - for (j = 0; j < len; j++) - desc[j] = (char) pos[j]; - desc[len] = '\0'; - - wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc); - - niface = os_zalloc(sizeof(*niface)); - if (niface == NULL) - break; - niface->drv_name = "ndis"; - if (os_strncmp(name, "\\DEVICE\\", 8) == 0) - niface->ifname = os_strdup(name + 8); - else - niface->ifname = os_strdup(name); - if (niface->ifname == NULL) { - os_free(niface); - break; - } - niface->desc = os_strdup(desc); - niface->next = iface; - iface = niface; - } - - os_free(b); - CloseHandle(ndisuio); -#else /* CONFIG_USE_NDISUIO */ - PTSTR _names; - char *names, *pos, *pos2; - ULONG len; - BOOLEAN res; - char *name[MAX_ADAPTERS]; - char *desc[MAX_ADAPTERS]; - int num_name, num_desc, i; - - wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s", - PacketGetVersion()); - - len = 8192; - _names = os_zalloc(len); - if (_names == NULL) - return NULL; - - res = PacketGetAdapterNames(_names, &len); - if (!res && len > 8192) { - os_free(_names); - _names = os_zalloc(len); - if (_names == NULL) - return NULL; - res = PacketGetAdapterNames(_names, &len); - } - - if (!res) { - wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list " - "(PacketGetAdapterNames)"); - os_free(_names); - return NULL; - } - - names = (char *) _names; - if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') { - wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in " - "UNICODE"); - /* Convert to ASCII */ - pos2 = pos = names; - while (pos2 < names + len) { - if (pos2[0] == '\0' && pos2[1] == '\0' && - pos2[2] == '\0' && pos2[3] == '\0') { - pos2 += 4; - break; - } - *pos++ = pos2[0]; - pos2 += 2; - } - os_memcpy(pos + 2, names, pos - names); - pos += 2; - } else - pos = names; - - num_name = 0; - while (pos < names + len) { - name[num_name] = pos; - while (*pos && pos < names + len) - pos++; - if (pos + 1 >= names + len) { - os_free(names); - return NULL; - } - pos++; - num_name++; - if (num_name >= MAX_ADAPTERS) { - wpa_printf(MSG_DEBUG, "NDIS: Too many adapters"); - os_free(names); - return NULL; - } - if (*pos == '\0') { - wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found", - num_name); - pos++; - break; - } - } - - num_desc = 0; - while (pos < names + len) { - desc[num_desc] = pos; - while (*pos && pos < names + len) - pos++; - if (pos + 1 >= names + len) { - os_free(names); - return NULL; - } - pos++; - num_desc++; - if (num_desc >= MAX_ADAPTERS) { - wpa_printf(MSG_DEBUG, "NDIS: Too many adapter " - "descriptions"); - os_free(names); - return NULL; - } - if (*pos == '\0') { - wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions " - "found", num_name); - pos++; - break; - } - } - - /* - * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter - * descriptions. Fill in dummy descriptors to work around this. - */ - while (num_desc < num_name) - desc[num_desc++] = "dummy description"; - - if (num_name != num_desc) { - wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and " - "description counts (%d != %d)", - num_name, num_desc); - os_free(names); - return NULL; - } - - for (i = 0; i < num_name; i++) { - niface = os_zalloc(sizeof(*niface)); - if (niface == NULL) - break; - niface->drv_name = "ndis"; - if (os_strncmp(name[i], "\\Device\\NPF_", 12) == 0) - niface->ifname = os_strdup(name[i] + 12); - else - niface->ifname = os_strdup(name[i]); - if (niface->ifname == NULL) { - os_free(niface); - break; - } - niface->desc = os_strdup(desc[i]); - niface->next = iface; - iface = niface; - } - -#endif /* CONFIG_USE_NDISUIO */ - - return iface; -} - - -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.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/contrib/hostapd/src/drivers/driver_ndis.h b/contrib/hostapd/src/drivers/driver_ndis.h deleted file mode 100644 index 89d136d3b4..0000000000 --- a/contrib/hostapd/src/drivers/driver_ndis.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * WPA Supplicant - Windows/NDIS driver interface - * Copyright (c) 2004-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef DRIVER_NDIS_H -#define DRIVER_NDIS_H - -#ifdef CONFIG_NDIS_EVENTS_INTEGRATED -struct ndis_events_data; -struct ndis_events_data * ndis_events_init(HANDLE *read_pipe, HANDLE *event, - const char *ifname, - const char *desc); -void ndis_events_deinit(struct ndis_events_data *events); -#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */ - -struct ndis_pmkid_entry { - struct ndis_pmkid_entry *next; - u8 bssid[ETH_ALEN]; - u8 pmkid[16]; -}; - -struct wpa_driver_ndis_data { - void *ctx; - char ifname[100]; /* GUID: {7EE3EFE5-C165-472F-986D-F6FBEDFE8C8D} */ -#ifdef _WIN32_WCE - TCHAR *adapter_name; - HANDLE event_queue; /* NDISUIO notifier MsgQueue */ - HANDLE connected_event; /* WpaSupplicantConnected event */ -#endif /* _WIN32_WCE */ - u8 own_addr[ETH_ALEN]; -#ifdef CONFIG_USE_NDISUIO - HANDLE ndisuio; -#else /* CONFIG_USE_NDISUIO */ - LPADAPTER adapter; -#endif /* CONFIG_USE_NDISUIO */ - u8 bssid[ETH_ALEN]; - - int has_capability; - int no_of_pmkid; - int radio_enabled; - struct wpa_driver_capa capa; - struct ndis_pmkid_entry *pmkid; - char *adapter_desc; - int wired; - int native80211; - int mode; - int wzc_disabled; - int oid_bssid_set; -#ifdef CONFIG_NDIS_EVENTS_INTEGRATED - HANDLE events_pipe, event_avail; - struct ndis_events_data *events; -#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */ -}; - -#endif /* DRIVER_NDIS_H */ diff --git a/contrib/hostapd/src/drivers/driver_ndis_.c b/contrib/hostapd/src/drivers/driver_ndis_.c deleted file mode 100644 index 4d23001964..0000000000 --- a/contrib/hostapd/src/drivers/driver_ndis_.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * WPA Supplicant - Windows/NDIS driver interface - event processing - * Copyright (c) 2004-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "driver.h" -#include "eloop.h" - -/* Keep this event processing in a separate file and without WinPcap headers to - * avoid conflicts with some of the header files. */ -struct _ADAPTER; -typedef struct _ADAPTER * LPADAPTER; -#include "driver_ndis.h" - - -void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv); -void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv); -void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv, - const u8 *data, size_t data_len); -void wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv); -void wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv); - - -enum event_types { EVENT_CONNECT, EVENT_DISCONNECT, - EVENT_MEDIA_SPECIFIC, EVENT_ADAPTER_ARRIVAL, - EVENT_ADAPTER_REMOVAL }; - -/* Event data: - * enum event_types (as int, i.e., 4 octets) - * data length (2 octets (big endian), optional) - * data (variable len, optional) - */ - - -static void wpa_driver_ndis_event_process(struct wpa_driver_ndis_data *drv, - u8 *buf, size_t len) -{ - u8 *pos, *data = NULL; - enum event_types type; - size_t data_len = 0; - - wpa_hexdump(MSG_MSGDUMP, "NDIS: received event data", buf, len); - if (len < sizeof(int)) - return; - type = *((int *) buf); - pos = buf + sizeof(int); - wpa_printf(MSG_DEBUG, "NDIS: event - type %d", type); - - if (buf + len - pos > 2) { - data_len = (int) *pos++ << 8; - data_len += *pos++; - if (data_len > (size_t) (buf + len - pos)) { - wpa_printf(MSG_DEBUG, "NDIS: event data overflow"); - return; - } - data = pos; - wpa_hexdump(MSG_MSGDUMP, "NDIS: event data", data, data_len); - } - - switch (type) { - case EVENT_CONNECT: - wpa_driver_ndis_event_connect(drv); - break; - case EVENT_DISCONNECT: - wpa_driver_ndis_event_disconnect(drv); - break; - case EVENT_MEDIA_SPECIFIC: - wpa_driver_ndis_event_media_specific(drv, data, data_len); - break; - case EVENT_ADAPTER_ARRIVAL: - wpa_driver_ndis_event_adapter_arrival(drv); - break; - case EVENT_ADAPTER_REMOVAL: - wpa_driver_ndis_event_adapter_removal(drv); - break; - } -} - - -void wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data) -{ - struct wpa_driver_ndis_data *drv = eloop_data; - u8 buf[512]; - DWORD len; - - ResetEvent(drv->event_avail); - if (ReadFile(drv->events_pipe, buf, sizeof(buf), &len, NULL)) - wpa_driver_ndis_event_process(drv, buf, len); - else { - wpa_printf(MSG_DEBUG, "%s: ReadFile() failed: %d", __func__, - (int) GetLastError()); - } -} diff --git a/contrib/hostapd/src/drivers/driver_nl80211.c b/contrib/hostapd/src/drivers/driver_nl80211.c deleted file mode 100644 index 5323e99c08..0000000000 --- a/contrib/hostapd/src/drivers/driver_nl80211.c +++ /dev/null @@ -1,11773 +0,0 @@ -/* - * Driver interaction with Linux nl80211/cfg80211 - * Copyright (c) 2002-2014, Jouni Malinen - * Copyright (c) 2003-2004, Instant802 Networks, Inc. - * Copyright (c) 2005-2006, Devicescape Software, Inc. - * Copyright (c) 2007, Johannes Berg - * Copyright (c) 2009-2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "nl80211_copy.h" - -#include "common.h" -#include "eloop.h" -#include "utils/list.h" -#include "common/qca-vendor.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" - -#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 -#define nl80211_handle_alloc nl_socket_alloc_cb -#define nl80211_handle_destroy nl_socket_free -#else -/* - * libnl 1.1 has a bug, it tries to allocate socket numbers densely - * but when you free a socket again it will mess up its bitmap and - * and use the wrong number the next time it needs a socket ID. - * Therefore, we wrap the handle alloc/destroy and add our own pid - * accounting. - */ -static uint32_t port_bitmap[32] = { 0 }; - -static struct nl_handle *nl80211_handle_alloc(void *cb) -{ - struct nl_handle *handle; - uint32_t pid = getpid() & 0x3FFFFF; - int i; - - handle = nl_handle_alloc_cb(cb); - - for (i = 0; i < 1024; i++) { - if (port_bitmap[i / 32] & (1 << (i % 32))) - continue; - port_bitmap[i / 32] |= 1 << (i % 32); - pid += i << 22; - break; - } - - nl_socket_set_local_port(handle, pid); - - return handle; -} - -static void nl80211_handle_destroy(struct nl_handle *handle) -{ - uint32_t port = nl_socket_get_local_port(handle); - - port >>= 22; - port_bitmap[port / 32] &= ~(1 << (port % 32)); - - nl_handle_destroy(handle); -} -#endif /* CONFIG_LIBNL20 */ - - -#ifdef ANDROID -/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */ -static int android_nl_socket_set_nonblocking(struct nl_handle *handle) -{ - return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK); -} -#undef nl_socket_set_nonblocking -#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h) -#endif /* ANDROID */ - - -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; -} - - -#if __WORDSIZE == 64 -#define ELOOP_SOCKET_INVALID (intptr_t) 0x8888888888888889ULL -#else -#define ELOOP_SOCKET_INVALID (intptr_t) 0x88888889ULL -#endif - -static void nl80211_register_eloop_read(struct nl_handle **handle, - eloop_sock_handler handler, - void *eloop_data) -{ - nl_socket_set_nonblocking(*handle); - eloop_register_read_sock(nl_socket_get_fd(*handle), handler, - eloop_data, *handle); - *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID); -} - - -static void nl80211_destroy_eloop_handle(struct nl_handle **handle) -{ - *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID); - eloop_unregister_read_sock(nl_socket_get_fd(*handle)); - nl_destroy_handles(handle); -} - - -#ifndef IFF_LOWER_UP -#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ -#endif -#ifndef IFF_DORMANT -#define IFF_DORMANT 0x20000 /* driver signals dormant */ -#endif - -#ifndef IF_OPER_DORMANT -#define IF_OPER_DORMANT 5 -#endif -#ifndef IF_OPER_UP -#define IF_OPER_UP 6 -#endif - -struct nl80211_global { - struct dl_list interfaces; - int if_add_ifindex; - u64 if_add_wdevid; - int if_add_wdevid_set; - struct netlink_data *netlink; - struct nl_cb *nl_cb; - struct nl_handle *nl; - 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); - -struct i802_bss { - struct wpa_driver_nl80211_data *drv; - struct i802_bss *next; - int ifindex; - u64 wdev_id; - char ifname[IFNAMSIZ + 1]; - char brname[IFNAMSIZ]; - unsigned int beacon_set:1; - unsigned int added_if_into_bridge:1; - unsigned int added_bridge:1; - unsigned int in_deinit:1; - unsigned int wdev_id_set:1; - unsigned int added_if:1; - - u8 addr[ETH_ALEN]; - - int freq; - int if_dynamic; - - void *ctx; - 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; - struct dl_list wiphy_list; - char phyname[32]; - void *ctx; - int ifindex; - int if_removed; - int if_disabled; - int ignore_if_down_event; - struct rfkill_data *rfkill; - struct wpa_driver_capa capa; - u8 *extended_capa, *extended_capa_mask; - unsigned int extended_capa_len; - int has_capability; - - int operstate; - - int scan_complete_events; - enum scan_states { - NO_SCAN, SCAN_REQUESTED, SCAN_STARTED, SCAN_COMPLETED, - SCAN_ABORTED, SCHED_SCAN_STARTED, SCHED_SCAN_STOPPED, - SCHED_SCAN_RESULTS - } scan_state; - - struct nl_cb *nl_cb; - - u8 auth_bssid[ETH_ALEN]; - u8 auth_attempt_bssid[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - u8 prev_bssid[ETH_ALEN]; - int associated; - u8 ssid[32]; - size_t ssid_len; - enum nl80211_iftype nlmode; - enum nl80211_iftype ap_scan_as_station; - unsigned int assoc_freq; - - int monitor_sock; - int monitor_ifidx; - 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; - unsigned int ignore_next_local_disconnect:1; - unsigned int allow_p2p_device:1; - unsigned int hostapd:1; - unsigned int start_mode_ap:1; - unsigned int start_iface_up:1; - - u64 remain_on_chan_cookie; - u64 send_action_cookie; - - unsigned int last_mgmt_freq; - - struct wpa_driver_scan_filter *filter_ssids; - size_t num_filter_ssids; - - struct i802_bss *first_bss; - - int eapol_tx_sock; - - int eapol_sock; /* socket for EAPOL frames */ - - int default_if_indices[16]; - int *if_indices; - int num_if_indices; - - /* 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_deinit(struct i802_bss *bss); -static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, - void *timeout_ctx); -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, - const u8 *set_addr, int first); -static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, - const u8 *addr, int cmd, u16 reason_code, - int local_state_change); -static void nl80211_remove_monitor_interface( - 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, - int no_cck, int no_ack, int offchanok); -static int nl80211_register_frame(struct i802_bss *bss, - struct nl_handle *hl_handle, - u16 type, const u8 *match, size_t match_len); -static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, - int report); -#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); -extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, - size_t buf_len); -#endif /* ANDROID */ -#ifdef ANDROID_P2P -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 /* ANDROID_P2P */ - -static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); -static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); -static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); -static int wpa_driver_nl80211_if_remove(struct i802_bss *bss, - enum wpa_driver_if_type type, - const char *ifname); - -static int wpa_driver_nl80211_set_freq(struct i802_bss *bss, - struct hostapd_freq_params *freq); -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 i802_set_iface_flags(struct i802_bss *bss, int up); - - -static const char * nl80211_command_to_string(enum nl80211_commands cmd) -{ -#define C2S(x) case x: return #x; - switch (cmd) { - C2S(NL80211_CMD_UNSPEC) - C2S(NL80211_CMD_GET_WIPHY) - C2S(NL80211_CMD_SET_WIPHY) - C2S(NL80211_CMD_NEW_WIPHY) - C2S(NL80211_CMD_DEL_WIPHY) - C2S(NL80211_CMD_GET_INTERFACE) - C2S(NL80211_CMD_SET_INTERFACE) - C2S(NL80211_CMD_NEW_INTERFACE) - C2S(NL80211_CMD_DEL_INTERFACE) - C2S(NL80211_CMD_GET_KEY) - C2S(NL80211_CMD_SET_KEY) - C2S(NL80211_CMD_NEW_KEY) - C2S(NL80211_CMD_DEL_KEY) - C2S(NL80211_CMD_GET_BEACON) - C2S(NL80211_CMD_SET_BEACON) - C2S(NL80211_CMD_START_AP) - C2S(NL80211_CMD_STOP_AP) - C2S(NL80211_CMD_GET_STATION) - C2S(NL80211_CMD_SET_STATION) - C2S(NL80211_CMD_NEW_STATION) - C2S(NL80211_CMD_DEL_STATION) - C2S(NL80211_CMD_GET_MPATH) - C2S(NL80211_CMD_SET_MPATH) - C2S(NL80211_CMD_NEW_MPATH) - C2S(NL80211_CMD_DEL_MPATH) - C2S(NL80211_CMD_SET_BSS) - C2S(NL80211_CMD_SET_REG) - C2S(NL80211_CMD_REQ_SET_REG) - C2S(NL80211_CMD_GET_MESH_CONFIG) - C2S(NL80211_CMD_SET_MESH_CONFIG) - C2S(NL80211_CMD_SET_MGMT_EXTRA_IE) - C2S(NL80211_CMD_GET_REG) - C2S(NL80211_CMD_GET_SCAN) - C2S(NL80211_CMD_TRIGGER_SCAN) - C2S(NL80211_CMD_NEW_SCAN_RESULTS) - C2S(NL80211_CMD_SCAN_ABORTED) - C2S(NL80211_CMD_REG_CHANGE) - C2S(NL80211_CMD_AUTHENTICATE) - C2S(NL80211_CMD_ASSOCIATE) - C2S(NL80211_CMD_DEAUTHENTICATE) - C2S(NL80211_CMD_DISASSOCIATE) - C2S(NL80211_CMD_MICHAEL_MIC_FAILURE) - C2S(NL80211_CMD_REG_BEACON_HINT) - C2S(NL80211_CMD_JOIN_IBSS) - C2S(NL80211_CMD_LEAVE_IBSS) - C2S(NL80211_CMD_TESTMODE) - C2S(NL80211_CMD_CONNECT) - C2S(NL80211_CMD_ROAM) - C2S(NL80211_CMD_DISCONNECT) - C2S(NL80211_CMD_SET_WIPHY_NETNS) - C2S(NL80211_CMD_GET_SURVEY) - C2S(NL80211_CMD_NEW_SURVEY_RESULTS) - C2S(NL80211_CMD_SET_PMKSA) - C2S(NL80211_CMD_DEL_PMKSA) - C2S(NL80211_CMD_FLUSH_PMKSA) - C2S(NL80211_CMD_REMAIN_ON_CHANNEL) - C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL) - C2S(NL80211_CMD_SET_TX_BITRATE_MASK) - C2S(NL80211_CMD_REGISTER_FRAME) - C2S(NL80211_CMD_FRAME) - C2S(NL80211_CMD_FRAME_TX_STATUS) - C2S(NL80211_CMD_SET_POWER_SAVE) - C2S(NL80211_CMD_GET_POWER_SAVE) - C2S(NL80211_CMD_SET_CQM) - C2S(NL80211_CMD_NOTIFY_CQM) - C2S(NL80211_CMD_SET_CHANNEL) - C2S(NL80211_CMD_SET_WDS_PEER) - C2S(NL80211_CMD_FRAME_WAIT_CANCEL) - C2S(NL80211_CMD_JOIN_MESH) - C2S(NL80211_CMD_LEAVE_MESH) - C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE) - C2S(NL80211_CMD_UNPROT_DISASSOCIATE) - C2S(NL80211_CMD_NEW_PEER_CANDIDATE) - C2S(NL80211_CMD_GET_WOWLAN) - C2S(NL80211_CMD_SET_WOWLAN) - C2S(NL80211_CMD_START_SCHED_SCAN) - C2S(NL80211_CMD_STOP_SCHED_SCAN) - C2S(NL80211_CMD_SCHED_SCAN_RESULTS) - C2S(NL80211_CMD_SCHED_SCAN_STOPPED) - C2S(NL80211_CMD_SET_REKEY_OFFLOAD) - C2S(NL80211_CMD_PMKSA_CANDIDATE) - C2S(NL80211_CMD_TDLS_OPER) - C2S(NL80211_CMD_TDLS_MGMT) - C2S(NL80211_CMD_UNEXPECTED_FRAME) - C2S(NL80211_CMD_PROBE_CLIENT) - C2S(NL80211_CMD_REGISTER_BEACONS) - C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME) - C2S(NL80211_CMD_SET_NOACK_MAP) - C2S(NL80211_CMD_CH_SWITCH_NOTIFY) - C2S(NL80211_CMD_START_P2P_DEVICE) - C2S(NL80211_CMD_STOP_P2P_DEVICE) - C2S(NL80211_CMD_CONN_FAILED) - C2S(NL80211_CMD_SET_MCAST_RATE) - C2S(NL80211_CMD_SET_MAC_ACL) - C2S(NL80211_CMD_RADAR_DETECT) - C2S(NL80211_CMD_GET_PROTOCOL_FEATURES) - C2S(NL80211_CMD_UPDATE_FT_IES) - C2S(NL80211_CMD_FT_EVENT) - C2S(NL80211_CMD_CRIT_PROTOCOL_START) - C2S(NL80211_CMD_CRIT_PROTOCOL_STOP) - C2S(NL80211_CMD_GET_COALESCE) - C2S(NL80211_CMD_SET_COALESCE) - C2S(NL80211_CMD_CHANNEL_SWITCH) - C2S(NL80211_CMD_VENDOR) - C2S(NL80211_CMD_SET_QOS_MAP) - default: - return "NL80211_CMD_UNKNOWN"; - } -#undef C2S -} - - -/* Converts nl80211_chan_width to a common format */ -static enum chan_width convert2width(int width) -{ - switch (width) { - case NL80211_CHAN_WIDTH_20_NOHT: - return CHAN_WIDTH_20_NOHT; - case NL80211_CHAN_WIDTH_20: - return CHAN_WIDTH_20; - case NL80211_CHAN_WIDTH_40: - return CHAN_WIDTH_40; - case NL80211_CHAN_WIDTH_80: - return CHAN_WIDTH_80; - case NL80211_CHAN_WIDTH_80P80: - return CHAN_WIDTH_80P80; - case NL80211_CHAN_WIDTH_160: - return CHAN_WIDTH_160; - } - return CHAN_WIDTH_UNKNOWN; -} - - -static int 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_net_interface(enum nl80211_iftype nlmode) -{ - return (nlmode == NL80211_IFTYPE_P2P_CLIENT || - nlmode == NL80211_IFTYPE_P2P_GO); -} - - -static void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv) -{ - if (drv->associated) - os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN); - drv->associated = 0; - os_memset(drv->bssid, 0, ETH_ALEN); -} - - -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); - - -/* nl80211 code */ -static int ack_handler(struct nl_msg *msg, void *arg) -{ - int *err = arg; - *err = 0; - return NL_STOP; -} - -static int finish_handler(struct nl_msg *msg, void *arg) -{ - int *ret = arg; - *ret = 0; - return NL_SKIP; -} - -static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, - void *arg) -{ - int *ret = arg; - *ret = err->error; - return NL_SKIP; -} - - -static int no_seq_check(struct nl_msg *msg, void *arg) -{ - return NL_OK; -} - - -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) -{ - struct nl_cb *cb; - int err = -ENOMEM; - - cb = nl_cb_clone(global->nl_cb); - if (!cb) - goto out; - - err = nl_send_auto_complete(nl_handle, msg); - if (err < 0) - goto out; - - err = 1; - - nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); - nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); - - if (valid_handler) - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, - valid_handler, valid_data); - - while (err > 0) { - int res = nl_recvmsgs(nl_handle, cb); - if (res) { - wpa_printf(MSG_INFO, - "nl80211: %s->nl_recvmsgs failed: %d", - __func__, res); - } - } - out: - nl_cb_put(cb); - nlmsg_free(msg); - return err; -} - - -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); -} - - -static 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->global, drv->global->nl, msg, - valid_handler, valid_data); -} - - -struct family_data { - const char *group; - int id; -}; - - -static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss) -{ - if (bss->wdev_id_set) - NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id); - else - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); - return 0; - -nla_put_failure: - return -1; -} - - -static int family_handler(struct nl_msg *msg, void *arg) -{ - struct family_data *res = arg; - struct nlattr *tb[CTRL_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct nlattr *mcgrp; - int i; - - nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - if (!tb[CTRL_ATTR_MCAST_GROUPS]) - return NL_SKIP; - - nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) { - struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1]; - nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp), - nla_len(mcgrp), NULL); - if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || - !tb2[CTRL_ATTR_MCAST_GRP_ID] || - os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]), - res->group, - nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0) - continue; - res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]); - break; - }; - - return NL_SKIP; -} - - -static int nl_get_multicast_id(struct nl80211_global *global, - const char *family, const char *group) -{ - struct nl_msg *msg; - int ret = -1; - struct family_data res = { group, -ENOENT }; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - 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_global(global, msg, family_handler, &res); - msg = NULL; - if (ret == 0) - ret = res.id; - -nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -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; - enum nl80211_iftype nlmode; - u8 *macaddr; -}; - - -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]); - - if (tb[NL80211_ATTR_IFTYPE]) - info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]); - - if (tb[NL80211_ATTR_MAC] && info->macaddr) - os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]), - ETH_ALEN); - - return NL_SKIP; -} - - -static int nl80211_get_wiphy_index(struct i802_bss *bss) -{ - struct nl_msg *msg; - struct wiphy_idx_data data = { - .wiphy_idx = -1, - .macaddr = NULL, - }; - - msg = nlmsg_alloc(); - if (!msg) - return NL80211_IFTYPE_UNSPECIFIED; - - nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE); - - if (nl80211_set_iface_id(msg, bss) < 0) - goto nla_put_failure; - - 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 enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss) -{ - struct nl_msg *msg; - struct wiphy_idx_data data = { - .nlmode = NL80211_IFTYPE_UNSPECIFIED, - .macaddr = NULL, - }; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE); - - if (nl80211_set_iface_id(msg, bss) < 0) - goto nla_put_failure; - - if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0) - return data.nlmode; - msg = NULL; -nla_put_failure: - nlmsg_free(msg); - return NL80211_IFTYPE_UNSPECIFIED; -} - - -static int nl80211_get_macaddr(struct i802_bss *bss) -{ - struct nl_msg *msg; - struct wiphy_idx_data data = { - .macaddr = bss->addr, - }; - - msg = nlmsg_alloc(); - if (!msg) - return NL80211_IFTYPE_UNSPECIFIED; - - nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE); - if (nl80211_set_iface_id(msg, bss) < 0) - goto nla_put_failure; - - return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data); - -nla_put_failure: - nlmsg_free(msg); - return NL80211_IFTYPE_UNSPECIFIED; -} - - -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; - int res; - - wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available"); - - res = nl_recvmsgs(handle, w->nl_cb); - if (res) { - wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d", - __func__, res); - } -} - - -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; - } - - nl80211_register_eloop_read(&w->nl_beacons, nl80211_recv_beacons, w); - - 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; - - nl80211_destroy_eloop_handle(&w->nl_beacons); - - nl_cb_put(w->nl_cb); - dl_list_del(&w->list); - os_free(w); -} - - -static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - if (!drv->associated) - return -1; - os_memcpy(bssid, drv->bssid, ETH_ALEN); - return 0; -} - - -static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - if (!drv->associated) - return -1; - os_memcpy(ssid, drv->ssid, drv->ssid_len); - return drv->ssid_len; -} - - -static void wpa_driver_nl80211_event_newlink( - struct wpa_driver_nl80211_data *drv, char *ifname) -{ - union wpa_event_data event; - - if (os_strcmp(drv->first_bss->ifname, ifname) == 0) { - if (if_nametoindex(drv->first_bss->ifname) == 0) { - wpa_printf(MSG_DEBUG, "nl80211: Interface %s does not exist - ignore RTM_NEWLINK", - drv->first_bss->ifname); - return; - } - if (!drv->if_removed) - return; - wpa_printf(MSG_DEBUG, "nl80211: Mark if_removed=0 for %s based on RTM_NEWLINK event", - drv->first_bss->ifname); - drv->if_removed = 0; - } - - os_memset(&event, 0, sizeof(event)); - os_strlcpy(event.interface_status.ifname, ifname, - sizeof(event.interface_status.ifname)); - event.interface_status.ievent = EVENT_INTERFACE_ADDED; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); -} - - -static void wpa_driver_nl80211_event_dellink( - struct wpa_driver_nl80211_data *drv, char *ifname) -{ - union wpa_event_data event; - - if (os_strcmp(drv->first_bss->ifname, ifname) == 0) { - if (drv->if_removed) { - wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s", - ifname); - return; - } - wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed - mark if_removed=1", - ifname); - drv->if_removed = 1; - } else { - wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed", - ifname); - } - - os_memset(&event, 0, sizeof(event)); - os_strlcpy(event.interface_status.ifname, ifname, - sizeof(event.interface_status.ifname)); - event.interface_status.ievent = EVENT_INTERFACE_REMOVED; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); -} - - -static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv, - u8 *buf, size_t len) -{ - int attrlen, rta_len; - struct rtattr *attr; - - attrlen = len; - attr = (struct rtattr *) buf; - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_IFNAME) { - if (os_strcmp(((char *) attr) + rta_len, - drv->first_bss->ifname) == 0) - return 1; - else - break; - } - attr = RTA_NEXT(attr, attrlen); - } - - return 0; -} - - -static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv, - int ifindex, u8 *buf, size_t len) -{ - if (drv->ifindex == ifindex) - return 1; - - if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) { - wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed " - "interface"); - wpa_driver_nl80211_finish_drv_init(drv, NULL, 0); - return 1; - } - - return 0; -} - - -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 nl80211_global *global = ctx; - struct wpa_driver_nl80211_data *drv; - int attrlen; - struct rtattr *attr; - u32 brid = 0; - char namebuf[IFNAMSIZ]; - char ifname[IFNAMSIZ + 1]; - char extra[100], *pos, *end; - - drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); - if (!drv) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_NEWLINK event for foreign ifindex %d", - ifi->ifi_index); - return; - } - - extra[0] = '\0'; - pos = extra; - end = pos + sizeof(extra); - ifname[0] = '\0'; - - attrlen = len; - attr = (struct rtattr *) buf; - while (RTA_OK(attr, attrlen)) { - switch (attr->rta_type) { - case IFLA_IFNAME: - if (RTA_PAYLOAD(attr) >= IFNAMSIZ) - break; - os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr)); - ifname[RTA_PAYLOAD(attr)] = '\0'; - break; - case IFLA_MASTER: - brid = nla_get_u32((struct nlattr *) attr); - pos += os_snprintf(pos, end - pos, " master=%u", brid); - break; - case IFLA_WIRELESS: - pos += os_snprintf(pos, end - pos, " wext"); - break; - case IFLA_OPERSTATE: - pos += os_snprintf(pos, end - pos, " operstate=%u", - nla_get_u32((struct nlattr *) attr)); - break; - case IFLA_LINKMODE: - pos += os_snprintf(pos, end - pos, " linkmode=%u", - nla_get_u32((struct nlattr *) attr)); - break; - } - attr = RTA_NEXT(attr, attrlen); - } - extra[sizeof(extra) - 1] = '\0'; - - wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_flags=0x%x (%s%s%s%s)", - ifi->ifi_index, ifname, extra, ifi->ifi_flags, - (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", - (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", - (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", - (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"); - 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)) { - 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 if (if_nametoindex(drv->first_bss->ifname) == 0) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up " - "event since interface %s does not exist", - drv->first_bss->ifname); - } else if (drv->if_removed) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up " - "event since interface %s is marked " - "removed", drv->first_bss->ifname); - } else { - wpa_printf(MSG_DEBUG, "nl80211: Interface up"); - drv->if_disabled = 0; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, - NULL); - } - } - - /* - * Some drivers send the association event before the operup event--in - * this case, lifting operstate in wpa_driver_nl80211_set_operstate() - * fails. This will hit us when wpa_supplicant does not need to do - * IEEE 802.1X authentication - */ - if (drv->operstate == 1 && - (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && - !(ifi->ifi_flags & IFF_RUNNING)) { - wpa_printf(MSG_DEBUG, "nl80211: Set IF_OPER_UP again based on ifi_flags and expected operstate"); - netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, - -1, IF_OPER_UP); - } - - if (ifname[0]) - wpa_driver_nl80211_event_newlink(drv, ifname); - - if (ifi->ifi_family == AF_BRIDGE && brid) { - /* device has been added to bridge */ - if_indextoname(brid, namebuf); - wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s", - brid, namebuf); - add_ifidx(drv, brid); - } -} - - -static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, - struct ifinfomsg *ifi, - u8 *buf, size_t len) -{ - struct nl80211_global *global = ctx; - struct wpa_driver_nl80211_data *drv; - int attrlen; - struct rtattr *attr; - u32 brid = 0; - char ifname[IFNAMSIZ + 1]; - - drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); - if (!drv) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_DELLINK event for foreign ifindex %d", - ifi->ifi_index); - return; - } - - ifname[0] = '\0'; - - attrlen = len; - attr = (struct rtattr *) buf; - while (RTA_OK(attr, attrlen)) { - switch (attr->rta_type) { - case IFLA_IFNAME: - if (RTA_PAYLOAD(attr) >= IFNAMSIZ) - break; - os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr)); - ifname[RTA_PAYLOAD(attr)] = '\0'; - break; - case IFLA_MASTER: - brid = nla_get_u32((struct nlattr *) attr); - break; - } - attr = RTA_NEXT(attr, attrlen); - } - - if (ifname[0]) - wpa_driver_nl80211_event_dellink(drv, ifname); - - if (ifi->ifi_family == AF_BRIDGE && brid) { - /* device has been removed from bridge */ - char namebuf[IFNAMSIZ]; - if_indextoname(brid, namebuf); - wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge " - "%s", brid, namebuf); - del_ifidx(drv, brid); - } -} - - -static void mlme_event_auth(struct wpa_driver_nl80211_data *drv, - const u8 *frame, size_t len) -{ - const struct ieee80211_mgmt *mgmt; - union wpa_event_data event; - - wpa_printf(MSG_DEBUG, "nl80211: Authenticate event"); - mgmt = (const struct ieee80211_mgmt *) frame; - if (len < 24 + sizeof(mgmt->u.auth)) { - wpa_printf(MSG_DEBUG, "nl80211: Too short association event " - "frame"); - return; - } - - os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN); - os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN); - os_memset(&event, 0, sizeof(event)); - os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN); - event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg); - event.auth.auth_transaction = - le_to_host16(mgmt->u.auth.auth_transaction); - event.auth.status_code = le_to_host16(mgmt->u.auth.status_code); - if (len > 24 + sizeof(mgmt->u.auth)) { - event.auth.ies = mgmt->u.auth.variable; - event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth); - } - - wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event); -} - - -static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv) -{ - 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) { - wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the " - "associated BSS from scan results: %u MHz", - arg.assoc_freq); - if (arg.assoc_freq) - drv->assoc_freq = arg.assoc_freq; - return drv->assoc_freq; - } - 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 void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, - const u8 *frame, size_t len) -{ - const struct ieee80211_mgmt *mgmt; - union wpa_event_data event; - u16 status; - - wpa_printf(MSG_DEBUG, "nl80211: Associate event"); - mgmt = (const struct ieee80211_mgmt *) frame; - if (len < 24 + sizeof(mgmt->u.assoc_resp)) { - wpa_printf(MSG_DEBUG, "nl80211: Too short association event " - "frame"); - return; - } - - status = le_to_host16(mgmt->u.assoc_resp.status_code); - if (status != WLAN_STATUS_SUCCESS) { - os_memset(&event, 0, sizeof(event)); - event.assoc_reject.bssid = mgmt->bssid; - if (len > 24 + sizeof(mgmt->u.assoc_resp)) { - event.assoc_reject.resp_ies = - (u8 *) mgmt->u.assoc_resp.variable; - event.assoc_reject.resp_ies_len = - len - 24 - sizeof(mgmt->u.assoc_resp); - } - event.assoc_reject.status_code = status; - - wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); - return; - } - - drv->associated = 1; - os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN); - os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN); - - os_memset(&event, 0, sizeof(event)); - if (len > 24 + sizeof(mgmt->u.assoc_resp)) { - event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable; - event.assoc_info.resp_ies_len = - len - 24 - sizeof(mgmt->u.assoc_resp); - } - - event.assoc_info.freq = drv->assoc_freq; - - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); -} - - -static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, - enum nl80211_commands cmd, struct nlattr *status, - struct nlattr *addr, struct nlattr *req_ie, - struct nlattr *resp_ie) -{ - union wpa_event_data event; - - if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { - /* - * Avoid reporting two association events that would confuse - * the core code. - */ - wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) " - "when using userspace SME", cmd); - return; - } - - if (cmd == NL80211_CMD_CONNECT) - wpa_printf(MSG_DEBUG, "nl80211: Connect event"); - else if (cmd == NL80211_CMD_ROAM) - wpa_printf(MSG_DEBUG, "nl80211: Roam event"); - - os_memset(&event, 0, sizeof(event)); - if (cmd == NL80211_CMD_CONNECT && - nla_get_u16(status) != WLAN_STATUS_SUCCESS) { - if (addr) - event.assoc_reject.bssid = nla_data(addr); - if (resp_ie) { - event.assoc_reject.resp_ies = nla_data(resp_ie); - event.assoc_reject.resp_ies_len = nla_len(resp_ie); - } - event.assoc_reject.status_code = nla_get_u16(status); - wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); - return; - } - - drv->associated = 1; - if (addr) { - os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN); - os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN); - } - - if (req_ie) { - event.assoc_info.req_ies = nla_data(req_ie); - event.assoc_info.req_ies_len = nla_len(req_ie); - } - if (resp_ie) { - event.assoc_info.resp_ies = nla_data(resp_ie); - event.assoc_info.resp_ies_len = nla_len(resp_ie); - } - - event.assoc_info.freq = nl80211_get_assoc_freq(drv); - - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); -} - - -static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv, - struct nlattr *reason, struct nlattr *addr, - struct nlattr *by_ap) -{ - union wpa_event_data data; - unsigned int locally_generated = by_ap == NULL; - - 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; - } - - if (drv->ignore_next_local_disconnect) { - drv->ignore_next_local_disconnect = 0; - if (locally_generated) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect " - "event triggered during reassociation"); - return; - } - wpa_printf(MSG_WARNING, "nl80211: Was expecting local " - "disconnect but got another disconnect " - "event first"); - } - - wpa_printf(MSG_DEBUG, "nl80211: Disconnect event"); - nl80211_mark_disconnected(drv); - os_memset(&data, 0, sizeof(data)); - if (reason) - data.deauth_info.reason_code = nla_get_u16(reason); - data.deauth_info.locally_generated = by_ap == NULL; - wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data); -} - - -static int calculate_chan_offset(int width, int freq, int cf1, int cf2) -{ - int freq1 = 0; - - switch (convert2width(width)) { - case CHAN_WIDTH_20_NOHT: - case CHAN_WIDTH_20: - return 0; - case CHAN_WIDTH_40: - freq1 = cf1 - 10; - break; - case CHAN_WIDTH_80: - freq1 = cf1 - 30; - break; - case CHAN_WIDTH_160: - freq1 = cf1 - 70; - break; - case CHAN_WIDTH_UNKNOWN: - case CHAN_WIDTH_80P80: - /* FIXME: implement this */ - return 0; - } - - return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1; -} - - -static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, - struct nlattr *ifindex, struct nlattr *freq, - struct nlattr *type, struct nlattr *bw, - struct nlattr *cf1, struct nlattr *cf2) -{ - struct i802_bss *bss; - union wpa_event_data data; - int ht_enabled = 1; - int chan_offset = 0; - int ifidx; - - wpa_printf(MSG_DEBUG, "nl80211: Channel switch event"); - - if (!freq) - return; - - ifidx = nla_get_u32(ifindex); - for (bss = drv->first_bss; bss; bss = bss->next) - if (bss->ifindex == ifidx) - break; - - if (bss == NULL) { - wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring", - ifidx); - return; - } - - if (type) { - switch (nla_get_u32(type)) { - case NL80211_CHAN_NO_HT: - ht_enabled = 0; - break; - case NL80211_CHAN_HT20: - break; - case NL80211_CHAN_HT40PLUS: - chan_offset = 1; - break; - case NL80211_CHAN_HT40MINUS: - chan_offset = -1; - break; - } - } else if (bw && cf1) { - /* This can happen for example with VHT80 ch switch */ - chan_offset = calculate_chan_offset(nla_get_u32(bw), - nla_get_u32(freq), - nla_get_u32(cf1), - cf2 ? nla_get_u32(cf2) : 0); - } else { - wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail"); - } - - os_memset(&data, 0, sizeof(data)); - data.ch_switch.freq = nla_get_u32(freq); - data.ch_switch.ht_enabled = ht_enabled; - data.ch_switch.ch_offset = chan_offset; - if (bw) - data.ch_switch.ch_width = convert2width(nla_get_u32(bw)); - if (cf1) - data.ch_switch.cf1 = nla_get_u32(cf1); - if (cf2) - data.ch_switch.cf2 = nla_get_u32(cf2); - - bss->freq = data.ch_switch.freq; - - wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data); -} - - -static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv, - enum nl80211_commands cmd, struct nlattr *addr) -{ - union wpa_event_data event; - enum wpa_event_type ev; - - if (nla_len(addr) != ETH_ALEN) - return; - - wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR, - cmd, MAC2STR((u8 *) nla_data(addr))); - - if (cmd == NL80211_CMD_AUTHENTICATE) - ev = EVENT_AUTH_TIMED_OUT; - else if (cmd == NL80211_CMD_ASSOCIATE) - ev = EVENT_ASSOC_TIMED_OUT; - else - return; - - os_memset(&event, 0, sizeof(event)); - os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN); - wpa_supplicant_event(drv->ctx, ev, &event); -} - - -static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, - struct nlattr *freq, struct nlattr *sig, - const u8 *frame, size_t len) -{ - const struct ieee80211_mgmt *mgmt; - union wpa_event_data event; - u16 fc, stype; - int ssi_signal = 0; - int rx_freq = 0; - - wpa_printf(MSG_MSGDUMP, "nl80211: Frame event"); - mgmt = (const struct ieee80211_mgmt *) frame; - if (len < 24) { - wpa_printf(MSG_DEBUG, "nl80211: Too short management frame"); - return; - } - - fc = le_to_host16(mgmt->frame_control); - stype = WLAN_FC_GET_STYPE(fc); - - if (sig) - ssi_signal = (s32) nla_get_u32(sig); - - os_memset(&event, 0, sizeof(event)); - if (freq) { - event.rx_mgmt.freq = nla_get_u32(freq); - rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq; - } - wpa_printf(MSG_DEBUG, - "nl80211: RX frame freq=%d ssi_signal=%d stype=%u len=%u", - rx_freq, ssi_signal, stype, (unsigned int) len); - event.rx_mgmt.frame = frame; - event.rx_mgmt.frame_len = len; - event.rx_mgmt.ssi_signal = ssi_signal; - wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); -} - - -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; - - wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event"); - if (!is_ap_interface(drv->nlmode)) { - u64 cookie_val; - - 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); - - os_memset(&event, 0, sizeof(event)); - event.tx_status.type = WLAN_FC_GET_TYPE(fc); - event.tx_status.stype = WLAN_FC_GET_STYPE(fc); - event.tx_status.dst = hdr->addr1; - event.tx_status.data = frame; - event.tx_status.data_len = len; - event.tx_status.ack = ack != NULL; - wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); -} - - -static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, - enum wpa_event_type type, - const u8 *frame, size_t len) -{ - const struct ieee80211_mgmt *mgmt; - union wpa_event_data event; - const u8 *bssid = NULL; - u16 reason_code = 0; - - if (type == EVENT_DEAUTH) - wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event"); - else - wpa_printf(MSG_DEBUG, "nl80211: Disassociate event"); - - mgmt = (const struct ieee80211_mgmt *) frame; - if (len >= 24) { - bssid = mgmt->bssid; - - if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) && - !drv->associated && - os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 && - os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 && - os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) { - /* - * Avoid issues with some roaming cases where - * disconnection event for the old AP may show up after - * we have started connection with the new AP. - */ - wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR, - MAC2STR(bssid), - MAC2STR(drv->auth_attempt_bssid)); - return; - } - - if (drv->associated != 0 && - os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 && - os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) { - /* - * We have presumably received this deauth as a - * response to a clear_state_mismatch() outgoing - * deauth. Don't let it take us offline! - */ - wpa_printf(MSG_DEBUG, "nl80211: Deauth received " - "from Unknown BSSID " MACSTR " -- ignoring", - MAC2STR(bssid)); - return; - } - } - - nl80211_mark_disconnected(drv); - os_memset(&event, 0, sizeof(event)); - - /* Note: Same offset for Reason Code in both frame subtypes */ - if (len >= 24 + sizeof(mgmt->u.deauth)) - reason_code = le_to_host16(mgmt->u.deauth.reason_code); - - if (type == EVENT_DISASSOC) { - event.disassoc_info.locally_generated = - !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN); - event.disassoc_info.addr = bssid; - event.disassoc_info.reason_code = reason_code; - if (frame + len > mgmt->u.disassoc.variable) { - event.disassoc_info.ie = mgmt->u.disassoc.variable; - event.disassoc_info.ie_len = frame + len - - mgmt->u.disassoc.variable; - } - } else { - event.deauth_info.locally_generated = - !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN); - event.deauth_info.addr = bssid; - event.deauth_info.reason_code = reason_code; - if (frame + len > mgmt->u.deauth.variable) { - event.deauth_info.ie = mgmt->u.deauth.variable; - event.deauth_info.ie_len = frame + len - - mgmt->u.deauth.variable; - } - } - - wpa_supplicant_event(drv->ctx, type, &event); -} - - -static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv, - enum wpa_event_type type, - const u8 *frame, size_t len) -{ - const struct ieee80211_mgmt *mgmt; - union wpa_event_data event; - u16 reason_code = 0; - - if (type == EVENT_UNPROT_DEAUTH) - wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event"); - else - wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event"); - - if (len < 24) - return; - - mgmt = (const struct ieee80211_mgmt *) frame; - - os_memset(&event, 0, sizeof(event)); - /* Note: Same offset for Reason Code in both frame subtypes */ - if (len >= 24 + sizeof(mgmt->u.deauth)) - reason_code = le_to_host16(mgmt->u.deauth.reason_code); - - if (type == EVENT_UNPROT_DISASSOC) { - event.unprot_disassoc.sa = mgmt->sa; - event.unprot_disassoc.da = mgmt->da; - event.unprot_disassoc.reason_code = reason_code; - } else { - event.unprot_deauth.sa = mgmt->sa; - event.unprot_deauth.da = mgmt->da; - event.unprot_deauth.reason_code = reason_code; - } - - wpa_supplicant_event(drv->ctx, type, &event); -} - - -static void mlme_event(struct i802_bss *bss, - enum nl80211_commands cmd, struct nlattr *frame, - struct nlattr *addr, struct nlattr *timed_out, - struct nlattr *freq, struct nlattr *ack, - struct nlattr *cookie, struct nlattr *sig) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - const u8 *data; - size_t len; - - if (timed_out && addr) { - mlme_timeout_event(drv, cmd, addr); - return; - } - - if (frame == NULL) { - wpa_printf(MSG_DEBUG, - "nl80211: MLME event %d (%s) without frame data", - cmd, nl80211_command_to_string(cmd)); - return; - } - - data = nla_data(frame); - len = nla_len(frame); - if (len < 4 + 2 * ETH_ALEN) { - wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" - MACSTR ") - too short", - cmd, nl80211_command_to_string(cmd), bss->ifname, - MAC2STR(bss->addr)); - return; - } - wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR - ") A1=" MACSTR " A2=" MACSTR, cmd, - nl80211_command_to_string(cmd), bss->ifname, - MAC2STR(bss->addr), MAC2STR(data + 4), - MAC2STR(data + 4 + ETH_ALEN)); - if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) && - os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 && - os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) { - wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event " - "for foreign address", bss->ifname); - return; - } - wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame", - nla_data(frame), nla_len(frame)); - - switch (cmd) { - case NL80211_CMD_AUTHENTICATE: - mlme_event_auth(drv, nla_data(frame), nla_len(frame)); - break; - case NL80211_CMD_ASSOCIATE: - mlme_event_assoc(drv, nla_data(frame), nla_len(frame)); - break; - case NL80211_CMD_DEAUTHENTICATE: - mlme_event_deauth_disassoc(drv, EVENT_DEAUTH, - nla_data(frame), nla_len(frame)); - break; - case NL80211_CMD_DISASSOCIATE: - mlme_event_deauth_disassoc(drv, EVENT_DISASSOC, - nla_data(frame), nla_len(frame)); - break; - case NL80211_CMD_FRAME: - mlme_event_mgmt(drv, freq, sig, nla_data(frame), - nla_len(frame)); - break; - case NL80211_CMD_FRAME_TX_STATUS: - mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame), - nla_len(frame), ack); - break; - case NL80211_CMD_UNPROT_DEAUTHENTICATE: - mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH, - nla_data(frame), nla_len(frame)); - break; - case NL80211_CMD_UNPROT_DISASSOCIATE: - mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC, - nla_data(frame), nla_len(frame)); - break; - default: - break; - } -} - - -static void mlme_event_michael_mic_failure(struct i802_bss *bss, - struct nlattr *tb[]) -{ - union wpa_event_data data; - - wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure"); - os_memset(&data, 0, sizeof(data)); - if (tb[NL80211_ATTR_MAC]) { - wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address", - nla_data(tb[NL80211_ATTR_MAC]), - nla_len(tb[NL80211_ATTR_MAC])); - data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]); - } - if (tb[NL80211_ATTR_KEY_SEQ]) { - wpa_hexdump(MSG_DEBUG, "nl80211: TSC", - nla_data(tb[NL80211_ATTR_KEY_SEQ]), - nla_len(tb[NL80211_ATTR_KEY_SEQ])); - } - if (tb[NL80211_ATTR_KEY_TYPE]) { - enum nl80211_key_type key_type = - nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]); - wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type); - if (key_type == NL80211_KEYTYPE_PAIRWISE) - data.michael_mic_failure.unicast = 1; - } else - data.michael_mic_failure.unicast = 1; - - if (tb[NL80211_ATTR_KEY_IDX]) { - u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]); - wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id); - } - - wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data); -} - - -static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv, - struct nlattr *tb[]) -{ - if (tb[NL80211_ATTR_MAC] == NULL) { - wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined " - "event"); - return; - } - os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); - - drv->associated = 1; - wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined", - MAC2STR(drv->bssid)); - - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); -} - - -static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv, - int cancel_event, struct nlattr *tb[]) -{ - unsigned int freq, chan_type, duration; - union wpa_event_data data; - u64 cookie; - - if (tb[NL80211_ATTR_WIPHY_FREQ]) - freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); - else - freq = 0; - - if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) - chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); - else - chan_type = 0; - - if (tb[NL80211_ATTR_DURATION]) - duration = nla_get_u32(tb[NL80211_ATTR_DURATION]); - else - duration = 0; - - if (tb[NL80211_ATTR_COOKIE]) - cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); - else - cookie = 0; - - wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d " - "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))", - cancel_event, freq, chan_type, duration, - (long long unsigned int) cookie, - cookie == drv->remain_on_chan_cookie ? "match" : "unknown"); - - if (cookie != drv->remain_on_chan_cookie) - return; /* not for us */ - - if (cancel_event) - drv->pending_remain_on_chan = 0; - - os_memset(&data, 0, sizeof(data)); - data.remain_on_channel.freq = freq; - data.remain_on_channel.duration = duration; - wpa_supplicant_event(drv->ctx, cancel_event ? - EVENT_CANCEL_REMAIN_ON_CHANNEL : - EVENT_REMAIN_ON_CHANNEL, &data); -} - - -static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv, - struct nlattr *tb[]) -{ - union wpa_event_data data; - - os_memset(&data, 0, sizeof(data)); - - if (tb[NL80211_ATTR_IE]) { - data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]); - data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]); - } - - if (tb[NL80211_ATTR_IE_RIC]) { - data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]); - data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]); - } - - if (tb[NL80211_ATTR_MAC]) - os_memcpy(data.ft_ies.target_ap, - nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); - - wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR, - MAC2STR(data.ft_ies.target_ap)); - - wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data); -} - - -static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, - struct nlattr *tb[]) -{ - union wpa_event_data event; - struct nlattr *nl; - int rem; - struct scan_info *info; -#define MAX_REPORT_FREQS 50 - 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; - - if (tb[NL80211_ATTR_SCAN_SSIDS]) { - nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) { - struct wpa_driver_scan_ssid *s = - &info->ssids[info->num_ssids]; - s->ssid = nla_data(nl); - s->ssid_len = nla_len(nl); - wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'", - wpa_ssid_txt(s->ssid, s->ssid_len)); - info->num_ssids++; - if (info->num_ssids == WPAS_MAX_SCAN_SSIDS) - break; - } - } - if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { - char msg[200], *pos, *end; - int res; - - pos = msg; - end = pos + sizeof(msg); - *pos = '\0'; - - nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem) - { - freqs[num_freqs] = nla_get_u32(nl); - res = os_snprintf(pos, end - pos, " %d", - freqs[num_freqs]); - if (res > 0 && end - pos > res) - pos += res; - num_freqs++; - if (num_freqs == MAX_REPORT_FREQS - 1) - break; - } - info->freqs = freqs; - info->num_freqs = num_freqs; - wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s", - msg); - } - wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event); -} - - -static int get_link_signal(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_STA_INFO_MAX + 1]; - static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = { - [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, - [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 }, - }; - struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; - static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { - [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, - [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, - [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG }, - [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, - }; - struct wpa_signal_info *sig_change = arg; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - if (!tb[NL80211_ATTR_STA_INFO] || - nla_parse_nested(sinfo, NL80211_STA_INFO_MAX, - tb[NL80211_ATTR_STA_INFO], policy)) - return NL_SKIP; - if (!sinfo[NL80211_STA_INFO_SIGNAL]) - return NL_SKIP; - - sig_change->current_signal = - (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]); - - if (sinfo[NL80211_STA_INFO_SIGNAL_AVG]) - sig_change->avg_signal = - (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]); - else - sig_change->avg_signal = 0; - - if (sinfo[NL80211_STA_INFO_TX_BITRATE]) { - if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, - sinfo[NL80211_STA_INFO_TX_BITRATE], - rate_policy)) { - sig_change->current_txrate = 0; - } else { - if (rinfo[NL80211_RATE_INFO_BITRATE]) { - sig_change->current_txrate = - nla_get_u16(rinfo[ - NL80211_RATE_INFO_BITRATE]) * 100; - } - } - } - - return NL_SKIP; -} - - -static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv, - struct wpa_signal_info *sig) -{ - struct nl_msg *msg; - - sig->current_signal = -9999; - sig->current_txrate = 0; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - 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; -} - - -static int get_link_noise(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_signal_info *sig_change = arg; - - 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_FREQUENCY]) - return NL_SKIP; - - if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) != - sig_change->frequency) - return NL_SKIP; - - if (!sinfo[NL80211_SURVEY_INFO_NOISE]) - return NL_SKIP; - - sig_change->current_noise = - (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); - - return NL_SKIP; -} - - -static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv, - struct wpa_signal_info *sig_change) -{ - struct nl_msg *msg; - - sig_change->current_noise = 9999; - sig_change->frequency = drv->assoc_freq; - - 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_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; -} - - -static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv, - struct nlattr *tb[]) -{ - static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { - [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, - [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 }, - [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, - [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 }, - }; - struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1]; - enum nl80211_cqm_rssi_threshold_event event; - union wpa_event_data ed; - struct wpa_signal_info sig; - int res; - - if (tb[NL80211_ATTR_CQM] == NULL || - nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM], - cqm_policy)) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event"); - return; - } - - os_memset(&ed, 0, sizeof(ed)); - - if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) { - if (!tb[NL80211_ATTR_MAC]) - return; - os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]), - ETH_ALEN); - wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed); - return; - } - - if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL) - return; - event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]); - - if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) { - wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor " - "event: RSSI high"); - ed.signal_change.above_threshold = 1; - } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) { - wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor " - "event: RSSI low"); - ed.signal_change.above_threshold = 0; - } else - return; - - res = nl80211_get_link_signal(drv, &sig); - if (res == 0) { - ed.signal_change.current_signal = sig.current_signal; - ed.signal_change.current_txrate = sig.current_txrate; - wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d", - sig.current_signal, sig.current_txrate); - } - - res = nl80211_get_link_noise(drv, &sig); - if (res == 0) { - ed.signal_change.current_noise = sig.current_noise; - wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm", - sig.current_noise); - } - - wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed); -} - - -static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - u8 *addr; - union wpa_event_data data; - - if (tb[NL80211_ATTR_MAC] == NULL) - return; - addr = nla_data(tb[NL80211_ATTR_MAC]); - wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr)); - - if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { - u8 *ies = NULL; - size_t ies_len = 0; - if (tb[NL80211_ATTR_IE]) { - ies = nla_data(tb[NL80211_ATTR_IE]); - ies_len = nla_len(tb[NL80211_ATTR_IE]); - } - wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len); - drv_event_assoc(drv->ctx, addr, ies, ies_len, 0); - return; - } - - if (drv->nlmode != NL80211_IFTYPE_ADHOC) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN); - wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data); -} - - -static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - u8 *addr; - union wpa_event_data data; - - if (tb[NL80211_ATTR_MAC] == NULL) - return; - addr = nla_data(tb[NL80211_ATTR_MAC]); - wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR, - MAC2STR(addr)); - - if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { - drv_event_disassoc(drv->ctx, addr); - return; - } - - if (drv->nlmode != NL80211_IFTYPE_ADHOC) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN); - wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data); -} - - -static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - 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; - - 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; - - wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event"); - - 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); -} - - -static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - union wpa_event_data data; - - wpa_printf(MSG_DEBUG, "nl80211: Probe client event"); - - 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_tdls_oper_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - union wpa_event_data data; - - wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event"); - - if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION]) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); - switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) { - case NL80211_TDLS_SETUP: - wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer " - MACSTR, MAC2STR(data.tdls.peer)); - data.tdls.oper = TDLS_REQUEST_SETUP; - break; - case NL80211_TDLS_TEARDOWN: - wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer " - MACSTR, MAC2STR(data.tdls.peer)); - data.tdls.oper = TDLS_REQUEST_TEARDOWN; - break; - default: - wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione " - "event"); - return; - } - if (tb[NL80211_ATTR_REASON_CODE]) { - data.tdls.reason_code = - nla_get_u16(tb[NL80211_ATTR_REASON_CODE]); - } - - wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data); -} - - -static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL); -} - - -static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - union wpa_event_data data; - u32 reason; - - wpa_printf(MSG_DEBUG, "nl80211: Connect failed event"); - - if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON]) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.connect_failed_reason.addr, - nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); - - reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]); - switch (reason) { - case NL80211_CONN_FAIL_MAX_CLIENTS: - wpa_printf(MSG_DEBUG, "nl80211: Max client reached"); - data.connect_failed_reason.code = MAX_CLIENT_REACHED; - break; - case NL80211_CONN_FAIL_BLOCKED_CLIENT: - wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR - " tried to connect", - MAC2STR(data.connect_failed_reason.addr)); - data.connect_failed_reason.code = BLOCKED_CLIENT; - break; - default: - wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason " - "%u", reason); - return; - } - - wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data); -} - - -static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - union wpa_event_data data; - enum nl80211_radar_event event_type; - - if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT]) - return; - - os_memset(&data, 0, sizeof(data)); - data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); - event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]); - - /* Check HT params */ - if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - data.dfs_event.ht_enabled = 1; - data.dfs_event.chan_offset = 0; - - switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) { - case NL80211_CHAN_NO_HT: - data.dfs_event.ht_enabled = 0; - break; - case NL80211_CHAN_HT20: - break; - case NL80211_CHAN_HT40PLUS: - data.dfs_event.chan_offset = 1; - break; - case NL80211_CHAN_HT40MINUS: - data.dfs_event.chan_offset = -1; - break; - } - } - - /* Get VHT params */ - if (tb[NL80211_ATTR_CHANNEL_WIDTH]) - data.dfs_event.chan_width = - convert2width(nla_get_u32( - tb[NL80211_ATTR_CHANNEL_WIDTH])); - if (tb[NL80211_ATTR_CENTER_FREQ1]) - data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]); - if (tb[NL80211_ATTR_CENTER_FREQ2]) - data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]); - - wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz", - data.dfs_event.freq, data.dfs_event.ht_enabled, - data.dfs_event.chan_offset, data.dfs_event.chan_width, - data.dfs_event.cf1, data.dfs_event.cf2); - - switch (event_type) { - case NL80211_RADAR_DETECTED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data); - break; - case NL80211_RADAR_CAC_FINISHED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data); - break; - case NL80211_RADAR_CAC_ABORTED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data); - break; - case NL80211_RADAR_NOP_FINISHED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data); - break; - default: - wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d " - "received", event_type); - break; - } -} - - -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 qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv, - const u8 *data, size_t len) -{ - u32 i, count; - union wpa_event_data event; - struct wpa_freq_range *range = NULL; - const struct qca_avoid_freq_list *freq_range; - - freq_range = (const struct qca_avoid_freq_list *) data; - if (len < sizeof(freq_range->count)) - return; - - count = freq_range->count; - if (len < sizeof(freq_range->count) + - count * sizeof(struct qca_avoid_freq_range)) { - wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)", - (unsigned int) len); - return; - } - - if (count > 0) { - range = os_calloc(count, sizeof(struct wpa_freq_range)); - if (range == NULL) - return; - } - - os_memset(&event, 0, sizeof(event)); - for (i = 0; i < count; i++) { - unsigned int idx = event.freq_range.num; - range[idx].min = freq_range->range[i].start_freq; - range[idx].max = freq_range->range[i].end_freq; - wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u", - range[idx].min, range[idx].max); - if (range[idx].min > range[idx].max) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range"); - continue; - } - event.freq_range.num++; - } - event.freq_range.range = range; - - wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event); - - os_free(range); -} - - -static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, - u32 subcmd, u8 *data, size_t len) -{ - switch (subcmd) { - case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: - qca_nl80211_avoid_freq(drv, data, len); - break; - default: - wpa_printf(MSG_DEBUG, - "nl80211: Ignore unsupported QCA vendor event %u", - subcmd); - break; - } -} - - -static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - u32 vendor_id, subcmd, wiphy = 0; - int wiphy_idx; - u8 *data = NULL; - size_t len = 0; - - if (!tb[NL80211_ATTR_VENDOR_ID] || - !tb[NL80211_ATTR_VENDOR_SUBCMD]) - return; - - vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]); - subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]); - - if (tb[NL80211_ATTR_WIPHY]) - wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); - - wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u", - wiphy, vendor_id, subcmd); - - if (tb[NL80211_ATTR_VENDOR_DATA]) { - data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]); - len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]); - wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len); - } - - wiphy_idx = nl80211_get_wiphy_index(drv->first_bss); - if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)", - wiphy, wiphy_idx); - return; - } - - switch (vendor_id) { - case OUI_QCA: - nl80211_vendor_event_qca(drv, subcmd, data, len); - break; - default: - wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event"); - break; - } -} - - -static void do_process_drv_event(struct i802_bss *bss, int cmd, - struct nlattr **tb) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - union wpa_event_data data; - - wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s", - cmd, nl80211_command_to_string(cmd), bss->ifname); - - if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED && - (cmd == NL80211_CMD_NEW_SCAN_RESULTS || - cmd == NL80211_CMD_SCAN_ABORTED)) { - wpa_driver_nl80211_set_mode(drv->first_bss, - drv->ap_scan_as_station); - drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; - } - - switch (cmd) { - case NL80211_CMD_TRIGGER_SCAN: - wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger"); - drv->scan_state = SCAN_STARTED; - wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL); - break; - case NL80211_CMD_START_SCHED_SCAN: - wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started"); - drv->scan_state = SCHED_SCAN_STARTED; - break; - case NL80211_CMD_SCHED_SCAN_STOPPED: - wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped"); - drv->scan_state = SCHED_SCAN_STOPPED; - wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL); - break; - case NL80211_CMD_NEW_SCAN_RESULTS: - wpa_dbg(drv->ctx, MSG_DEBUG, - "nl80211: New scan results available"); - drv->scan_state = SCAN_COMPLETED; - drv->scan_complete_events = 1; - eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, - drv->ctx); - send_scan_event(drv, 0, tb); - break; - case NL80211_CMD_SCHED_SCAN_RESULTS: - wpa_dbg(drv->ctx, MSG_DEBUG, - "nl80211: New sched scan results available"); - drv->scan_state = SCHED_SCAN_RESULTS; - send_scan_event(drv, 0, tb); - break; - case NL80211_CMD_SCAN_ABORTED: - wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted"); - drv->scan_state = SCAN_ABORTED; - /* - * Need to indicate that scan results are available in order - * not to make wpa_supplicant stop its scanning. - */ - eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, - drv->ctx); - send_scan_event(drv, 1, tb); - break; - case NL80211_CMD_AUTHENTICATE: - case NL80211_CMD_ASSOCIATE: - case NL80211_CMD_DEAUTHENTICATE: - case NL80211_CMD_DISASSOCIATE: - case NL80211_CMD_FRAME_TX_STATUS: - case NL80211_CMD_UNPROT_DEAUTHENTICATE: - case NL80211_CMD_UNPROT_DISASSOCIATE: - mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME], - tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], - tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], - tb[NL80211_ATTR_COOKIE], - tb[NL80211_ATTR_RX_SIGNAL_DBM]); - break; - case NL80211_CMD_CONNECT: - case NL80211_CMD_ROAM: - 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_CH_SWITCH_NOTIFY: - mlme_event_ch_switch(drv, - tb[NL80211_ATTR_IFINDEX], - tb[NL80211_ATTR_WIPHY_FREQ], - tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE], - tb[NL80211_ATTR_CHANNEL_WIDTH], - tb[NL80211_ATTR_CENTER_FREQ1], - tb[NL80211_ATTR_CENTER_FREQ2]); - break; - case NL80211_CMD_DISCONNECT: - mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE], - tb[NL80211_ATTR_MAC], - tb[NL80211_ATTR_DISCONNECTED_BY_AP]); - break; - case NL80211_CMD_MICHAEL_MIC_FAILURE: - mlme_event_michael_mic_failure(bss, tb); - break; - case NL80211_CMD_JOIN_IBSS: - mlme_event_join_ibss(drv, tb); - break; - case NL80211_CMD_REMAIN_ON_CHANNEL: - mlme_event_remain_on_channel(drv, 0, tb); - break; - case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: - mlme_event_remain_on_channel(drv, 1, tb); - break; - case NL80211_CMD_NOTIFY_CQM: - nl80211_cqm_event(drv, tb); - break; - case NL80211_CMD_REG_CHANGE: - wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change"); - if (tb[NL80211_ATTR_REG_INITIATOR] == NULL) - break; - os_memset(&data, 0, sizeof(data)); - switch (nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])) { - case NL80211_REGDOM_SET_BY_CORE: - data.channel_list_changed.initiator = - REGDOM_SET_BY_CORE; - break; - case NL80211_REGDOM_SET_BY_USER: - data.channel_list_changed.initiator = - REGDOM_SET_BY_USER; - break; - case NL80211_REGDOM_SET_BY_DRIVER: - data.channel_list_changed.initiator = - REGDOM_SET_BY_DRIVER; - break; - case NL80211_REGDOM_SET_BY_COUNTRY_IE: - data.channel_list_changed.initiator = - REGDOM_SET_BY_COUNTRY_IE; - break; - default: - wpa_printf(MSG_DEBUG, "nl80211: Unknown reg change initiator %d received", - nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])); - break; - } - wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, - &data); - break; - case NL80211_CMD_REG_BEACON_HINT: - wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint"); - os_memset(&data, 0, sizeof(data)); - data.channel_list_changed.initiator = REGDOM_BEACON_HINT; - wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, - &data); - break; - case NL80211_CMD_NEW_STATION: - nl80211_new_station_event(drv, tb); - break; - 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; - case NL80211_CMD_TDLS_OPER: - nl80211_tdls_oper_event(drv, tb); - break; - case NL80211_CMD_CONN_FAILED: - nl80211_connect_failed_event(drv, tb); - break; - case NL80211_CMD_FT_EVENT: - mlme_event_ft_event(drv, tb); - break; - case NL80211_CMD_RADAR_DETECT: - nl80211_radar_event(drv, tb); - break; - case NL80211_CMD_STOP_AP: - nl80211_stop_ap(drv, tb); - break; - case NL80211_CMD_VENDOR: - nl80211_vendor_event(drv, tb); - break; - default: - wpa_dbg(drv->ctx, 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]; - struct i802_bss *bss; - 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]); - - for (bss = drv->first_bss; bss; bss = bss->next) - if (ifidx == -1 || ifidx == bss->ifindex) { - do_process_drv_event(bss, gnlh->cmd, tb); - return NL_SKIP; - } - wpa_printf(MSG_DEBUG, - "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d)", - gnlh->cmd, ifidx); - } else if (tb[NL80211_ATTR_WDEV]) { - u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]); - wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device"); - for (bss = drv->first_bss; bss; bss = bss->next) { - if (bss->wdev_id_set && wdev_id == bss->wdev_id) { - do_process_drv_event(bss, gnlh->cmd, tb); - return NL_SKIP; - } - } - wpa_printf(MSG_DEBUG, - "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)", - gnlh->cmd, (long long unsigned int) wdev_id); - } - - 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, *tmp; - int ifidx = -1; - struct i802_bss *bss; - u64 wdev_id = 0; - int wdev_id_set = 0; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (tb[NL80211_ATTR_IFINDEX]) - ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); - else if (tb[NL80211_ATTR_WDEV]) { - wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]); - wdev_id_set = 1; - } - - dl_list_for_each_safe(drv, tmp, &global->interfaces, - struct wpa_driver_nl80211_data, list) { - for (bss = drv->first_bss; bss; bss = bss->next) { - if ((ifidx == -1 && !wdev_id_set) || - ifidx == bss->ifindex || - (wdev_id_set && bss->wdev_id_set && - wdev_id == bss->wdev_id)) { - do_process_drv_event(bss, gnlh->cmd, tb); - return NL_SKIP; - } - } - } - - 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); - - wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s", - gnlh->cmd, nl80211_command_to_string(gnlh->cmd), - bss->ifname); - - switch (gnlh->cmd) { - case NL80211_CMD_FRAME: - case NL80211_CMD_FRAME_TX_STATUS: - mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME], - tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], - tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], - tb[NL80211_ATTR_COOKIE], - tb[NL80211_ATTR_RX_SIGNAL_DBM]); - 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); - break; - } - - return NL_SKIP; -} - - -static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx, - void *handle) -{ - struct nl_cb *cb = eloop_ctx; - int res; - - wpa_printf(MSG_MSGDUMP, "nl80211: Event message available"); - - res = nl_recvmsgs(handle, cb); - if (res) { - wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d", - __func__, res); - } -} - - -/** - * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain - * @priv: driver_nl80211 private data - * @alpha2_arg: country to which to switch to - * Returns: 0 on success, -1 on failure - * - * This asks nl80211 to set the regulatory domain for given - * country ISO / IEC alpha2. - */ -static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - char alpha2[3]; - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - alpha2[0] = alpha2_arg[0]; - alpha2[1] = alpha2_arg[1]; - alpha2[2] = '\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; -} - - -static int nl80211_get_country(struct nl_msg *msg, void *arg) -{ - char *alpha2 = arg; - struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - if (!tb_msg[NL80211_ATTR_REG_ALPHA2]) { - wpa_printf(MSG_DEBUG, "nl80211: No country information available"); - return NL_SKIP; - } - os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3); - return NL_SKIP; -} - - -static int wpa_driver_nl80211_get_country(void *priv, char *alpha2) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG); - alpha2[0] = '\0'; - ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2); - if (!alpha2[0]) - ret = -1; - - return ret; -} - - -static int protocol_feature_handler(struct nl_msg *msg, void *arg) -{ - u32 *feat = arg; - struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]) - *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]); - - return NL_SKIP; -} - - -static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv) -{ - u32 feat = 0; - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - goto nla_put_failure; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES); - if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0) - return feat; - - msg = NULL; -nla_put_failure: - nlmsg_free(msg); - return 0; -} - - -struct wiphy_info_data { - struct wpa_driver_nl80211_data *drv; - struct wpa_driver_capa *capa; - - unsigned int num_multichan_concurrent; - - 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; - unsigned int auth_supported:1; - unsigned int connect_supported:1; - unsigned int p2p_go_supported:1; - unsigned int p2p_client_supported:1; - unsigned int p2p_concurrent:1; - unsigned int channel_switch_supported:1; - unsigned int set_qos_map_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 void wiphy_info_supported_iftypes(struct wiphy_info_data *info, - struct nlattr *tb) -{ - struct nlattr *nl_mode; - int i; - - if (tb == NULL) - return; - - nla_for_each_nested(nl_mode, tb, i) { - switch (nla_type(nl_mode)) { - case NL80211_IFTYPE_AP: - info->capa->flags |= WPA_DRIVER_FLAGS_AP; - break; - case NL80211_IFTYPE_ADHOC: - info->capa->flags |= WPA_DRIVER_FLAGS_IBSS; - break; - case NL80211_IFTYPE_P2P_DEVICE: - info->capa->flags |= - WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE; - break; - case NL80211_IFTYPE_P2P_GO: - info->p2p_go_supported = 1; - break; - case NL80211_IFTYPE_P2P_CLIENT: - info->p2p_client_supported = 1; - break; - case NL80211_IFTYPE_MONITOR: - info->monitor_supported = 1; - break; - } - } -} - - -static int wiphy_info_iface_comb_process(struct wiphy_info_data *info, - struct nlattr *nl_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; - 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 }, - [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 }, - }, - iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = { - [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED }, - [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 }, - }; - - 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]) - return 0; /* broken combination */ - - if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS]) - info->capa->flags |= WPA_DRIVER_FLAGS_RADAR; - - 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]) - return 0; /* 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) { - info->p2p_concurrent = 1; - info->num_multichan_concurrent = - nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]); - return 1; - } - - return 0; -} - - -static void wiphy_info_iface_comb(struct wiphy_info_data *info, - struct nlattr *tb) -{ - struct nlattr *nl_combi; - int rem_combi; - - if (tb == NULL) - return; - - nla_for_each_nested(nl_combi, tb, rem_combi) { - if (wiphy_info_iface_comb_process(info, nl_combi) > 0) - break; - } -} - - -static void wiphy_info_supp_cmds(struct wiphy_info_data *info, - struct nlattr *tb) -{ - struct nlattr *nl_cmd; - int i; - - if (tb == NULL) - return; - - nla_for_each_nested(nl_cmd, tb, i) { - switch (nla_get_u32(nl_cmd)) { - case NL80211_CMD_AUTHENTICATE: - info->auth_supported = 1; - break; - case NL80211_CMD_CONNECT: - info->connect_supported = 1; - break; - case NL80211_CMD_START_SCHED_SCAN: - info->capa->sched_scan_supported = 1; - break; - case NL80211_CMD_PROBE_CLIENT: - info->poll_command_supported = 1; - break; - case NL80211_CMD_CHANNEL_SWITCH: - info->channel_switch_supported = 1; - break; - case NL80211_CMD_SET_QOS_MAP: - info->set_qos_map_supported = 1; - break; - } - } -} - - -static void wiphy_info_cipher_suites(struct wiphy_info_data *info, - struct nlattr *tb) -{ - int i, num; - u32 *ciphers; - - if (tb == NULL) - return; - - num = nla_len(tb) / sizeof(u32); - ciphers = nla_data(tb); - for (i = 0; i < num; i++) { - u32 c = ciphers[i]; - - wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d", - c >> 24, (c >> 16) & 0xff, - (c >> 8) & 0xff, c & 0xff); - switch (c) { - case WLAN_CIPHER_SUITE_CCMP_256: - info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256; - break; - case WLAN_CIPHER_SUITE_GCMP_256: - info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256; - break; - case WLAN_CIPHER_SUITE_CCMP: - info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP; - break; - case WLAN_CIPHER_SUITE_GCMP: - info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP; - break; - case WLAN_CIPHER_SUITE_TKIP: - info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP; - break; - case WLAN_CIPHER_SUITE_WEP104: - info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104; - break; - case WLAN_CIPHER_SUITE_WEP40: - info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40; - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_128: - info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_256: - info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256; - break; - case WLAN_CIPHER_SUITE_BIP_CMAC_256: - info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256; - break; - } - } -} - - -static void wiphy_info_max_roc(struct wpa_driver_capa *capa, - struct nlattr *tb) -{ - if (tb) - capa->max_remain_on_chan = nla_get_u32(tb); -} - - -static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls, - struct nlattr *ext_setup) -{ - if (tdls == NULL) - return; - - wpa_printf(MSG_DEBUG, "nl80211: TDLS supported"); - capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT; - - if (ext_setup) { - wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup"); - capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP; - } -} - - -static void wiphy_info_feature_flags(struct wiphy_info_data *info, - struct nlattr *tb) -{ - u32 flags; - struct wpa_driver_capa *capa = info->capa; - - if (tb == NULL) - return; - - flags = nla_get_u32(tb); - - if (flags & NL80211_FEATURE_SK_TX_STATUS) - info->data_tx_status = 1; - - if (flags & NL80211_FEATURE_INACTIVITY_TIMER) - capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER; - - if (flags & NL80211_FEATURE_SAE) - capa->flags |= WPA_DRIVER_FLAGS_SAE; - - if (flags & NL80211_FEATURE_NEED_OBSS_SCAN) - capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN; -} - - -static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa, - struct nlattr *tb) -{ - u32 protocols; - - if (tb == NULL) - return; - - protocols = nla_get_u32(tb); - 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); -} - - -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; - struct wpa_driver_capa *capa = info->capa; - struct wpa_driver_nl80211_data *drv = info->drv; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (tb[NL80211_ATTR_WIPHY_NAME]) - os_strlcpy(drv->phyname, - nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]), - sizeof(drv->phyname)); - if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) - capa->max_scan_ssids = - nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]); - - 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_MAC_ACL_MAX]) - capa->max_acl_mac_addrs = - nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]); - - wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]); - wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]); - wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]); - wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]); - - 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; - } - - wiphy_info_max_roc(capa, - tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]); - - if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD]) - capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD; - - wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT], - tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]); - - if (tb[NL80211_ATTR_DEVICE_AP_SME]) - info->device_ap_sme = 1; - - wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]); - wiphy_info_probe_resp_offload(capa, - tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]); - - if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] && - drv->extended_capa == NULL) { - drv->extended_capa = - os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA])); - if (drv->extended_capa) { - os_memcpy(drv->extended_capa, - nla_data(tb[NL80211_ATTR_EXT_CAPA]), - nla_len(tb[NL80211_ATTR_EXT_CAPA])); - drv->extended_capa_len = - nla_len(tb[NL80211_ATTR_EXT_CAPA]); - } - drv->extended_capa_mask = - os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA])); - if (drv->extended_capa_mask) { - os_memcpy(drv->extended_capa_mask, - nla_data(tb[NL80211_ATTR_EXT_CAPA]), - nla_len(tb[NL80211_ATTR_EXT_CAPA])); - } else { - os_free(drv->extended_capa); - drv->extended_capa = NULL; - drv->extended_capa_len = 0; - } - } - - if (tb[NL80211_ATTR_VENDOR_DATA]) { - struct nlattr *nl; - int rem; - - nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) { - struct nl80211_vendor_cmd_info *vinfo; - if (nla_len(nl) != sizeof(*vinfo)) { - wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info"); - continue; - } - vinfo = nla_data(nl); - wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u", - vinfo->vendor_id, vinfo->subcmd); - } - } - - if (tb[NL80211_ATTR_VENDOR_EVENTS]) { - struct nlattr *nl; - int rem; - - nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) { - struct nl80211_vendor_cmd_info *vinfo; - if (nla_len(nl) != sizeof(*vinfo)) { - wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info"); - continue; - } - vinfo = nla_data(nl); - wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u", - vinfo->vendor_id, vinfo->subcmd); - } - } - - return NL_SKIP; -} - - -static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv, - struct wiphy_info_data *info) -{ - u32 feat; - struct nl_msg *msg; - - os_memset(info, 0, sizeof(*info)); - info->capa = &drv->capa; - info->drv = drv; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - feat = get_nl80211_protocol_features(drv); - if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP) - nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY); - else - nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY); - - NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP); - if (nl80211_set_iface_id(msg, drv->first_bss) < 0) - goto nla_put_failure; - - if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info)) - return -1; - - 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"); - info->error = 1; - } - - if (info->p2p_go_supported && info->p2p_client_supported) - drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE; - if (info->p2p_concurrent) { - wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group " - "interface (driver advertised support)"); - drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; - drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; - } - if (info->num_multichan_concurrent > 1) { - wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel " - "concurrent (driver advertised support)"); - drv->capa.num_multichan_concurrent = - info->num_multichan_concurrent; - } - - /* default to 5000 since early versions of mac80211 don't set it */ - if (!drv->capa.max_remain_on_chan) - drv->capa.max_remain_on_chan = 5000; - - if (info->channel_switch_supported) - drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA; - - return 0; -nla_put_failure: - nlmsg_free(msg); - return -1; -} - - -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; - drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | - WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; - drv->capa.auth = WPA_DRIVER_AUTH_OPEN | - WPA_DRIVER_AUTH_SHARED | - WPA_DRIVER_AUTH_LEAP; - - 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; - - if (!info.device_ap_sme) { - drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS; - - /* - * No AP SME is currently assumed to also indicate no AP MLME - * in the driver/firmware. - */ - drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME; - } - - 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.set_qos_map_supported) - drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING; - - /* - * If poll command and tx status are supported, mac80211 is new enough - * to have everything we need to not need monitor interfaces. - */ - drv->use_monitor = !info.poll_command_supported || !info.data_tx_status; - - 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; - } - } - - /* - * 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; -} - - -#ifdef ANDROID -static int android_genl_ctrl_resolve(struct nl_handle *handle, - const char *name) -{ - /* - * 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; - - if (genl_ctrl_alloc_cache(handle, &cache) < 0) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " - "netlink cache"); - goto fail; - } - - nl80211 = genl_ctrl_search_by_name(cache, name); - if (nl80211 == NULL) - goto fail; - - id = genl_family_get_id(nl80211); - -fail: - if (nl80211) - genl_family_put(nl80211); - if (cache) - nl_cache_free(cache); - - return id; -} -#define genl_ctrl_resolve android_genl_ctrl_resolve -#endif /* ANDROID */ - - -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; - } - - 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 err; - } - - 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(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 err; - } - - ret = nl_get_multicast_id(global, "nl80211", "mlme"); - if (ret >= 0) - 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 err; - } - - ret = nl_get_multicast_id(global, "nl80211", "regulatory"); - if (ret >= 0) - 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)", - ret, strerror(-ret)); - /* Continue without regulatory events */ - } - - ret = nl_get_multicast_id(global, "nl80211", "vendor"); - if (ret >= 0) - ret = nl_socket_add_membership(global->nl_event, ret); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast " - "membership for vendor events: %d (%s)", - ret, strerror(-ret)); - /* Continue without vendor events */ - } - - 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); - - nl80211_register_eloop_read(&global->nl_event, - wpa_driver_nl80211_event_receive, - global->nl_cb); - - return 0; - -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"); - /* - * This may be for any interface; use ifdown event to disable - * interface. - */ -} - - -static void wpa_driver_nl80211_rfkill_unblocked(void *ctx) -{ - struct wpa_driver_nl80211_data *drv = ctx; - wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked"); - if (i802_set_iface_flags(drv->first_bss, 1)) { - wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP " - "after rfkill unblock"); - return; - } - /* rtnetlink ifup handler will report interface as enabled */ -} - - -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; - u8 control[512]; - 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; -} - - -static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname, - void *global_priv, int hostapd, - const u8 *set_addr) -{ - struct wpa_driver_nl80211_data *drv; - struct rfkill_config *rcfg; - struct i802_bss *bss; - - if (global_priv == NULL) - return NULL; - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - drv->global = global_priv; - drv->ctx = ctx; - drv->hostapd = !!hostapd; - drv->eapol_sock = -1; - drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); - drv->if_indices = drv->default_if_indices; - - drv->first_bss = os_zalloc(sizeof(*drv->first_bss)); - if (!drv->first_bss) { - os_free(drv); - return NULL; - } - bss = drv->first_bss; - bss->drv = drv; - bss->ctx = ctx; - - os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname)); - drv->monitor_ifidx = -1; - drv->monitor_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; - } - - if (nl80211_init_bss(bss)) - goto failed; - - rcfg = os_zalloc(sizeof(*rcfg)); - if (rcfg == NULL) - goto failed; - rcfg->ctx = drv; - os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname)); - rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked; - rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked; - drv->rfkill = rfkill_init(rcfg); - if (drv->rfkill == NULL) { - wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available"); - os_free(rcfg); - } - - if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0) - drv->start_iface_up = 1; - - if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1)) - goto failed; - - 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: - wpa_driver_nl80211_deinit(bss); - return NULL; -} - - -/** - * wpa_driver_nl80211_init - Initialize nl80211 driver interface - * @ctx: context to be used when calling wpa_supplicant functions, - * e.g., wpa_supplicant_event() - * @ifname: interface name, e.g., wlan0 - * @global_priv: private driver global data from global_init() - * Returns: Pointer to private data, %NULL on failure - */ -static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, - void *global_priv) -{ - return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL); -} - - -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; - char buf[30]; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - buf[0] = '\0'; - wpa_snprintf_hex(buf, sizeof(buf), match, match_len); - wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p match=%s", - type, nl_handle, buf); - - nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION); - - if (nl80211_set_iface_id(msg, bss) < 0) - goto nla_put_failure; - - NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type); - NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match); - - ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL); - msg = NULL; - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: Register frame command " - "failed (type=%u): ret=%d (%s)", - type, ret, strerror(-ret)); - wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match", - match, match_len); - goto nla_put_failure; - } - ret = 0; -nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -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; - - return 0; -} - - -static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss) -{ - nl80211_register_eloop_read(&bss->nl_mgmt, - wpa_driver_nl80211_event_receive, - bss->nl_cb); -} - - -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(bss, bss->nl_mgmt, - type, match, match_len); -} - - -static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - int ret = 0; - - 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 (drv->nlmode == NL80211_IFTYPE_ADHOC) { - u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4); - - /* register for any AUTH message */ - nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0); - } - -#ifdef CONFIG_INTERWORKING - /* QoS Map Configure */ - if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0) - ret = -1; -#endif /* CONFIG_INTERWORKING */ -#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) - /* GAS Initial Request */ - if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0) - ret = -1; - /* GAS Initial Response */ - if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0) - ret = -1; - /* GAS Comeback Request */ - if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0) - ret = -1; - /* GAS Comeback Response */ - if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0) - ret = -1; - /* Protected GAS Initial Request */ - if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0a", 2) < 0) - ret = -1; - /* Protected GAS Initial Response */ - if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0b", 2) < 0) - ret = -1; - /* Protected GAS Comeback Request */ - if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0c", 2) < 0) - ret = -1; - /* Protected GAS Comeback Response */ - if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0) - ret = -1; -#endif /* CONFIG_P2P || CONFIG_INTERWORKING */ -#ifdef CONFIG_P2P - /* P2P Public Action */ - if (nl80211_register_action_frame(bss, - (u8 *) "\x04\x09\x50\x6f\x9a\x09", - 6) < 0) - ret = -1; - /* P2P Action */ - if (nl80211_register_action_frame(bss, - (u8 *) "\x7f\x50\x6f\x9a\x09", - 5) < 0) - ret = -1; -#endif /* CONFIG_P2P */ -#ifdef CONFIG_IEEE80211W - /* SA Query Response */ - if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0) - ret = -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) - ret = -1; - } -#endif /* CONFIG_TDLS */ - - /* FT Action frames */ - if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0) - ret = -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) - ret = -1; - /* WNM-Sleep Mode Response */ - if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0) - ret = -1; - - nl80211_mgmt_handle_register_eloop(bss); - - return ret; -} - - -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 < ARRAY_SIZE(stypes); 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; - - nl80211_mgmt_handle_register_eloop(bss); - return 0; - -out_err: - 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; - - nl80211_mgmt_handle_register_eloop(bss); - return 0; - -out_err: - 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); - nl80211_destroy_eloop_handle(&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); -} - - -static void nl80211_del_p2pdev(struct i802_bss *bss) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret; - - msg = nlmsg_alloc(); - if (!msg) - return; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE); - NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - msg = NULL; - - wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s", - bss->ifname, (long long unsigned int) bss->wdev_id, - strerror(-ret)); - -nla_put_failure: - nlmsg_free(msg); -} - - -static int nl80211_set_p2pdev(struct i802_bss *bss, int start) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret = -1; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - if (start) - nl80211_cmd(drv, msg, 0, NL80211_CMD_START_P2P_DEVICE); - else - nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_P2P_DEVICE); - - NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - msg = NULL; - - wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s", - start ? "Start" : "Stop", - bss->ifname, (long long unsigned int) bss->wdev_id, - strerror(-ret)); - -nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -static int i802_set_iface_flags(struct i802_bss *bss, int up) -{ - enum nl80211_iftype nlmode; - - nlmode = nl80211_get_ifmode(bss); - if (nlmode != NL80211_IFTYPE_P2P_DEVICE) { - return linux_set_iface_flags(bss->drv->global->ioctl_sock, - bss->ifname, up); - } - - /* P2P Device has start/stop which is equivalent */ - return nl80211_set_p2pdev(bss, up); -} - - -static int -wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, - const u8 *set_addr, int first) -{ - struct i802_bss *bss = drv->first_bss; - int send_rfkill_event = 0; - enum nl80211_iftype nlmode; - - drv->ifindex = if_nametoindex(bss->ifname); - bss->ifindex = drv->ifindex; - bss->wdev_id = drv->global->if_add_wdevid; - bss->wdev_id_set = drv->global->if_add_wdevid_set; - - bss->if_dynamic = drv->ifindex == drv->global->if_add_ifindex; - bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set; - drv->global->if_add_wdevid_set = 0; - - if (wpa_driver_nl80211_capa(drv)) - return -1; - - wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s", - bss->ifname, drv->phyname); - - if (set_addr && - (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) || - linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, - set_addr))) - return -1; - - if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP) - drv->start_mode_ap = 1; - - if (drv->hostapd) - nlmode = NL80211_IFTYPE_AP; - else if (bss->if_dynamic) - nlmode = nl80211_get_ifmode(bss); - else - nlmode = NL80211_IFTYPE_STATION; - - if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) { - wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode"); - return -1; - } - - if (nlmode == NL80211_IFTYPE_P2P_DEVICE) { - int ret = nl80211_set_p2pdev(bss, 1); - if (ret < 0) - wpa_printf(MSG_ERROR, "nl80211: Could not start P2P device"); - nl80211_get_macaddr(bss); - return ret; - } - - if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) { - if (rfkill_is_blocked(drv->rfkill)) { - wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable " - "interface '%s' due to rfkill", - bss->ifname); - drv->if_disabled = 1; - send_rfkill_event = 1; - } else { - wpa_printf(MSG_ERROR, "nl80211: Could not set " - "interface '%s' UP", bss->ifname); - return -1; - } - } - - if (!drv->hostapd) - netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, - 1, IF_OPER_DORMANT); - - if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, - bss->addr)) - return -1; - - if (send_rfkill_event) { - eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill, - drv, drv->ctx); - } - - return 0; -} - - -static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv) -{ - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)", - drv->ifindex); - 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; -} - - -/** - * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface - * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init() - * - * Shut down driver interface and processing of driver events. Free - * private data buffer if one was allocated in wpa_driver_nl80211_init(). - */ -static void wpa_driver_nl80211_deinit(struct i802_bss *bss) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - - bss->in_deinit = 1; - if (drv->data_tx_status) - eloop_unregister_read_sock(drv->eapol_tx_sock); - if (drv->eapol_tx_sock >= 0) - 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->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->global->ioctl_sock, bss->brname) < 0) - wpa_printf(MSG_INFO, "nl80211: Failed to remove " - "bridge %s: %s", - bss->brname, strerror(errno)); - } - - nl80211_remove_monitor_interface(drv); - - if (is_ap_interface(drv->nlmode)) - wpa_driver_nl80211_del_beacon(drv); - - if (drv->eapol_sock >= 0) { - eloop_unregister_read_sock(drv->eapol_sock); - close(drv->eapol_sock); - } - - if (drv->if_indices != drv->default_if_indices) - os_free(drv->if_indices); - - if (drv->disabled_11b_rates) - nl80211_disable_11b_rates(drv, drv->ifindex, 0); - - 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); - - if (!drv->start_iface_up) - (void) i802_set_iface_flags(bss, 0); - if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) { - if (!drv->hostapd || !drv->start_mode_ap) - wpa_driver_nl80211_set_mode(bss, - NL80211_IFTYPE_STATION); - nl80211_mgmt_unsubscribe(bss, "deinit"); - } else { - nl80211_mgmt_unsubscribe(bss, "deinit"); - nl80211_del_p2pdev(bss); - } - nl_cb_put(drv->nl_cb); - - nl80211_destroy_bss(drv->first_bss); - - os_free(drv->filter_ssids); - - os_free(drv->auth_ie); - - if (drv->in_interface_list) - dl_list_del(&drv->list); - - os_free(drv->extended_capa); - os_free(drv->extended_capa_mask); - os_free(drv->first_bss); - os_free(drv); -} - - -/** - * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion - * @eloop_ctx: Driver private data - * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init() - * - * This function can be used as registered timeout when starting a scan to - * generate a scan completed event if the driver does not report this. - */ -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 != NL80211_IFTYPE_UNSPECIFIED) { - wpa_driver_nl80211_set_mode(drv->first_bss, - 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); -} - - -static struct nl_msg * -nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd, - struct wpa_driver_scan_params *params, u64 *wdev_id) -{ - struct nl_msg *msg; - size_t i; - - msg = nlmsg_alloc(); - if (!msg) - return NULL; - - nl80211_cmd(drv, msg, 0, cmd); - - if (!wdev_id) - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - else - NLA_PUT_U64(msg, NL80211_ATTR_WDEV, *wdev_id); - - if (params->num_ssids) { - struct nlattr *ssids; - - ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS); - if (ssids == NULL) - goto fail; - for (i = 0; i < params->num_ssids; i++) { - wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID", - params->ssids[i].ssid, - params->ssids[i].ssid_len); - if (nla_put(msg, i + 1, params->ssids[i].ssid_len, - params->ssids[i].ssid) < 0) - goto fail; - } - nla_nest_end(msg, ssids); - } - - if (params->extra_ies) { - wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs", - params->extra_ies, params->extra_ies_len); - if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len, - params->extra_ies) < 0) - goto fail; - } - - if (params->freqs) { - struct nlattr *freqs; - freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); - if (freqs == NULL) - goto fail; - for (i = 0; params->freqs[i]; i++) { - wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u " - "MHz", params->freqs[i]); - if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0) - goto fail; - } - nla_nest_end(msg, freqs); - } - - os_free(drv->filter_ssids); - drv->filter_ssids = params->filter_ssids; - params->filter_ssids = NULL; - drv->num_filter_ssids = params->num_filter_ssids; - - if (params->only_new_results) { - wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH"); - NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, - NL80211_SCAN_FLAG_FLUSH); - } - - return msg; - -fail: -nla_put_failure: - nlmsg_free(msg); - return NULL; -} - - -/** - * wpa_driver_nl80211_scan - Request the driver to initiate scan - * @bss: Pointer to private driver data from wpa_driver_nl80211_init() - * @params: Scan parameters - * Returns: 0 on success, -1 on failure - */ -static int wpa_driver_nl80211_scan(struct i802_bss *bss, - struct wpa_driver_scan_params *params) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - int ret = -1, timeout; - struct nl_msg *msg = NULL; - - wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request"); - drv->scan_for_auth = 0; - - msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params, - bss->wdev_id_set ? &bss->wdev_id : NULL); - if (!msg) - return -1; - - if (params->p2p_probe) { - struct nlattr *rates; - - wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates"); - - rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES); - if (rates == NULL) - goto nla_put_failure; - - /* - * 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(msg, NL80211_BAND_2GHZ, 8, - "\x0c\x12\x18\x24\x30\x48\x60\x6c"); - nla_nest_end(msg, 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)); - if (drv->hostapd && 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, NL80211_IFTYPE_STATION)) - goto nla_put_failure; - - if (wpa_driver_nl80211_scan(bss, params)) { - wpa_driver_nl80211_set_mode(bss, drv->nlmode); - goto nla_put_failure; - } - - /* Restore AP mode when processing scan results */ - drv->ap_scan_as_station = drv->nlmode; - ret = 0; - } else - goto nla_put_failure; - } - - drv->scan_state = SCAN_REQUESTED; - /* Not all drivers generate "scan completed" wireless event, so try to - * read results after a timeout. */ - timeout = 10; - if (drv->scan_complete_events) { - /* - * The driver seems to deliver events to notify when scan is - * complete, so use longer timeout to avoid race conditions - * with scanning and following association request. - */ - timeout = 30; - } - wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " - "seconds", ret, timeout); - eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); - eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout, - drv, drv->ctx); - -nla_put_failure: - nlmsg_free(msg); - 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 = -1; - struct nl_msg *msg; - size_t i; - - wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request"); - -#ifdef ANDROID - if (!drv->capa.sched_scan_supported) - return android_pno_start(bss, params); -#endif /* ANDROID */ - - msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params, - bss->wdev_id_set ? &bss->wdev_id : NULL); - if (!msg) - goto nla_put_failure; - - 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) || - params->filter_rssi) { - struct nlattr *match_sets; - match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH); - if (match_sets == NULL) - goto nla_put_failure; - - for (i = 0; i < drv->num_filter_ssids; i++) { - struct nlattr *match_set_ssid; - wpa_hexdump_ascii(MSG_MSGDUMP, - "nl80211: Sched scan filter SSID", - drv->filter_ssids[i].ssid, - drv->filter_ssids[i].ssid_len); - - match_set_ssid = nla_nest_start(msg, i + 1); - if (match_set_ssid == NULL) - goto nla_put_failure; - NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID, - drv->filter_ssids[i].ssid_len, - drv->filter_ssids[i].ssid); - if (params->filter_rssi) - NLA_PUT_U32(msg, - NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, - params->filter_rssi); - - nla_nest_end(msg, match_set_ssid); - } - - /* - * Due to backward compatibility code, newer kernels treat this - * matchset (with only an RSSI filter) as the default for all - * other matchsets, unless it's the only one, in which case the - * matchset will actually allow all SSIDs above the RSSI. - */ - if (params->filter_rssi) { - struct nlattr *match_set_rssi; - match_set_rssi = nla_nest_start(msg, 0); - if (match_set_rssi == NULL) - goto nla_put_failure; - NLA_PUT_U32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, - params->filter_rssi); - wpa_printf(MSG_MSGDUMP, - "nl80211: Sched scan RSSI filter %d dBm", - params->filter_rssi); - nla_nest_end(msg, match_set_rssi); - } - - nla_nest_end(msg, match_sets); - } - - 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(msg); - 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; -} - - -static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie) -{ - const u8 *end, *pos; - - if (ies == NULL) - return NULL; - - pos = ies; - end = ies + ies_len; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == ie) - return pos; - pos += 2 + pos[1]; - } - - return NULL; -} - - -static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv, - const u8 *ie, size_t ie_len) -{ - const u8 *ssid; - size_t i; - - if (drv->filter_ssids == NULL) - return 0; - - ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID); - if (ssid == NULL) - return 1; - - for (i = 0; i < drv->num_filter_ssids; i++) { - if (ssid[1] == drv->filter_ssids[i].ssid_len && - os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) == - 0) - return 0; - } - - return 1; -} - - -static int bss_info_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct nlattr *bss[NL80211_BSS_MAX + 1]; - static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { - [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC }, - [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, - [NL80211_BSS_TSF] = { .type = NLA_U64 }, - [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, - [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, - [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC }, - [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, - [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, - [NL80211_BSS_STATUS] = { .type = NLA_U32 }, - [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 }, - [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC }, - }; - struct nl80211_bss_info_arg *_arg = arg; - struct wpa_scan_results *res = _arg->res; - struct wpa_scan_res **tmp; - struct wpa_scan_res *r; - const u8 *ie, *beacon_ie; - size_t ie_len, beacon_ie_len; - u8 *pos; - size_t i; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - if (!tb[NL80211_ATTR_BSS]) - return NL_SKIP; - if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], - bss_policy)) - return NL_SKIP; - if (bss[NL80211_BSS_STATUS]) { - enum nl80211_bss_status status; - status = nla_get_u32(bss[NL80211_BSS_STATUS]); - if (status == NL80211_BSS_STATUS_ASSOCIATED && - bss[NL80211_BSS_FREQUENCY]) { - _arg->assoc_freq = - nla_get_u32(bss[NL80211_BSS_FREQUENCY]); - 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; - if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) { - ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]); - ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]); - } else { - ie = NULL; - ie_len = 0; - } - if (bss[NL80211_BSS_BEACON_IES]) { - beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]); - beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]); - } else { - beacon_ie = NULL; - beacon_ie_len = 0; - } - - if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie, - ie ? ie_len : beacon_ie_len)) - return NL_SKIP; - - r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len); - if (r == NULL) - return NL_SKIP; - if (bss[NL80211_BSS_BSSID]) - os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]), - ETH_ALEN); - if (bss[NL80211_BSS_FREQUENCY]) - r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); - if (bss[NL80211_BSS_BEACON_INTERVAL]) - r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]); - if (bss[NL80211_BSS_CAPABILITY]) - r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]); - r->flags |= WPA_SCAN_NOISE_INVALID; - if (bss[NL80211_BSS_SIGNAL_MBM]) { - r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]); - r->level /= 100; /* mBm to dBm */ - 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_QUAL_INVALID; - } else - r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID; - if (bss[NL80211_BSS_TSF]) - r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]); - if (bss[NL80211_BSS_SEEN_MS_AGO]) - r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]); - r->ie_len = ie_len; - pos = (u8 *) (r + 1); - if (ie) { - os_memcpy(pos, ie, ie_len); - pos += ie_len; - } - r->beacon_ie_len = beacon_ie_len; - if (beacon_ie) - os_memcpy(pos, beacon_ie, beacon_ie_len); - - if (bss[NL80211_BSS_STATUS]) { - enum nl80211_bss_status status; - status = nla_get_u32(bss[NL80211_BSS_STATUS]); - switch (status) { - case NL80211_BSS_STATUS_AUTHENTICATED: - r->flags |= WPA_SCAN_AUTHENTICATED; - break; - case NL80211_BSS_STATUS_ASSOCIATED: - r->flags |= WPA_SCAN_ASSOCIATED; - break; - default: - break; - } - } - - /* - * cfg80211 maintains separate BSS table entries for APs if the same - * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does - * not use frequency as a separate key in the BSS table, so filter out - * duplicated entries. Prefer associated BSS entry in such a case in - * order to get the correct frequency into the BSS table. Similarly, - * prefer newer entries over older. - */ - for (i = 0; i < res->num; i++) { - const u8 *s1, *s2; - if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0) - continue; - - s1 = nl80211_get_ie((u8 *) (res->res[i] + 1), - res->res[i]->ie_len, WLAN_EID_SSID); - s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID); - if (s1 == NULL || s2 == NULL || s1[1] != s2[1] || - os_memcmp(s1, s2, 2 + s1[1]) != 0) - continue; - - /* Same BSSID,SSID was already included in scan results */ - wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result " - "for " MACSTR, MAC2STR(r->bssid)); - - if (((r->flags & WPA_SCAN_ASSOCIATED) && - !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) || - r->age < res->res[i]->age) { - os_free(res->res[i]); - res->res[i] = r; - } else - os_free(r); - return NL_SKIP; - } - - tmp = os_realloc_array(res->res, res->num + 1, - sizeof(struct wpa_scan_res *)); - if (tmp == NULL) { - os_free(r); - return NL_SKIP; - } - tmp[res->num++] = r; - res->res = tmp; - - return NL_SKIP; -} - - -static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv, - const u8 *addr) -{ - if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { - wpa_printf(MSG_DEBUG, "nl80211: Clear possible state " - "mismatch (" MACSTR ")", MAC2STR(addr)); - wpa_driver_nl80211_mlme(drv, addr, - NL80211_CMD_DEAUTHENTICATE, - WLAN_REASON_PREV_AUTH_NOT_VALID, 1); - } -} - - -static void wpa_driver_nl80211_check_bss_status( - struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res) -{ - size_t i; - - for (i = 0; i < res->num; i++) { - struct wpa_scan_res *r = res->res[i]; - if (r->flags & WPA_SCAN_AUTHENTICATED) { - wpa_printf(MSG_DEBUG, "nl80211: Scan results " - "indicates BSS status with " MACSTR - " as authenticated", - MAC2STR(r->bssid)); - 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) { - wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID" - " in local state (auth=" MACSTR - " assoc=" MACSTR ")", - MAC2STR(drv->auth_bssid), - MAC2STR(drv->bssid)); - clear_state_mismatch(drv, r->bssid); - } - } - - if (r->flags & WPA_SCAN_ASSOCIATED) { - wpa_printf(MSG_DEBUG, "nl80211: Scan results " - "indicate BSS status with " MACSTR - " as associated", - MAC2STR(r->bssid)); - 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 (is_sta_interface(drv->nlmode) && - os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != - 0) { - wpa_printf(MSG_DEBUG, "nl80211: Local state " - "(associated with " MACSTR ") does " - "not match with BSS state", - MAC2STR(drv->bssid)); - clear_state_mismatch(drv, r->bssid); - clear_state_mismatch(drv, drv->bssid); - } - } - } -} - - -static struct wpa_scan_results * -nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) -{ - struct nl_msg *msg; - struct wpa_scan_results *res; - int ret; - struct nl80211_bss_info_arg arg; - - res = os_zalloc(sizeof(*res)); - if (res == NULL) - return NULL; - msg = nlmsg_alloc(); - if (!msg) - goto nla_put_failure; - - nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); - if (nl80211_set_iface_id(msg, drv->first_bss) < 0) - goto nla_put_failure; - - arg.drv = drv; - arg.res = res; - ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); - msg = NULL; - if (ret == 0) { - 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 " - "(%s)", ret, strerror(-ret)); -nla_put_failure: - nlmsg_free(msg); - wpa_scan_results_free(res); - return NULL; -} - - -/** - * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results - * @priv: Pointer to private wext data from wpa_driver_nl80211_init() - * Returns: Scan results on success, -1 on failure - */ -static struct wpa_scan_results * -wpa_driver_nl80211_get_scan_results(void *priv) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct wpa_scan_results *res; - - res = nl80211_get_scan_results(drv); - if (res) - wpa_driver_nl80211_check_bss_status(drv, res); - return res; -} - - -static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv) -{ - struct wpa_scan_results *res; - size_t i; - - res = nl80211_get_scan_results(drv); - if (res == NULL) { - wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results"); - return; - } - - wpa_printf(MSG_DEBUG, "nl80211: Scan result dump"); - for (i = 0; i < res->num; i++) { - struct wpa_scan_res *r = res->res[i]; - wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s", - (int) i, (int) res->num, MAC2STR(r->bssid), - r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "", - r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : ""); - } - - wpa_scan_results_free(res); -} - - -static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len) -{ - switch (alg) { - case WPA_ALG_WEP: - if (key_len == 5) - return WLAN_CIPHER_SUITE_WEP40; - return WLAN_CIPHER_SUITE_WEP104; - case WPA_ALG_TKIP: - return WLAN_CIPHER_SUITE_TKIP; - case WPA_ALG_CCMP: - return WLAN_CIPHER_SUITE_CCMP; - case WPA_ALG_GCMP: - return WLAN_CIPHER_SUITE_GCMP; - case WPA_ALG_CCMP_256: - return WLAN_CIPHER_SUITE_CCMP_256; - case WPA_ALG_GCMP_256: - return WLAN_CIPHER_SUITE_GCMP_256; - case WPA_ALG_IGTK: - return WLAN_CIPHER_SUITE_AES_CMAC; - case WPA_ALG_BIP_GMAC_128: - return WLAN_CIPHER_SUITE_BIP_GMAC_128; - case WPA_ALG_BIP_GMAC_256: - return WLAN_CIPHER_SUITE_BIP_GMAC_256; - case WPA_ALG_BIP_CMAC_256: - return WLAN_CIPHER_SUITE_BIP_CMAC_256; - case WPA_ALG_SMS4: - return WLAN_CIPHER_SUITE_SMS4; - case WPA_ALG_KRK: - return WLAN_CIPHER_SUITE_KRK; - case WPA_ALG_NONE: - case WPA_ALG_PMK: - wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d", - alg); - return 0; - } - - wpa_printf(MSG_ERROR, "nl80211: Unsupported encryption algorithm %d", - alg); - return 0; -} - - -static u32 wpa_cipher_to_cipher_suite(unsigned int cipher) -{ - switch (cipher) { - case WPA_CIPHER_CCMP_256: - return WLAN_CIPHER_SUITE_CCMP_256; - case WPA_CIPHER_GCMP_256: - return WLAN_CIPHER_SUITE_GCMP_256; - case WPA_CIPHER_CCMP: - return WLAN_CIPHER_SUITE_CCMP; - case WPA_CIPHER_GCMP: - return WLAN_CIPHER_SUITE_GCMP; - case WPA_CIPHER_TKIP: - return WLAN_CIPHER_SUITE_TKIP; - case WPA_CIPHER_WEP104: - return WLAN_CIPHER_SUITE_WEP104; - case WPA_CIPHER_WEP40: - return WLAN_CIPHER_SUITE_WEP40; - } - - return 0; -} - - -static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[], - int max_suites) -{ - int num_suites = 0; - - if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP_256) - suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP_256; - if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP_256) - suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP_256; - if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP) - suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP; - if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP) - suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP; - if (num_suites < max_suites && ciphers & WPA_CIPHER_TKIP) - suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP; - if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP104) - suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104; - if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP40) - suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40; - - return num_suites; -} - - -static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, - 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_nl80211_data *drv = bss->drv; - int ifindex; - struct nl_msg *msg; - int ret; - int tdls = 0; - - /* Ignore for P2P Device */ - if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) - return 0; - - ifindex = if_nametoindex(ifname); - wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d " - "set_tx=%d seq_len=%lu key_len=%lu", - __func__, ifindex, ifname, alg, addr, key_idx, set_tx, - (unsigned long) seq_len, (unsigned long) key_len); -#ifdef CONFIG_TDLS - if (key_idx == -1) { - key_idx = 0; - tdls = 1; - } -#endif /* CONFIG_TDLS */ - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - if (alg == WPA_ALG_NONE) { - nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY); - } else { - nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY); - NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - wpa_alg_to_cipher_suite(alg, key_len)); - } - - if (seq && seq_len) - NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq); - - if (addr && !is_broadcast_ether_addr(addr)) { - wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - - if (alg != WPA_ALG_WEP && key_idx && !set_tx) { - wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK"); - NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, - NL80211_KEYTYPE_GROUP); - } - } else if (addr && is_broadcast_ether_addr(addr)) { - struct nlattr *types; - - wpa_printf(MSG_DEBUG, " broadcast key"); - - types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES); - if (!types) - goto nla_put_failure; - NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST); - nla_nest_end(msg, types); - } - NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE) - ret = 0; - if (ret) - wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)", - ret, strerror(-ret)); - - /* - * If we failed or don't need to set the default TX key (below), - * we're done here. - */ - if (ret || !set_tx || alg == WPA_ALG_NONE || tdls) - return ret; - if (is_ap_interface(drv->nlmode) && addr && - !is_broadcast_ether_addr(addr)) - return ret; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - 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) - NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT); - else - NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); - if (addr && is_broadcast_ether_addr(addr)) { - struct nlattr *types; - - types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES); - if (!types) - goto nla_put_failure; - NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST); - nla_nest_end(msg, types); - } else if (addr) { - struct nlattr *types; - - types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES); - if (!types) - goto nla_put_failure; - NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST); - nla_nest_end(msg, types); - } - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret == -ENOENT) - ret = 0; - if (ret) - wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; " - "err=%d %s)", ret, strerror(-ret)); - return ret; - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} - - -static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg, - int key_idx, int defkey, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) -{ - struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY); - if (!key_attr) - return -1; - - if (defkey && alg == WPA_ALG_IGTK) - NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT); - else if (defkey) - NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); - - NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx); - - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, - wpa_alg_to_cipher_suite(alg, key_len)); - - if (seq && seq_len) - NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq); - - NLA_PUT(msg, NL80211_KEY_DATA, key_len, key); - - nla_nest_end(msg, key_attr); - - return 0; - nla_put_failure: - return -1; -} - - -static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params, - struct nl_msg *msg) -{ - int i, privacy = 0; - struct nlattr *nl_keys, *nl_key; - - for (i = 0; i < 4; i++) { - if (!params->wep_key[i]) - continue; - privacy = 1; - break; - } - if (params->wps == WPS_MODE_PRIVACY) - privacy = 1; - if (params->pairwise_suite && - params->pairwise_suite != WPA_CIPHER_NONE) - privacy = 1; - - if (!privacy) - return 0; - - NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); - - nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS); - if (!nl_keys) - goto nla_put_failure; - - for (i = 0; i < 4; i++) { - if (!params->wep_key[i]) - continue; - - nl_key = nla_nest_start(msg, i); - if (!nl_key) - goto nla_put_failure; - - NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i], - params->wep_key[i]); - if (params->wep_key_len[i] == 5) - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, - WLAN_CIPHER_SUITE_WEP40); - else - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, - WLAN_CIPHER_SUITE_WEP104); - - NLA_PUT_U8(msg, NL80211_KEY_IDX, i); - - if (i == params->wep_tx_keyidx) - NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); - - nla_nest_end(msg, nl_key); - } - nla_nest_end(msg, nl_keys); - - return 0; - -nla_put_failure: - return -ENOBUFS; -} - - -static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, - const u8 *addr, int cmd, u16 reason_code, - int local_state_change) -{ - int ret = -1; - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - 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); - if (addr) - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - if (local_state_change) - NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - msg = NULL; - if (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; - -nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv, - int reason_code) -{ - int ret; - - wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code); - nl80211_mark_disconnected(drv); - /* Disconnect command doesn't need BSSID - it uses cached value */ - ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT, - reason_code, 0); - /* - * For locally generated disconnect, supplicant already generates a - * DEAUTH event, so ignore the event from NL80211. - */ - drv->ignore_next_local_disconnect = ret == 0; - - return ret; -} - - -static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss, - const u8 *addr, int reason_code) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) - return wpa_driver_nl80211_disconnect(drv, reason_code); - wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)", - __func__, MAC2STR(addr), reason_code); - nl80211_mark_disconnected(drv); - if (drv->nlmode == NL80211_IFTYPE_ADHOC) - return nl80211_leave_ibss(drv); - return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE, - reason_code, 0); -} - - -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( - struct i802_bss *bss, struct wpa_driver_auth_params *params) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - 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; - - nl80211_mark_disconnected(drv); - os_memset(drv->auth_bssid, 0, ETH_ALEN); - if (params->bssid) - os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN); - else - os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN); - /* FIX: IBSS mode */ - nlmode = params->p2p ? - NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION; - if (drv->nlmode != nlmode && - wpa_driver_nl80211_set_mode(bss, nlmode) < 0) - return -1; - -retry: - msg = nlmsg_alloc(); - if (!msg) - return -1; - - wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)", - drv->ifindex); - - nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE); - - for (i = 0; i < 4; i++) { - if (!params->wep_key[i]) - continue; - wpa_driver_nl80211_set_key(bss->ifname, bss, WPA_ALG_WEP, - NULL, i, - i == params->wep_tx_keyidx, NULL, 0, - params->wep_key[i], - params->wep_key_len[i]); - if (params->wep_tx_keyidx != i) - continue; - if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0, - params->wep_key[i], params->wep_key_len[i])) { - nlmsg_free(msg); - return -1; - } - } - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - if (params->bssid) { - wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, - MAC2STR(params->bssid)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); - } - if (params->freq) { - wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); - } - if (params->ssid) { - wpa_hexdump_ascii(MSG_DEBUG, " * SSID", - params->ssid, params->ssid_len); - NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, - params->ssid); - } - wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len); - if (params->ie) - NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie); - if (params->sae_data) { - wpa_hexdump(MSG_DEBUG, " * SAE data", params->sae_data, - params->sae_data_len); - NLA_PUT(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len, - params->sae_data); - } - if (params->auth_alg & WPA_AUTH_ALG_OPEN) - type = NL80211_AUTHTYPE_OPEN_SYSTEM; - else if (params->auth_alg & WPA_AUTH_ALG_SHARED) - type = NL80211_AUTHTYPE_SHARED_KEY; - else if (params->auth_alg & WPA_AUTH_ALG_LEAP) - type = NL80211_AUTHTYPE_NETWORK_EAP; - else if (params->auth_alg & WPA_AUTH_ALG_FT) - type = NL80211_AUTHTYPE_FT; - else if (params->auth_alg & WPA_AUTH_ALG_SAE) - type = NL80211_AUTHTYPE_SAE; - else - goto nla_put_failure; - wpa_printf(MSG_DEBUG, " * Auth Type %d", type); - NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); - if (params->local_state_change) { - wpa_printf(MSG_DEBUG, " * Local state change only"); - NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE); - } - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - msg = NULL; - if (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) { - /* - * mac80211 does not currently accept new - * authentication if we are already authenticated. As a - * workaround, force deauthentication and try again. - */ - wpa_printf(MSG_DEBUG, "nl80211: Retry authentication " - "after forced deauthentication"); - wpa_driver_nl80211_deauthenticate( - bss, params->bssid, - WLAN_REASON_PREV_AUTH_NOT_VALID); - 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; - wpa_printf(MSG_DEBUG, "nl80211: Authentication request send " - "successfully"); - -nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -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(¶ms, 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, ¶ms); -} - - -struct phy_info_arg { - u16 *num_modes; - struct hostapd_hw_modes *modes; - int last_mode, last_chan_idx; -}; - -static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa, - struct nlattr *ampdu_factor, - struct nlattr *ampdu_density, - struct nlattr *mcs_set) -{ - if (capa) - mode->ht_capab = nla_get_u16(capa); - - if (ampdu_factor) - mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03; - - if (ampdu_density) - mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2; - - if (mcs_set && nla_len(mcs_set) >= 16) { - u8 *mcs; - mcs = nla_data(mcs_set); - os_memcpy(mode->mcs_set, mcs, 16); - } -} - - -static void phy_info_vht_capa(struct hostapd_hw_modes *mode, - struct nlattr *capa, - struct nlattr *mcs_set) -{ - if (capa) - mode->vht_capab = nla_get_u32(capa); - - if (mcs_set && nla_len(mcs_set) >= 8) { - u8 *mcs; - mcs = nla_data(mcs_set); - os_memcpy(mode->vht_mcs_set, mcs, 8); - } -} - - -static void phy_info_freq(struct hostapd_hw_modes *mode, - struct hostapd_channel_data *chan, - struct nlattr *tb_freq[]) -{ - u8 channel; - chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); - chan->flag = 0; - if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES) - chan->chan = channel; - - if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) - chan->flag |= HOSTAPD_CHAN_DISABLED; - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR]) - chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN | HOSTAPD_CHAN_NO_IBSS; - if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) - chan->flag |= HOSTAPD_CHAN_RADAR; - - if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) { - enum nl80211_dfs_state state = - nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]); - - switch (state) { - case NL80211_DFS_USABLE: - chan->flag |= HOSTAPD_CHAN_DFS_USABLE; - break; - case NL80211_DFS_AVAILABLE: - chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE; - break; - case NL80211_DFS_UNAVAILABLE: - chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE; - break; - } - } -} - - -static int phy_info_freqs(struct phy_info_arg *phy_info, - struct hostapd_hw_modes *mode, struct nlattr *tb) -{ - static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { - [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, - [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, - [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 }, - }; - int new_channels = 0; - struct hostapd_channel_data *channel; - struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; - struct nlattr *nl_freq; - int rem_freq, idx; - - if (tb == NULL) - return NL_OK; - - nla_for_each_nested(nl_freq, tb, rem_freq) { - nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, - nla_data(nl_freq), nla_len(nl_freq), freq_policy); - if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) - continue; - new_channels++; - } - - channel = os_realloc_array(mode->channels, - mode->num_channels + new_channels, - sizeof(struct hostapd_channel_data)); - if (!channel) - return NL_SKIP; - - mode->channels = channel; - mode->num_channels += new_channels; - - idx = phy_info->last_chan_idx; - - nla_for_each_nested(nl_freq, tb, rem_freq) { - nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, - nla_data(nl_freq), nla_len(nl_freq), freq_policy); - if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) - continue; - phy_info_freq(mode, &mode->channels[idx], tb_freq); - idx++; - } - phy_info->last_chan_idx = idx; - - return NL_OK; -} - - -static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb) -{ - static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { - [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, - [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = - { .type = NLA_FLAG }, - }; - struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; - struct nlattr *nl_rate; - int rem_rate, idx; - - if (tb == NULL) - return NL_OK; - - nla_for_each_nested(nl_rate, tb, rem_rate) { - nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, - nla_data(nl_rate), nla_len(nl_rate), - rate_policy); - if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) - continue; - mode->num_rates++; - } - - mode->rates = os_calloc(mode->num_rates, sizeof(int)); - if (!mode->rates) - return NL_SKIP; - - idx = 0; - - nla_for_each_nested(nl_rate, tb, rem_rate) { - nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, - nla_data(nl_rate), nla_len(nl_rate), - rate_policy); - if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) - continue; - mode->rates[idx] = nla_get_u32( - tb_rate[NL80211_BITRATE_ATTR_RATE]); - idx++; - } - - return NL_OK; -} - - -static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band) -{ - struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; - struct hostapd_hw_modes *mode; - int ret; - - if (phy_info->last_mode != nl_band->nla_type) { - mode = os_realloc_array(phy_info->modes, - *phy_info->num_modes + 1, - sizeof(*mode)); - if (!mode) - return NL_SKIP; - phy_info->modes = mode; - - mode = &phy_info->modes[*(phy_info->num_modes)]; - os_memset(mode, 0, sizeof(*mode)); - mode->mode = NUM_HOSTAPD_MODES; - mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN | - HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN; - - /* - * Unsupported VHT MCS stream is defined as value 3, so the VHT - * MCS RX/TX map must be initialized with 0xffff to mark all 8 - * possible streams as unsupported. This will be overridden if - * driver advertises VHT support. - */ - mode->vht_mcs_set[0] = 0xff; - mode->vht_mcs_set[1] = 0xff; - mode->vht_mcs_set[4] = 0xff; - mode->vht_mcs_set[5] = 0xff; - - *(phy_info->num_modes) += 1; - phy_info->last_mode = nl_band->nla_type; - phy_info->last_chan_idx = 0; - } else - mode = &phy_info->modes[*(phy_info->num_modes) - 1]; - - nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), - nla_len(nl_band), NULL); - - phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA], - tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR], - tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY], - tb_band[NL80211_BAND_ATTR_HT_MCS_SET]); - phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA], - tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]); - ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]); - if (ret != NL_OK) - return ret; - ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]); - if (ret != NL_OK) - return ret; - - return NL_OK; -} - - -static int phy_info_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct phy_info_arg *phy_info = arg; - struct nlattr *nl_band; - int rem_band; - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) - return NL_SKIP; - - nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) - { - int res = phy_info_band(phy_info, nl_band); - if (res != NL_OK) - return res; - } - - return NL_SKIP; -} - - -static struct hostapd_hw_modes * -wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes, - u16 *num_modes) -{ - u16 m; - struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode; - int i, mode11g_idx = -1; - - /* heuristic to set up modes */ - for (m = 0; m < *num_modes; m++) { - if (!modes[m].num_channels) - continue; - if (modes[m].channels[0].freq < 4000) { - modes[m].mode = HOSTAPD_MODE_IEEE80211B; - for (i = 0; i < modes[m].num_rates; i++) { - if (modes[m].rates[i] > 200) { - modes[m].mode = HOSTAPD_MODE_IEEE80211G; - break; - } - } - } else if (modes[m].channels[0].freq > 50000) - modes[m].mode = HOSTAPD_MODE_IEEE80211AD; - else - modes[m].mode = HOSTAPD_MODE_IEEE80211A; - } - - /* If only 802.11g mode is included, use it to construct matching - * 802.11b mode data. */ - - for (m = 0; m < *num_modes; m++) { - if (modes[m].mode == HOSTAPD_MODE_IEEE80211B) - return modes; /* 802.11b already included */ - if (modes[m].mode == HOSTAPD_MODE_IEEE80211G) - mode11g_idx = m; - } - - if (mode11g_idx < 0) - return modes; /* 2.4 GHz band not supported at all */ - - nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes)); - if (nmodes == NULL) - return modes; /* Could not add 802.11b mode */ - - mode = &nmodes[*num_modes]; - os_memset(mode, 0, sizeof(*mode)); - (*num_modes)++; - modes = nmodes; - - mode->mode = HOSTAPD_MODE_IEEE80211B; - - mode11g = &modes[mode11g_idx]; - mode->num_channels = mode11g->num_channels; - mode->channels = os_malloc(mode11g->num_channels * - sizeof(struct hostapd_channel_data)); - if (mode->channels == NULL) { - (*num_modes)--; - return modes; /* Could not add 802.11b mode */ - } - os_memcpy(mode->channels, mode11g->channels, - mode11g->num_channels * sizeof(struct hostapd_channel_data)); - - mode->num_rates = 0; - mode->rates = os_malloc(4 * sizeof(int)); - if (mode->rates == NULL) { - os_free(mode->channels); - (*num_modes)--; - return modes; /* Could not add 802.11b mode */ - } - - for (i = 0; i < mode11g->num_rates; i++) { - if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 && - mode11g->rates[i] != 55 && mode11g->rates[i] != 110) - continue; - mode->rates[mode->num_rates] = mode11g->rates[i]; - mode->num_rates++; - if (mode->num_rates == 4) - break; - } - - if (mode->num_rates == 0) { - os_free(mode->channels); - os_free(mode->rates); - (*num_modes)--; - return modes; /* No 802.11b rates */ - } - - wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g " - "information"); - - return modes; -} - - -static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start, - int end) -{ - int c; - - for (c = 0; c < mode->num_channels; c++) { - struct hostapd_channel_data *chan = &mode->channels[c]; - if (chan->freq - 10 >= start && chan->freq + 10 <= end) - chan->flag |= HOSTAPD_CHAN_HT40; - } -} - - -static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start, - int end) -{ - int c; - - for (c = 0; c < mode->num_channels; c++) { - struct hostapd_channel_data *chan = &mode->channels[c]; - if (!(chan->flag & HOSTAPD_CHAN_HT40)) - continue; - if (chan->freq - 30 >= start && chan->freq - 10 <= end) - chan->flag |= HOSTAPD_CHAN_HT40MINUS; - if (chan->freq + 10 >= start && chan->freq + 30 <= end) - chan->flag |= HOSTAPD_CHAN_HT40PLUS; - } -} - - -static void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp, - struct phy_info_arg *results) -{ - u16 m; - - for (m = 0; m < *results->num_modes; m++) { - int c; - struct hostapd_hw_modes *mode = &results->modes[m]; - - for (c = 0; c < mode->num_channels; c++) { - struct hostapd_channel_data *chan = &mode->channels[c]; - if ((u32) chan->freq - 10 >= start && - (u32) chan->freq + 10 <= end) - chan->max_tx_power = max_eirp; - } - } -} - - -static void nl80211_reg_rule_ht40(u32 start, u32 end, - struct phy_info_arg *results) -{ - u16 m; - - for (m = 0; m < *results->num_modes; m++) { - if (!(results->modes[m].ht_capab & - HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) - continue; - nl80211_set_ht40_mode(&results->modes[m], start, end); - } -} - - -static void nl80211_reg_rule_sec(struct nlattr *tb[], - struct phy_info_arg *results) -{ - u32 start, end, max_bw; - u16 m; - - if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || - tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || - tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL) - return; - - start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; - end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; - max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; - - if (max_bw < 20) - return; - - for (m = 0; m < *results->num_modes; m++) { - if (!(results->modes[m].ht_capab & - HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) - continue; - nl80211_set_ht40_mode_sec(&results->modes[m], start, end); - } -} - - -static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start, - int end) -{ - int c; - - for (c = 0; c < mode->num_channels; c++) { - struct hostapd_channel_data *chan = &mode->channels[c]; - if (chan->freq - 10 >= start && chan->freq + 70 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_10_70; - - if (chan->freq - 30 >= start && chan->freq + 50 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_30_50; - - if (chan->freq - 50 >= start && chan->freq + 30 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_50_30; - - if (chan->freq - 70 >= start && chan->freq + 10 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_70_10; - } -} - - -static void nl80211_reg_rule_vht(struct nlattr *tb[], - struct phy_info_arg *results) -{ - u32 start, end, max_bw; - u16 m; - - if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || - tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || - tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL) - return; - - start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; - end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; - max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; - - if (max_bw < 80) - return; - - for (m = 0; m < *results->num_modes; m++) { - if (!(results->modes[m].ht_capab & - HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) - continue; - /* TODO: use a real VHT support indication */ - if (!results->modes[m].vht_capab) - continue; - - nl80211_set_vht_mode(&results->modes[m], start, end); - } -} - - -static const char * dfs_domain_name(enum nl80211_dfs_regions region) -{ - switch (region) { - case NL80211_DFS_UNSET: - return "DFS-UNSET"; - case NL80211_DFS_FCC: - return "DFS-FCC"; - case NL80211_DFS_ETSI: - return "DFS-ETSI"; - case NL80211_DFS_JP: - return "DFS-JP"; - default: - return "DFS-invalid"; - } -} - - -static int nl80211_get_reg(struct nl_msg *msg, void *arg) -{ - struct phy_info_arg *results = arg; - struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct nlattr *nl_rule; - struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1]; - int rem_rule; - static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { - [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, - [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, - [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, - [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, - [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, - [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, - }; - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - if (!tb_msg[NL80211_ATTR_REG_ALPHA2] || - !tb_msg[NL80211_ATTR_REG_RULES]) { - wpa_printf(MSG_DEBUG, "nl80211: No regulatory information " - "available"); - return NL_SKIP; - } - - if (tb_msg[NL80211_ATTR_DFS_REGION]) { - enum nl80211_dfs_regions dfs_domain; - dfs_domain = nla_get_u8(tb_msg[NL80211_ATTR_DFS_REGION]); - wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s (%s)", - (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), - dfs_domain_name(dfs_domain)); - } else { - wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s", - (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2])); - } - - nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) - { - u32 start, end, max_eirp = 0, max_bw = 0; - nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, - nla_data(nl_rule), nla_len(nl_rule), reg_policy); - if (tb_rule[NL80211_ATTR_FREQ_RANGE_START] == NULL || - tb_rule[NL80211_ATTR_FREQ_RANGE_END] == NULL) - continue; - start = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]) / 1000; - end = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]) / 1000; - if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) - max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100; - if (tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) - max_bw = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; - - wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm", - start, end, max_bw, max_eirp); - if (max_bw >= 40) - nl80211_reg_rule_ht40(start, end, results); - if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) - nl80211_reg_rule_max_eirp(start, end, max_eirp, - results); - } - - nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) - { - nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, - nla_data(nl_rule), nla_len(nl_rule), reg_policy); - nl80211_reg_rule_sec(tb_rule, results); - } - - nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) - { - nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, - nla_data(nl_rule), nla_len(nl_rule), reg_policy); - nl80211_reg_rule_vht(tb_rule, results); - } - - return NL_SKIP; -} - - -static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv, - struct phy_info_arg *results) -{ - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG); - return send_and_recv_msgs(drv, msg, nl80211_get_reg, results); -} - - -static struct hostapd_hw_modes * -wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) -{ - u32 feat; - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - struct phy_info_arg result = { - .num_modes = num_modes, - .modes = NULL, - .last_mode = -1, - }; - - *num_modes = 0; - *flags = 0; - - msg = nlmsg_alloc(); - if (!msg) - return NULL; - - feat = get_nl80211_protocol_features(drv); - if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP) - nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY); - else - nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY); - - NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - - if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) { - nl80211_set_regulatory_flags(drv, &result); - return wpa_driver_nl80211_postprocess_modes(result.modes, - num_modes); - } - msg = NULL; - nla_put_failure: - nlmsg_free(msg); - return NULL; -} - - -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 */ - 0x0e, 0x00, /* radiotap length */ - 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */ - IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */ - 0x00, /* padding */ - 0x00, 0x00, /* RX and TX flags to indicate that */ - 0x00, 0x00, /* this is the injected frame directly */ - }; - struct iovec iov[2] = { - { - .iov_base = &rtap_hdr, - .iov_len = sizeof(rtap_hdr), - }, - { - .iov_base = (void *) data, - .iov_len = len, - } - }; - struct msghdr msg = { - .msg_name = NULL, - .msg_namelen = 0, - .msg_iov = iov, - .msg_iovlen = 2, - .msg_control = NULL, - .msg_controllen = 0, - .msg_flags = 0, - }; - int res; - u16 txflags = 0; - - if (encrypt) - rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP; - - if (drv->monitor_sock < 0) { - wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available " - "for %s", __func__); - return -1; - } - - if (noack) - txflags |= IEEE80211_RADIOTAP_F_TX_NOACK; - WPA_PUT_LE16(&rtap_hdr[12], txflags); - - res = sendmsg(drv->monitor_sock, &msg, 0); - if (res < 0) { - wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno)); - return -1; - } - return 0; -} - - -static int wpa_driver_nl80211_send_frame(struct i802_bss *bss, - const void *data, size_t len, - int encrypt, int noack, - unsigned int freq, int no_cck, - int offchanok, unsigned int wait_time) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - u64 cookie; - int res; - - if (freq == 0) { - wpa_printf(MSG_DEBUG, "nl80211: send_frame - Use bss->freq=%u", - bss->freq); - freq = bss->freq; - } - - if (drv->use_monitor) { - wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_mntr", - freq, bss->freq); - return wpa_driver_nl80211_send_mntr(drv, data, len, - encrypt, noack); - } - - wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd"); - res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len, - &cookie, no_cck, noack, offchanok); - if (res == 0 && !noack) { - const struct ieee80211_mgmt *mgmt; - u16 fc; - - mgmt = (const struct ieee80211_mgmt *) data; - fc = le_to_host16(mgmt->frame_control); - if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) { - wpa_printf(MSG_MSGDUMP, - "nl80211: Update send_action_cookie from 0x%llx to 0x%llx", - (long long unsigned int) - drv->send_action_cookie, - (long long unsigned int) cookie); - drv->send_action_cookie = cookie; - } - } - - return res; -} - - -static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data, - size_t data_len, int noack, - unsigned int freq, int no_cck, - int offchanok, - unsigned int wait_time) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - struct ieee80211_mgmt *mgmt; - int encrypt = 1; - u16 fc; - - mgmt = (struct ieee80211_mgmt *) data; - fc = le_to_host16(mgmt->frame_control); - wpa_printf(MSG_DEBUG, "nl80211: send_mlme - noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x nlmode=%d", - noack, freq, no_cck, offchanok, wait_time, fc, drv->nlmode); - - if ((is_sta_interface(drv->nlmode) || - drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) && - WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) { - /* - * The use of last_mgmt_freq is a bit of a hack, - * but it works due to the single-threaded nature - * of wpa_supplicant. - */ - if (freq == 0) { - wpa_printf(MSG_DEBUG, "nl80211: Use last_mgmt_freq=%d", - drv->last_mgmt_freq); - freq = drv->last_mgmt_freq; - } - return nl80211_send_frame_cmd(bss, freq, 0, - data, data_len, NULL, 1, noack, - 1); - } - - if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) { - if (freq == 0) { - wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d", - bss->freq); - freq = bss->freq; - } - return nl80211_send_frame_cmd(bss, freq, - (int) freq == bss->freq ? 0 : - wait_time, - data, data_len, - &drv->send_action_cookie, - no_cck, noack, offchanok); - } - - if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) { - /* - * Only one of the authentication frame types is encrypted. - * In order for static WEP encryption to work properly (i.e., - * to not encrypt the frame), we need to tell mac80211 about - * the frames that must not be encrypted. - */ - u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg); - u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction); - if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3) - encrypt = 0; - } - - wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame"); - return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, - noack, freq, no_cck, offchanok, - wait_time); -} - - -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_acl(void *priv, - struct hostapd_acl_params *params) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - struct nlattr *acl; - unsigned int i; - int ret = 0; - - if (!(drv->capa.max_acl_mac_addrs)) - return -ENOTSUP; - - if (params->num_mac_acl > drv->capa.max_acl_mac_addrs) - return -ENOTSUP; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)", - params->acl_policy ? "Accept" : "Deny", params->num_mac_acl); - - nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_MAC_ACL); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - - NLA_PUT_U32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ? - NL80211_ACL_POLICY_DENY_UNLESS_LISTED : - NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED); - - acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS); - if (acl == NULL) - goto nla_put_failure; - - for (i = 0; i < params->num_mac_acl; i++) - NLA_PUT(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr); - - nla_nest_end(msg, acl); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - msg = NULL; - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)", - ret, strerror(-ret)); - } - -nla_put_failure: - nlmsg_free(msg); - - return ret; -} - - -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; - struct nl_msg *msg; - u8 cmd = NL80211_CMD_NEW_BEACON; - int ret; - int beacon_set; - int ifindex = if_nametoindex(bss->ifname); - int num_suites; - u32 suites[10], suite; - u32 ver; - - beacon_set = bss->beacon_set; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)", - beacon_set); - if (beacon_set) - cmd = NL80211_CMD_SET_BEACON; - - nl80211_cmd(drv, msg, 0, cmd); - wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head", - params->head, params->head_len); - NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head); - wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail", - params->tail, params->tail_len); - NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail); - wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); - wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int); - NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int); - wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period); - NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period); - wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid", - params->ssid, params->ssid_len); - NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, - params->ssid); - if (params->proberesp && params->proberesp_len) { - wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)", - 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: - wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use"); - NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, - NL80211_HIDDEN_SSID_NOT_IN_USE); - break; - case HIDDEN_SSID_ZERO_LEN: - wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len"); - NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, - NL80211_HIDDEN_SSID_ZERO_LEN); - break; - case HIDDEN_SSID_ZERO_CONTENTS: - wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents"); - NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, - NL80211_HIDDEN_SSID_ZERO_CONTENTS); - break; - } - wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy); - if (params->privacy) - NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); - wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs); - 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); - - wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version); - 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); - - wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x", - params->key_mgmt_suites); - 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); - - wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x", - params->pairwise_ciphers); - num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers, - suites, ARRAY_SIZE(suites)); - if (num_suites) { - NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, - num_suites * sizeof(u32), suites); - } - - wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x", - params->group_cipher); - suite = wpa_cipher_to_cipher_suite(params->group_cipher); - if (suite) - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite); - - if (params->beacon_ies) { - wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies", - params->beacon_ies); - NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies), - wpabuf_head(params->beacon_ies)); - } - if (params->proberesp_ies) { - wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies", - 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) { - wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies", - params->assocresp_ies); - NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP, - wpabuf_len(params->assocresp_ies), - wpabuf_head(params->assocresp_ies)); - } - - if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) { - wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d", - params->ap_max_inactivity); - NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT, - params->ap_max_inactivity); - } - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)", - 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); - } - return ret; - nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} - - -static int nl80211_put_freq_params(struct nl_msg *msg, - struct hostapd_freq_params *freq) -{ - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq); - if (freq->vht_enabled) { - switch (freq->bandwidth) { - case 20: - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_20); - break; - case 40: - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_40); - break; - case 80: - if (freq->center_freq2) - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_80P80); - else - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_80); - break; - case 160: - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_160); - break; - default: - return -EINVAL; - } - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1); - if (freq->center_freq2) - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, - freq->center_freq2); - } else if (freq->ht_enabled) { - switch (freq->sec_channel_offset) { - case -1: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - NL80211_CHAN_HT40MINUS); - break; - case 1: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - NL80211_CHAN_HT40PLUS); - break; - default: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - NL80211_CHAN_HT20); - break; - } - } - return 0; - -nla_put_failure: - return -ENOBUFS; -} - - -static int wpa_driver_nl80211_set_freq(struct i802_bss *bss, - struct hostapd_freq_params *freq) -{ - 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, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)", - freq->freq, freq->ht_enabled, freq->vht_enabled, - freq->bandwidth, freq->center_freq1, freq->center_freq2); - msg = nlmsg_alloc(); - if (!msg) - return -1; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - if (nl80211_put_freq_params(msg, freq) < 0) - goto nla_put_failure; - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - msg = NULL; - if (ret == 0) { - bss->freq = freq->freq; - return 0; - } - wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): " - "%d (%s)", freq->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 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; - - wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR, - params->set ? "Set" : "Add", MAC2STR(params->addr)); - nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION : - NL80211_CMD_NEW_STATION); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr); - NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len, - params->supp_rates); - wpa_hexdump(MSG_DEBUG, " * supported rates", params->supp_rates, - params->supp_rates_len); - if (!params->set) { - if (params->aid) { - wpa_printf(MSG_DEBUG, " * aid=%u", params->aid); - NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid); - } else { - /* - * cfg80211 validates that AID is non-zero, so we have - * to make this a non-zero value for the TDLS case where - * a dummy STA entry is used for now. - */ - wpa_printf(MSG_DEBUG, " * aid=1 (TDLS workaround)"); - NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1); - } - wpa_printf(MSG_DEBUG, " * listen_interval=%u", - params->listen_interval); - NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, - params->listen_interval); - } else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) { - wpa_printf(MSG_DEBUG, " * peer_aid=%u", params->aid); - NLA_PUT_U16(msg, NL80211_ATTR_PEER_AID, params->aid); - } - if (params->ht_capabilities) { - wpa_hexdump(MSG_DEBUG, " * ht_capabilities", - (u8 *) params->ht_capabilities, - sizeof(*params->ht_capabilities)); - NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, - sizeof(*params->ht_capabilities), - params->ht_capabilities); - } - - if (params->vht_capabilities) { - wpa_hexdump(MSG_DEBUG, " * vht_capabilities", - (u8 *) params->vht_capabilities, - sizeof(*params->vht_capabilities)); - NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, - sizeof(*params->vht_capabilities), - params->vht_capabilities); - } - - wpa_printf(MSG_DEBUG, " * capability=0x%x", params->capability); - NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability); - - if (params->ext_capab) { - wpa_hexdump(MSG_DEBUG, " * ext_capab", - params->ext_capab, params->ext_capab_len); - NLA_PUT(msg, NL80211_ATTR_STA_EXT_CAPABILITY, - params->ext_capab_len, params->ext_capab); - } - - if (params->supp_channels) { - wpa_hexdump(MSG_DEBUG, " * supported channels", - params->supp_channels, params->supp_channels_len); - NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS, - params->supp_channels_len, params->supp_channels); - } - - if (params->supp_oper_classes) { - wpa_hexdump(MSG_DEBUG, " * supported operating classes", - params->supp_oper_classes, - params->supp_oper_classes_len); - NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES, - params->supp_oper_classes_len, - params->supp_oper_classes); - } - - os_memset(&upd, 0, sizeof(upd)); - upd.mask = sta_flags_nl80211(params->flags); - upd.set = upd.mask; - wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x", - upd.set, upd.mask); - NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); - - if (params->flags & WPA_STA_WMM) { - struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME); - - if (!wme) - goto nla_put_failure; - - wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo); - NLA_PUT_U8(msg, NL80211_STA_WME_UAPSD_QUEUES, - params->qosinfo & WMM_QOSINFO_STA_AC_MASK); - NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP, - (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) & - WMM_QOSINFO_STA_SP_MASK); - nla_nest_end(msg, wme); - } - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - msg = NULL; - if (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(msg); - return ret; -} - - -static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(bss->ifname)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR - " --> %d (%s)", - bss->ifname, MAC2STR(addr), ret, strerror(-ret)); - if (ret == -ENOENT) - return 0; - return ret; - nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} - - -static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, - int ifidx) -{ - struct nl_msg *msg; - - wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx); - - /* stop listening for EAPOL on this interface */ - del_ifidx(drv, ifidx); - - msg = nlmsg_alloc(); - if (!msg) - goto nla_put_failure; - - 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_AP_VLAN: - return "AP_VLAN"; - case NL80211_IFTYPE_WDS: - return "WDS"; - case NL80211_IFTYPE_MONITOR: - return "MONITOR"; - case NL80211_IFTYPE_MESH_POINT: - return "MESH_POINT"; - case NL80211_IFTYPE_P2P_CLIENT: - return "P2P_CLIENT"; - case NL80211_IFTYPE_P2P_GO: - return "P2P_GO"; - case NL80211_IFTYPE_P2P_DEVICE: - return "P2P_DEVICE"; - default: - return "unknown"; - } -} - - -static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, - const char *ifname, - enum nl80211_iftype iftype, - const u8 *addr, int wds, - int (*handler)(struct nl_msg *, void *), - void *arg) -{ - struct nl_msg *msg; - 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; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE); - if (nl80211_set_iface_id(msg, drv->first_bss) < 0) - goto nla_put_failure; - NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); - - if (iftype == NL80211_IFTYPE_MONITOR) { - struct nlattr *flags; - - flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS); - if (!flags) - goto nla_put_failure; - - NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES); - - nla_nest_end(msg, flags); - } else if (wds) { - NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds); - } - - ret = send_and_recv_msgs(drv, msg, handler, arg); - 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; - } - - if (iftype == NL80211_IFTYPE_P2P_DEVICE) - return 0; - - ifidx = if_nametoindex(ifname); - wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d", - ifname, ifidx); - - if (ifidx <= 0) - return -1; - - /* start listening for EAPOL on this interface */ - add_ifidx(drv, ifidx); - - if (addr && iftype != NL80211_IFTYPE_MONITOR && - linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) { - nl80211_remove_iface(drv, ifidx); - return -1; - } - - return ifidx; -} - - -static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv, - const char *ifname, enum nl80211_iftype iftype, - const u8 *addr, int wds, - int (*handler)(struct nl_msg *, void *), - void *arg, int use_existing) -{ - int ret; - - ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler, - arg); - - /* if error occurred and interface exists already */ - if (ret == -ENFILE && if_nametoindex(ifname)) { - if (use_existing) { - wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s", - ifname); - return -ENFILE; - } - wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname); - - /* Try to remove the interface that was already there. */ - nl80211_remove_iface(drv, if_nametoindex(ifname)); - - /* Try to create the interface again */ - ret = nl80211_create_iface_once(drv, ifname, iftype, addr, - wds, handler, arg); - } - - if (ret >= 0 && is_p2p_net_interface(iftype)) - nl80211_disable_11b_rates(drv, ret, 1); - - return ret; -} - - -static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok) -{ - struct ieee80211_hdr *hdr; - u16 fc; - union wpa_event_data event; - - hdr = (struct ieee80211_hdr *) buf; - fc = le_to_host16(hdr->frame_control); - - os_memset(&event, 0, sizeof(event)); - event.tx_status.type = WLAN_FC_GET_TYPE(fc); - event.tx_status.stype = WLAN_FC_GET_STYPE(fc); - event.tx_status.dst = hdr->addr1; - event.tx_status.data = buf; - event.tx_status.data_len = len; - event.tx_status.ack = ok; - wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event); -} - - -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.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); -} - - -static void handle_frame(struct wpa_driver_nl80211_data *drv, - u8 *buf, size_t len, int datarate, int ssi_signal) -{ - struct ieee80211_hdr *hdr; - u16 fc; - union wpa_event_data event; - - hdr = (struct ieee80211_hdr *) buf; - fc = le_to_host16(hdr->frame_control); - - switch (WLAN_FC_GET_TYPE(fc)) { - case WLAN_FC_TYPE_MGMT: - os_memset(&event, 0, sizeof(event)); - event.rx_mgmt.frame = buf; - event.rx_mgmt.frame_len = len; - event.rx_mgmt.datarate = datarate; - event.rx_mgmt.ssi_signal = ssi_signal; - wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); - break; - case WLAN_FC_TYPE_CTRL: - /* can only get here with PS-Poll frames */ - wpa_printf(MSG_DEBUG, "CTRL"); - from_unknown_sta(drv, buf, len); - break; - case WLAN_FC_TYPE_DATA: - from_unknown_sta(drv, buf, len); - break; - } -} - - -static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct wpa_driver_nl80211_data *drv = eloop_ctx; - int len; - unsigned char buf[3000]; - struct ieee80211_radiotap_iterator iter; - int ret; - int datarate = 0, ssi_signal = 0; - int injected = 0, failed = 0, rxflags = 0; - - len = recv(sock, buf, sizeof(buf), 0); - if (len < 0) { - wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s", - strerror(errno)); - return; - } - - if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) { - wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame"); - return; - } - - while (1) { - ret = ieee80211_radiotap_iterator_next(&iter); - if (ret == -ENOENT) - break; - if (ret) { - wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)", - ret); - return; - } - switch (iter.this_arg_index) { - case IEEE80211_RADIOTAP_FLAGS: - if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS) - len -= 4; - break; - case IEEE80211_RADIOTAP_RX_FLAGS: - rxflags = 1; - break; - case IEEE80211_RADIOTAP_TX_FLAGS: - injected = 1; - failed = le_to_host16((*(uint16_t *) iter.this_arg)) & - IEEE80211_RADIOTAP_F_TX_FAIL; - break; - case IEEE80211_RADIOTAP_DATA_RETRIES: - break; - case IEEE80211_RADIOTAP_CHANNEL: - /* TODO: convert from freq/flags to channel number */ - break; - case IEEE80211_RADIOTAP_RATE: - datarate = *iter.this_arg * 5; - break; - case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: - ssi_signal = (s8) *iter.this_arg; - break; - } - } - - if (rxflags && injected) - return; - - if (!injected) - handle_frame(drv, buf + iter.max_length, - len - iter.max_length, datarate, ssi_signal); - else - handle_tx_callback(drv->ctx, buf + iter.max_length, - len - iter.max_length, !failed); -} - - -/* - * we post-process the filter code later and rewrite - * this to the offset to the last instruction - */ -#define PASS 0xFF -#define FAIL 0xFE - -static struct sock_filter msock_filter_insns[] = { - /* - * do a little-endian load of the radiotap length field - */ - /* load lower byte into A */ - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2), - /* put it into X (== index register) */ - BPF_STMT(BPF_MISC| BPF_TAX, 0), - /* load upper byte into A */ - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3), - /* left-shift it by 8 */ - BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8), - /* or with X */ - BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0), - /* put result into X */ - BPF_STMT(BPF_MISC| BPF_TAX, 0), - - /* - * Allow management frames through, this also gives us those - * management frames that we sent ourselves with status - */ - /* load the lower byte of the IEEE 802.11 frame control field */ - BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), - /* mask off frame type and version */ - BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF), - /* accept frame if it's both 0, fall through otherwise */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0), - - /* - * TODO: add a bit to radiotap RX flags that indicates - * that the sending station is not associated, then - * add a filter here that filters on our DA and that flag - * to allow us to deauth frames to that bad station. - * - * For now allow all To DS data frames through. - */ - /* load the IEEE 802.11 frame control field */ - BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0), - /* mask off frame type, version and DS status */ - BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03), - /* accept frame if version 0, type 2 and To DS, fall through otherwise - */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0), - -#if 0 - /* - * drop non-data frames - */ - /* load the lower byte of the frame control field */ - BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), - /* mask off QoS bit */ - BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c), - /* drop non-data frames */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL), -#endif - /* load the upper byte of the frame control field */ - BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1), - /* mask off toDS/fromDS */ - BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03), - /* accept WDS frames */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0), - - /* - * add header length to index - */ - /* load the lower byte of the frame control field */ - BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), - /* mask off QoS bit */ - BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80), - /* right shift it by 6 to give 0 or 2 */ - BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6), - /* add data frame header length */ - BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24), - /* add index, was start of 802.11 header */ - BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0), - /* move to index, now start of LL header */ - BPF_STMT(BPF_MISC | BPF_TAX, 0), - - /* - * Accept empty data frames, we use those for - * polling activity. - */ - BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0), - - /* - * Accept EAPOL frames - */ - BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL), - BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL), - - /* keep these last two statements or change the code below */ - /* return 0 == "DROP" */ - BPF_STMT(BPF_RET | BPF_K, 0), - /* return ~0 == "keep all" */ - BPF_STMT(BPF_RET | BPF_K, ~0), -}; - -static struct sock_fprog msock_filter = { - .len = ARRAY_SIZE(msock_filter_insns), - .filter = msock_filter_insns, -}; - - -static int add_monitor_filter(int s) -{ - int idx; - - /* rewrite all PASS/FAIL jump offsets */ - for (idx = 0; idx < msock_filter.len; idx++) { - struct sock_filter *insn = &msock_filter_insns[idx]; - - if (BPF_CLASS(insn->code) == BPF_JMP) { - if (insn->code == (BPF_JMP|BPF_JA)) { - if (insn->k == PASS) - insn->k = msock_filter.len - idx - 2; - else if (insn->k == FAIL) - insn->k = msock_filter.len - idx - 3; - } - - if (insn->jt == PASS) - insn->jt = msock_filter.len - idx - 2; - else if (insn->jt == FAIL) - insn->jt = msock_filter.len - idx - 3; - - if (insn->jf == PASS) - insn->jf = msock_filter.len - idx - 2; - else if (insn->jf == FAIL) - insn->jf = msock_filter.len - idx - 3; - } - } - - if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, - &msock_filter, sizeof(msock_filter))) { - wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s", - strerror(errno)); - return -1; - } - - return 0; -} - - -static void nl80211_remove_monitor_interface( - struct wpa_driver_nl80211_data *drv) -{ - if (drv->monitor_refcount > 0) - drv->monitor_refcount--; - wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d", - 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; - } - if (drv->monitor_sock >= 0) { - eloop_unregister_read_sock(drv->monitor_sock); - close(drv->monitor_sock); - drv->monitor_sock = -1; - } -} - - -static int -nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv) -{ - char buf[IFNAMSIZ]; - struct sockaddr_ll ll; - int optval; - socklen_t optlen; - - if (drv->monitor_ifidx >= 0) { - drv->monitor_refcount++; - wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d", - 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 = - nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL, - 0, NULL, NULL, 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->device_ap_sme = 1; - } - - if (drv->monitor_ifidx < 0) - return -1; - - if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1)) - goto error; - - memset(&ll, 0, sizeof(ll)); - ll.sll_family = AF_PACKET; - ll.sll_ifindex = drv->monitor_ifidx; - drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (drv->monitor_sock < 0) { - wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s", - strerror(errno)); - goto error; - } - - if (add_monitor_filter(drv->monitor_sock)) { - wpa_printf(MSG_INFO, "Failed to set socket filter for monitor " - "interface; do filtering in user space"); - /* This works, but will cost in performance. */ - } - - if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) { - wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s", - strerror(errno)); - goto error; - } - - optlen = sizeof(optval); - optval = 20; - if (setsockopt - (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) { - wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s", - strerror(errno)); - goto error; - } - - if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read, - drv, NULL)) { - wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket"); - goto error; - } - - drv->monitor_refcount++; - return 0; - error: - nl80211_remove_monitor_interface(drv); - return -1; -} - - -static int nl80211_setup_ap(struct i802_bss *bss) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - - wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d", - bss->ifname, 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 */ - } - - return 0; -} - - -static void nl80211_teardown_ap(struct i802_bss *bss) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - - wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d", - bss->ifname, drv->device_ap_sme, drv->use_monitor); - 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( - void *priv, const u8 *addr, const u8 *data, - size_t data_len, int encrypt, const u8 *own_addr, u32 flags) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct ieee80211_hdr *hdr; - size_t len; - u8 *pos; - 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); - if (hdr == NULL) { - wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)", - (unsigned long) len); - return -1; - } - - hdr->frame_control = - IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); - hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); - if (encrypt) - hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); - if (qos) { - hdr->frame_control |= - host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); - } - - memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); - memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); - memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); - pos = (u8 *) (hdr + 1); - - if (qos) { - /* Set highest priority in QoS header */ - pos[0] = 7; - pos[1] = 0; - pos += 2; - } - - memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); - pos += sizeof(rfc1042_header); - WPA_PUT_BE16(pos, ETH_P_PAE); - pos += 2; - memcpy(pos, data, data_len); - - res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0, - 0, 0, 0, 0); - if (res < 0) { - wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - " - "failed: %d (%s)", - (unsigned long) len, errno, strerror(errno)); - } - os_free(hdr); - - return res; -} - - -static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, - int total_flags, - int flags_or, int flags_and) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - struct nlattr *flags; - struct nl80211_sta_flag_update upd; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(bss->ifname)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - - /* - * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This - * can be removed eventually. - */ - flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS); - if (!flags) - goto nla_put_failure; - if (total_flags & WPA_STA_AUTHORIZED) - NLA_PUT_FLAG(msg, NL80211_STA_FLAG_AUTHORIZED); - - if (total_flags & WPA_STA_WMM) - NLA_PUT_FLAG(msg, NL80211_STA_FLAG_WME); - - if (total_flags & WPA_STA_SHORT_PREAMBLE) - NLA_PUT_FLAG(msg, NL80211_STA_FLAG_SHORT_PREAMBLE); - - if (total_flags & WPA_STA_MFP) - NLA_PUT_FLAG(msg, NL80211_STA_FLAG_MFP); - - if (total_flags & WPA_STA_TDLS_PEER) - NLA_PUT_FLAG(msg, NL80211_STA_FLAG_TDLS_PEER); - - nla_nest_end(msg, flags); - - os_memset(&upd, 0, sizeof(upd)); - upd.mask = sta_flags_nl80211(flags_or | ~flags_and); - upd.set = sta_flags_nl80211(flags_or); - NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} - - -static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv, - struct wpa_driver_associate_params *params) -{ - enum nl80211_iftype nlmode, old_mode; - struct hostapd_freq_params freq = { - .freq = params->freq, - }; - - if (params->p2p) { - wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P " - "group (GO)"); - nlmode = NL80211_IFTYPE_P2P_GO; - } else - nlmode = NL80211_IFTYPE_AP; - - old_mode = drv->nlmode; - if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode)) { - nl80211_remove_monitor_interface(drv); - return -1; - } - - if (wpa_driver_nl80211_set_freq(drv->first_bss, &freq)) { - if (old_mode != nlmode) - wpa_driver_nl80211_set_mode(drv->first_bss, old_mode); - nl80211_remove_monitor_interface(drv); - return -1; - } - - return 0; -} - - -static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv) -{ - struct nl_msg *msg; - int ret = -1; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - 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; - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d " - "(%s)", ret, strerror(-ret)); - goto nla_put_failure; - } - - ret = 0; - wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully"); - -nla_put_failure: - if (wpa_driver_nl80211_set_mode(drv->first_bss, - NL80211_IFTYPE_STATION)) { - wpa_printf(MSG_INFO, "nl80211: Failed to set interface into " - "station mode"); - } - - nlmsg_free(msg); - return ret; -} - - -static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv, - struct wpa_driver_associate_params *params) -{ - struct nl_msg *msg; - int ret = -1; - int count = 0; - - wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex); - - 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; - } - -retry: - msg = nlmsg_alloc(); - if (!msg) - return -1; - - 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)) - goto nla_put_failure; - - wpa_hexdump_ascii(MSG_DEBUG, " * SSID", - params->ssid, params->ssid_len); - NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, - params->ssid); - os_memcpy(drv->ssid, params->ssid, params->ssid_len); - drv->ssid_len = params->ssid_len; - - wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); - - ret = nl80211_set_conn_keys(params, msg); - if (ret) - goto nla_put_failure; - - if (params->bssid && params->fixed_bssid) { - wpa_printf(MSG_DEBUG, " * BSSID=" MACSTR, - MAC2STR(params->bssid)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); - } - - if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || - params->key_mgmt_suite == WPA_KEY_MGMT_PSK || - params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 || - params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) { - wpa_printf(MSG_DEBUG, " * control port"); - NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT); - } - - if (params->wpa_ie) { - wpa_hexdump(MSG_DEBUG, - " * Extra IEs for Beacon/Probe Response frames", - params->wpa_ie, params->wpa_ie_len); - NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, - params->wpa_ie); - } - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - msg = NULL; - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)", - ret, strerror(-ret)); - count++; - if (ret == -EALREADY && count == 1) { - wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after " - "forced leave"); - nl80211_leave_ibss(drv); - nlmsg_free(msg); - goto retry; - } - - goto nla_put_failure; - } - ret = 0; - wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully"); - -nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, - struct wpa_driver_associate_params *params, - struct nl_msg *msg) -{ - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - - if (params->bssid) { - wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, - MAC2STR(params->bssid)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); - } - - if (params->freq) { - wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); - drv->assoc_freq = params->freq; - } else - drv->assoc_freq = 0; - - if (params->bg_scan_period >= 0) { - wpa_printf(MSG_DEBUG, " * bg scan period=%d", - params->bg_scan_period); - NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD, - params->bg_scan_period); - } - - if (params->ssid) { - wpa_hexdump_ascii(MSG_DEBUG, " * SSID", - params->ssid, params->ssid_len); - NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, - params->ssid); - if (params->ssid_len > sizeof(drv->ssid)) - goto nla_put_failure; - os_memcpy(drv->ssid, params->ssid, params->ssid_len); - drv->ssid_len = params->ssid_len; - } - - wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); - if (params->wpa_ie) - NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, - params->wpa_ie); - - if (params->wpa_proto) { - enum nl80211_wpa_versions ver = 0; - - 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 Versions 0x%x", ver); - NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); - } - - if (params->pairwise_suite != WPA_CIPHER_NONE) { - u32 cipher = wpa_cipher_to_cipher_suite(params->pairwise_suite); - wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher); - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher); - } - - if (params->group_suite != WPA_CIPHER_NONE) { - u32 cipher = wpa_cipher_to_cipher_suite(params->group_suite); - wpa_printf(MSG_DEBUG, " * group=0x%x", cipher); - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher); - } - - if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || - params->key_mgmt_suite == WPA_KEY_MGMT_PSK || - params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X || - params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK || - params->key_mgmt_suite == WPA_KEY_MGMT_CCKM) { - int mgmt = WLAN_AKM_SUITE_PSK; - - switch (params->key_mgmt_suite) { - case WPA_KEY_MGMT_CCKM: - mgmt = WLAN_AKM_SUITE_CCKM; - break; - case WPA_KEY_MGMT_IEEE8021X: - mgmt = WLAN_AKM_SUITE_8021X; - break; - case WPA_KEY_MGMT_FT_IEEE8021X: - mgmt = WLAN_AKM_SUITE_FT_8021X; - break; - case WPA_KEY_MGMT_FT_PSK: - mgmt = WLAN_AKM_SUITE_FT_PSK; - break; - case WPA_KEY_MGMT_PSK: - default: - mgmt = WLAN_AKM_SUITE_PSK; - break; - } - NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt); - } - - NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT); - - if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED) - NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED); - - if (params->disable_ht) - NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT); - - if (params->htcaps && params->htcaps_mask) { - int sz = sizeof(struct ieee80211_ht_capabilities); - NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps); - NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz, - params->htcaps_mask); - } - -#ifdef CONFIG_VHT_OVERRIDES - if (params->disable_vht) { - wpa_printf(MSG_DEBUG, " * VHT disabled"); - NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT); - } - - if (params->vhtcaps && params->vhtcaps_mask) { - int sz = sizeof(struct ieee80211_vht_capabilities); - NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps); - NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz, - params->vhtcaps_mask); - } -#endif /* CONFIG_VHT_OVERRIDES */ - - if (params->p2p) - wpa_printf(MSG_DEBUG, " * P2P group"); - - return 0; -nla_put_failure: - return -1; -} - - -static int wpa_driver_nl80211_try_connect( - struct wpa_driver_nl80211_data *drv, - struct wpa_driver_associate_params *params) -{ - struct nl_msg *msg; - enum nl80211_auth_type type; - int ret; - int algs; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex); - nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT); - - ret = nl80211_connect_common(drv, params, msg); - if (ret) - goto nla_put_failure; - - algs = 0; - if (params->auth_alg & WPA_AUTH_ALG_OPEN) - algs++; - if (params->auth_alg & WPA_AUTH_ALG_SHARED) - algs++; - if (params->auth_alg & WPA_AUTH_ALG_LEAP) - algs++; - if (algs > 1) { - wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic " - "selection"); - goto skip_auth_type; - } - - if (params->auth_alg & WPA_AUTH_ALG_OPEN) - type = NL80211_AUTHTYPE_OPEN_SYSTEM; - else if (params->auth_alg & WPA_AUTH_ALG_SHARED) - type = NL80211_AUTHTYPE_SHARED_KEY; - else if (params->auth_alg & WPA_AUTH_ALG_LEAP) - type = NL80211_AUTHTYPE_NETWORK_EAP; - else if (params->auth_alg & WPA_AUTH_ALG_FT) - type = NL80211_AUTHTYPE_FT; - else - goto nla_put_failure; - - wpa_printf(MSG_DEBUG, " * Auth Type %d", type); - NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); - -skip_auth_type: - ret = nl80211_set_conn_keys(params, msg); - if (ret) - goto nla_put_failure; - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - msg = NULL; - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d " - "(%s)", ret, strerror(-ret)); - goto nla_put_failure; - } - ret = 0; - wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully"); - -nla_put_failure: - nlmsg_free(msg); - return ret; - -} - - -static int wpa_driver_nl80211_connect( - struct wpa_driver_nl80211_data *drv, - struct wpa_driver_associate_params *params) -{ - int ret = wpa_driver_nl80211_try_connect(drv, params); - if (ret == -EALREADY) { - /* - * cfg80211 does not currently accept new connections if - * we are already connected. As a workaround, force - * disconnection and try again. - */ - wpa_printf(MSG_DEBUG, "nl80211: Explicitly " - "disconnecting before reassociation " - "attempt"); - if (wpa_driver_nl80211_disconnect( - drv, WLAN_REASON_PREV_AUTH_NOT_VALID)) - return -1; - ret = wpa_driver_nl80211_try_connect(drv, params); - } - return ret; -} - - -static int wpa_driver_nl80211_associate( - void *priv, struct wpa_driver_associate_params *params) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - int ret; - struct nl_msg *msg; - - if (params->mode == IEEE80211_MODE_AP) - return wpa_driver_nl80211_ap(drv, params); - - if (params->mode == IEEE80211_MODE_IBSS) - return wpa_driver_nl80211_ibss(drv, params); - - if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { - 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); - } - - nl80211_mark_disconnected(drv); - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)", - drv->ifindex); - nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE); - - ret = nl80211_connect_common(drv, params, msg); - if (ret) - goto nla_put_failure; - - if (params->prev_bssid) { - wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR, - MAC2STR(params->prev_bssid)); - NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN, - params->prev_bssid); - } - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - msg = NULL; - if (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; - } - ret = 0; - wpa_printf(MSG_DEBUG, "nl80211: Association request send " - "successfully"); - -nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv, - 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; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE); - if (nl80211_set_iface_id(msg, drv->first_bss) < 0) - goto nla_put_failure; - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - 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(struct i802_bss *bss, - enum nl80211_iftype nlmode) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - int ret = -1; - int i; - int was_ap = is_ap_interface(drv->nlmode); - int res; - - res = nl80211_set_mode(drv, drv->ifindex, nlmode); - if (res && nlmode == nl80211_get_ifmode(bss)) - res = 0; - - if (res == 0) { - drv->nlmode = nlmode; - ret = 0; - goto done; - } - - if (res == -ENODEV) - return -1; - - if (nlmode == drv->nlmode) { - wpa_printf(MSG_DEBUG, "nl80211: Interface already in " - "requested mode - ignore error"); - ret = 0; - goto done; /* Already in the requested mode */ - } - - /* mac80211 doesn't allow mode changes while the device is up, so - * take the device down, try to set the mode again, and bring the - * device back up. - */ - wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting " - "interface down"); - for (i = 0; i < 10; i++) { - res = i802_set_iface_flags(bss, 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 (ret == -EACCES) - break; - res = i802_set_iface_flags(bss, 1); - if (res && !ret) - ret = -1; - else if (ret != -EBUSY) - break; - } else - wpa_printf(MSG_DEBUG, "nl80211: Failed to set " - "interface down"); - os_sleep(0, 100000); - } - - if (!ret) { - wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while " - "interface is down"); - drv->nlmode = nlmode; - drv->ignore_if_down_event = 1; - } - -done: - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d " - "from %d failed", nlmode, drv->nlmode); - return ret; - } - - if (is_p2p_net_interface(nlmode)) - nl80211_disable_11b_rates(drv, drv->ifindex, 1); - else if (drv->disabled_11b_rates) - nl80211_disable_11b_rates(drv, drv->ifindex, 0); - - if (is_ap_interface(nlmode)) { - nl80211_mgmt_unsubscribe(bss, "start AP"); - /* Setup additional AP mode functionality if needed */ - if (nl80211_setup_ap(bss)) - return -1; - } else if (was_ap) { - /* Remove additional AP mode functionality */ - nl80211_teardown_ap(bss); - } else { - nl80211_mgmt_unsubscribe(bss, "mode change"); - } - - if (!bss->in_deinit && !is_ap_interface(nlmode) && - nl80211_mgmt_subscribe_non_ap(bss) < 0) - wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action " - "frame processing - ignore for now"); - - return 0; -} - - -static int wpa_driver_nl80211_get_capa(void *priv, - struct wpa_driver_capa *capa) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - if (!drv->has_capability) - return -1; - os_memcpy(capa, &drv->capa, sizeof(*capa)); - if (drv->extended_capa && drv->extended_capa_mask) { - capa->extended_capa = drv->extended_capa; - capa->extended_capa_mask = drv->extended_capa_mask; - capa->extended_capa_len = drv->extended_capa_len; - } - - if ((capa->flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) && - !drv->allow_p2p_device) { - wpa_printf(MSG_DEBUG, "nl80211: Do not indicate P2P_DEVICE support (p2p_device=1 driver param not specified)"); - capa->flags &= ~WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE; - } - - return 0; -} - - -static int wpa_driver_nl80211_set_operstate(void *priv, int state) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - - wpa_printf(MSG_DEBUG, "nl80211: Set %s operstate %d->%d (%s)", - bss->ifname, drv->operstate, state, - state ? "UP" : "DORMANT"); - drv->operstate = state; - return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, - state ? IF_OPER_UP : IF_OPER_DORMANT); -} - - -static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - struct nl80211_sta_flag_update upd; - int ret = -ENOBUFS; - - if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) { - wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated"); - return 0; - } - - wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for " - MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid)); - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(bss->ifname)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid); - - os_memset(&upd, 0, sizeof(upd)); - upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED); - if (authorized) - upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED); - NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); - - 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 STA flag: %d (%s)", - ret, strerror(-ret)); - return ret; -} - - -/* Set kernel driver on given frequency (MHz) */ -static int i802_set_freq(void *priv, struct hostapd_freq_params *freq) -{ - struct i802_bss *bss = priv; - return wpa_driver_nl80211_set_freq(bss, freq); -} - - -static inline int min_int(int a, int b) -{ - if (a < b) - return a; - return b; -} - - -static int get_key_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - /* - * TODO: validate the key index and mac address! - * Otherwise, there's a race condition as soon as - * the kernel starts sending key notifications. - */ - - if (tb[NL80211_ATTR_KEY_SEQ]) - memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]), - min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6)); - return NL_SKIP; -} - - -static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, - int idx, u8 *seq) -{ - struct i802_bss *bss = priv; - 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_GET_KEY); - - if (addr) - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); - - memset(seq, 0, 6); - - return send_and_recv_msgs(drv, msg, get_key_handler, seq); - nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} - - -static int i802_set_rts(void *priv, int rts) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret = -ENOBUFS; - u32 val; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - if (rts >= 2347) - val = (u32) -1; - else - val = rts; - - 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; -} - - -static int i802_set_frag(void *priv, int frag) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret = -ENOBUFS; - u32 val; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - if (frag >= 2346) - val = (u32) -1; - else - val = frag; - - 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; -} - - -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; - - wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)", - bss->ifname); - nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION); - - /* - * XXX: FIX! this needs to flush all VLANs too - */ - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(bss->ifname)); - - 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; -} - - -static int get_sta_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct hostap_sta_driver_data *data = arg; - struct nlattr *stats[NL80211_STA_INFO_MAX + 1]; - static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { - [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, - [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, - [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, - [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, - [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, - [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 }, - }; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - /* - * TODO: validate the interface and mac address! - * Otherwise, there's a race condition as soon as - * the kernel starts sending station notifications. - */ - - if (!tb[NL80211_ATTR_STA_INFO]) { - wpa_printf(MSG_DEBUG, "sta stats missing!"); - return NL_SKIP; - } - if (nla_parse_nested(stats, NL80211_STA_INFO_MAX, - tb[NL80211_ATTR_STA_INFO], - stats_policy)) { - wpa_printf(MSG_DEBUG, "failed to parse nested attributes!"); - return NL_SKIP; - } - - if (stats[NL80211_STA_INFO_INACTIVE_TIME]) - data->inactive_msec = - nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]); - if (stats[NL80211_STA_INFO_RX_BYTES]) - data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]); - if (stats[NL80211_STA_INFO_TX_BYTES]) - data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]); - if (stats[NL80211_STA_INFO_RX_PACKETS]) - data->rx_packets = - nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]); - if (stats[NL80211_STA_INFO_TX_PACKETS]) - data->tx_packets = - nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]); - if (stats[NL80211_STA_INFO_TX_FAILED]) - data->tx_retry_failed = - nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]); - - return NL_SKIP; -} - -static int i802_read_sta_data(struct i802_bss *bss, - struct hostap_sta_driver_data *data, - const u8 *addr) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - - os_memset(data, 0, sizeof(*data)); - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - 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; -} - - -static int i802_set_tx_queue_params(void *priv, int queue, int aifs, - int cw_min, int cw_max, int burst_time) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - struct nlattr *txq, *params; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); - - txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS); - if (!txq) - goto nla_put_failure; - - /* We are only sending parameters for a single TXQ at a time */ - params = nla_nest_start(msg, 1); - if (!params) - goto nla_put_failure; - - switch (queue) { - case 0: - NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO); - break; - case 1: - NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI); - break; - case 2: - NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE); - break; - case 3: - NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK); - break; - } - /* Burst time is configured in units of 0.1 msec and TXOP parameter in - * 32 usec, so need to convert the value here. */ - NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32); - NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min); - NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max); - NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs); - - nla_nest_end(msg, params); - - nla_nest_end(msg, txq); - - 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_sta_vlan(struct i802_bss *bss, const u8 *addr, - const char *ifname, int vlan_id) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret = -ENOBUFS; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR - ", ifname=%s[%d], vlan_id=%d)", - bss->ifname, if_nametoindex(bss->ifname), - MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id); - nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(bss->ifname)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN, - 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)", - MAC2STR(addr), ifname, vlan_id, ret, - strerror(-ret)); - } - nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -static int i802_get_inact_sec(void *priv, const u8 *addr) -{ - struct hostap_sta_driver_data data; - int ret; - - data.inactive_msec = (unsigned long) -1; - ret = i802_read_sta_data(priv, &data, addr); - if (ret || data.inactive_msec == (unsigned long) -1) - return -1; - return data.inactive_msec / 1000; -} - - -static int i802_sta_clear_stats(void *priv, const u8 *addr) -{ -#if 0 - /* TODO */ -#endif - return 0; -} - - -static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, - int reason) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct ieee80211_mgmt mgmt; - - if (drv->device_ap_sme) - return wpa_driver_nl80211_sta_remove(bss, addr); - - memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DEAUTH); - memcpy(mgmt.da, addr, ETH_ALEN); - memcpy(mgmt.sa, own_addr, ETH_ALEN); - memcpy(mgmt.bssid, own_addr, ETH_ALEN); - mgmt.u.deauth.reason_code = host_to_le16(reason); - return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, - IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth), 0, 0, 0, 0, - 0); -} - - -static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, - int reason) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct ieee80211_mgmt mgmt; - - if (drv->device_ap_sme) - return wpa_driver_nl80211_sta_remove(bss, addr); - - memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DISASSOC); - memcpy(mgmt.da, addr, ETH_ALEN); - memcpy(mgmt.sa, own_addr, ETH_ALEN); - memcpy(mgmt.bssid, own_addr, ETH_ALEN); - mgmt.u.disassoc.reason_code = host_to_le16(reason); - return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, - IEEE80211_HDRLEN + - sizeof(mgmt.u.disassoc), 0, 0, 0, 0, - 0); -} - - -static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) -{ - int i; - int *old; - - wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d", - ifidx); - for (i = 0; i < drv->num_if_indices; i++) { - if (drv->if_indices[i] == 0) { - drv->if_indices[i] = ifidx; - return; - } - } - - if (drv->if_indices != drv->default_if_indices) - old = drv->if_indices; - else - old = NULL; - - drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1, - sizeof(int)); - if (!drv->if_indices) { - if (!old) - drv->if_indices = drv->default_if_indices; - else - drv->if_indices = old; - wpa_printf(MSG_ERROR, "Failed to reallocate memory for " - "interfaces"); - wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx); - return; - } else if (!old) - os_memcpy(drv->if_indices, drv->default_if_indices, - sizeof(drv->default_if_indices)); - drv->if_indices[drv->num_if_indices] = ifidx; - drv->num_if_indices++; -} - - -static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) -{ - int i; - - for (i = 0; i < drv->num_if_indices; i++) { - if (drv->if_indices[i] == ifidx) { - drv->if_indices[i] = 0; - break; - } - } -} - - -static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) -{ - int i; - - for (i = 0; i < drv->num_if_indices; i++) - if (drv->if_indices[i] == ifidx) - return 1; - - return 0; -} - - -static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val, - const char *bridge_ifname, char *ifname_wds) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - char name[IFNAMSIZ + 1]; - - os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid); - if (ifname_wds) - os_strlcpy(ifname_wds, name, IFNAMSIZ + 1); - - wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR - " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name); - if (val) { - if (!if_nametoindex(name)) { - if (nl80211_create_iface(drv, name, - NL80211_IFTYPE_AP_VLAN, - bss->addr, 1, NULL, NULL, 0) < - 0) - return -1; - if (bridge_ifname && - linux_br_add_if(drv->global->ioctl_sock, - bridge_ifname, name) < 0) - return -1; - } - if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) { - wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA " - "interface %s up", name); - } - return i802_set_sta_vlan(priv, addr, name, 0); - } else { - if (bridge_ifname) - linux_br_del_if(drv->global->ioctl_sock, bridge_ifname, - name); - - i802_set_sta_vlan(priv, addr, bss->ifname, 0); - return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN, - name); - } -} - - -static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct wpa_driver_nl80211_data *drv = eloop_ctx; - struct sockaddr_ll lladdr; - unsigned char buf[3000]; - int len; - socklen_t fromlen = sizeof(lladdr); - - len = recvfrom(sock, buf, sizeof(buf), 0, - (struct sockaddr *)&lladdr, &fromlen); - if (len < 0) { - wpa_printf(MSG_ERROR, "nl80211: EAPOL recv failed: %s", - strerror(errno)); - return; - } - - if (have_ifidx(drv, lladdr.sll_ifindex)) - drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len); -} - - -static int i802_check_bridge(struct wpa_driver_nl80211_data *drv, - struct i802_bss *bss, - const char *brname, const char *ifname) -{ - int ifindex; - char in_br[IFNAMSIZ]; - - os_strlcpy(bss->brname, brname, IFNAMSIZ); - ifindex = if_nametoindex(brname); - if (ifindex == 0) { - /* - * Bridge was configured, but the bridge device does - * not exist. Try to add it now. - */ - 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)); - return -1; - } - bss->added_bridge = 1; - add_ifidx(drv, if_nametoindex(brname)); - } - - if (linux_br_get(in_br, ifname) == 0) { - if (os_strcmp(in_br, brname) == 0) - return 0; /* already in the bridge */ - - wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from " - "bridge %s", ifname, in_br); - 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", - ifname, brname, strerror(errno)); - return -1; - } - } - - wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s", - ifname, brname); - 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)); - return -1; - } - bss->added_if_into_bridge = 1; - - return 0; -} - - -static void *i802_init(struct hostapd_data *hapd, - struct wpa_init_params *params) -{ - struct wpa_driver_nl80211_data *drv; - struct i802_bss *bss; - size_t i; - char brname[IFNAMSIZ]; - int ifindex, br_ifindex; - int br_added = 0; - - bss = wpa_driver_nl80211_drv_init(hapd, params->ifname, - params->global_priv, 1, - params->bssid); - if (bss == NULL) - return NULL; - - drv = bss->drv; - - if (linux_br_get(brname, params->ifname) == 0) { - wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s", - params->ifname, brname); - br_ifindex = if_nametoindex(brname); - } else { - brname[0] = '\0'; - br_ifindex = 0; - } - - for (i = 0; i < params->num_bridge; i++) { - if (params->bridge[i]) { - ifindex = if_nametoindex(params->bridge[i]); - if (ifindex) - add_ifidx(drv, ifindex); - if (ifindex == br_ifindex) - br_added = 1; - } - } - if (!br_added && br_ifindex && - (params->num_bridge == 0 || !params->bridge[0])) - add_ifidx(drv, br_ifindex); - - /* start listening for EAPOL on the default AP interface */ - add_ifidx(drv, drv->ifindex); - - if (params->num_bridge && params->bridge[0] && - i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0) - goto failed; - - drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); - if (drv->eapol_sock < 0) { - wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s", - strerror(errno)); - goto failed; - } - - if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL)) - { - wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol"); - goto failed; - } - - 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: - wpa_driver_nl80211_deinit(bss); - return NULL; -} - - -static void i802_deinit(void *priv) -{ - struct i802_bss *bss = priv; - wpa_driver_nl80211_deinit(bss); -} - - -static enum nl80211_iftype wpa_driver_nl80211_if_type( - enum wpa_driver_if_type type) -{ - switch (type) { - case WPA_IF_STATION: - return NL80211_IFTYPE_STATION; - case WPA_IF_P2P_CLIENT: - case WPA_IF_P2P_GROUP: - return NL80211_IFTYPE_P2P_CLIENT; - case WPA_IF_AP_VLAN: - return NL80211_IFTYPE_AP_VLAN; - case WPA_IF_AP_BSS: - return NL80211_IFTYPE_AP; - case WPA_IF_P2P_GO: - return NL80211_IFTYPE_P2P_GO; - case WPA_IF_P2P_DEVICE: - return NL80211_IFTYPE_P2P_DEVICE; - } - return -1; -} - - -#ifdef CONFIG_P2P - -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->first_bss->addr, ETH_ALEN) == 0) - return 1; - } - return 0; -} - - -static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv, - u8 *new_addr) -{ - unsigned int idx; - - if (!drv->global) - return -1; - - os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN); - for (idx = 0; idx < 64; idx++) { - new_addr[0] = drv->first_bss->addr[0] | 0x02; - new_addr[0] ^= idx << 2; - if (!nl80211_addr_in_use(drv->global, new_addr)) - break; - } - if (idx == 64) - return -1; - - wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address " - MACSTR, MAC2STR(new_addr)); - - return 0; -} - -#endif /* CONFIG_P2P */ - - -struct wdev_info { - u64 wdev_id; - int wdev_id_set; - u8 macaddr[ETH_ALEN]; -}; - -static int nl80211_wdev_handler(struct nl_msg *msg, void *arg) -{ - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct wdev_info *wi = arg; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - if (tb[NL80211_ATTR_WDEV]) { - wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]); - wi->wdev_id_set = 1; - } - - if (tb[NL80211_ATTR_MAC]) - os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]), - ETH_ALEN); - - return NL_SKIP; -} - - -static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, - const char *ifname, const u8 *addr, - void *bss_ctx, void **drv_priv, - char *force_ifname, u8 *if_addr, - const char *bridge, int use_existing) -{ - enum nl80211_iftype nlmode; - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - int ifidx; - int added = 1; - - if (addr) - os_memcpy(if_addr, addr, ETH_ALEN); - nlmode = wpa_driver_nl80211_if_type(type); - if (nlmode == NL80211_IFTYPE_P2P_DEVICE) { - struct wdev_info p2pdev_info; - - os_memset(&p2pdev_info, 0, sizeof(p2pdev_info)); - ifidx = nl80211_create_iface(drv, ifname, nlmode, addr, - 0, nl80211_wdev_handler, - &p2pdev_info, use_existing); - if (!p2pdev_info.wdev_id_set || ifidx != 0) { - wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s", - ifname); - return -1; - } - - drv->global->if_add_wdevid = p2pdev_info.wdev_id; - drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set; - if (!is_zero_ether_addr(p2pdev_info.macaddr)) - os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN); - wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created", - ifname, - (long long unsigned int) p2pdev_info.wdev_id); - } else { - ifidx = nl80211_create_iface(drv, ifname, nlmode, addr, - 0, NULL, NULL, use_existing); - if (use_existing && ifidx == -ENFILE) { - added = 0; - ifidx = if_nametoindex(ifname); - } else if (ifidx < 0) { - return -1; - } - } - - if (!addr) { - if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) - os_memcpy(if_addr, bss->addr, ETH_ALEN); - else if (linux_get_ifhwaddr(drv->global->ioctl_sock, - bss->ifname, if_addr) < 0) { - if (added) - nl80211_remove_iface(drv, ifidx); - return -1; - } - } - -#ifdef CONFIG_P2P - if (!addr && - (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP || - type == WPA_IF_P2P_GO)) { - /* Enforce unique P2P Interface Address */ - u8 new_addr[ETH_ALEN]; - - if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname, - new_addr) < 0) { - nl80211_remove_iface(drv, ifidx); - return -1; - } - if (nl80211_addr_in_use(drv->global, new_addr)) { - wpa_printf(MSG_DEBUG, "nl80211: Allocate new address " - "for P2P group interface"); - if (nl80211_p2p_interface_addr(drv, new_addr) < 0) { - nl80211_remove_iface(drv, ifidx); - return -1; - } - if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, - new_addr) < 0) { - nl80211_remove_iface(drv, ifidx); - return -1; - } - } - os_memcpy(if_addr, new_addr, ETH_ALEN); - } -#endif /* CONFIG_P2P */ - - if (type == WPA_IF_AP_BSS) { - struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss)); - if (new_bss == NULL) { - if (added) - nl80211_remove_iface(drv, ifidx); - return -1; - } - - if (bridge && - i802_check_bridge(drv, new_bss, bridge, ifname) < 0) { - wpa_printf(MSG_ERROR, "nl80211: Failed to add the new " - "interface %s to a bridge %s", - ifname, bridge); - if (added) - nl80211_remove_iface(drv, ifidx); - os_free(new_bss); - return -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; - new_bss->freq = drv->first_bss->freq; - new_bss->ctx = bss_ctx; - new_bss->added_if = added; - drv->first_bss->next = new_bss; - if (drv_priv) - *drv_priv = new_bss; - nl80211_init_bss(new_bss); - - /* Subscribe management frames for this WPA_IF_AP_BSS */ - if (nl80211_setup_ap(new_bss)) - return -1; - } - - if (drv->global) - drv->global->if_add_ifindex = ifidx; - - return 0; -} - - -static int wpa_driver_nl80211_if_remove(struct i802_bss *bss, - enum wpa_driver_if_type type, - const char *ifname) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - int ifindex = if_nametoindex(ifname); - - wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d", - __func__, type, ifname, ifindex, bss->added_if); - if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex)) - nl80211_remove_iface(drv, ifindex); - - if (type != WPA_IF_AP_BSS) - return 0; - - if (bss->added_if_into_bridge) { - 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->global->ioctl_sock, bss->brname) < 0) - wpa_printf(MSG_INFO, "nl80211: Failed to remove " - "bridge %s: %s", - bss->brname, strerror(errno)); - } - - if (bss != drv->first_bss) { - struct i802_bss *tbss; - - wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it"); - for (tbss = drv->first_bss; tbss; tbss = tbss->next) { - if (tbss->next == bss) { - tbss->next = bss->next; - /* Unsubscribe management frames */ - nl80211_teardown_ap(bss); - nl80211_destroy_bss(bss); - os_free(bss); - bss = NULL; - break; - } - } - if (bss) - wpa_printf(MSG_INFO, "nl80211: %s - could not find " - "BSS %p in the list", __func__, bss); - } else { - wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context"); - nl80211_teardown_ap(bss); - if (!bss->added_if && !drv->first_bss->next) - wpa_driver_nl80211_del_beacon(drv); - nl80211_destroy_bss(bss); - if (!bss->added_if) - i802_set_iface_flags(bss, 0); - if (drv->first_bss->next) { - drv->first_bss = drv->first_bss->next; - drv->ctx = drv->first_bss->ctx; - os_free(bss); - } else { - wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to"); - } - } - - return 0; -} - - -static int cookie_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - u64 *cookie = arg; - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - if (tb[NL80211_ATTR_COOKIE]) - *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); - return NL_SKIP; -} - - -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, 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; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d " - "no_ack=%d offchanok=%d", - freq, wait, no_cck, no_ack, offchanok); - wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len); - nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME); - - if (nl80211_set_iface_id(msg, bss) < 0) - goto nla_put_failure; - if (freq) - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); - if (wait) - NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait); - if (offchanok && (drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX)) - 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; - ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie); - msg = NULL; - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d " - "(%s) (freq=%u wait=%u)", ret, strerror(-ret), - freq, wait); - goto nla_put_failure; - } - wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; " - "cookie 0x%llx", no_ack ? " (no ACK)" : "", - (long long unsigned int) cookie); - - if (cookie_out) - *cookie_out = no_ack ? (u64) -1 : cookie; - -nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -static int wpa_driver_nl80211_send_action(struct i802_bss *bss, - unsigned int freq, - unsigned int wait_time, - const u8 *dst, const u8 *src, - const u8 *bssid, - const u8 *data, size_t data_len, - int no_cck) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - int ret = -1; - u8 *buf; - struct ieee80211_hdr *hdr; - - wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, " - "freq=%u MHz wait=%d ms no_cck=%d)", - drv->ifindex, freq, wait_time, no_cck); - - buf = os_zalloc(24 + data_len); - if (buf == NULL) - return ret; - os_memcpy(buf + 24, data, data_len); - hdr = (struct ieee80211_hdr *) buf; - hdr->frame_control = - IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); - os_memcpy(hdr->addr1, dst, ETH_ALEN); - os_memcpy(hdr->addr2, src, ETH_ALEN); - os_memcpy(hdr->addr3, bssid, ETH_ALEN); - - if (is_ap_interface(drv->nlmode) && - (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) || - (int) freq == bss->freq || drv->device_ap_sme || - !drv->use_monitor)) - ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len, - 0, freq, no_cck, 1, - wait_time); - else - ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf, - 24 + data_len, - &drv->send_action_cookie, - no_cck, 0, 1); - - os_free(buf); - return ret; -} - - -static void wpa_driver_nl80211_send_action_cancel_wait(void *priv) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret; - - msg = nlmsg_alloc(); - if (!msg) - return; - - wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx", - (long long unsigned int) drv->send_action_cookie); - nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL); - - if (nl80211_set_iface_id(msg, bss) < 0) - goto nla_put_failure; - NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - msg = NULL; - if (ret) - wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d " - "(%s)", ret, strerror(-ret)); - - nla_put_failure: - nlmsg_free(msg); -} - - -static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq, - unsigned int duration) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret; - u64 cookie; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL); - - if (nl80211_set_iface_id(msg, bss) < 0) - goto nla_put_failure; - - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); - NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration); - - 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; -} - - -static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret; - - if (!drv->pending_remain_on_chan) { - wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel " - "to cancel"); - return -1; - } - - wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie " - "0x%llx", - (long long unsigned int) drv->remain_on_chan_cookie); - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL); - - if (nl80211_set_iface_id(msg, bss) < 0) - goto nla_put_failure; - - NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - 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; -} - - -static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - - if (!report) { - 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); - nl80211_destroy_eloop_handle(&bss->nl_preq); - } - return 0; - } - - if (bss->nl_preq) { - wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting " - "already on! nl_preq=%p", bss->nl_preq); - return 0; - } - - 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); - - if (nl80211_register_frame(bss, bss->nl_preq, - (WLAN_FC_TYPE_MGMT << 2) | - (WLAN_FC_STYPE_PROBE_REQ << 4), - NULL, 0) < 0) - goto out_err; - - nl80211_register_eloop_read(&bss->nl_preq, - wpa_driver_nl80211_event_receive, - bss->nl_cb); - - return 0; - - out_err: - nl_destroy_handles(&bss->nl_preq); - return -1; -} - - -static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv, - int ifindex, int disabled) -{ - struct nl_msg *msg; - struct nlattr *bands, *band; - int ret; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - 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); - if (!bands) - goto nla_put_failure; - - /* - * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything - * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS - * rates. All 5 GHz rates are left enabled. - */ - band = nla_nest_start(msg, NL80211_BAND_2GHZ); - if (!band) - goto nla_put_failure; - 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); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - msg = NULL; - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d " - "(%s)", ret, strerror(-ret)); - } else - drv->disabled_11b_rates = disabled; - - return ret; - -nla_put_failure: - nlmsg_free(msg); - return -1; -} - - -static int wpa_driver_nl80211_deinit_ap(void *priv) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - if (!is_ap_interface(drv->nlmode)) - return -1; - wpa_driver_nl80211_del_beacon(drv); - - /* - * If the P2P GO interface was dynamically added, then it is - * possible that the interface change to station is not possible. - */ - if (drv->nlmode == NL80211_IFTYPE_P2P_GO && bss->if_dynamic) - return 0; - - return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION); -} - - -static int wpa_driver_nl80211_stop_ap(void *priv) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - if (!is_ap_interface(drv->nlmode)) - return -1; - wpa_driver_nl80211_del_beacon(drv); - bss->beacon_set = 0; - return 0; -} - - -static int wpa_driver_nl80211_deinit_p2p_cli(void *priv) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT) - return -1; - - /* - * If the P2P Client interface was dynamically added, then it is - * possible that the interface change to station is not possible. - */ - if (bss->if_dynamic) - return 0; - - return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION); -} - - -static void wpa_driver_nl80211_resume(void *priv) -{ - struct i802_bss *bss = priv; - - if (i802_set_iface_flags(bss, 1)) - wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event"); -} - - -static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap, - const u8 *ies, size_t ies_len) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - int ret; - u8 *data, *pos; - size_t data_len; - const u8 *own_addr = bss->addr; - - if (action != 1) { - wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action " - "action %d", action); - return -1; - } - - /* - * Action frame payload: - * Category[1] = 6 (Fast BSS Transition) - * Action[1] = 1 (Fast BSS Transition Request) - * STA Address - * Target AP Address - * FT IEs - */ - - data_len = 2 + 2 * ETH_ALEN + ies_len; - data = os_malloc(data_len); - if (data == NULL) - return -1; - pos = data; - *pos++ = 0x06; /* FT Action category */ - *pos++ = action; - os_memcpy(pos, own_addr, ETH_ALEN); - pos += ETH_ALEN; - os_memcpy(pos, target_ap, ETH_ALEN); - pos += ETH_ALEN; - os_memcpy(pos, ies, ies_len); - - ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0, - drv->bssid, own_addr, drv->bssid, - data, data_len, 0); - os_free(data); - - return ret; -} - - -static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - struct nlattr *cqm; - int ret = -1; - - wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d " - "hysteresis=%d", threshold, hysteresis); - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); - - cqm = nla_nest_start(msg, NL80211_ATTR_CQM); - if (cqm == NULL) - goto nla_put_failure; - - NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold); - NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis); - nla_nest_end(msg, cqm); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - msg = NULL; - -nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -static int get_channel_width(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct wpa_signal_info *sig_change = arg; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - sig_change->center_frq1 = -1; - sig_change->center_frq2 = -1; - sig_change->chanwidth = CHAN_WIDTH_UNKNOWN; - - if (tb[NL80211_ATTR_CHANNEL_WIDTH]) { - sig_change->chanwidth = convert2width( - nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH])); - if (tb[NL80211_ATTR_CENTER_FREQ1]) - sig_change->center_frq1 = - nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]); - if (tb[NL80211_ATTR_CENTER_FREQ2]) - sig_change->center_frq2 = - nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]); - } - - return NL_SKIP; -} - - -static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv, - struct wpa_signal_info *sig) -{ - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_INTERFACE); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - - return send_and_recv_msgs(drv, msg, get_channel_width, sig); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} - - -static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - int res; - - os_memset(si, 0, sizeof(*si)); - res = nl80211_get_link_signal(drv, si); - if (res != 0) - return res; - - res = nl80211_get_channel_width(drv, si); - if (res != 0) - return res; - - return nl80211_get_link_noise(drv, si); -} - - -static int wpa_driver_nl80211_shared_freq(void *priv) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - 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); - - dl_list_for_each(driver, &drv->global->interfaces, - struct wpa_driver_nl80211_data, list) { - if (drv == driver || - os_strcmp(drv->phyname, driver->phyname) != 0 || - !driver->associated) - continue; - - wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s " - MACSTR, - driver->phyname, driver->first_bss->ifname, - MAC2STR(driver->first_bss->addr)); - if (is_ap_interface(driver->nlmode)) - freq = driver->first_bss->freq; - else - freq = nl80211_get_assoc_freq(driver); - wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d", - drv->phyname, freq); - } - - if (!freq) - wpa_printf(MSG_DEBUG, "nl80211: No shared interface for " - "PHY (%s) in associated state", drv->phyname); - - return freq; -} - - -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, - 0, 0, 0, 0); -} - - -static int nl80211_set_param(void *priv, const char *param) -{ - wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param); - if (param == NULL) - return 0; - -#ifdef CONFIG_P2P - if (os_strstr(param, "use_p2p_group_interface=1")) { - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - - wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group " - "interface"); - drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; - drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; - } - - if (os_strstr(param, "p2p_device=1")) { - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - drv->allow_p2p_device = 1; - } -#endif /* CONFIG_P2P */ - - if (os_strstr(param, "use_monitor=1")) { - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - drv->use_monitor = 1; - } - - if (os_strstr(param, "force_connect_cmd=1")) { - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME; - } - - return 0; -} - - -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) { - wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s", - strerror(errno)); - goto err; - } - - return global; - -err: - nl80211_global_deinit(global); - return NULL; -} - - -static void nl80211_global_deinit(void *priv) -{ - struct nl80211_global *global = priv; - if (global == NULL) - return; - if (!dl_list_empty(&global->interfaces)) { - wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at " - "nl80211_global_deinit", - dl_list_len(&global->interfaces)); - } - - if (global->netlink) - netlink_deinit(global->netlink); - - nl_destroy_handles(&global->nl); - - if (global->nl_event) - nl80211_destroy_eloop_handle(&global->nl_event); - - nl_cb_put(global->nl_cb); - - if (global->ioctl_sock >= 0) - close(global->ioctl_sock); - - os_free(global); -} - - -static const char * nl80211_get_radio_name(void *priv) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - return drv->phyname; -} - - -static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid, - const u8 *pmkid) -{ - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - nl80211_cmd(bss->drv, msg, 0, cmd); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); - if (pmkid) - NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid); - if (bssid) - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); - - return send_and_recv_msgs(bss->drv, msg, NULL, NULL); - nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} - - -static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid) -{ - struct i802_bss *bss = priv; - wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid)); - return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid); -} - - -static int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid) -{ - struct i802_bss *bss = priv; - wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR, - MAC2STR(bssid)); - return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid); -} - - -static int nl80211_flush_pmkid(void *priv) -{ - struct i802_bss *bss = priv; - wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs"); - return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL); -} - - -static void clean_survey_results(struct survey_results *survey_results) -{ - struct freq_survey *survey, *tmp; - - if (dl_list_empty(&survey_results->survey_list)) - return; - - dl_list_for_each_safe(survey, tmp, &survey_results->survey_list, - struct freq_survey, list) { - dl_list_del(&survey->list); - os_free(survey); - } -} - - -static void add_survey(struct nlattr **sinfo, u32 ifidx, - struct dl_list *survey_list) -{ - struct freq_survey *survey; - - survey = os_zalloc(sizeof(struct freq_survey)); - if (!survey) - return; - - survey->ifidx = ifidx; - survey->freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]); - survey->filled = 0; - - if (sinfo[NL80211_SURVEY_INFO_NOISE]) { - survey->nf = (int8_t) - nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); - survey->filled |= SURVEY_HAS_NF; - } - - if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) { - survey->channel_time = - nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]); - survey->filled |= SURVEY_HAS_CHAN_TIME; - } - - if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) { - survey->channel_time_busy = - nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]); - survey->filled |= SURVEY_HAS_CHAN_TIME_BUSY; - } - - if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) { - survey->channel_time_rx = - nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]); - survey->filled |= SURVEY_HAS_CHAN_TIME_RX; - } - - if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) { - survey->channel_time_tx = - nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]); - survey->filled |= SURVEY_HAS_CHAN_TIME_TX; - } - - wpa_printf(MSG_DEBUG, "nl80211: Freq survey dump event (freq=%d MHz noise=%d channel_time=%ld busy_time=%ld tx_time=%ld rx_time=%ld filled=%04x)", - survey->freq, - survey->nf, - (unsigned long int) survey->channel_time, - (unsigned long int) survey->channel_time_busy, - (unsigned long int) survey->channel_time_tx, - (unsigned long int) survey->channel_time_rx, - survey->filled); - - dl_list_add_tail(survey_list, &survey->list); -} - - -static int check_survey_ok(struct nlattr **sinfo, u32 surveyed_freq, - unsigned int freq_filter) -{ - if (!freq_filter) - return 1; - - return freq_filter == surveyed_freq; -} - - -static int survey_handler(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]; - struct survey_results *survey_results; - u32 surveyed_freq = 0; - u32 ifidx; - - 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 }, - }; - - survey_results = (struct survey_results *) arg; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (!tb[NL80211_ATTR_IFINDEX]) - return NL_SKIP; - - ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); - - if (!tb[NL80211_ATTR_SURVEY_INFO]) - return NL_SKIP; - - if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, - tb[NL80211_ATTR_SURVEY_INFO], - survey_policy)) - return NL_SKIP; - - if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) { - wpa_printf(MSG_ERROR, "nl80211: Invalid survey data"); - return NL_SKIP; - } - - surveyed_freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]); - - if (!check_survey_ok(sinfo, surveyed_freq, - survey_results->freq_filter)) - return NL_SKIP; - - if (survey_results->freq_filter && - survey_results->freq_filter != surveyed_freq) { - wpa_printf(MSG_EXCESSIVE, "nl80211: Ignoring survey data for freq %d MHz", - surveyed_freq); - return NL_SKIP; - } - - add_survey(sinfo, ifidx, &survey_results->survey_list); - - return NL_SKIP; -} - - -static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int err = -ENOBUFS; - union wpa_event_data data; - struct survey_results *survey_results; - - os_memset(&data, 0, sizeof(data)); - survey_results = &data.survey_results; - - dl_list_init(&survey_results->survey_list); - - msg = nlmsg_alloc(); - if (!msg) - goto nla_put_failure; - - nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - - if (freq) - data.survey_results.freq_filter = freq; - - do { - wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data"); - err = send_and_recv_msgs(drv, msg, survey_handler, - survey_results); - } while (err > 0); - - if (err) { - wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data"); - goto out_clean; - } - - wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data); - -out_clean: - clean_survey_results(survey_results); -nla_put_failure: - return err; -} - - -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, 0, - 0, 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) { -#ifdef ANDROID_P2P - wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow); -#else /* ANDROID_P2P */ - return -1; /* Not yet supported */ -#endif /* ANDROID_P2P */ - } - - 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); -} - - -static int nl80211_start_radar_detection(void *priv, - struct hostapd_freq_params *freq) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret; - - wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC) %d MHz (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)", - freq->freq, freq->ht_enabled, freq->vht_enabled, - freq->bandwidth, freq->center_freq1, freq->center_freq2); - - if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) { - wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar " - "detection"); - return -1; - } - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq); - - if (freq->vht_enabled) { - switch (freq->bandwidth) { - case 20: - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_20); - break; - case 40: - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_40); - break; - case 80: - if (freq->center_freq2) - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_80P80); - else - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_80); - break; - case 160: - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_160); - break; - default: - return -1; - } - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1); - if (freq->center_freq2) - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, - freq->center_freq2); - } else if (freq->ht_enabled) { - switch (freq->sec_channel_offset) { - case -1: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - NL80211_CHAN_HT40MINUS); - break; - case 1: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - NL80211_CHAN_HT40PLUS); - break; - default: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - NL80211_CHAN_HT20); - break; - } - } - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret == 0) - return 0; - wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: " - "%d (%s)", ret, strerror(-ret)); -nla_put_failure: - return -1; -} - -#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_strlcpy(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 */ - - -static int driver_nl80211_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 i802_bss *bss = priv; - return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx, - set_tx, seq, seq_len, key, key_len); -} - - -static int driver_nl80211_scan2(void *priv, - struct wpa_driver_scan_params *params) -{ - struct i802_bss *bss = priv; - return wpa_driver_nl80211_scan(bss, params); -} - - -static int driver_nl80211_deauthenticate(void *priv, const u8 *addr, - int reason_code) -{ - struct i802_bss *bss = priv; - return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code); -} - - -static int driver_nl80211_authenticate(void *priv, - struct wpa_driver_auth_params *params) -{ - struct i802_bss *bss = priv; - return wpa_driver_nl80211_authenticate(bss, params); -} - - -static void driver_nl80211_deinit(void *priv) -{ - struct i802_bss *bss = priv; - wpa_driver_nl80211_deinit(bss); -} - - -static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type, - const char *ifname) -{ - struct i802_bss *bss = priv; - return wpa_driver_nl80211_if_remove(bss, type, ifname); -} - - -static int driver_nl80211_send_mlme(void *priv, const u8 *data, - size_t data_len, int noack) -{ - struct i802_bss *bss = priv; - return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack, - 0, 0, 0, 0); -} - - -static int driver_nl80211_sta_remove(void *priv, const u8 *addr) -{ - struct i802_bss *bss = priv; - return wpa_driver_nl80211_sta_remove(bss, addr); -} - - -static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr, - const char *ifname, int vlan_id) -{ - struct i802_bss *bss = priv; - return i802_set_sta_vlan(bss, addr, ifname, vlan_id); -} - - -static int driver_nl80211_read_sta_data(void *priv, - struct hostap_sta_driver_data *data, - const u8 *addr) -{ - struct i802_bss *bss = priv; - return i802_read_sta_data(bss, data, addr); -} - - -static int 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, - int no_cck) -{ - struct i802_bss *bss = priv; - return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src, - bssid, data, data_len, no_cck); -} - - -static int driver_nl80211_probe_req_report(void *priv, int report) -{ - struct i802_bss *bss = priv; - return wpa_driver_nl80211_probe_req_report(bss, report); -} - - -static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md, - const u8 *ies, size_t ies_len) -{ - int ret; - struct nl_msg *msg; - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - u16 mdid = WPA_GET_LE16(md); - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs"); - nl80211_cmd(drv, msg, 0, NL80211_CMD_UPDATE_FT_IES); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies); - NLA_PUT_U16(msg, NL80211_ATTR_MDID, mdid); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed " - "err=%d (%s)", ret, strerror(-ret)); - } - - return ret; - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} - - -const u8 * wpa_driver_nl80211_get_macaddr(void *priv) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - - if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) - return NULL; - - return bss->addr; -} - - -static const char * scan_state_str(enum scan_states scan_state) -{ - switch (scan_state) { - case NO_SCAN: - return "NO_SCAN"; - case SCAN_REQUESTED: - return "SCAN_REQUESTED"; - case SCAN_STARTED: - return "SCAN_STARTED"; - case SCAN_COMPLETED: - return "SCAN_COMPLETED"; - case SCAN_ABORTED: - return "SCAN_ABORTED"; - case SCHED_SCAN_STARTED: - return "SCHED_SCAN_STARTED"; - case SCHED_SCAN_STOPPED: - return "SCHED_SCAN_STOPPED"; - case SCHED_SCAN_RESULTS: - return "SCHED_SCAN_RESULTS"; - } - - return "??"; -} - - -static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - int res; - char *pos, *end; - - pos = buf; - end = buf + buflen; - - res = os_snprintf(pos, end - pos, - "ifindex=%d\n" - "ifname=%s\n" - "brname=%s\n" - "addr=" MACSTR "\n" - "freq=%d\n" - "%s%s%s%s%s", - bss->ifindex, - bss->ifname, - bss->brname, - MAC2STR(bss->addr), - bss->freq, - bss->beacon_set ? "beacon_set=1\n" : "", - bss->added_if_into_bridge ? - "added_if_into_bridge=1\n" : "", - bss->added_bridge ? "added_bridge=1\n" : "", - bss->in_deinit ? "in_deinit=1\n" : "", - bss->if_dynamic ? "if_dynamic=1\n" : ""); - if (res < 0 || res >= end - pos) - return pos - buf; - pos += res; - - if (bss->wdev_id_set) { - res = os_snprintf(pos, end - pos, "wdev_id=%llu\n", - (unsigned long long) bss->wdev_id); - if (res < 0 || res >= end - pos) - return pos - buf; - pos += res; - } - - res = os_snprintf(pos, end - pos, - "phyname=%s\n" - "drv_ifindex=%d\n" - "operstate=%d\n" - "scan_state=%s\n" - "auth_bssid=" MACSTR "\n" - "auth_attempt_bssid=" MACSTR "\n" - "bssid=" MACSTR "\n" - "prev_bssid=" MACSTR "\n" - "associated=%d\n" - "assoc_freq=%u\n" - "monitor_sock=%d\n" - "monitor_ifidx=%d\n" - "monitor_refcount=%d\n" - "last_mgmt_freq=%u\n" - "eapol_tx_sock=%d\n" - "%s%s%s%s%s%s%s%s%s%s%s%s%s", - drv->phyname, - drv->ifindex, - drv->operstate, - scan_state_str(drv->scan_state), - MAC2STR(drv->auth_bssid), - MAC2STR(drv->auth_attempt_bssid), - MAC2STR(drv->bssid), - MAC2STR(drv->prev_bssid), - drv->associated, - drv->assoc_freq, - drv->monitor_sock, - drv->monitor_ifidx, - drv->monitor_refcount, - drv->last_mgmt_freq, - drv->eapol_tx_sock, - drv->ignore_if_down_event ? - "ignore_if_down_event=1\n" : "", - drv->scan_complete_events ? - "scan_complete_events=1\n" : "", - drv->disabled_11b_rates ? - "disabled_11b_rates=1\n" : "", - drv->pending_remain_on_chan ? - "pending_remain_on_chan=1\n" : "", - drv->in_interface_list ? "in_interface_list=1\n" : "", - drv->device_ap_sme ? "device_ap_sme=1\n" : "", - drv->poll_command_supported ? - "poll_command_supported=1\n" : "", - drv->data_tx_status ? "data_tx_status=1\n" : "", - drv->scan_for_auth ? "scan_for_auth=1\n" : "", - drv->retry_auth ? "retry_auth=1\n" : "", - drv->use_monitor ? "use_monitor=1\n" : "", - drv->ignore_next_local_disconnect ? - "ignore_next_local_disconnect=1\n" : "", - drv->allow_p2p_device ? "allow_p2p_device=1\n" : ""); - if (res < 0 || res >= end - pos) - return pos - buf; - pos += res; - - if (drv->has_capability) { - res = os_snprintf(pos, end - pos, - "capa.key_mgmt=0x%x\n" - "capa.enc=0x%x\n" - "capa.auth=0x%x\n" - "capa.flags=0x%x\n" - "capa.max_scan_ssids=%d\n" - "capa.max_sched_scan_ssids=%d\n" - "capa.sched_scan_supported=%d\n" - "capa.max_match_sets=%d\n" - "capa.max_remain_on_chan=%u\n" - "capa.max_stations=%u\n" - "capa.probe_resp_offloads=0x%x\n" - "capa.max_acl_mac_addrs=%u\n" - "capa.num_multichan_concurrent=%u\n", - drv->capa.key_mgmt, - drv->capa.enc, - drv->capa.auth, - drv->capa.flags, - drv->capa.max_scan_ssids, - drv->capa.max_sched_scan_ssids, - drv->capa.sched_scan_supported, - drv->capa.max_match_sets, - drv->capa.max_remain_on_chan, - drv->capa.max_stations, - drv->capa.probe_resp_offloads, - drv->capa.max_acl_mac_addrs, - drv->capa.num_multichan_concurrent); - if (res < 0 || res >= end - pos) - return pos - buf; - pos += res; - } - - return pos - buf; -} - - -static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings) -{ - if (settings->head) - NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, - settings->head_len, settings->head); - - if (settings->tail) - NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, - settings->tail_len, settings->tail); - - if (settings->beacon_ies) - NLA_PUT(msg, NL80211_ATTR_IE, - settings->beacon_ies_len, settings->beacon_ies); - - if (settings->proberesp_ies) - NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP, - settings->proberesp_ies_len, settings->proberesp_ies); - - if (settings->assocresp_ies) - NLA_PUT(msg, - NL80211_ATTR_IE_ASSOC_RESP, - settings->assocresp_ies_len, settings->assocresp_ies); - - if (settings->probe_resp) - NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, - settings->probe_resp_len, settings->probe_resp); - - return 0; - -nla_put_failure: - return -ENOBUFS; -} - - -static int nl80211_switch_channel(void *priv, struct csa_settings *settings) -{ - struct nl_msg *msg; - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nlattr *beacon_csa; - int ret = -ENOBUFS; - - wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d width=%d cf1=%d cf2=%d)", - settings->cs_count, settings->block_tx, - settings->freq_params.freq, settings->freq_params.bandwidth, - settings->freq_params.center_freq1, - settings->freq_params.center_freq2); - - if (!(drv->capa.flags & WPA_DRIVER_FLAGS_AP_CSA)) { - wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command"); - return -EOPNOTSUPP; - } - - if ((drv->nlmode != NL80211_IFTYPE_AP) && - (drv->nlmode != NL80211_IFTYPE_P2P_GO)) - return -EOPNOTSUPP; - - /* check settings validity */ - if (!settings->beacon_csa.tail || - ((settings->beacon_csa.tail_len <= - settings->counter_offset_beacon) || - (settings->beacon_csa.tail[settings->counter_offset_beacon] != - settings->cs_count))) - return -EINVAL; - - if (settings->beacon_csa.probe_resp && - ((settings->beacon_csa.probe_resp_len <= - settings->counter_offset_presp) || - (settings->beacon_csa.probe_resp[settings->counter_offset_presp] != - settings->cs_count))) - return -EINVAL; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_CHANNEL_SWITCH); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, settings->cs_count); - ret = nl80211_put_freq_params(msg, &settings->freq_params); - if (ret) - goto error; - - if (settings->block_tx) - NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX); - - /* beacon_after params */ - ret = set_beacon_data(msg, &settings->beacon_after); - if (ret) - goto error; - - /* beacon_csa params */ - beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES); - if (!beacon_csa) - goto nla_put_failure; - - ret = set_beacon_data(msg, &settings->beacon_csa); - if (ret) - goto error; - - NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_BEACON, - settings->counter_offset_beacon); - - if (settings->beacon_csa.probe_resp) - NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_PRESP, - settings->counter_offset_presp); - - nla_nest_end(msg, beacon_csa); - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)", - ret, strerror(-ret)); - } - return ret; - -nla_put_failure: - ret = -ENOBUFS; -error: - nlmsg_free(msg); - wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request"); - return ret; -} - - -static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set, - u8 qos_map_set_len) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map", - qos_map_set, qos_map_set_len); - - nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_QOS_MAP); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret) - wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed"); - - return ret; - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} - - -const struct wpa_driver_ops wpa_driver_nl80211_ops = { - .name = "nl80211", - .desc = "Linux nl80211/cfg80211", - .get_bssid = wpa_driver_nl80211_get_bssid, - .get_ssid = wpa_driver_nl80211_get_ssid, - .set_key = driver_nl80211_set_key, - .scan2 = driver_nl80211_scan2, - .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 = driver_nl80211_deauthenticate, - .authenticate = driver_nl80211_authenticate, - .associate = wpa_driver_nl80211_associate, - .global_init = nl80211_global_init, - .global_deinit = nl80211_global_deinit, - .init2 = wpa_driver_nl80211_init, - .deinit = driver_nl80211_deinit, - .get_capa = wpa_driver_nl80211_get_capa, - .set_operstate = wpa_driver_nl80211_set_operstate, - .set_supp_port = wpa_driver_nl80211_set_supp_port, - .set_country = wpa_driver_nl80211_set_country, - .get_country = wpa_driver_nl80211_get_country, - .set_ap = wpa_driver_nl80211_set_ap, - .set_acl = wpa_driver_nl80211_set_acl, - .if_add = wpa_driver_nl80211_if_add, - .if_remove = driver_nl80211_if_remove, - .send_mlme = driver_nl80211_send_mlme, - .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data, - .sta_add = wpa_driver_nl80211_sta_add, - .sta_remove = driver_nl80211_sta_remove, - .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol, - .sta_set_flags = wpa_driver_nl80211_sta_set_flags, - .hapd_init = i802_init, - .hapd_deinit = i802_deinit, - .set_wds_sta = i802_set_wds_sta, - .get_seqnum = i802_get_seqnum, - .flush = i802_flush, - .get_inact_sec = i802_get_inact_sec, - .sta_clear_stats = i802_sta_clear_stats, - .set_rts = i802_set_rts, - .set_frag = i802_set_frag, - .set_tx_queue_params = i802_set_tx_queue_params, - .set_sta_vlan = driver_nl80211_set_sta_vlan, - .sta_deauth = i802_sta_deauth, - .sta_disassoc = i802_sta_disassoc, - .read_sta_data = driver_nl80211_read_sta_data, - .set_freq = i802_set_freq, - .send_action = driver_nl80211_send_action, - .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait, - .remain_on_channel = wpa_driver_nl80211_remain_on_channel, - .cancel_remain_on_channel = - wpa_driver_nl80211_cancel_remain_on_channel, - .probe_req_report = driver_nl80211_probe_req_report, - .deinit_ap = wpa_driver_nl80211_deinit_ap, - .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli, - .resume = wpa_driver_nl80211_resume, - .send_ft_action = nl80211_send_ft_action, - .signal_monitor = nl80211_signal_monitor, - .signal_poll = nl80211_signal_poll, - .send_frame = nl80211_send_frame, - .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, - .set_rekey_info = nl80211_set_rekey_info, - .poll_client = nl80211_poll_client, - .set_p2p_powersave = nl80211_set_p2p_powersave, - .start_dfs_cac = nl80211_start_radar_detection, - .stop_ap = wpa_driver_nl80211_stop_ap, -#ifdef CONFIG_TDLS - .send_tdls_mgmt = nl80211_send_tdls_mgmt, - .tdls_oper = nl80211_tdls_oper, -#endif /* CONFIG_TDLS */ - .update_ft_ies = wpa_driver_nl80211_update_ft_ies, - .get_mac_addr = wpa_driver_nl80211_get_macaddr, - .get_survey = wpa_driver_nl80211_get_survey, - .status = wpa_driver_nl80211_status, - .switch_channel = nl80211_switch_channel, -#ifdef ANDROID_P2P - .set_noa = wpa_driver_set_p2p_noa, - .get_noa = wpa_driver_get_p2p_noa, - .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie, -#endif /* ANDROID_P2P */ -#ifdef ANDROID - .driver_cmd = wpa_driver_nl80211_driver_cmd, -#endif /* ANDROID */ - .set_qos_map = nl80211_set_qos_map, -}; diff --git a/contrib/hostapd/src/drivers/driver_none.c b/contrib/hostapd/src/drivers/driver_none.c deleted file mode 100644 index d75c14b182..0000000000 --- a/contrib/hostapd/src/drivers/driver_none.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Driver interface for RADIUS server or WPS ER only (no driver) - * Copyright (c) 2008, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "driver.h" - - -struct none_driver_data { - struct hostapd_data *hapd; - void *ctx; -}; - - -static void * none_driver_hapd_init(struct hostapd_data *hapd, - struct wpa_init_params *params) -{ - struct none_driver_data *drv; - - drv = os_zalloc(sizeof(struct none_driver_data)); - if (drv == NULL) { - wpa_printf(MSG_ERROR, "Could not allocate memory for none " - "driver data"); - return NULL; - } - drv->hapd = hapd; - - return drv; -} - - -static void none_driver_hapd_deinit(void *priv) -{ - struct none_driver_data *drv = priv; - - os_free(drv); -} - - -static int none_driver_send_ether(void *priv, const u8 *dst, const u8 *src, - u16 proto, const u8 *data, size_t data_len) -{ - return 0; -} - - -static void * none_driver_init(void *ctx, const char *ifname) -{ - struct none_driver_data *drv; - - drv = os_zalloc(sizeof(struct none_driver_data)); - if (drv == NULL) { - wpa_printf(MSG_ERROR, "Could not allocate memory for none " - "driver data"); - return NULL; - } - drv->ctx = ctx; - - return drv; -} - - -static void none_driver_deinit(void *priv) -{ - struct none_driver_data *drv = priv; - - os_free(drv); -} - - -static int none_driver_send_eapol(void *priv, const u8 *dest, u16 proto, - const u8 *data, size_t data_len) -{ - return -1; -} - - -const struct wpa_driver_ops wpa_driver_none_ops = { - .name = "none", - .desc = "no driver (RADIUS server/WPS ER)", - .hapd_init = none_driver_hapd_init, - .hapd_deinit = none_driver_hapd_deinit, - .send_ether = none_driver_send_ether, - .init = none_driver_init, - .deinit = none_driver_deinit, - .send_eapol = none_driver_send_eapol, -}; diff --git a/contrib/hostapd/src/drivers/driver_openbsd.c b/contrib/hostapd/src/drivers/driver_openbsd.c deleted file mode 100644 index e94eda08f6..0000000000 --- a/contrib/hostapd/src/drivers/driver_openbsd.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Driver interaction with OpenBSD net80211 layer - * Copyright (c) 2013, Mark Kettenis - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include -#include -#include -#include - -#include "common.h" -#include "driver.h" - -struct openbsd_driver_data { - char ifname[IFNAMSIZ + 1]; - void *ctx; - - int sock; /* open socket for 802.11 ioctls */ -}; - - -static int -wpa_driver_openbsd_get_ssid(void *priv, u8 *ssid) -{ - struct openbsd_driver_data *drv = priv; - struct ieee80211_nwid nwid; - struct ifreq ifr; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); - ifr.ifr_data = (void *)&nwid; - if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 || - nwid.i_len > IEEE80211_NWID_LEN) - return -1; - - os_memcpy(ssid, nwid.i_nwid, nwid.i_len); - return nwid.i_len; -} - -static int -wpa_driver_openbsd_get_bssid(void *priv, u8 *bssid) -{ - struct openbsd_driver_data *drv = priv; - struct ieee80211_bssid id; - - os_strlcpy(id.i_name, drv->ifname, sizeof(id.i_name)); - if (ioctl(drv->sock, SIOCG80211BSSID, &id) < 0) - return -1; - - os_memcpy(bssid, id.i_bssid, IEEE80211_ADDR_LEN); - return 0; -} - - -static int -wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa) -{ - os_memset(capa, 0, sizeof(*capa)); - capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE; - return 0; -} - - -static int -wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg, - const unsigned char *addr, int key_idx, int set_tx, const u8 *seq, - size_t seq_len, const u8 *key, size_t key_len) -{ - struct openbsd_driver_data *drv = priv; - struct ieee80211_keyavail keyavail; - - if (alg != WPA_ALG_PMK || key_len > IEEE80211_PMK_LEN) - return -1; - - memset(&keyavail, 0, sizeof(keyavail)); - os_strlcpy(keyavail.i_name, drv->ifname, sizeof(keyavail.i_name)); - if (wpa_driver_openbsd_get_bssid(priv, keyavail.i_macaddr) < 0) - return -1; - memcpy(keyavail.i_key, key, key_len); - - if (ioctl(drv->sock, SIOCS80211KEYAVAIL, &keyavail) < 0) - return -1; - - return 0; -} - -static void * -wpa_driver_openbsd_init(void *ctx, const char *ifname) -{ - struct openbsd_driver_data *drv; - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - - drv->sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->sock < 0) - goto fail; - - drv->ctx = ctx; - os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); - - return drv; - -fail: - os_free(drv); - return NULL; -} - - -static void -wpa_driver_openbsd_deinit(void *priv) -{ - struct openbsd_driver_data *drv = priv; - - close(drv->sock); - os_free(drv); -} - - -const struct wpa_driver_ops wpa_driver_openbsd_ops = { - .name = "openbsd", - .desc = "OpenBSD 802.11 support", - .get_ssid = wpa_driver_openbsd_get_ssid, - .get_bssid = wpa_driver_openbsd_get_bssid, - .get_capa = wpa_driver_openbsd_get_capa, - .set_key = wpa_driver_openbsd_set_key, - .init = wpa_driver_openbsd_init, - .deinit = wpa_driver_openbsd_deinit, -}; diff --git a/contrib/hostapd/src/drivers/driver_privsep.c b/contrib/hostapd/src/drivers/driver_privsep.c deleted file mode 100644 index ed88e71c3a..0000000000 --- a/contrib/hostapd/src/drivers/driver_privsep.c +++ /dev/null @@ -1,740 +0,0 @@ -/* - * WPA Supplicant - privilege separated driver interface - * Copyright (c) 2007-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "driver.h" -#include "eloop.h" -#include "common/privsep_commands.h" - - -struct wpa_driver_privsep_data { - void *ctx; - u8 own_addr[ETH_ALEN]; - int priv_socket; - char *own_socket_path; - int cmd_socket; - char *own_cmd_path; - struct sockaddr_un priv_addr; - char ifname[16]; -}; - - -static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data *drv, int cmd) -{ - int res; - - res = sendto(drv->priv_socket, &cmd, sizeof(cmd), 0, - (struct sockaddr *) &drv->priv_addr, - sizeof(drv->priv_addr)); - if (res < 0) - perror("sendto"); - return res < 0 ? -1 : 0; -} - - -static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd, - const void *data, size_t data_len, - void *reply, size_t *reply_len) -{ - struct msghdr msg; - struct iovec io[2]; - - io[0].iov_base = &cmd; - io[0].iov_len = sizeof(cmd); - io[1].iov_base = (u8 *) data; - io[1].iov_len = data_len; - - os_memset(&msg, 0, sizeof(msg)); - msg.msg_iov = io; - msg.msg_iovlen = data ? 2 : 1; - msg.msg_name = &drv->priv_addr; - msg.msg_namelen = sizeof(drv->priv_addr); - - if (sendmsg(drv->cmd_socket, &msg, 0) < 0) { - perror("sendmsg(cmd_socket)"); - return -1; - } - - if (reply) { - fd_set rfds; - struct timeval tv; - int res; - - FD_ZERO(&rfds); - FD_SET(drv->cmd_socket, &rfds); - tv.tv_sec = 5; - tv.tv_usec = 0; - res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv); - if (res < 0 && errno != EINTR) { - perror("select"); - return -1; - } - - if (FD_ISSET(drv->cmd_socket, &rfds)) { - res = recv(drv->cmd_socket, reply, *reply_len, 0); - if (res < 0) { - perror("recv"); - return -1; - } - *reply_len = res; - } else { - wpa_printf(MSG_DEBUG, "PRIVSEP: Timeout while waiting " - "for reply (cmd=%d)", cmd); - return -1; - } - } - - return 0; -} - - -static int wpa_driver_privsep_scan(void *priv, - struct wpa_driver_scan_params *params) -{ - struct wpa_driver_privsep_data *drv = priv; - const u8 *ssid = params->ssids[0].ssid; - size_t ssid_len = params->ssids[0].ssid_len; - wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv); - return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len, - NULL, NULL); -} - - -static struct wpa_scan_results * -wpa_driver_privsep_get_scan_results2(void *priv) -{ - struct wpa_driver_privsep_data *drv = priv; - int res, num; - u8 *buf, *pos, *end; - size_t reply_len = 60000; - struct wpa_scan_results *results; - struct wpa_scan_res *r; - - buf = os_malloc(reply_len); - if (buf == NULL) - return NULL; - res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SCAN_RESULTS, - NULL, 0, buf, &reply_len); - if (res < 0) { - os_free(buf); - return NULL; - } - - wpa_printf(MSG_DEBUG, "privsep: Received %lu bytes of scan results", - (unsigned long) reply_len); - if (reply_len < sizeof(int)) { - wpa_printf(MSG_DEBUG, "privsep: Invalid scan result len %lu", - (unsigned long) reply_len); - os_free(buf); - return NULL; - } - - pos = buf; - end = buf + reply_len; - os_memcpy(&num, pos, sizeof(int)); - if (num < 0 || num > 1000) { - os_free(buf); - return NULL; - } - pos += sizeof(int); - - results = os_zalloc(sizeof(*results)); - if (results == NULL) { - os_free(buf); - return NULL; - } - - results->res = os_calloc(num, sizeof(struct wpa_scan_res *)); - if (results->res == NULL) { - os_free(results); - os_free(buf); - return NULL; - } - - while (results->num < (size_t) num && pos + sizeof(int) < end) { - int len; - os_memcpy(&len, pos, sizeof(int)); - pos += sizeof(int); - if (len < 0 || len > 10000 || pos + len > end) - break; - - r = os_malloc(len); - if (r == NULL) - break; - os_memcpy(r, pos, len); - pos += len; - if (sizeof(*r) + r->ie_len > (size_t) len) { - os_free(r); - break; - } - - results->res[results->num++] = r; - } - - os_free(buf); - return results; -} - - -static int wpa_driver_privsep_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_privsep_data *drv = priv; - struct privsep_cmd_set_key cmd; - - wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d", - __func__, priv, alg, key_idx, set_tx); - - os_memset(&cmd, 0, sizeof(cmd)); - cmd.alg = alg; - if (addr) - os_memcpy(cmd.addr, addr, ETH_ALEN); - else - os_memset(cmd.addr, 0xff, ETH_ALEN); - cmd.key_idx = key_idx; - cmd.set_tx = set_tx; - if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) { - os_memcpy(cmd.seq, seq, seq_len); - cmd.seq_len = seq_len; - } - if (key && key_len > 0 && key_len < sizeof(cmd.key)) { - os_memcpy(cmd.key, key, key_len); - cmd.key_len = key_len; - } - - return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_KEY, &cmd, sizeof(cmd), - NULL, NULL); -} - - -static int wpa_driver_privsep_associate( - void *priv, struct wpa_driver_associate_params *params) -{ - struct wpa_driver_privsep_data *drv = priv; - struct privsep_cmd_associate *data; - int res; - size_t buflen; - - wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d " - "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d", - __func__, priv, params->freq, params->pairwise_suite, - params->group_suite, params->key_mgmt_suite, - params->auth_alg, params->mode); - - buflen = sizeof(*data) + params->wpa_ie_len; - data = os_zalloc(buflen); - if (data == NULL) - return -1; - - if (params->bssid) - os_memcpy(data->bssid, params->bssid, ETH_ALEN); - os_memcpy(data->ssid, params->ssid, params->ssid_len); - data->ssid_len = params->ssid_len; - data->freq = params->freq; - data->pairwise_suite = params->pairwise_suite; - data->group_suite = params->group_suite; - data->key_mgmt_suite = params->key_mgmt_suite; - data->auth_alg = params->auth_alg; - data->mode = params->mode; - data->wpa_ie_len = params->wpa_ie_len; - if (params->wpa_ie) - os_memcpy(data + 1, params->wpa_ie, params->wpa_ie_len); - /* TODO: add support for other assoc parameters */ - - res = wpa_priv_cmd(drv, PRIVSEP_CMD_ASSOCIATE, data, buflen, - NULL, NULL); - os_free(data); - - return res; -} - - -static int wpa_driver_privsep_get_bssid(void *priv, u8 *bssid) -{ - struct wpa_driver_privsep_data *drv = priv; - int res; - size_t len = ETH_ALEN; - - res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_BSSID, NULL, 0, bssid, &len); - if (res < 0 || len != ETH_ALEN) - return -1; - return 0; -} - - -static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid) -{ - struct wpa_driver_privsep_data *drv = priv; - int res, ssid_len; - u8 reply[sizeof(int) + 32]; - size_t len = sizeof(reply); - - res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len); - if (res < 0 || len < sizeof(int)) - return -1; - os_memcpy(&ssid_len, reply, sizeof(int)); - if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) { - wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply"); - return -1; - } - os_memcpy(ssid, &reply[sizeof(int)], ssid_len); - return ssid_len; -} - - -static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr, - int reason_code) -{ - //struct wpa_driver_privsep_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d", - __func__, MAC2STR(addr), reason_code); - wpa_printf(MSG_DEBUG, "%s - TODO", __func__); - return 0; -} - - -static void wpa_driver_privsep_event_assoc(void *ctx, - enum wpa_event_type event, - u8 *buf, size_t len) -{ - union wpa_event_data data; - int inc_data = 0; - u8 *pos, *end; - int ie_len; - - os_memset(&data, 0, sizeof(data)); - - pos = buf; - end = buf + len; - - if (end - pos < (int) sizeof(int)) - return; - os_memcpy(&ie_len, pos, sizeof(int)); - pos += sizeof(int); - if (ie_len < 0 || ie_len > end - pos) - return; - if (ie_len) { - data.assoc_info.req_ies = pos; - data.assoc_info.req_ies_len = ie_len; - pos += ie_len; - inc_data = 1; - } - - wpa_supplicant_event(ctx, event, inc_data ? &data : NULL); -} - - -static void wpa_driver_privsep_event_interface_status(void *ctx, u8 *buf, - size_t len) -{ - union wpa_event_data data; - int ievent; - - if (len < sizeof(int) || - len - sizeof(int) > sizeof(data.interface_status.ifname)) - return; - - os_memcpy(&ievent, buf, sizeof(int)); - - os_memset(&data, 0, sizeof(data)); - data.interface_status.ievent = ievent; - os_memcpy(data.interface_status.ifname, buf + sizeof(int), - len - sizeof(int)); - wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &data); -} - - -static void wpa_driver_privsep_event_michael_mic_failure( - void *ctx, u8 *buf, size_t len) -{ - union wpa_event_data data; - - if (len != sizeof(int)) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(&data.michael_mic_failure.unicast, buf, sizeof(int)); - wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); -} - - -static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf, - size_t len) -{ - union wpa_event_data data; - - if (len != sizeof(struct pmkid_candidate)) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(&data.pmkid_candidate, buf, len); - wpa_supplicant_event(ctx, EVENT_PMKID_CANDIDATE, &data); -} - - -static void wpa_driver_privsep_event_stkstart(void *ctx, u8 *buf, size_t len) -{ - union wpa_event_data data; - - if (len != ETH_ALEN) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.stkstart.peer, buf, ETH_ALEN); - wpa_supplicant_event(ctx, EVENT_STKSTART, &data); -} - - -static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf, - size_t len) -{ - union wpa_event_data data; - - if (len < sizeof(int) + ETH_ALEN) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(&data.ft_ies.ft_action, buf, sizeof(int)); - os_memcpy(data.ft_ies.target_ap, buf + sizeof(int), ETH_ALEN); - data.ft_ies.ies = buf + sizeof(int) + ETH_ALEN; - data.ft_ies.ies_len = len - sizeof(int) - ETH_ALEN; - wpa_supplicant_event(ctx, EVENT_FT_RESPONSE, &data); -} - - -static void wpa_driver_privsep_event_rx_eapol(void *ctx, u8 *buf, size_t len) -{ - if (len < ETH_ALEN) - return; - drv_event_eapol_rx(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN); -} - - -static void wpa_driver_privsep_receive(int sock, void *eloop_ctx, - void *sock_ctx) -{ - struct wpa_driver_privsep_data *drv = eloop_ctx; - u8 *buf, *event_buf; - size_t event_len; - int res, event; - enum privsep_event e; - struct sockaddr_un from; - socklen_t fromlen = sizeof(from); - const size_t buflen = 2000; - - buf = os_malloc(buflen); - if (buf == NULL) - return; - res = recvfrom(sock, buf, buflen, 0, - (struct sockaddr *) &from, &fromlen); - if (res < 0) { - perror("recvfrom(priv_socket)"); - os_free(buf); - return; - } - - wpa_printf(MSG_DEBUG, "privsep_driver: received %u bytes", res); - - if (res < (int) sizeof(int)) { - wpa_printf(MSG_DEBUG, "Too short event message (len=%d)", res); - return; - } - - os_memcpy(&event, buf, sizeof(int)); - event_buf = &buf[sizeof(int)]; - event_len = res - sizeof(int); - wpa_printf(MSG_DEBUG, "privsep: Event %d received (len=%lu)", - event, (unsigned long) event_len); - - e = event; - switch (e) { - case PRIVSEP_EVENT_SCAN_RESULTS: - wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL); - break; - case PRIVSEP_EVENT_ASSOC: - wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC, - event_buf, event_len); - break; - case PRIVSEP_EVENT_DISASSOC: - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); - break; - case PRIVSEP_EVENT_ASSOCINFO: - wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOCINFO, - event_buf, event_len); - break; - case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE: - wpa_driver_privsep_event_michael_mic_failure( - drv->ctx, event_buf, event_len); - break; - case PRIVSEP_EVENT_INTERFACE_STATUS: - wpa_driver_privsep_event_interface_status(drv->ctx, event_buf, - event_len); - break; - case PRIVSEP_EVENT_PMKID_CANDIDATE: - wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf, - event_len); - break; - case PRIVSEP_EVENT_STKSTART: - wpa_driver_privsep_event_stkstart(drv->ctx, event_buf, - event_len); - break; - case PRIVSEP_EVENT_FT_RESPONSE: - wpa_driver_privsep_event_ft_response(drv->ctx, event_buf, - event_len); - break; - case PRIVSEP_EVENT_RX_EAPOL: - wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf, - event_len); - break; - } - - os_free(buf); -} - - -static void * wpa_driver_privsep_init(void *ctx, const char *ifname) -{ - struct wpa_driver_privsep_data *drv; - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - drv->ctx = ctx; - drv->priv_socket = -1; - drv->cmd_socket = -1; - os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); - - return drv; -} - - -static void wpa_driver_privsep_deinit(void *priv) -{ - struct wpa_driver_privsep_data *drv = priv; - - if (drv->priv_socket >= 0) { - wpa_priv_reg_cmd(drv, PRIVSEP_CMD_UNREGISTER); - eloop_unregister_read_sock(drv->priv_socket); - close(drv->priv_socket); - } - - if (drv->own_socket_path) { - unlink(drv->own_socket_path); - os_free(drv->own_socket_path); - } - - if (drv->cmd_socket >= 0) { - eloop_unregister_read_sock(drv->cmd_socket); - close(drv->cmd_socket); - } - - if (drv->own_cmd_path) { - unlink(drv->own_cmd_path); - os_free(drv->own_cmd_path); - } - - os_free(drv); -} - - -static int wpa_driver_privsep_set_param(void *priv, const char *param) -{ - struct wpa_driver_privsep_data *drv = priv; - const char *pos; - char *own_dir, *priv_dir; - static unsigned int counter = 0; - size_t len; - struct sockaddr_un addr; - - wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param); - if (param == NULL) - pos = NULL; - else - pos = os_strstr(param, "own_dir="); - if (pos) { - char *end; - own_dir = os_strdup(pos + 8); - if (own_dir == NULL) - return -1; - end = os_strchr(own_dir, ' '); - if (end) - *end = '\0'; - } else { - own_dir = os_strdup("/tmp"); - if (own_dir == NULL) - return -1; - } - - if (param == NULL) - pos = NULL; - else - pos = os_strstr(param, "priv_dir="); - if (pos) { - char *end; - priv_dir = os_strdup(pos + 9); - if (priv_dir == NULL) { - os_free(own_dir); - return -1; - } - end = os_strchr(priv_dir, ' '); - if (end) - *end = '\0'; - } else { - priv_dir = os_strdup("/var/run/wpa_priv"); - if (priv_dir == NULL) { - os_free(own_dir); - return -1; - } - } - - len = os_strlen(own_dir) + 50; - drv->own_socket_path = os_malloc(len); - if (drv->own_socket_path == NULL) { - os_free(priv_dir); - os_free(own_dir); - return -1; - } - os_snprintf(drv->own_socket_path, len, "%s/wpa_privsep-%d-%d", - own_dir, getpid(), counter++); - - len = os_strlen(own_dir) + 50; - drv->own_cmd_path = os_malloc(len); - if (drv->own_cmd_path == NULL) { - os_free(drv->own_socket_path); - drv->own_socket_path = NULL; - os_free(priv_dir); - os_free(own_dir); - return -1; - } - os_snprintf(drv->own_cmd_path, len, "%s/wpa_privsep-%d-%d", - own_dir, getpid(), counter++); - - os_free(own_dir); - - drv->priv_addr.sun_family = AF_UNIX; - os_snprintf(drv->priv_addr.sun_path, sizeof(drv->priv_addr.sun_path), - "%s/%s", priv_dir, drv->ifname); - os_free(priv_dir); - - drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0); - if (drv->priv_socket < 0) { - perror("socket(PF_UNIX)"); - os_free(drv->own_socket_path); - drv->own_socket_path = NULL; - return -1; - } - - os_memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path)); - if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) < - 0) { - perror("privsep-set-params priv-sock: bind(PF_UNIX)"); - close(drv->priv_socket); - drv->priv_socket = -1; - unlink(drv->own_socket_path); - os_free(drv->own_socket_path); - drv->own_socket_path = NULL; - return -1; - } - - eloop_register_read_sock(drv->priv_socket, wpa_driver_privsep_receive, - drv, NULL); - - drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0); - if (drv->cmd_socket < 0) { - perror("socket(PF_UNIX)"); - os_free(drv->own_cmd_path); - drv->own_cmd_path = NULL; - return -1; - } - - os_memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path)); - if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0) - { - perror("privsep-set-params cmd-sock: bind(PF_UNIX)"); - close(drv->cmd_socket); - drv->cmd_socket = -1; - unlink(drv->own_cmd_path); - os_free(drv->own_cmd_path); - drv->own_cmd_path = NULL; - return -1; - } - - if (wpa_priv_reg_cmd(drv, PRIVSEP_CMD_REGISTER) < 0) { - wpa_printf(MSG_ERROR, "Failed to register with wpa_priv"); - return -1; - } - - return 0; -} - - -static int wpa_driver_privsep_get_capa(void *priv, - struct wpa_driver_capa *capa) -{ - struct wpa_driver_privsep_data *drv = priv; - int res; - size_t len = sizeof(*capa); - - res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len); - if (res < 0 || len != sizeof(*capa)) - return -1; - return 0; -} - - -static const u8 * wpa_driver_privsep_get_mac_addr(void *priv) -{ - struct wpa_driver_privsep_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s", __func__); - return drv->own_addr; -} - - -static int wpa_driver_privsep_set_country(void *priv, const char *alpha2) -{ - struct wpa_driver_privsep_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s country='%s'", __func__, alpha2); - return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_COUNTRY, alpha2, - os_strlen(alpha2), NULL, NULL); -} - - -struct wpa_driver_ops wpa_driver_privsep_ops = { - "privsep", - "wpa_supplicant privilege separated driver", - .get_bssid = wpa_driver_privsep_get_bssid, - .get_ssid = wpa_driver_privsep_get_ssid, - .set_key = wpa_driver_privsep_set_key, - .init = wpa_driver_privsep_init, - .deinit = wpa_driver_privsep_deinit, - .set_param = wpa_driver_privsep_set_param, - .scan2 = wpa_driver_privsep_scan, - .deauthenticate = wpa_driver_privsep_deauthenticate, - .associate = wpa_driver_privsep_associate, - .get_capa = wpa_driver_privsep_get_capa, - .get_mac_addr = wpa_driver_privsep_get_mac_addr, - .get_scan_results2 = wpa_driver_privsep_get_scan_results2, - .set_country = wpa_driver_privsep_set_country, -}; - - -struct wpa_driver_ops *wpa_drivers[] = -{ - &wpa_driver_privsep_ops, - NULL -}; diff --git a/contrib/hostapd/src/drivers/driver_roboswitch.c b/contrib/hostapd/src/drivers/driver_roboswitch.c deleted file mode 100644 index 0a9078a4ab..0000000000 --- a/contrib/hostapd/src/drivers/driver_roboswitch.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * WPA Supplicant - roboswitch driver interface - * Copyright (c) 2008-2009 Jouke Witteveen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include -#include -#include -#include -#include - -#include "common.h" -#include "driver.h" -#include "l2_packet/l2_packet.h" - -#define ROBO_PHY_ADDR 0x1e /* RoboSwitch PHY address */ - -/* MII access registers */ -#define ROBO_MII_PAGE 0x10 /* MII page register */ -#define ROBO_MII_ADDR 0x11 /* MII address register */ -#define ROBO_MII_DATA_OFFSET 0x18 /* Start of MII data registers */ - -#define ROBO_MII_PAGE_ENABLE 0x01 /* MII page op code */ -#define ROBO_MII_ADDR_WRITE 0x01 /* MII address write op code */ -#define ROBO_MII_ADDR_READ 0x02 /* MII address read op code */ -#define ROBO_MII_DATA_MAX 4 /* Consecutive MII data registers */ -#define ROBO_MII_RETRY_MAX 10 /* Read attempts before giving up */ - -/* Page numbers */ -#define ROBO_ARLCTRL_PAGE 0x04 /* ARL control page */ -#define ROBO_VLAN_PAGE 0x34 /* VLAN page */ - -/* ARL control page registers */ -#define ROBO_ARLCTRL_CONF 0x00 /* ARL configuration register */ -#define ROBO_ARLCTRL_ADDR_1 0x10 /* Multiport address 1 */ -#define ROBO_ARLCTRL_VEC_1 0x16 /* Multiport vector 1 */ -#define ROBO_ARLCTRL_ADDR_2 0x20 /* Multiport address 2 */ -#define ROBO_ARLCTRL_VEC_2 0x26 /* Multiport vector 2 */ - -/* VLAN page registers */ -#define ROBO_VLAN_ACCESS 0x08 /* VLAN table access register */ -#define ROBO_VLAN_ACCESS_5350 0x06 /* VLAN table access register (5350) */ -#define ROBO_VLAN_READ 0x0c /* VLAN read register */ -#define ROBO_VLAN_MAX 0xff /* Maximum number of VLANs */ - - -static const u8 pae_group_addr[ETH_ALEN] = -{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; - - -struct wpa_driver_roboswitch_data { - void *ctx; - struct l2_packet_data *l2; - char ifname[IFNAMSIZ + 1]; - u8 own_addr[ETH_ALEN]; - struct ifreq ifr; - int fd, is_5350; - u16 ports; -}; - - -/* Copied from the kernel-only part of mii.h. */ -static inline struct mii_ioctl_data *if_mii(struct ifreq *rq) -{ - return (struct mii_ioctl_data *) &rq->ifr_ifru; -} - - -/* - * RoboSwitch uses 16-bit Big Endian addresses. - * The ordering of the words is reversed in the MII registers. - */ -static void wpa_driver_roboswitch_addr_be16(const u8 addr[ETH_ALEN], u16 *be) -{ - int i; - for (i = 0; i < ETH_ALEN; i += 2) - be[(ETH_ALEN - i) / 2 - 1] = WPA_GET_BE16(addr + i); -} - - -static u16 wpa_driver_roboswitch_mdio_read( - struct wpa_driver_roboswitch_data *drv, u8 reg) -{ - struct mii_ioctl_data *mii = if_mii(&drv->ifr); - - mii->phy_id = ROBO_PHY_ADDR; - mii->reg_num = reg; - - if (ioctl(drv->fd, SIOCGMIIREG, &drv->ifr) < 0) { - perror("ioctl[SIOCGMIIREG]"); - return 0x00; - } - return mii->val_out; -} - - -static void wpa_driver_roboswitch_mdio_write( - struct wpa_driver_roboswitch_data *drv, u8 reg, u16 val) -{ - struct mii_ioctl_data *mii = if_mii(&drv->ifr); - - mii->phy_id = ROBO_PHY_ADDR; - mii->reg_num = reg; - mii->val_in = val; - - if (ioctl(drv->fd, SIOCSMIIREG, &drv->ifr) < 0) { - perror("ioctl[SIOCSMIIREG"); - } -} - - -static int wpa_driver_roboswitch_reg(struct wpa_driver_roboswitch_data *drv, - u8 page, u8 reg, u8 op) -{ - int i; - - /* set page number */ - wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_PAGE, - (page << 8) | ROBO_MII_PAGE_ENABLE); - /* set register address */ - wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_ADDR, (reg << 8) | op); - - /* check if operation completed */ - for (i = 0; i < ROBO_MII_RETRY_MAX; ++i) { - if ((wpa_driver_roboswitch_mdio_read(drv, ROBO_MII_ADDR) & 3) - == 0) - return 0; - } - /* timeout */ - return -1; -} - - -static int wpa_driver_roboswitch_read(struct wpa_driver_roboswitch_data *drv, - u8 page, u8 reg, u16 *val, int len) -{ - int i; - - if (len > ROBO_MII_DATA_MAX || - wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_READ) < 0) - return -1; - - for (i = 0; i < len; ++i) { - val[i] = wpa_driver_roboswitch_mdio_read( - drv, ROBO_MII_DATA_OFFSET + i); - } - - return 0; -} - - -static int wpa_driver_roboswitch_write(struct wpa_driver_roboswitch_data *drv, - u8 page, u8 reg, u16 *val, int len) -{ - int i; - - if (len > ROBO_MII_DATA_MAX) return -1; - for (i = 0; i < len; ++i) { - wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_DATA_OFFSET + i, - val[i]); - } - return wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_WRITE); -} - - -static void wpa_driver_roboswitch_receive(void *priv, const u8 *src_addr, - const u8 *buf, size_t len) -{ - struct wpa_driver_roboswitch_data *drv = priv; - - if (len > 14 && WPA_GET_BE16(buf + 12) == ETH_P_EAPOL && - os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0) - drv_event_eapol_rx(drv->ctx, src_addr, buf + 14, len - 14); -} - - -static int wpa_driver_roboswitch_get_ssid(void *priv, u8 *ssid) -{ - ssid[0] = 0; - return 0; -} - - -static int wpa_driver_roboswitch_get_bssid(void *priv, u8 *bssid) -{ - /* Report PAE group address as the "BSSID" for wired connection. */ - os_memcpy(bssid, pae_group_addr, ETH_ALEN); - return 0; -} - - -static int wpa_driver_roboswitch_get_capa(void *priv, - struct wpa_driver_capa *capa) -{ - os_memset(capa, 0, sizeof(*capa)); - capa->flags = WPA_DRIVER_FLAGS_WIRED; - return 0; -} - - -static int wpa_driver_roboswitch_set_param(void *priv, const char *param) -{ - struct wpa_driver_roboswitch_data *drv = priv; - char *sep; - - if (param == NULL || os_strstr(param, "multicast_only=1") == NULL) { - sep = drv->ifname + os_strlen(drv->ifname); - *sep = '.'; - drv->l2 = l2_packet_init(drv->ifname, NULL, ETH_P_ALL, - wpa_driver_roboswitch_receive, drv, - 1); - if (drv->l2 == NULL) { - wpa_printf(MSG_INFO, "%s: Unable to listen on %s", - __func__, drv->ifname); - return -1; - } - *sep = '\0'; - l2_packet_get_own_addr(drv->l2, drv->own_addr); - } else { - wpa_printf(MSG_DEBUG, "%s: Ignoring unicast frames", __func__); - drv->l2 = NULL; - } - return 0; -} - - -static const char * wpa_driver_roboswitch_get_ifname(void *priv) -{ - struct wpa_driver_roboswitch_data *drv = priv; - return drv->ifname; -} - - -static int wpa_driver_roboswitch_join(struct wpa_driver_roboswitch_data *drv, - u16 ports, const u8 *addr) -{ - u16 read1[3], read2[3], addr_be16[3]; - - wpa_driver_roboswitch_addr_be16(addr, addr_be16); - - if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_CONF, read1, 1) < 0) - return -1; - if (!(read1[0] & (1 << 4))) { - /* multiport addresses are not yet enabled */ - read1[0] |= 1 << 4; - wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_ADDR_1, addr_be16, 3); - wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_VEC_1, &ports, 1); - wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_ADDR_2, addr_be16, 3); - wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_VEC_2, &ports, 1); - wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_CONF, read1, 1); - } else { - /* if both multiport addresses are the same we can add */ - wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_ADDR_1, read1, 3); - wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_ADDR_2, read2, 3); - if (os_memcmp(read1, read2, 6) != 0) - return -1; - wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_VEC_1, read1, 1); - wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_VEC_2, read2, 1); - if (read1[0] != read2[0]) - return -1; - wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_ADDR_1, addr_be16, 3); - wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_VEC_1, &ports, 1); - } - return 0; -} - - -static int wpa_driver_roboswitch_leave(struct wpa_driver_roboswitch_data *drv, - u16 ports, const u8 *addr) -{ - u16 _read, addr_be16[3], addr_read[3], ports_read; - - wpa_driver_roboswitch_addr_be16(addr, addr_be16); - - wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_CONF, - &_read, 1); - /* If ARL control is disabled, there is nothing to leave. */ - if (!(_read & (1 << 4))) return -1; - - wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_ADDR_1, addr_read, 3); - wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_VEC_1, - &ports_read, 1); - /* check if we occupy multiport address 1 */ - if (os_memcmp(addr_read, addr_be16, 6) == 0 && ports_read == ports) { - wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_ADDR_2, addr_read, 3); - wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_VEC_2, &ports_read, 1); - /* and multiport address 2 */ - if (os_memcmp(addr_read, addr_be16, 6) == 0 && - ports_read == ports) { - _read &= ~(1 << 4); - wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_CONF, &_read, - 1); - } else { - wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_ADDR_1, - addr_read, 3); - wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_VEC_1, - &ports_read, 1); - wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_ADDR_2, - addr_read, 3); - wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_VEC_2, - &ports_read, 1); - } - } else { - wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_ADDR_2, addr_read, 3); - wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_VEC_2, &ports_read, 1); - /* or multiport address 2 */ - if (os_memcmp(addr_read, addr_be16, 6) == 0 && - ports_read == ports) { - wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_ADDR_1, - addr_read, 3); - wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, - ROBO_ARLCTRL_VEC_1, - &ports_read, 1); - } else return -1; - } - return 0; -} - - -static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname) -{ - struct wpa_driver_roboswitch_data *drv; - char *sep; - u16 vlan = 0, _read[2]; - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) return NULL; - drv->ctx = ctx; - drv->own_addr[0] = '\0'; - - /* 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 '.' separating and */ - while (sep > drv->ifname && *sep != '.') sep--; - if (sep <= drv->ifname) { - wpa_printf(MSG_INFO, "%s: No . pair in " - "interface name %s", __func__, drv->ifname); - os_free(drv); - return NULL; - } - *sep = '\0'; - while (*++sep) { - if (*sep < '0' || *sep > '9') { - wpa_printf(MSG_INFO, "%s: Invalid vlan specification " - "in interface name %s", __func__, ifname); - os_free(drv); - return NULL; - } - vlan *= 10; - vlan += *sep - '0'; - if (vlan > ROBO_VLAN_MAX) { - wpa_printf(MSG_INFO, "%s: VLAN out of range in " - "interface name %s", __func__, ifname); - os_free(drv); - return NULL; - } - } - - drv->fd = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->fd < 0) { - wpa_printf(MSG_INFO, "%s: Unable to create socket", __func__); - os_free(drv); - return NULL; - } - - os_memset(&drv->ifr, 0, sizeof(drv->ifr)); - os_strlcpy(drv->ifr.ifr_name, drv->ifname, IFNAMSIZ); - if (ioctl(drv->fd, SIOCGMIIPHY, &drv->ifr) < 0) { - perror("ioctl[SIOCGMIIPHY]"); - os_free(drv); - return NULL; - } - if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR) { - wpa_printf(MSG_INFO, "%s: Invalid phy address (not a " - "RoboSwitch?)", __func__); - os_free(drv); - return NULL; - } - - /* set and read back to see if the register can be used */ - _read[0] = ROBO_VLAN_MAX; - wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350, - _read, 1); - wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350, - _read + 1, 1); - drv->is_5350 = _read[0] == _read[1]; - - /* set the read bit */ - vlan |= 1 << 13; - wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE, - drv->is_5350 ? ROBO_VLAN_ACCESS_5350 - : ROBO_VLAN_ACCESS, - &vlan, 1); - wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_READ, _read, - drv->is_5350 ? 2 : 1); - if (!(drv->is_5350 ? _read[1] & (1 << 4) : _read[0] & (1 << 14))) { - wpa_printf(MSG_INFO, "%s: Could not get port information for " - "VLAN %d", __func__, vlan & ~(1 << 13)); - os_free(drv); - return NULL; - } - drv->ports = _read[0] & 0x001F; - /* add the MII port */ - drv->ports |= 1 << 8; - if (wpa_driver_roboswitch_join(drv, drv->ports, pae_group_addr) < 0) { - wpa_printf(MSG_INFO, "%s: Unable to join PAE group", __func__); - os_free(drv); - return NULL; - } else { - wpa_printf(MSG_DEBUG, "%s: Added PAE group address to " - "RoboSwitch ARL", __func__); - } - - return drv; -} - - -static void wpa_driver_roboswitch_deinit(void *priv) -{ - struct wpa_driver_roboswitch_data *drv = priv; - - if (drv->l2) { - l2_packet_deinit(drv->l2); - drv->l2 = NULL; - } - if (wpa_driver_roboswitch_leave(drv, drv->ports, pae_group_addr) < 0) { - wpa_printf(MSG_DEBUG, "%s: Unable to leave PAE group", - __func__); - } - - close(drv->fd); - os_free(drv); -} - - -const struct wpa_driver_ops wpa_driver_roboswitch_ops = { - .name = "roboswitch", - .desc = "wpa_supplicant roboswitch driver", - .get_ssid = wpa_driver_roboswitch_get_ssid, - .get_bssid = wpa_driver_roboswitch_get_bssid, - .get_capa = wpa_driver_roboswitch_get_capa, - .init = wpa_driver_roboswitch_init, - .deinit = wpa_driver_roboswitch_deinit, - .set_param = wpa_driver_roboswitch_set_param, - .get_ifname = wpa_driver_roboswitch_get_ifname, -}; diff --git a/contrib/hostapd/src/drivers/driver_test.c b/contrib/hostapd/src/drivers/driver_test.c deleted file mode 100644 index 7d306553dd..0000000000 --- a/contrib/hostapd/src/drivers/driver_test.c +++ /dev/null @@ -1,2678 +0,0 @@ -/* - * Testing driver interface for a simulated network driver - * Copyright (c) 2004-2010, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -/* Make sure we get winsock2.h for Windows build to get sockaddr_storage */ -#include "build_config.h" -#ifdef CONFIG_NATIVE_WINDOWS -#include -#endif /* CONFIG_NATIVE_WINDOWS */ - -#include "utils/includes.h" - -#ifndef CONFIG_NATIVE_WINDOWS -#include -#include -#include -#define DRIVER_TEST_UNIX -#endif /* CONFIG_NATIVE_WINDOWS */ - -#include "utils/common.h" -#include "utils/eloop.h" -#include "utils/list.h" -#include "utils/trace.h" -#include "common/ieee802_11_defs.h" -#include "crypto/sha1.h" -#include "l2_packet/l2_packet.h" -#include "wps/wps.h" -#include "driver.h" - - -struct test_client_socket { - struct test_client_socket *next; - u8 addr[ETH_ALEN]; - struct sockaddr_un un; - socklen_t unlen; - struct test_driver_bss *bss; -}; - -struct test_driver_bss { - struct wpa_driver_test_data *drv; - struct dl_list list; - void *bss_ctx; - char ifname[IFNAMSIZ]; - u8 bssid[ETH_ALEN]; - u8 *ie; - size_t ielen; - u8 *wps_beacon_ie; - size_t wps_beacon_ie_len; - u8 *wps_probe_resp_ie; - size_t wps_probe_resp_ie_len; - u8 ssid[32]; - size_t ssid_len; - int privacy; -}; - -struct wpa_driver_test_global { - int bss_add_used; - u8 req_addr[ETH_ALEN]; -}; - -struct wpa_driver_test_data { - struct wpa_driver_test_global *global; - void *ctx; - WPA_TRACE_REF(ctx); - u8 own_addr[ETH_ALEN]; - int test_socket; -#ifdef DRIVER_TEST_UNIX - struct sockaddr_un hostapd_addr; -#endif /* DRIVER_TEST_UNIX */ - int hostapd_addr_set; - struct sockaddr_in hostapd_addr_udp; - int hostapd_addr_udp_set; - char *own_socket_path; - char *test_dir; -#define MAX_SCAN_RESULTS 30 - struct wpa_scan_res *scanres[MAX_SCAN_RESULTS]; - size_t num_scanres; - int use_associnfo; - u8 assoc_wpa_ie[80]; - size_t assoc_wpa_ie_len; - int associated; - u8 *probe_req_ie; - size_t probe_req_ie_len; - u8 probe_req_ssid[32]; - size_t probe_req_ssid_len; - int ibss; - int ap; - - struct test_client_socket *cli; - struct dl_list bss; - int udp_port; - - int alloc_iface_idx; - - int probe_req_report; - unsigned int remain_on_channel_freq; - unsigned int remain_on_channel_duration; - - int current_freq; -}; - - -static void wpa_driver_test_deinit(void *priv); -static int wpa_driver_test_attach(struct wpa_driver_test_data *drv, - const char *dir, int ap); -static void wpa_driver_test_close_test_socket( - struct wpa_driver_test_data *drv); -static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx); - - -static void test_driver_free_bss(struct test_driver_bss *bss) -{ - os_free(bss->ie); - os_free(bss->wps_beacon_ie); - os_free(bss->wps_probe_resp_ie); - os_free(bss); -} - - -static void test_driver_free_bsses(struct wpa_driver_test_data *drv) -{ - struct test_driver_bss *bss, *tmp; - - dl_list_for_each_safe(bss, tmp, &drv->bss, struct test_driver_bss, - list) { - dl_list_del(&bss->list); - test_driver_free_bss(bss); - } -} - - -static struct test_client_socket * -test_driver_get_cli(struct wpa_driver_test_data *drv, struct sockaddr_un *from, - socklen_t fromlen) -{ - struct test_client_socket *cli = drv->cli; - - while (cli) { - if (cli->unlen == fromlen && - strncmp(cli->un.sun_path, from->sun_path, - fromlen - sizeof(cli->un.sun_family)) == 0) - return cli; - cli = cli->next; - } - - return NULL; -} - - -static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data, - size_t data_len, int encrypt, - const u8 *own_addr, u32 flags) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - struct test_client_socket *cli; - struct msghdr msg; - struct iovec io[3]; - struct l2_ethhdr eth; - - if (drv->test_socket < 0) - return -1; - - cli = drv->cli; - while (cli) { - if (memcmp(cli->addr, addr, ETH_ALEN) == 0) - break; - cli = cli->next; - } - - if (!cli) { - wpa_printf(MSG_DEBUG, "%s: no destination client entry", - __func__); - return -1; - } - - memcpy(eth.h_dest, addr, ETH_ALEN); - memcpy(eth.h_source, own_addr, ETH_ALEN); - eth.h_proto = host_to_be16(ETH_P_EAPOL); - - io[0].iov_base = "EAPOL "; - io[0].iov_len = 6; - io[1].iov_base = ð - io[1].iov_len = sizeof(eth); - io[2].iov_base = (u8 *) data; - io[2].iov_len = data_len; - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = io; - msg.msg_iovlen = 3; - msg.msg_name = &cli->un; - msg.msg_namelen = cli->unlen; - return sendmsg(drv->test_socket, &msg, 0); -} - - -static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src, - u16 proto, const u8 *data, size_t data_len) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - struct msghdr msg; - struct iovec io[3]; - struct l2_ethhdr eth; - char desttxt[30]; - struct sockaddr_un addr; - struct dirent *dent; - DIR *dir; - int ret = 0, broadcast = 0, count = 0; - - if (drv->test_socket < 0 || drv->test_dir == NULL) { - wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d " - "test_dir=%p)", - __func__, drv->test_socket, drv->test_dir); - return -1; - } - - broadcast = memcmp(dst, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0; - snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dst)); - - memcpy(eth.h_dest, dst, ETH_ALEN); - memcpy(eth.h_source, src, ETH_ALEN); - eth.h_proto = host_to_be16(proto); - - io[0].iov_base = "ETHER "; - io[0].iov_len = 6; - io[1].iov_base = ð - io[1].iov_len = sizeof(eth); - io[2].iov_base = (u8 *) data; - io[2].iov_len = data_len; - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = io; - msg.msg_iovlen = 3; - - dir = opendir(drv->test_dir); - if (dir == NULL) { - perror("test_driver: opendir"); - return -1; - } - while ((dent = readdir(dir))) { -#ifdef _DIRENT_HAVE_D_TYPE - /* Skip the file if it is not a socket. Also accept - * DT_UNKNOWN (0) in case the C library or underlying file - * system does not support d_type. */ - if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN) - continue; -#endif /* _DIRENT_HAVE_D_TYPE */ - if (strcmp(dent->d_name, ".") == 0 || - strcmp(dent->d_name, "..") == 0) - continue; - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", - drv->test_dir, dent->d_name); - - if (strcmp(addr.sun_path, drv->own_socket_path) == 0) - continue; - if (!broadcast && strstr(dent->d_name, desttxt) == NULL) - continue; - - wpa_printf(MSG_DEBUG, "%s: Send ether frame to %s", - __func__, dent->d_name); - - msg.msg_name = &addr; - msg.msg_namelen = sizeof(addr); - ret = sendmsg(drv->test_socket, &msg, 0); - if (ret < 0) - perror("driver_test: sendmsg"); - count++; - } - closedir(dir); - - if (!broadcast && count == 0) { - wpa_printf(MSG_DEBUG, "%s: Destination " MACSTR " not found", - __func__, MAC2STR(dst)); - return -1; - } - - return ret; -} - - -static int wpa_driver_test_send_mlme(void *priv, const u8 *data, - size_t data_len, int noack) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - struct msghdr msg; - struct iovec io[2]; - const u8 *dest; - struct sockaddr_un addr; - struct dirent *dent; - DIR *dir; - int broadcast; - int ret = 0; - struct ieee80211_hdr *hdr; - u16 fc; - char cmd[50]; - int freq; -#ifdef HOSTAPD - char desttxt[30]; -#endif /* HOSTAPD */ - union wpa_event_data event; - - wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len); - if (drv->test_socket < 0 || data_len < 10) { - wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d len=%lu" - " test_dir=%p)", - __func__, drv->test_socket, - (unsigned long) data_len, - drv->test_dir); - return -1; - } - - dest = data + 4; - broadcast = os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0; - -#ifdef HOSTAPD - snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dest)); -#endif /* HOSTAPD */ - - if (drv->remain_on_channel_freq) - freq = drv->remain_on_channel_freq; - else - freq = drv->current_freq; - wpa_printf(MSG_DEBUG, "test_driver(%s): MLME TX on freq %d MHz", - dbss->ifname, freq); - os_snprintf(cmd, sizeof(cmd), "MLME freq=%d ", freq); - io[0].iov_base = cmd; - io[0].iov_len = os_strlen(cmd); - io[1].iov_base = (void *) data; - io[1].iov_len = data_len; - - os_memset(&msg, 0, sizeof(msg)); - msg.msg_iov = io; - msg.msg_iovlen = 2; - -#ifdef HOSTAPD - if (drv->test_dir == NULL) { - wpa_printf(MSG_DEBUG, "%s: test_dir == NULL", __func__); - return -1; - } - - dir = opendir(drv->test_dir); - if (dir == NULL) { - perror("test_driver: opendir"); - return -1; - } - while ((dent = readdir(dir))) { -#ifdef _DIRENT_HAVE_D_TYPE - /* Skip the file if it is not a socket. Also accept - * DT_UNKNOWN (0) in case the C library or underlying file - * system does not support d_type. */ - if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN) - continue; -#endif /* _DIRENT_HAVE_D_TYPE */ - if (os_strcmp(dent->d_name, ".") == 0 || - os_strcmp(dent->d_name, "..") == 0) - continue; - - os_memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", - drv->test_dir, dent->d_name); - - if (os_strcmp(addr.sun_path, drv->own_socket_path) == 0) - continue; - if (!broadcast && os_strstr(dent->d_name, desttxt) == NULL) - continue; - - wpa_printf(MSG_DEBUG, "%s: Send management frame to %s", - __func__, dent->d_name); - - msg.msg_name = &addr; - msg.msg_namelen = sizeof(addr); - ret = sendmsg(drv->test_socket, &msg, 0); - if (ret < 0) - perror("driver_test: sendmsg(test_socket)"); - } - closedir(dir); -#else /* HOSTAPD */ - - if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 || - drv->test_dir == NULL) { - if (drv->hostapd_addr_udp_set) { - msg.msg_name = &drv->hostapd_addr_udp; - msg.msg_namelen = sizeof(drv->hostapd_addr_udp); - } else { -#ifdef DRIVER_TEST_UNIX - msg.msg_name = &drv->hostapd_addr; - msg.msg_namelen = sizeof(drv->hostapd_addr); -#endif /* DRIVER_TEST_UNIX */ - } - } else if (broadcast) { - dir = opendir(drv->test_dir); - if (dir == NULL) - return -1; - while ((dent = readdir(dir))) { -#ifdef _DIRENT_HAVE_D_TYPE - /* Skip the file if it is not a socket. - * Also accept DT_UNKNOWN (0) in case - * the C library or underlying file - * system does not support d_type. */ - if (dent->d_type != DT_SOCK && - dent->d_type != DT_UNKNOWN) - continue; -#endif /* _DIRENT_HAVE_D_TYPE */ - if (os_strcmp(dent->d_name, ".") == 0 || - os_strcmp(dent->d_name, "..") == 0) - continue; - wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s", - __func__, dent->d_name); - os_memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - os_snprintf(addr.sun_path, sizeof(addr.sun_path), - "%s/%s", drv->test_dir, dent->d_name); - - msg.msg_name = &addr; - msg.msg_namelen = sizeof(addr); - - ret = sendmsg(drv->test_socket, &msg, 0); - if (ret < 0) - perror("driver_test: sendmsg(test_socket)"); - } - closedir(dir); - return ret; - } else { - struct stat st; - os_memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - os_snprintf(addr.sun_path, sizeof(addr.sun_path), - "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest)); - if (stat(addr.sun_path, &st) < 0) { - os_snprintf(addr.sun_path, sizeof(addr.sun_path), - "%s/STA-" MACSTR, - drv->test_dir, MAC2STR(dest)); - } - msg.msg_name = &addr; - msg.msg_namelen = sizeof(addr); - } - - if (sendmsg(drv->test_socket, &msg, 0) < 0) { - perror("sendmsg(test_socket)"); - return -1; - } -#endif /* HOSTAPD */ - - hdr = (struct ieee80211_hdr *) data; - fc = le_to_host16(hdr->frame_control); - - os_memset(&event, 0, sizeof(event)); - event.tx_status.type = WLAN_FC_GET_TYPE(fc); - event.tx_status.stype = WLAN_FC_GET_STYPE(fc); - event.tx_status.dst = hdr->addr1; - event.tx_status.data = data; - event.tx_status.data_len = data_len; - event.tx_status.ack = ret >= 0; - wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); - - return ret; -} - - -static void test_driver_scan(struct wpa_driver_test_data *drv, - struct sockaddr_un *from, socklen_t fromlen, - char *data) -{ - char buf[512], *pos, *end; - int ret; - struct test_driver_bss *bss; - u8 sa[ETH_ALEN]; - u8 ie[512]; - size_t ielen; - union wpa_event_data event; - - /* data: optional [ ' ' | STA-addr | ' ' | IEs(hex) ] */ - - wpa_printf(MSG_DEBUG, "test_driver: SCAN"); - - if (*data) { - if (*data != ' ' || - hwaddr_aton(data + 1, sa)) { - wpa_printf(MSG_DEBUG, "test_driver: Unexpected SCAN " - "command format"); - return; - } - - data += 18; - while (*data == ' ') - data++; - ielen = os_strlen(data) / 2; - if (ielen > sizeof(ie)) - ielen = sizeof(ie); - if (hexstr2bin(data, ie, ielen) < 0) - ielen = 0; - - wpa_printf(MSG_DEBUG, "test_driver: Scan from " MACSTR, - MAC2STR(sa)); - wpa_hexdump(MSG_MSGDUMP, "test_driver: scan IEs", ie, ielen); - - os_memset(&event, 0, sizeof(event)); - event.rx_probe_req.sa = sa; - event.rx_probe_req.ie = ie; - event.rx_probe_req.ie_len = ielen; - wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event); - } - - dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) { - pos = buf; - end = buf + sizeof(buf); - - /* reply: SCANRESP BSSID SSID IEs */ - ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ", - MAC2STR(bss->bssid)); - if (ret < 0 || ret >= end - pos) - return; - pos += ret; - pos += wpa_snprintf_hex(pos, end - pos, - bss->ssid, bss->ssid_len); - ret = snprintf(pos, end - pos, " "); - if (ret < 0 || ret >= end - pos) - return; - pos += ret; - pos += wpa_snprintf_hex(pos, end - pos, bss->ie, bss->ielen); - pos += wpa_snprintf_hex(pos, end - pos, bss->wps_probe_resp_ie, - bss->wps_probe_resp_ie_len); - - if (bss->privacy) { - ret = snprintf(pos, end - pos, " PRIVACY"); - if (ret < 0 || ret >= end - pos) - return; - pos += ret; - } - - sendto(drv->test_socket, buf, pos - buf, 0, - (struct sockaddr *) from, fromlen); - } -} - - -static void test_driver_assoc(struct wpa_driver_test_data *drv, - struct sockaddr_un *from, socklen_t fromlen, - char *data) -{ - struct test_client_socket *cli; - u8 ie[256], ssid[32]; - size_t ielen, ssid_len = 0; - char *pos, *pos2, cmd[50]; - struct test_driver_bss *bss, *tmp; - - /* data: STA-addr SSID(hex) IEs(hex) */ - - cli = os_zalloc(sizeof(*cli)); - if (cli == NULL) - return; - - if (hwaddr_aton(data, cli->addr)) { - printf("test_socket: Invalid MAC address '%s' in ASSOC\n", - data); - os_free(cli); - return; - } - pos = data + 17; - while (*pos == ' ') - pos++; - pos2 = strchr(pos, ' '); - ielen = 0; - if (pos2) { - ssid_len = (pos2 - pos) / 2; - if (hexstr2bin(pos, ssid, ssid_len) < 0) { - wpa_printf(MSG_DEBUG, "%s: Invalid SSID", __func__); - os_free(cli); - return; - } - wpa_hexdump_ascii(MSG_DEBUG, "test_driver_assoc: SSID", - ssid, ssid_len); - - pos = pos2 + 1; - ielen = strlen(pos) / 2; - if (ielen > sizeof(ie)) - ielen = sizeof(ie); - if (hexstr2bin(pos, ie, ielen) < 0) - ielen = 0; - } - - bss = NULL; - dl_list_for_each(tmp, &drv->bss, struct test_driver_bss, list) { - if (tmp->ssid_len == ssid_len && - os_memcmp(tmp->ssid, ssid, ssid_len) == 0) { - bss = tmp; - break; - } - } - if (bss == NULL) { - wpa_printf(MSG_DEBUG, "%s: No matching SSID found from " - "configured BSSes", __func__); - os_free(cli); - return; - } - - cli->bss = bss; - memcpy(&cli->un, from, sizeof(cli->un)); - cli->unlen = fromlen; - cli->next = drv->cli; - drv->cli = cli; - wpa_hexdump_ascii(MSG_DEBUG, "test_socket: ASSOC sun_path", - (const u8 *) cli->un.sun_path, - cli->unlen - sizeof(cli->un.sun_family)); - - snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0", - MAC2STR(bss->bssid)); - sendto(drv->test_socket, cmd, strlen(cmd), 0, - (struct sockaddr *) from, fromlen); - - drv_event_assoc(bss->bss_ctx, cli->addr, ie, ielen, 0); -} - - -static void test_driver_disassoc(struct wpa_driver_test_data *drv, - struct sockaddr_un *from, socklen_t fromlen) -{ - struct test_client_socket *cli; - - cli = test_driver_get_cli(drv, from, fromlen); - if (!cli) - return; - - drv_event_disassoc(drv->ctx, cli->addr); -} - - -static void test_driver_eapol(struct wpa_driver_test_data *drv, - struct sockaddr_un *from, socklen_t fromlen, - u8 *data, size_t datalen) -{ -#ifdef HOSTAPD - struct test_client_socket *cli; -#endif /* HOSTAPD */ - const u8 *src = NULL; - - if (datalen > 14) { - /* Skip Ethernet header */ - src = data + ETH_ALEN; - wpa_printf(MSG_DEBUG, "test_driver: dst=" MACSTR " src=" - MACSTR " proto=%04x", - MAC2STR(data), MAC2STR(src), - WPA_GET_BE16(data + 2 * ETH_ALEN)); - data += 14; - datalen -= 14; - } - -#ifdef HOSTAPD - cli = test_driver_get_cli(drv, from, fromlen); - if (cli) { - drv_event_eapol_rx(cli->bss->bss_ctx, cli->addr, data, - datalen); - } else { - wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown " - "client"); - } -#else /* HOSTAPD */ - if (src) - drv_event_eapol_rx(drv->ctx, src, data, datalen); -#endif /* HOSTAPD */ -} - - -static void test_driver_ether(struct wpa_driver_test_data *drv, - struct sockaddr_un *from, socklen_t fromlen, - u8 *data, size_t datalen) -{ - struct l2_ethhdr *eth; - - if (datalen < sizeof(*eth)) - return; - - eth = (struct l2_ethhdr *) data; - wpa_printf(MSG_DEBUG, "test_driver: RX ETHER dst=" MACSTR " src=" - MACSTR " proto=%04x", - MAC2STR(eth->h_dest), MAC2STR(eth->h_source), - be_to_host16(eth->h_proto)); - -#ifdef CONFIG_IEEE80211R - if (be_to_host16(eth->h_proto) == ETH_P_RRB) { - union wpa_event_data ev; - os_memset(&ev, 0, sizeof(ev)); - ev.ft_rrb_rx.src = eth->h_source; - ev.ft_rrb_rx.data = data + sizeof(*eth); - ev.ft_rrb_rx.data_len = datalen - sizeof(*eth); - } -#endif /* CONFIG_IEEE80211R */ -} - - -static void test_driver_mlme(struct wpa_driver_test_data *drv, - struct sockaddr_un *from, socklen_t fromlen, - u8 *data, size_t datalen) -{ - struct ieee80211_hdr *hdr; - u16 fc; - union wpa_event_data event; - int freq = 0, own_freq; - struct test_driver_bss *bss; - - bss = dl_list_first(&drv->bss, struct test_driver_bss, list); - - if (datalen > 6 && os_memcmp(data, "freq=", 5) == 0) { - size_t pos; - for (pos = 5; pos < datalen; pos++) { - if (data[pos] == ' ') - break; - } - if (pos < datalen) { - freq = atoi((const char *) &data[5]); - wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on " - "freq %d MHz", bss->ifname, freq); - pos++; - data += pos; - datalen -= pos; - } - } - - if (drv->remain_on_channel_freq) - own_freq = drv->remain_on_channel_freq; - else - own_freq = drv->current_freq; - - if (freq && own_freq && freq != own_freq) { - wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on " - "another frequency %d MHz (own %d MHz)", - bss->ifname, freq, own_freq); - return; - } - - hdr = (struct ieee80211_hdr *) data; - - if (test_driver_get_cli(drv, from, fromlen) == NULL && datalen >= 16) { - struct test_client_socket *cli; - cli = os_zalloc(sizeof(*cli)); - if (cli == NULL) - return; - wpa_printf(MSG_DEBUG, "Adding client entry for " MACSTR, - MAC2STR(hdr->addr2)); - memcpy(cli->addr, hdr->addr2, ETH_ALEN); - memcpy(&cli->un, from, sizeof(cli->un)); - cli->unlen = fromlen; - cli->next = drv->cli; - drv->cli = cli; - } - - wpa_hexdump(MSG_MSGDUMP, "test_driver_mlme: received frame", - data, datalen); - fc = le_to_host16(hdr->frame_control); - if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) { - wpa_printf(MSG_ERROR, "%s: received non-mgmt frame", - __func__); - return; - } - - os_memset(&event, 0, sizeof(event)); - event.rx_mgmt.frame = data; - event.rx_mgmt.frame_len = datalen; - wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); -} - - -static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct wpa_driver_test_data *drv = eloop_ctx; - char buf[2000]; - int res; - struct sockaddr_un from; - socklen_t fromlen = sizeof(from); - - res = recvfrom(sock, buf, sizeof(buf) - 1, 0, - (struct sockaddr *) &from, &fromlen); - if (res < 0) { - perror("recvfrom(test_socket)"); - return; - } - buf[res] = '\0'; - - wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res); - - if (strncmp(buf, "SCAN", 4) == 0) { - test_driver_scan(drv, &from, fromlen, buf + 4); - } else if (strncmp(buf, "ASSOC ", 6) == 0) { - test_driver_assoc(drv, &from, fromlen, buf + 6); - } else if (strcmp(buf, "DISASSOC") == 0) { - test_driver_disassoc(drv, &from, fromlen); - } else if (strncmp(buf, "EAPOL ", 6) == 0) { - test_driver_eapol(drv, &from, fromlen, (u8 *) buf + 6, - res - 6); - } else if (strncmp(buf, "ETHER ", 6) == 0) { - test_driver_ether(drv, &from, fromlen, (u8 *) buf + 6, - res - 6); - } else if (strncmp(buf, "MLME ", 5) == 0) { - test_driver_mlme(drv, &from, fromlen, (u8 *) buf + 5, res - 5); - } else { - wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command", - (u8 *) buf, res); - } -} - - -static int test_driver_set_generic_elem(void *priv, - const u8 *elem, size_t elem_len) -{ - struct test_driver_bss *bss = priv; - - os_free(bss->ie); - - if (elem == NULL) { - bss->ie = NULL; - bss->ielen = 0; - return 0; - } - - bss->ie = os_malloc(elem_len); - if (bss->ie == NULL) { - bss->ielen = 0; - return -1; - } - - memcpy(bss->ie, elem, elem_len); - bss->ielen = elem_len; - return 0; -} - - -static int test_driver_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, - const struct wpabuf *proberesp, - const struct wpabuf *assocresp) -{ - struct test_driver_bss *bss = priv; - - if (beacon == NULL) - wpa_printf(MSG_DEBUG, "test_driver: Clear Beacon WPS IE"); - else - wpa_hexdump_buf(MSG_DEBUG, "test_driver: Beacon WPS IE", - beacon); - - os_free(bss->wps_beacon_ie); - - if (beacon == NULL) { - bss->wps_beacon_ie = NULL; - bss->wps_beacon_ie_len = 0; - } else { - bss->wps_beacon_ie = os_malloc(wpabuf_len(beacon)); - if (bss->wps_beacon_ie == NULL) { - bss->wps_beacon_ie_len = 0; - return -1; - } - - os_memcpy(bss->wps_beacon_ie, wpabuf_head(beacon), - wpabuf_len(beacon)); - bss->wps_beacon_ie_len = wpabuf_len(beacon); - } - - if (proberesp == NULL) - wpa_printf(MSG_DEBUG, "test_driver: Clear Probe Response WPS " - "IE"); - else - wpa_hexdump_buf(MSG_DEBUG, "test_driver: Probe Response WPS " - "IE", proberesp); - - os_free(bss->wps_probe_resp_ie); - - if (proberesp == NULL) { - bss->wps_probe_resp_ie = NULL; - bss->wps_probe_resp_ie_len = 0; - } else { - bss->wps_probe_resp_ie = os_malloc(wpabuf_len(proberesp)); - if (bss->wps_probe_resp_ie == NULL) { - bss->wps_probe_resp_ie_len = 0; - return -1; - } - - os_memcpy(bss->wps_probe_resp_ie, wpabuf_head(proberesp), - wpabuf_len(proberesp)); - bss->wps_probe_resp_ie_len = wpabuf_len(proberesp); - } - - return 0; -} - - -static int test_driver_sta_deauth(void *priv, const u8 *own_addr, - const u8 *addr, int reason) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - struct test_client_socket *cli; - - if (drv->test_socket < 0) - return -1; - - cli = drv->cli; - while (cli) { - if (memcmp(cli->addr, addr, ETH_ALEN) == 0) - break; - cli = cli->next; - } - - if (!cli) - return -1; - - return sendto(drv->test_socket, "DEAUTH", 6, 0, - (struct sockaddr *) &cli->un, cli->unlen); -} - - -static int test_driver_sta_disassoc(void *priv, const u8 *own_addr, - const u8 *addr, int reason) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - struct test_client_socket *cli; - - if (drv->test_socket < 0) - return -1; - - cli = drv->cli; - while (cli) { - if (memcmp(cli->addr, addr, ETH_ALEN) == 0) - break; - cli = cli->next; - } - - if (!cli) - return -1; - - return sendto(drv->test_socket, "DISASSOC", 8, 0, - (struct sockaddr *) &cli->un, cli->unlen); -} - - -static int test_driver_bss_add(void *priv, const char *ifname, const u8 *bssid, - void *bss_ctx, void **drv_priv) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - struct test_driver_bss *bss; - - wpa_printf(MSG_DEBUG, "%s(ifname=%s bssid=" MACSTR ")", - __func__, ifname, MAC2STR(bssid)); - - bss = os_zalloc(sizeof(*bss)); - if (bss == NULL) - return -1; - - bss->bss_ctx = bss_ctx; - bss->drv = drv; - os_strlcpy(bss->ifname, ifname, IFNAMSIZ); - os_memcpy(bss->bssid, bssid, ETH_ALEN); - - dl_list_add(&drv->bss, &bss->list); - if (drv->global) { - drv->global->bss_add_used = 1; - os_memcpy(drv->global->req_addr, bssid, ETH_ALEN); - } - - if (drv_priv) - *drv_priv = bss; - - return 0; -} - - -static int test_driver_bss_remove(void *priv, const char *ifname) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - struct test_driver_bss *bss; - struct test_client_socket *cli, *prev_c; - - wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname); - - dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) { - if (strcmp(bss->ifname, ifname) != 0) - continue; - - for (prev_c = NULL, cli = drv->cli; cli; - prev_c = cli, cli = cli->next) { - if (cli->bss != bss) - continue; - if (prev_c) - prev_c->next = cli->next; - else - drv->cli = cli->next; - os_free(cli); - break; - } - - dl_list_del(&bss->list); - test_driver_free_bss(bss); - return 0; - } - - return -1; -} - - -static int test_driver_if_add(void *priv, enum wpa_driver_if_type type, - const char *ifname, const u8 *addr, - void *bss_ctx, void **drv_priv, - char *force_ifname, u8 *if_addr, - const char *bridge, int use_existing) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - - wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s bss_ctx=%p)", - __func__, type, ifname, bss_ctx); - if (addr) - os_memcpy(if_addr, addr, ETH_ALEN); - else { - drv->alloc_iface_idx++; - if_addr[0] = 0x02; /* locally administered */ - sha1_prf(drv->own_addr, ETH_ALEN, - "hostapd test addr generation", - (const u8 *) &drv->alloc_iface_idx, - sizeof(drv->alloc_iface_idx), - if_addr + 1, ETH_ALEN - 1); - } - if (type == WPA_IF_AP_BSS || type == WPA_IF_P2P_GO || - type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP) - return test_driver_bss_add(priv, ifname, if_addr, bss_ctx, - drv_priv); - return 0; -} - - -static int test_driver_if_remove(void *priv, enum wpa_driver_if_type type, - const char *ifname) -{ - wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname); - if (type == WPA_IF_AP_BSS || type == WPA_IF_P2P_GO || - type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP) - return test_driver_bss_remove(priv, ifname); - return 0; -} - - -static int test_driver_set_ssid(void *priv, const u8 *buf, int len) -{ - struct test_driver_bss *bss = priv; - - wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, bss->ifname); - if (len < 0) - return -1; - wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len); - - if ((size_t) len > sizeof(bss->ssid)) - return -1; - - os_memcpy(bss->ssid, buf, len); - bss->ssid_len = len; - - return 0; -} - - -static int test_driver_set_privacy(void *priv, int enabled) -{ - struct test_driver_bss *dbss = priv; - - wpa_printf(MSG_DEBUG, "%s(enabled=%d)", __func__, enabled); - dbss->privacy = enabled; - - return 0; -} - - -static int test_driver_set_sta_vlan(void *priv, const u8 *addr, - const char *ifname, int vlan_id) -{ - wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " ifname=%s vlan_id=%d)", - __func__, MAC2STR(addr), ifname, vlan_id); - return 0; -} - - -static int test_driver_sta_add(void *priv, - struct hostapd_sta_add_params *params) -{ - struct test_driver_bss *bss = priv; - struct wpa_driver_test_data *drv = bss->drv; - struct test_client_socket *cli; - - wpa_printf(MSG_DEBUG, "%s(ifname=%s addr=" MACSTR " aid=%d " - "capability=0x%x listen_interval=%d)", - __func__, bss->ifname, MAC2STR(params->addr), params->aid, - params->capability, params->listen_interval); - wpa_hexdump(MSG_DEBUG, "test_driver_sta_add - supp_rates", - params->supp_rates, params->supp_rates_len); - - cli = drv->cli; - while (cli) { - if (os_memcmp(cli->addr, params->addr, ETH_ALEN) == 0) - break; - cli = cli->next; - } - if (!cli) { - wpa_printf(MSG_DEBUG, "%s: no matching client entry", - __func__); - return -1; - } - - cli->bss = bss; - - return 0; -} - - -static struct wpa_driver_test_data * test_alloc_data(void *ctx, - const char *ifname) -{ - struct wpa_driver_test_data *drv; - struct test_driver_bss *bss; - - drv = os_zalloc(sizeof(struct wpa_driver_test_data)); - if (drv == NULL) { - wpa_printf(MSG_ERROR, "Could not allocate memory for test " - "driver data"); - return NULL; - } - - bss = os_zalloc(sizeof(struct test_driver_bss)); - if (bss == NULL) { - os_free(drv); - return NULL; - } - - drv->ctx = ctx; - wpa_trace_add_ref(drv, ctx, ctx); - dl_list_init(&drv->bss); - dl_list_add(&drv->bss, &bss->list); - os_strlcpy(bss->ifname, ifname, IFNAMSIZ); - bss->bss_ctx = ctx; - bss->drv = drv; - - /* Generate a MAC address to help testing with multiple STAs */ - drv->own_addr[0] = 0x02; /* locally administered */ - sha1_prf((const u8 *) ifname, os_strlen(ifname), - "test mac addr generation", - NULL, 0, drv->own_addr + 1, ETH_ALEN - 1); - - return drv; -} - - -static void * test_driver_init(struct hostapd_data *hapd, - struct wpa_init_params *params) -{ - struct wpa_driver_test_data *drv; - struct sockaddr_un addr_un; - struct sockaddr_in addr_in; - struct sockaddr *addr; - socklen_t alen; - struct test_driver_bss *bss; - - drv = test_alloc_data(hapd, params->ifname); - if (drv == NULL) - 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); - os_memcpy(params->own_addr, drv->own_addr, ETH_ALEN); - - if (params->test_socket) { - if (os_strlen(params->test_socket) >= - sizeof(addr_un.sun_path)) { - printf("Too long test_socket path\n"); - wpa_driver_test_deinit(bss); - return NULL; - } - if (strncmp(params->test_socket, "DIR:", 4) == 0) { - size_t len = strlen(params->test_socket) + 30; - drv->test_dir = os_strdup(params->test_socket + 4); - drv->own_socket_path = os_malloc(len); - if (drv->own_socket_path) { - snprintf(drv->own_socket_path, len, - "%s/AP-" MACSTR, - params->test_socket + 4, - MAC2STR(params->own_addr)); - } - } else if (strncmp(params->test_socket, "UDP:", 4) == 0) { - drv->udp_port = atoi(params->test_socket + 4); - } else { - drv->own_socket_path = os_strdup(params->test_socket); - } - if (drv->own_socket_path == NULL && drv->udp_port == 0) { - wpa_driver_test_deinit(bss); - return NULL; - } - - drv->test_socket = socket(drv->udp_port ? PF_INET : PF_UNIX, - SOCK_DGRAM, 0); - if (drv->test_socket < 0) { - perror("socket"); - wpa_driver_test_deinit(bss); - return NULL; - } - - if (drv->udp_port) { - os_memset(&addr_in, 0, sizeof(addr_in)); - addr_in.sin_family = AF_INET; - addr_in.sin_port = htons(drv->udp_port); - addr = (struct sockaddr *) &addr_in; - alen = sizeof(addr_in); - } else { - os_memset(&addr_un, 0, sizeof(addr_un)); - addr_un.sun_family = AF_UNIX; - os_strlcpy(addr_un.sun_path, drv->own_socket_path, - sizeof(addr_un.sun_path)); - addr = (struct sockaddr *) &addr_un; - alen = sizeof(addr_un); - } - if (bind(drv->test_socket, addr, alen) < 0) { - perror("test-driver-init: bind(PF_UNIX)"); - close(drv->test_socket); - if (drv->own_socket_path) - unlink(drv->own_socket_path); - wpa_driver_test_deinit(bss); - return NULL; - } - eloop_register_read_sock(drv->test_socket, - test_driver_receive_unix, drv, NULL); - } else - drv->test_socket = -1; - - return bss; -} - - -static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_driver_test_data *drv = eloop_ctx; - -#ifdef DRIVER_TEST_UNIX - if (drv->associated && drv->hostapd_addr_set) { - struct stat st; - if (stat(drv->hostapd_addr.sun_path, &st) < 0) { - wpa_printf(MSG_DEBUG, "%s: lost connection to AP: %s", - __func__, strerror(errno)); - drv->associated = 0; - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); - } - } -#endif /* DRIVER_TEST_UNIX */ - - eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL); -} - - -static void wpa_driver_test_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); -} - - -#ifdef DRIVER_TEST_UNIX -static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv, - const char *path) -{ - struct dirent *dent; - DIR *dir; - struct sockaddr_un addr; - char cmd[512], *pos, *end; - int ret; - - dir = opendir(path); - if (dir == NULL) - return; - - end = cmd + sizeof(cmd); - pos = cmd; - ret = os_snprintf(pos, end - pos, "SCAN " MACSTR, - MAC2STR(drv->own_addr)); - if (ret >= 0 && ret < end - pos) - pos += ret; - if (drv->probe_req_ie) { - ret = os_snprintf(pos, end - pos, " "); - if (ret >= 0 && ret < end - pos) - pos += ret; - pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie, - drv->probe_req_ie_len); - } - if (drv->probe_req_ssid_len) { - /* Add SSID IE */ - ret = os_snprintf(pos, end - pos, "%02x%02x", - WLAN_EID_SSID, - (unsigned int) drv->probe_req_ssid_len); - if (ret >= 0 && ret < end - pos) - pos += ret; - pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ssid, - drv->probe_req_ssid_len); - } - end[-1] = '\0'; - - while ((dent = readdir(dir))) { - if (os_strncmp(dent->d_name, "AP-", 3) != 0 && - os_strncmp(dent->d_name, "STA-", 4) != 0) - continue; - if (drv->own_socket_path) { - size_t olen, dlen; - olen = os_strlen(drv->own_socket_path); - dlen = os_strlen(dent->d_name); - if (olen >= dlen && - os_strcmp(dent->d_name, - drv->own_socket_path + olen - dlen) == 0) - continue; - } - wpa_printf(MSG_DEBUG, "%s: SCAN %s", __func__, dent->d_name); - - os_memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", - path, dent->d_name); - - if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0, - (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("sendto(test_socket)"); - } - } - closedir(dir); -} -#endif /* DRIVER_TEST_UNIX */ - - -static int wpa_driver_test_scan(void *priv, - struct wpa_driver_scan_params *params) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - size_t i; - - wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv); - - os_free(drv->probe_req_ie); - if (params->extra_ies) { - drv->probe_req_ie = os_malloc(params->extra_ies_len); - if (drv->probe_req_ie == NULL) { - drv->probe_req_ie_len = 0; - return -1; - } - os_memcpy(drv->probe_req_ie, params->extra_ies, - params->extra_ies_len); - drv->probe_req_ie_len = params->extra_ies_len; - } else { - drv->probe_req_ie = NULL; - drv->probe_req_ie_len = 0; - } - - for (i = 0; i < params->num_ssids; i++) - wpa_hexdump(MSG_DEBUG, "Scan SSID", - params->ssids[i].ssid, params->ssids[i].ssid_len); - drv->probe_req_ssid_len = 0; - if (params->num_ssids) { - os_memcpy(drv->probe_req_ssid, params->ssids[0].ssid, - params->ssids[0].ssid_len); - drv->probe_req_ssid_len = params->ssids[0].ssid_len; - } - wpa_hexdump(MSG_DEBUG, "Scan extra IE(s)", - params->extra_ies, params->extra_ies_len); - - drv->num_scanres = 0; - -#ifdef DRIVER_TEST_UNIX - if (drv->test_socket >= 0 && drv->test_dir) - wpa_driver_scan_dir(drv, drv->test_dir); - - if (drv->test_socket >= 0 && drv->hostapd_addr_set && - sendto(drv->test_socket, "SCAN", 4, 0, - (struct sockaddr *) &drv->hostapd_addr, - sizeof(drv->hostapd_addr)) < 0) { - perror("sendto(test_socket)"); - } -#endif /* DRIVER_TEST_UNIX */ - - if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set && - sendto(drv->test_socket, "SCAN", 4, 0, - (struct sockaddr *) &drv->hostapd_addr_udp, - sizeof(drv->hostapd_addr_udp)) < 0) { - perror("sendto(test_socket)"); - } - - eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx); - eloop_register_timeout(1, 0, wpa_driver_test_scan_timeout, drv, - drv->ctx); - return 0; -} - - -static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - struct wpa_scan_results *res; - size_t i; - - res = os_zalloc(sizeof(*res)); - if (res == NULL) - return NULL; - - res->res = os_calloc(drv->num_scanres, sizeof(struct wpa_scan_res *)); - if (res->res == NULL) { - os_free(res); - return NULL; - } - - for (i = 0; i < drv->num_scanres; i++) { - struct wpa_scan_res *r; - if (drv->scanres[i] == NULL) - continue; - r = os_malloc(sizeof(*r) + drv->scanres[i]->ie_len); - if (r == NULL) - break; - os_memcpy(r, drv->scanres[i], - sizeof(*r) + drv->scanres[i]->ie_len); - res->res[res->num++] = r; - } - - return res; -} - - -static int wpa_driver_test_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) -{ - wpa_printf(MSG_DEBUG, "%s: ifname=%s priv=%p alg=%d key_idx=%d " - "set_tx=%d", - __func__, ifname, priv, alg, key_idx, set_tx); - if (addr) - wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr)); - if (seq) - wpa_hexdump(MSG_DEBUG, " seq", seq, seq_len); - if (key) - wpa_hexdump_key(MSG_DEBUG, " key", key, key_len); - return 0; -} - - -static int wpa_driver_update_mode(struct wpa_driver_test_data *drv, int ap) -{ - if (ap && !drv->ap) { - wpa_driver_test_close_test_socket(drv); - wpa_driver_test_attach(drv, drv->test_dir, 1); - drv->ap = 1; - } else if (!ap && drv->ap) { - wpa_driver_test_close_test_socket(drv); - wpa_driver_test_attach(drv, drv->test_dir, 0); - drv->ap = 0; - } - - return 0; -} - - -static int wpa_driver_test_associate( - void *priv, struct wpa_driver_associate_params *params) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d " - "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d", - __func__, priv, params->freq, params->pairwise_suite, - params->group_suite, params->key_mgmt_suite, - params->auth_alg, params->mode); - wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP); - if (params->bssid) { - wpa_printf(MSG_DEBUG, " bssid=" MACSTR, - MAC2STR(params->bssid)); - } - if (params->ssid) { - wpa_hexdump_ascii(MSG_DEBUG, " ssid", - params->ssid, params->ssid_len); - } - if (params->wpa_ie) { - wpa_hexdump(MSG_DEBUG, " wpa_ie", - params->wpa_ie, params->wpa_ie_len); - drv->assoc_wpa_ie_len = params->wpa_ie_len; - if (drv->assoc_wpa_ie_len > sizeof(drv->assoc_wpa_ie)) - drv->assoc_wpa_ie_len = sizeof(drv->assoc_wpa_ie); - os_memcpy(drv->assoc_wpa_ie, params->wpa_ie, - drv->assoc_wpa_ie_len); - } else - drv->assoc_wpa_ie_len = 0; - - wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP); - - drv->ibss = params->mode == IEEE80211_MODE_IBSS; - dbss->privacy = params->key_mgmt_suite & - (WPA_KEY_MGMT_IEEE8021X | - WPA_KEY_MGMT_PSK | - WPA_KEY_MGMT_WPA_NONE | - WPA_KEY_MGMT_FT_IEEE8021X | - WPA_KEY_MGMT_FT_PSK | - WPA_KEY_MGMT_IEEE8021X_SHA256 | - WPA_KEY_MGMT_PSK_SHA256); - if (params->wep_key_len[params->wep_tx_keyidx]) - dbss->privacy = 1; - -#ifdef DRIVER_TEST_UNIX - if (drv->test_dir && params->bssid && - params->mode != IEEE80211_MODE_IBSS) { - os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr)); - drv->hostapd_addr.sun_family = AF_UNIX; - os_snprintf(drv->hostapd_addr.sun_path, - sizeof(drv->hostapd_addr.sun_path), - "%s/AP-" MACSTR, - drv->test_dir, MAC2STR(params->bssid)); - drv->hostapd_addr_set = 1; - } -#endif /* DRIVER_TEST_UNIX */ - - if (params->mode == IEEE80211_MODE_AP) { - os_memcpy(dbss->ssid, params->ssid, params->ssid_len); - dbss->ssid_len = params->ssid_len; - os_memcpy(dbss->bssid, drv->own_addr, ETH_ALEN); - if (params->wpa_ie && params->wpa_ie_len) { - dbss->ie = os_malloc(params->wpa_ie_len); - if (dbss->ie) { - os_memcpy(dbss->ie, params->wpa_ie, - params->wpa_ie_len); - dbss->ielen = params->wpa_ie_len; - } - } - } else if (drv->test_socket >= 0 && - (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) { - char cmd[200], *pos, *end; - int ret; - end = cmd + sizeof(cmd); - pos = cmd; - ret = os_snprintf(pos, end - pos, "ASSOC " MACSTR " ", - MAC2STR(drv->own_addr)); - if (ret >= 0 && ret < end - pos) - pos += ret; - pos += wpa_snprintf_hex(pos, end - pos, params->ssid, - params->ssid_len); - ret = os_snprintf(pos, end - pos, " "); - if (ret >= 0 && ret < end - pos) - pos += ret; - pos += wpa_snprintf_hex(pos, end - pos, params->wpa_ie, - params->wpa_ie_len); - end[-1] = '\0'; -#ifdef DRIVER_TEST_UNIX - if (drv->hostapd_addr_set && - sendto(drv->test_socket, cmd, os_strlen(cmd), 0, - (struct sockaddr *) &drv->hostapd_addr, - sizeof(drv->hostapd_addr)) < 0) { - perror("sendto(test_socket)"); - return -1; - } -#endif /* DRIVER_TEST_UNIX */ - if (drv->hostapd_addr_udp_set && - sendto(drv->test_socket, cmd, os_strlen(cmd), 0, - (struct sockaddr *) &drv->hostapd_addr_udp, - sizeof(drv->hostapd_addr_udp)) < 0) { - perror("sendto(test_socket)"); - return -1; - } - - os_memcpy(dbss->ssid, params->ssid, params->ssid_len); - dbss->ssid_len = params->ssid_len; - } else { - drv->associated = 1; - if (params->mode == IEEE80211_MODE_IBSS) { - os_memcpy(dbss->ssid, params->ssid, params->ssid_len); - dbss->ssid_len = params->ssid_len; - if (params->bssid) - os_memcpy(dbss->bssid, params->bssid, - ETH_ALEN); - else { - os_get_random(dbss->bssid, ETH_ALEN); - dbss->bssid[0] &= ~0x01; - dbss->bssid[0] |= 0x02; - } - } - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); - } - - return 0; -} - - -static int wpa_driver_test_get_bssid(void *priv, u8 *bssid) -{ - struct test_driver_bss *dbss = priv; - os_memcpy(bssid, dbss->bssid, ETH_ALEN); - return 0; -} - - -static int wpa_driver_test_get_ssid(void *priv, u8 *ssid) -{ - struct test_driver_bss *dbss = priv; - os_memcpy(ssid, dbss->ssid, 32); - return dbss->ssid_len; -} - - -static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv) -{ -#ifdef DRIVER_TEST_UNIX - if (drv->test_socket >= 0 && - sendto(drv->test_socket, "DISASSOC", 8, 0, - (struct sockaddr *) &drv->hostapd_addr, - sizeof(drv->hostapd_addr)) < 0) { - perror("sendto(test_socket)"); - return -1; - } -#endif /* DRIVER_TEST_UNIX */ - if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set && - sendto(drv->test_socket, "DISASSOC", 8, 0, - (struct sockaddr *) &drv->hostapd_addr_udp, - sizeof(drv->hostapd_addr_udp)) < 0) { - perror("sendto(test_socket)"); - return -1; - } - return 0; -} - - -static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr, - int reason_code) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d", - __func__, MAC2STR(addr), reason_code); - os_memset(dbss->bssid, 0, ETH_ALEN); - drv->associated = 0; - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); - return wpa_driver_test_send_disassoc(drv); -} - - -static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) -{ - const u8 *end, *pos; - - pos = (const u8 *) (res + 1); - end = pos + res->ie_len; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == ie) - return pos; - pos += 2 + pos[1]; - } - - return NULL; -} - - -static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv, - struct sockaddr *from, - socklen_t fromlen, - const char *data) -{ - struct wpa_scan_res *res; - const char *pos, *pos2; - size_t len; - u8 *ie_pos, *ie_start, *ie_end; -#define MAX_IE_LEN 1000 - const u8 *ds_params; - - wpa_printf(MSG_DEBUG, "test_driver: SCANRESP %s", data); - if (drv->num_scanres >= MAX_SCAN_RESULTS) { - wpa_printf(MSG_DEBUG, "test_driver: No room for the new scan " - "result"); - return; - } - - /* SCANRESP BSSID SSID IEs */ - - res = os_zalloc(sizeof(*res) + MAX_IE_LEN); - if (res == NULL) - return; - ie_start = ie_pos = (u8 *) (res + 1); - ie_end = ie_pos + MAX_IE_LEN; - - if (hwaddr_aton(data, res->bssid)) { - wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in scanres"); - os_free(res); - return; - } - - pos = data + 17; - while (*pos == ' ') - pos++; - pos2 = os_strchr(pos, ' '); - if (pos2 == NULL) { - wpa_printf(MSG_DEBUG, "test_driver: invalid SSID termination " - "in scanres"); - os_free(res); - return; - } - len = (pos2 - pos) / 2; - if (len > 32) - len = 32; - /* - * Generate SSID IE from the SSID field since this IE is not included - * in the main IE field. - */ - *ie_pos++ = WLAN_EID_SSID; - *ie_pos++ = len; - if (hexstr2bin(pos, ie_pos, len) < 0) { - wpa_printf(MSG_DEBUG, "test_driver: invalid SSID in scanres"); - os_free(res); - return; - } - ie_pos += len; - - pos = pos2 + 1; - pos2 = os_strchr(pos, ' '); - if (pos2 == NULL) - len = os_strlen(pos) / 2; - else - len = (pos2 - pos) / 2; - if ((int) len > ie_end - ie_pos) - len = ie_end - ie_pos; - if (hexstr2bin(pos, ie_pos, len) < 0) { - wpa_printf(MSG_DEBUG, "test_driver: invalid IEs in scanres"); - os_free(res); - return; - } - ie_pos += len; - res->ie_len = ie_pos - ie_start; - - if (pos2) { - pos = pos2 + 1; - while (*pos == ' ') - pos++; - if (os_strstr(pos, "PRIVACY")) - res->caps |= IEEE80211_CAP_PRIVACY; - if (os_strstr(pos, "IBSS")) - res->caps |= IEEE80211_CAP_IBSS; - } - - ds_params = wpa_scan_get_ie(res, WLAN_EID_DS_PARAMS); - if (ds_params && ds_params[1] > 0) { - if (ds_params[2] >= 1 && ds_params[2] <= 13) - res->freq = 2407 + ds_params[2] * 5; - } - - os_free(drv->scanres[drv->num_scanres]); - drv->scanres[drv->num_scanres++] = res; -} - - -static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv, - struct sockaddr *from, - socklen_t fromlen, - const char *data) -{ - struct test_driver_bss *bss; - - bss = dl_list_first(&drv->bss, struct test_driver_bss, list); - - /* ASSOCRESP BSSID */ - if (hwaddr_aton(data, bss->bssid)) { - wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in " - "assocresp"); - } - if (drv->use_associnfo) { - union wpa_event_data event; - os_memset(&event, 0, sizeof(event)); - event.assoc_info.req_ies = drv->assoc_wpa_ie; - event.assoc_info.req_ies_len = drv->assoc_wpa_ie_len; - wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &event); - } - drv->associated = 1; - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); -} - - -static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv, - struct sockaddr *from, - socklen_t fromlen) -{ - drv->associated = 0; - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); -} - - -static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv, - struct sockaddr *from, - socklen_t fromlen, - const u8 *data, size_t data_len) -{ - const u8 *src; - struct test_driver_bss *bss; - - bss = dl_list_first(&drv->bss, struct test_driver_bss, list); - - if (data_len > 14) { - /* Skip Ethernet header */ - src = data + ETH_ALEN; - data += 14; - data_len -= 14; - } else - src = bss->bssid; - - drv_event_eapol_rx(drv->ctx, src, data, data_len); -} - - -static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, - struct sockaddr *from, - socklen_t fromlen, - const u8 *data, size_t data_len) -{ - int freq = 0, own_freq; - union wpa_event_data event; - const struct ieee80211_mgmt *mgmt; - u16 fc; - struct test_driver_bss *bss; - - bss = dl_list_first(&drv->bss, struct test_driver_bss, list); - if (data_len > 6 && os_memcmp(data, "freq=", 5) == 0) { - size_t pos; - for (pos = 5; pos < data_len; pos++) { - if (data[pos] == ' ') - break; - } - if (pos < data_len) { - freq = atoi((const char *) &data[5]); - wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on " - "freq %d MHz", bss->ifname, freq); - pos++; - data += pos; - data_len -= pos; - } - } - - if (drv->remain_on_channel_freq) - own_freq = drv->remain_on_channel_freq; - else - own_freq = drv->current_freq; - - if (freq && own_freq && freq != own_freq) { - wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on " - "another frequency %d MHz (own %d MHz)", - bss->ifname, freq, own_freq); - return; - } - - os_memset(&event, 0, sizeof(event)); - event.mlme_rx.buf = data; - event.mlme_rx.len = data_len; - event.mlme_rx.freq = freq; - wpa_supplicant_event(drv->ctx, EVENT_MLME_RX, &event); - - mgmt = (const struct ieee80211_mgmt *) data; - fc = le_to_host16(mgmt->frame_control); - - if (drv->probe_req_report && data_len >= 24) { - if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - 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); - wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, - &event); - } - } -} - - -static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv, - struct sockaddr *from, - socklen_t fromlen, - const u8 *data, size_t data_len) -{ - char buf[512], *pos, *end; - int ret; - struct test_driver_bss *bss; - - bss = dl_list_first(&drv->bss, struct test_driver_bss, list); - - /* data: optional [ STA-addr | ' ' | IEs(hex) ] */ - - if (!drv->ibss) - return; - - pos = buf; - end = buf + sizeof(buf); - - /* reply: SCANRESP BSSID SSID IEs */ - ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ", - MAC2STR(bss->bssid)); - if (ret < 0 || ret >= end - pos) - return; - pos += ret; - pos += wpa_snprintf_hex(pos, end - pos, - bss->ssid, bss->ssid_len); - ret = snprintf(pos, end - pos, " "); - if (ret < 0 || ret >= end - pos) - return; - pos += ret; - pos += wpa_snprintf_hex(pos, end - pos, drv->assoc_wpa_ie, - drv->assoc_wpa_ie_len); - - if (bss->privacy) { - ret = snprintf(pos, end - pos, " PRIVACY"); - if (ret < 0 || ret >= end - pos) - return; - pos += ret; - } - - ret = snprintf(pos, end - pos, " IBSS"); - if (ret < 0 || ret >= end - pos) - return; - pos += ret; - - sendto(drv->test_socket, buf, pos - buf, 0, - (struct sockaddr *) from, fromlen); -} - - -static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx, - void *sock_ctx) -{ - struct wpa_driver_test_data *drv = eloop_ctx; - char *buf; - int res; - struct sockaddr_storage from; - socklen_t fromlen = sizeof(from); - const size_t buflen = 2000; - - if (drv->ap) { - test_driver_receive_unix(sock, eloop_ctx, sock_ctx); - return; - } - - buf = os_malloc(buflen); - if (buf == NULL) - return; - res = recvfrom(sock, buf, buflen - 1, 0, - (struct sockaddr *) &from, &fromlen); - if (res < 0) { - perror("recvfrom(test_socket)"); - os_free(buf); - return; - } - buf[res] = '\0'; - - wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res); - - if (os_strncmp(buf, "SCANRESP ", 9) == 0) { - wpa_driver_test_scanresp(drv, (struct sockaddr *) &from, - fromlen, buf + 9); - } else if (os_strncmp(buf, "ASSOCRESP ", 10) == 0) { - wpa_driver_test_assocresp(drv, (struct sockaddr *) &from, - fromlen, buf + 10); - } else if (os_strcmp(buf, "DISASSOC") == 0) { - wpa_driver_test_disassoc(drv, (struct sockaddr *) &from, - fromlen); - } else if (os_strcmp(buf, "DEAUTH") == 0) { - wpa_driver_test_disassoc(drv, (struct sockaddr *) &from, - fromlen); - } else if (os_strncmp(buf, "EAPOL ", 6) == 0) { - wpa_driver_test_eapol(drv, (struct sockaddr *) &from, fromlen, - (const u8 *) buf + 6, res - 6); - } else if (os_strncmp(buf, "MLME ", 5) == 0) { - wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen, - (const u8 *) buf + 5, res - 5); - } else if (os_strncmp(buf, "SCAN ", 5) == 0) { - wpa_driver_test_scan_cmd(drv, (struct sockaddr *) &from, - fromlen, - (const u8 *) buf + 5, res - 5); - } else { - wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command", - (u8 *) buf, res); - } - os_free(buf); -} - - -static void * wpa_driver_test_init2(void *ctx, const char *ifname, - void *global_priv) -{ - struct wpa_driver_test_data *drv; - struct wpa_driver_test_global *global = global_priv; - struct test_driver_bss *bss; - - drv = test_alloc_data(ctx, ifname); - if (drv == NULL) - return NULL; - bss = dl_list_first(&drv->bss, struct test_driver_bss, list); - drv->global = global_priv; - drv->test_socket = -1; - - /* Set dummy BSSID and SSID for testing. */ - bss->bssid[0] = 0x02; - bss->bssid[1] = 0x00; - bss->bssid[2] = 0x00; - bss->bssid[3] = 0x00; - bss->bssid[4] = 0x00; - bss->bssid[5] = 0x01; - os_memcpy(bss->ssid, "test", 5); - bss->ssid_len = 4; - - if (global->bss_add_used) { - os_memcpy(drv->own_addr, global->req_addr, ETH_ALEN); - global->bss_add_used = 0; - } - - eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL); - - return bss; -} - - -static void wpa_driver_test_close_test_socket(struct wpa_driver_test_data *drv) -{ - if (drv->test_socket >= 0) { - eloop_unregister_read_sock(drv->test_socket); - close(drv->test_socket); - drv->test_socket = -1; - } - - if (drv->own_socket_path) { - unlink(drv->own_socket_path); - os_free(drv->own_socket_path); - drv->own_socket_path = NULL; - } -} - - -static void wpa_driver_test_deinit(void *priv) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - struct test_client_socket *cli, *prev; - int i; - - cli = drv->cli; - while (cli) { - prev = cli; - cli = cli->next; - os_free(prev); - } - -#ifdef HOSTAPD - /* There should be only one BSS remaining at this point. */ - if (dl_list_len(&drv->bss) != 1) - wpa_printf(MSG_ERROR, "%s: %u remaining BSS entries", - __func__, dl_list_len(&drv->bss)); -#endif /* HOSTAPD */ - - test_driver_free_bsses(drv); - - wpa_driver_test_close_test_socket(drv); - eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx); - eloop_cancel_timeout(wpa_driver_test_poll, drv, NULL); - eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL); - os_free(drv->test_dir); - for (i = 0; i < MAX_SCAN_RESULTS; i++) - os_free(drv->scanres[i]); - os_free(drv->probe_req_ie); - wpa_trace_remove_ref(drv, ctx, drv->ctx); - os_free(drv); -} - - -static int wpa_driver_test_attach(struct wpa_driver_test_data *drv, - const char *dir, int ap) -{ -#ifdef DRIVER_TEST_UNIX - static unsigned int counter = 0; - struct sockaddr_un addr; - size_t len; - - os_free(drv->own_socket_path); - if (dir) { - len = os_strlen(dir) + 30; - drv->own_socket_path = os_malloc(len); - if (drv->own_socket_path == NULL) - return -1; - os_snprintf(drv->own_socket_path, len, "%s/%s-" MACSTR, - dir, ap ? "AP" : "STA", MAC2STR(drv->own_addr)); - } else { - drv->own_socket_path = os_malloc(100); - if (drv->own_socket_path == NULL) - return -1; - os_snprintf(drv->own_socket_path, 100, - "/tmp/wpa_supplicant_test-%d-%d", - getpid(), counter++); - } - - drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0); - if (drv->test_socket < 0) { - perror("socket(PF_UNIX)"); - os_free(drv->own_socket_path); - drv->own_socket_path = NULL; - return -1; - } - - os_memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path)); - if (bind(drv->test_socket, (struct sockaddr *) &addr, - sizeof(addr)) < 0) { - perror("test-driver-attach: bind(PF_UNIX)"); - close(drv->test_socket); - unlink(drv->own_socket_path); - os_free(drv->own_socket_path); - drv->own_socket_path = NULL; - return -1; - } - - eloop_register_read_sock(drv->test_socket, - wpa_driver_test_receive_unix, drv, NULL); - - return 0; -#else /* DRIVER_TEST_UNIX */ - return -1; -#endif /* DRIVER_TEST_UNIX */ -} - - -static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv, - char *dst) -{ - char *pos; - - pos = os_strchr(dst, ':'); - if (pos == NULL) - return -1; - *pos++ = '\0'; - wpa_printf(MSG_DEBUG, "%s: addr=%s port=%s", __func__, dst, pos); - - drv->test_socket = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->test_socket < 0) { - perror("socket(PF_INET)"); - return -1; - } - - os_memset(&drv->hostapd_addr_udp, 0, sizeof(drv->hostapd_addr_udp)); - drv->hostapd_addr_udp.sin_family = AF_INET; -#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA) - { - int a[4]; - u8 *pos; - sscanf(dst, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]); - pos = (u8 *) &drv->hostapd_addr_udp.sin_addr; - *pos++ = a[0]; - *pos++ = a[1]; - *pos++ = a[2]; - *pos++ = a[3]; - } -#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */ - inet_aton(dst, &drv->hostapd_addr_udp.sin_addr); -#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */ - drv->hostapd_addr_udp.sin_port = htons(atoi(pos)); - - drv->hostapd_addr_udp_set = 1; - - eloop_register_read_sock(drv->test_socket, - wpa_driver_test_receive_unix, drv, NULL); - - return 0; -} - - -static int wpa_driver_test_set_param(void *priv, const char *param) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - const char *pos; - - wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param); - if (param == NULL) - return 0; - - wpa_driver_test_close_test_socket(drv); - -#ifdef DRIVER_TEST_UNIX - pos = os_strstr(param, "test_socket="); - if (pos) { - const char *pos2; - size_t len; - - pos += 12; - pos2 = os_strchr(pos, ' '); - if (pos2) - len = pos2 - pos; - else - len = os_strlen(pos); - if (len > sizeof(drv->hostapd_addr.sun_path)) - return -1; - os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr)); - drv->hostapd_addr.sun_family = AF_UNIX; - os_memcpy(drv->hostapd_addr.sun_path, pos, len); - drv->hostapd_addr_set = 1; - } -#endif /* DRIVER_TEST_UNIX */ - - pos = os_strstr(param, "test_dir="); - if (pos) { - char *end; - os_free(drv->test_dir); - drv->test_dir = os_strdup(pos + 9); - if (drv->test_dir == NULL) - return -1; - end = os_strchr(drv->test_dir, ' '); - if (end) - *end = '\0'; - if (wpa_driver_test_attach(drv, drv->test_dir, 0)) - return -1; - } else { - pos = os_strstr(param, "test_udp="); - if (pos) { - char *dst, *epos; - dst = os_strdup(pos + 9); - if (dst == NULL) - return -1; - epos = os_strchr(dst, ' '); - if (epos) - *epos = '\0'; - if (wpa_driver_test_attach_udp(drv, dst)) - return -1; - os_free(dst); - } else if (wpa_driver_test_attach(drv, NULL, 0)) - return -1; - } - - if (os_strstr(param, "use_associnfo=1")) { - wpa_printf(MSG_DEBUG, "test_driver: Use AssocInfo events"); - drv->use_associnfo = 1; - } - - return 0; -} - - -static const u8 * wpa_driver_test_get_mac_addr(void *priv) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s", __func__); - return drv->own_addr; -} - - -static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto, - const u8 *data, size_t data_len) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - char *msg; - size_t msg_len; - struct l2_ethhdr eth; - struct sockaddr *addr; - socklen_t alen; -#ifdef DRIVER_TEST_UNIX - struct sockaddr_un addr_un; -#endif /* DRIVER_TEST_UNIX */ - - wpa_hexdump(MSG_MSGDUMP, "test_send_eapol TX frame", data, data_len); - - os_memset(ð, 0, sizeof(eth)); - os_memcpy(eth.h_dest, dest, ETH_ALEN); - os_memcpy(eth.h_source, drv->own_addr, ETH_ALEN); - eth.h_proto = host_to_be16(proto); - - msg_len = 6 + sizeof(eth) + data_len; - msg = os_malloc(msg_len); - if (msg == NULL) - return -1; - os_memcpy(msg, "EAPOL ", 6); - os_memcpy(msg + 6, ð, sizeof(eth)); - os_memcpy(msg + 6 + sizeof(eth), data, data_len); - - if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 || - drv->test_dir == NULL) { - if (drv->hostapd_addr_udp_set) { - addr = (struct sockaddr *) &drv->hostapd_addr_udp; - alen = sizeof(drv->hostapd_addr_udp); - } else { -#ifdef DRIVER_TEST_UNIX - addr = (struct sockaddr *) &drv->hostapd_addr; - alen = sizeof(drv->hostapd_addr); -#else /* DRIVER_TEST_UNIX */ - os_free(msg); - return -1; -#endif /* DRIVER_TEST_UNIX */ - } - } else { -#ifdef DRIVER_TEST_UNIX - struct stat st; - os_memset(&addr_un, 0, sizeof(addr_un)); - addr_un.sun_family = AF_UNIX; - os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path), - "%s/STA-" MACSTR, drv->test_dir, MAC2STR(dest)); - if (stat(addr_un.sun_path, &st) < 0) { - os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path), - "%s/AP-" MACSTR, - drv->test_dir, MAC2STR(dest)); - } - addr = (struct sockaddr *) &addr_un; - alen = sizeof(addr_un); -#else /* DRIVER_TEST_UNIX */ - os_free(msg); - return -1; -#endif /* DRIVER_TEST_UNIX */ - } - - if (sendto(drv->test_socket, msg, msg_len, 0, addr, alen) < 0) { - perror("sendmsg(test_socket)"); - os_free(msg); - return -1; - } - - os_free(msg); - return 0; -} - - -static int wpa_driver_test_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 | - WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE | - WPA_DRIVER_CAPA_KEY_MGMT_FT | - WPA_DRIVER_CAPA_KEY_MGMT_FT_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_AP; - capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; - capa->flags |= WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE; - capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE; - capa->max_scan_ssids = 2; - capa->max_remain_on_chan = 60000; - - return 0; -} - - -static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr, - int protect_type, - int key_type) -{ - wpa_printf(MSG_DEBUG, "%s: protect_type=%d key_type=%d", - __func__, protect_type, key_type); - - if (addr) { - wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, - __func__, MAC2STR(addr)); - } - - return 0; -} - - -static void * wpa_driver_test_global_init(void) -{ - struct wpa_driver_test_global *global; - - global = os_zalloc(sizeof(*global)); - return global; -} - - -static void wpa_driver_test_global_deinit(void *priv) -{ - struct wpa_driver_test_global *global = priv; - os_free(global); -} - - -static struct wpa_interface_info * -wpa_driver_test_get_interfaces(void *global_priv) -{ - /* struct wpa_driver_test_global *global = priv; */ - struct wpa_interface_info *iface; - - iface = os_zalloc(sizeof(*iface)); - if (iface == NULL) - return iface; - iface->ifname = os_strdup("sta0"); - iface->desc = os_strdup("test interface 0"); - iface->drv_name = "test"; - iface->next = os_zalloc(sizeof(*iface)); - if (iface->next) { - iface->next->ifname = os_strdup("sta1"); - iface->next->desc = os_strdup("test interface 1"); - iface->next->drv_name = "test"; - } - - return iface; -} - - -static struct hostapd_hw_modes * -wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) -{ - struct hostapd_hw_modes *modes; - size_t i; - - *num_modes = 3; - *flags = 0; - modes = os_calloc(*num_modes, sizeof(struct hostapd_hw_modes)); - if (modes == NULL) - return NULL; - modes[0].mode = HOSTAPD_MODE_IEEE80211G; - modes[0].num_channels = 11; - modes[0].num_rates = 12; - modes[0].channels = os_calloc(11, sizeof(struct hostapd_channel_data)); - modes[0].rates = os_calloc(modes[0].num_rates, sizeof(int)); - if (modes[0].channels == NULL || modes[0].rates == NULL) - goto fail; - for (i = 0; i < 11; i++) { - modes[0].channels[i].chan = i + 1; - modes[0].channels[i].freq = 2412 + 5 * i; - modes[0].channels[i].flag = 0; - } - modes[0].rates[0] = 10; - modes[0].rates[1] = 20; - modes[0].rates[2] = 55; - modes[0].rates[3] = 110; - modes[0].rates[4] = 60; - modes[0].rates[5] = 90; - modes[0].rates[6] = 120; - modes[0].rates[7] = 180; - modes[0].rates[8] = 240; - modes[0].rates[9] = 360; - modes[0].rates[10] = 480; - modes[0].rates[11] = 540; - - modes[1].mode = HOSTAPD_MODE_IEEE80211B; - modes[1].num_channels = 11; - modes[1].num_rates = 4; - modes[1].channels = os_calloc(11, sizeof(struct hostapd_channel_data)); - modes[1].rates = os_calloc(modes[1].num_rates, sizeof(int)); - if (modes[1].channels == NULL || modes[1].rates == NULL) - goto fail; - for (i = 0; i < 11; i++) { - modes[1].channels[i].chan = i + 1; - modes[1].channels[i].freq = 2412 + 5 * i; - modes[1].channels[i].flag = 0; - } - modes[1].rates[0] = 10; - modes[1].rates[1] = 20; - modes[1].rates[2] = 55; - modes[1].rates[3] = 110; - - modes[2].mode = HOSTAPD_MODE_IEEE80211A; - modes[2].num_channels = 1; - modes[2].num_rates = 8; - modes[2].channels = os_calloc(1, sizeof(struct hostapd_channel_data)); - modes[2].rates = os_calloc(modes[2].num_rates, sizeof(int)); - if (modes[2].channels == NULL || modes[2].rates == NULL) - goto fail; - modes[2].channels[0].chan = 60; - modes[2].channels[0].freq = 5300; - modes[2].channels[0].flag = 0; - modes[2].rates[0] = 60; - modes[2].rates[1] = 90; - modes[2].rates[2] = 120; - modes[2].rates[3] = 180; - modes[2].rates[4] = 240; - modes[2].rates[5] = 360; - modes[2].rates[6] = 480; - modes[2].rates[7] = 540; - - return modes; - -fail: - if (modes) { - for (i = 0; i < *num_modes; i++) { - os_free(modes[i].channels); - os_free(modes[i].rates); - } - os_free(modes); - } - return NULL; -} - - -static int wpa_driver_test_set_freq(void *priv, - struct hostapd_freq_params *freq) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "test: set_freq %u MHz", freq->freq); - drv->current_freq = freq->freq; - return 0; -} - - -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, - int no_cck) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - int ret = -1; - u8 *buf; - struct ieee80211_hdr *hdr; - - wpa_printf(MSG_DEBUG, "test: Send Action frame"); - - if ((drv->remain_on_channel_freq && - freq != drv->remain_on_channel_freq) || - (drv->remain_on_channel_freq == 0 && - freq != (unsigned int) drv->current_freq)) { - wpa_printf(MSG_DEBUG, "test: Reject Action frame TX on " - "unexpected channel: freq=%u MHz (current_freq=%u " - "MHz, remain-on-channel freq=%u MHz)", - freq, drv->current_freq, - drv->remain_on_channel_freq); - return -1; - } - - buf = os_zalloc(24 + data_len); - if (buf == NULL) - return ret; - os_memcpy(buf + 24, data, data_len); - hdr = (struct ieee80211_hdr *) buf; - hdr->frame_control = - IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); - os_memcpy(hdr->addr1, dst, ETH_ALEN); - 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, 0); - os_free(buf); - return ret; -} - - -static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_driver_test_data *drv = eloop_ctx; - union wpa_event_data data; - - wpa_printf(MSG_DEBUG, "test: Remain-on-channel timeout"); - - os_memset(&data, 0, sizeof(data)); - data.remain_on_channel.freq = drv->remain_on_channel_freq; - data.remain_on_channel.duration = drv->remain_on_channel_duration; - - drv->remain_on_channel_freq = 0; - - wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data); -} - - -static int wpa_driver_test_remain_on_channel(void *priv, unsigned int freq, - unsigned int duration) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - union wpa_event_data data; - - wpa_printf(MSG_DEBUG, "%s(freq=%u, duration=%u)", - __func__, freq, duration); - if (drv->remain_on_channel_freq && - drv->remain_on_channel_freq != freq) { - wpa_printf(MSG_DEBUG, "test: Refuse concurrent " - "remain_on_channel request"); - return -1; - } - - drv->remain_on_channel_freq = freq; - drv->remain_on_channel_duration = duration; - eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL); - eloop_register_timeout(duration / 1000, (duration % 1000) * 1000, - test_remain_on_channel_timeout, drv, NULL); - - os_memset(&data, 0, sizeof(data)); - data.remain_on_channel.freq = freq; - data.remain_on_channel.duration = duration; - wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data); - - return 0; -} - - -static int wpa_driver_test_cancel_remain_on_channel(void *priv) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s", __func__); - if (!drv->remain_on_channel_freq) - return -1; - drv->remain_on_channel_freq = 0; - eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL); - return 0; -} - - -static int wpa_driver_test_probe_req_report(void *priv, int report) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s(report=%d)", __func__, report); - drv->probe_req_report = report; - return 0; -} - - -const struct wpa_driver_ops wpa_driver_test_ops = { - "test", - "wpa_supplicant test driver", - .hapd_init = test_driver_init, - .hapd_deinit = wpa_driver_test_deinit, - .hapd_send_eapol = test_driver_send_eapol, - .send_mlme = wpa_driver_test_send_mlme, - .set_generic_elem = test_driver_set_generic_elem, - .sta_deauth = test_driver_sta_deauth, - .sta_disassoc = test_driver_sta_disassoc, - .get_hw_feature_data = wpa_driver_test_get_hw_feature_data, - .if_add = test_driver_if_add, - .if_remove = test_driver_if_remove, - .hapd_set_ssid = test_driver_set_ssid, - .set_privacy = test_driver_set_privacy, - .set_sta_vlan = test_driver_set_sta_vlan, - .sta_add = test_driver_sta_add, - .send_ether = test_driver_send_ether, - .set_ap_wps_ie = test_driver_set_ap_wps_ie, - .get_bssid = wpa_driver_test_get_bssid, - .get_ssid = wpa_driver_test_get_ssid, - .set_key = wpa_driver_test_set_key, - .deinit = wpa_driver_test_deinit, - .set_param = wpa_driver_test_set_param, - .deauthenticate = wpa_driver_test_deauthenticate, - .associate = wpa_driver_test_associate, - .get_capa = wpa_driver_test_get_capa, - .get_mac_addr = wpa_driver_test_get_mac_addr, - .send_eapol = wpa_driver_test_send_eapol, - .mlme_setprotection = wpa_driver_test_mlme_setprotection, - .get_scan_results2 = wpa_driver_test_get_scan_results2, - .global_init = wpa_driver_test_global_init, - .global_deinit = wpa_driver_test_global_deinit, - .init2 = wpa_driver_test_init2, - .get_interfaces = wpa_driver_test_get_interfaces, - .scan2 = wpa_driver_test_scan, - .set_freq = wpa_driver_test_set_freq, - .send_action = wpa_driver_test_send_action, - .remain_on_channel = wpa_driver_test_remain_on_channel, - .cancel_remain_on_channel = wpa_driver_test_cancel_remain_on_channel, - .probe_req_report = wpa_driver_test_probe_req_report, -}; diff --git a/contrib/hostapd/src/drivers/driver_wext.c b/contrib/hostapd/src/drivers/driver_wext.c deleted file mode 100644 index e5734bddc3..0000000000 --- a/contrib/hostapd/src/drivers/driver_wext.c +++ /dev/null @@ -1,2338 +0,0 @@ -/* - * Driver interaction with generic Linux Wireless Extensions - * Copyright (c) 2003-2010, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file implements a driver interface for the Linux Wireless Extensions. - * When used with WE-18 or newer, this interface can be used as-is with number - * of drivers. In addition to this, some of the common functions in this file - * can be used by other driver interface implementations that use generic WE - * ioctls, but require private ioctls for some of the functionality. - */ - -#include "includes.h" -#include -#include -#include -#include -#include - -#include "linux_wext.h" -#include "common.h" -#include "eloop.h" -#include "common/ieee802_11_defs.h" -#include "common/wpa_common.h" -#include "priv_netlink.h" -#include "netlink.h" -#include "linux_ioctl.h" -#include "rfkill.h" -#include "driver.h" -#include "driver_wext.h" - -static int wpa_driver_wext_flush_pmkid(void *priv); -static int wpa_driver_wext_get_range(void *priv); -static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv); -static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv); -static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg); - - -int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv, - int idx, u32 value) -{ - struct iwreq iwr; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.param.flags = idx & IW_AUTH_INDEX; - iwr.u.param.value = value; - - if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) { - if (errno != EOPNOTSUPP) { - wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d " - "value 0x%x) failed: %s)", - idx, value, strerror(errno)); - } - ret = errno == EOPNOTSUPP ? -2 : -1; - } - - return ret; -} - - -/** - * wpa_driver_wext_get_bssid - Get BSSID, SIOCGIWAP - * @priv: Pointer to private wext data from wpa_driver_wext_init() - * @bssid: Buffer for BSSID - * Returns: 0 on success, -1 on failure - */ -int wpa_driver_wext_get_bssid(void *priv, u8 *bssid) -{ - struct wpa_driver_wext_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - 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; -} - - -/** - * wpa_driver_wext_set_bssid - Set BSSID, SIOCSIWAP - * @priv: Pointer to private wext data from wpa_driver_wext_init() - * @bssid: BSSID - * Returns: 0 on success, -1 on failure - */ -int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid) -{ - struct wpa_driver_wext_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.ap_addr.sa_family = ARPHRD_ETHER; - if (bssid) - os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN); - else - os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN); - - if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) { - perror("ioctl[SIOCSIWAP]"); - ret = -1; - } - - return ret; -} - - -/** - * wpa_driver_wext_get_ssid - Get SSID, SIOCGIWESSID - * @priv: Pointer to private wext data from wpa_driver_wext_init() - * @ssid: Buffer for the SSID; must be at least 32 bytes long - * Returns: SSID length on success, -1 on failure - */ -int wpa_driver_wext_get_ssid(void *priv, u8 *ssid) -{ - struct wpa_driver_wext_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.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 > 32) - ret = 32; - /* Some drivers include nul termination in the SSID, so let's - * remove it here before further processing. WE-21 changes this - * to explicitly require the length _not_ to include nul - * termination. */ - if (ret > 0 && ssid[ret - 1] == '\0' && - drv->we_version_compiled < 21) - ret--; - } - - return ret; -} - - -/** - * wpa_driver_wext_set_ssid - Set SSID, SIOCSIWESSID - * @priv: Pointer to private wext data from wpa_driver_wext_init() - * @ssid: SSID - * @ssid_len: Length of SSID (0..32) - * Returns: 0 on success, -1 on failure - */ -int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len) -{ - struct wpa_driver_wext_data *drv = priv; - struct iwreq iwr; - int ret = 0; - char buf[33]; - - if (ssid_len > 32) - return -1; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - /* flags: 1 = ESSID is active, 0 = not (promiscuous) */ - iwr.u.essid.flags = (ssid_len != 0); - os_memset(buf, 0, sizeof(buf)); - os_memcpy(buf, ssid, ssid_len); - iwr.u.essid.pointer = (caddr_t) buf; - if (drv->we_version_compiled < 21) { - /* For historic reasons, set SSID length to include one extra - * character, C string nul termination, even though SSID is - * really an octet string that should not be presented as a C - * string. Some Linux drivers decrement the length by one and - * can thus end up missing the last octet of the SSID if the - * length is not incremented here. WE-21 changes this to - * explicitly require the length _not_ to include nul - * termination. */ - if (ssid_len) - ssid_len++; - } - iwr.u.essid.length = ssid_len; - - if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { - perror("ioctl[SIOCSIWESSID]"); - ret = -1; - } - - return ret; -} - - -/** - * wpa_driver_wext_set_freq - Set frequency/channel, SIOCSIWFREQ - * @priv: Pointer to private wext data from wpa_driver_wext_init() - * @freq: Frequency in MHz - * Returns: 0 on success, -1 on failure - */ -int wpa_driver_wext_set_freq(void *priv, int freq) -{ - struct wpa_driver_wext_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.freq.m = freq * 100000; - iwr.u.freq.e = 1; - - if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { - perror("ioctl[SIOCSIWFREQ]"); - ret = -1; - } - - return ret; -} - - -static void -wpa_driver_wext_event_wireless_custom(void *ctx, char *custom) -{ - union wpa_event_data data; - - wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'", - custom); - - os_memset(&data, 0, sizeof(data)); - /* Host AP driver */ - if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { - 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) { - char *spos; - int bytes; - u8 *req_ies = NULL, *resp_ies = NULL; - - spos = custom + 17; - - bytes = strspn(spos, "0123456789abcdefABCDEF"); - if (!bytes || (bytes & 1)) - return; - bytes /= 2; - - req_ies = os_malloc(bytes); - if (req_ies == NULL || - hexstr2bin(spos, req_ies, bytes) < 0) - goto done; - data.assoc_info.req_ies = req_ies; - data.assoc_info.req_ies_len = bytes; - - spos += bytes * 2; - - data.assoc_info.resp_ies = NULL; - data.assoc_info.resp_ies_len = 0; - - if (os_strncmp(spos, " RespIEs=", 9) == 0) { - spos += 9; - - bytes = strspn(spos, "0123456789abcdefABCDEF"); - if (!bytes || (bytes & 1)) - goto done; - bytes /= 2; - - resp_ies = os_malloc(bytes); - if (resp_ies == NULL || - hexstr2bin(spos, resp_ies, bytes) < 0) - goto done; - data.assoc_info.resp_ies = resp_ies; - data.assoc_info.resp_ies_len = bytes; - } - - wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); - - done: - os_free(resp_ies); - os_free(req_ies); -#ifdef CONFIG_PEERKEY - } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) { - if (hwaddr_aton(custom + 17, data.stkstart.peer)) { - wpa_printf(MSG_DEBUG, "WEXT: unrecognized " - "STKSTART.request '%s'", custom + 17); - return; - } - wpa_supplicant_event(ctx, EVENT_STKSTART, &data); -#endif /* CONFIG_PEERKEY */ - } -} - - -static int wpa_driver_wext_event_wireless_michaelmicfailure( - void *ctx, const char *ev, size_t len) -{ - const struct iw_michaelmicfailure *mic; - union wpa_event_data data; - - if (len < sizeof(*mic)) - return -1; - - mic = (const struct iw_michaelmicfailure *) ev; - - wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: " - "flags=0x%x src_addr=" MACSTR, mic->flags, - MAC2STR(mic->src_addr.sa_data)); - - os_memset(&data, 0, sizeof(data)); - data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP); - wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); - - return 0; -} - - -static int wpa_driver_wext_event_wireless_pmkidcand( - struct wpa_driver_wext_data *drv, const char *ev, size_t len) -{ - const struct iw_pmkid_cand *cand; - union wpa_event_data data; - const u8 *addr; - - if (len < sizeof(*cand)) - return -1; - - cand = (const struct iw_pmkid_cand *) ev; - addr = (const u8 *) cand->bssid.sa_data; - - wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: " - "flags=0x%x index=%d bssid=" MACSTR, cand->flags, - cand->index, MAC2STR(addr)); - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN); - data.pmkid_candidate.index = cand->index; - data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH; - wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); - - return 0; -} - - -static int wpa_driver_wext_event_wireless_assocreqie( - struct wpa_driver_wext_data *drv, const char *ev, int len) -{ - if (len < 0) - return -1; - - wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev, - len); - os_free(drv->assoc_req_ies); - drv->assoc_req_ies = os_malloc(len); - if (drv->assoc_req_ies == NULL) { - drv->assoc_req_ies_len = 0; - return -1; - } - os_memcpy(drv->assoc_req_ies, ev, len); - drv->assoc_req_ies_len = len; - - return 0; -} - - -static int wpa_driver_wext_event_wireless_assocrespie( - struct wpa_driver_wext_data *drv, const char *ev, int len) -{ - if (len < 0) - return -1; - - wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev, - len); - os_free(drv->assoc_resp_ies); - drv->assoc_resp_ies = os_malloc(len); - if (drv->assoc_resp_ies == NULL) { - drv->assoc_resp_ies_len = 0; - return -1; - } - os_memcpy(drv->assoc_resp_ies, ev, len); - drv->assoc_resp_ies_len = len; - - return 0; -} - - -static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv) -{ - union wpa_event_data data; - - if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL) - return; - - os_memset(&data, 0, sizeof(data)); - if (drv->assoc_req_ies) { - data.assoc_info.req_ies = drv->assoc_req_ies; - data.assoc_info.req_ies_len = drv->assoc_req_ies_len; - } - if (drv->assoc_resp_ies) { - data.assoc_info.resp_ies = drv->assoc_resp_ies; - data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len; - } - - wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data); - - os_free(drv->assoc_req_ies); - drv->assoc_req_ies = NULL; - os_free(drv->assoc_resp_ies); - drv->assoc_resp_ies = NULL; -} - - -static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, - char *data, int len) -{ - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end, *custom, *buf; - - 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 == IWEVMICHAELMICFAILURE || - iwe->cmd == IWEVCUSTOM || - iwe->cmd == IWEVASSOCREQIE || - iwe->cmd == IWEVASSOCRESPIE || - iwe->cmd == IWEVPMKIDCAND)) { - /* 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 SIOCGIWAP: - wpa_printf(MSG_DEBUG, "Wireless event: new AP: " - MACSTR, - MAC2STR((u8 *) iwe->u.ap_addr.sa_data)); - if (is_zero_ether_addr( - (const u8 *) iwe->u.ap_addr.sa_data) || - os_memcmp(iwe->u.ap_addr.sa_data, - "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == - 0) { - os_free(drv->assoc_req_ies); - drv->assoc_req_ies = NULL; - os_free(drv->assoc_resp_ies); - drv->assoc_resp_ies = NULL; - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, - NULL); - - } else { - wpa_driver_wext_event_assoc_ies(drv); - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, - NULL); - } - break; - case IWEVMICHAELMICFAILURE: - if (custom + iwe->u.data.length > end) { - wpa_printf(MSG_DEBUG, "WEXT: Invalid " - "IWEVMICHAELMICFAILURE length"); - return; - } - wpa_driver_wext_event_wireless_michaelmicfailure( - drv->ctx, custom, iwe->u.data.length); - break; - case IWEVCUSTOM: - if (custom + iwe->u.data.length > end) { - wpa_printf(MSG_DEBUG, "WEXT: Invalid " - "IWEVCUSTOM length"); - return; - } - buf = dup_binstr(custom, iwe->u.data.length); - if (buf == NULL) - return; - wpa_driver_wext_event_wireless_custom(drv->ctx, buf); - os_free(buf); - break; - case SIOCGIWSCAN: - drv->scan_complete_events = 1; - eloop_cancel_timeout(wpa_driver_wext_scan_timeout, - drv, drv->ctx); - wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, - NULL); - break; - case IWEVASSOCREQIE: - if (custom + iwe->u.data.length > end) { - wpa_printf(MSG_DEBUG, "WEXT: Invalid " - "IWEVASSOCREQIE length"); - return; - } - wpa_driver_wext_event_wireless_assocreqie( - drv, custom, iwe->u.data.length); - break; - case IWEVASSOCRESPIE: - if (custom + iwe->u.data.length > end) { - wpa_printf(MSG_DEBUG, "WEXT: Invalid " - "IWEVASSOCRESPIE length"); - return; - } - wpa_driver_wext_event_wireless_assocrespie( - drv, custom, iwe->u.data.length); - break; - case IWEVPMKIDCAND: - if (custom + iwe->u.data.length > end) { - wpa_printf(MSG_DEBUG, "WEXT: Invalid " - "IWEVPMKIDCAND length"); - return; - } - wpa_driver_wext_event_wireless_pmkidcand( - drv, custom, iwe->u.data.length); - break; - } - - pos += iwe->len; - } -} - - -static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv, - char *buf, size_t len, int del) -{ - union wpa_event_data event; - - os_memset(&event, 0, sizeof(event)); - if (len > sizeof(event.interface_status.ifname)) - len = sizeof(event.interface_status.ifname) - 1; - os_memcpy(event.interface_status.ifname, buf, len); - event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED : - EVENT_INTERFACE_ADDED; - - wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s", - del ? "DEL" : "NEW", - event.interface_status.ifname, - del ? "removed" : "added"); - - if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) { - if (del) { - if (drv->if_removed) { - wpa_printf(MSG_DEBUG, "WEXT: if_removed " - "already set - ignore event"); - return; - } - drv->if_removed = 1; - } else { - if (if_nametoindex(drv->ifname) == 0) { - wpa_printf(MSG_DEBUG, "WEXT: Interface %s " - "does not exist - ignore " - "RTM_NEWLINK", - drv->ifname); - return; - } - if (!drv->if_removed) { - wpa_printf(MSG_DEBUG, "WEXT: if_removed " - "already cleared - ignore event"); - return; - } - drv->if_removed = 0; - } - } - - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); -} - - -static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv, - u8 *buf, size_t len) -{ - int attrlen, rta_len; - struct rtattr *attr; - - attrlen = len; - attr = (struct rtattr *) buf; - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_IFNAME) { - if (os_strcmp(((char *) attr) + rta_len, drv->ifname) - == 0) - return 1; - else - break; - } - attr = RTA_NEXT(attr, attrlen); - } - - return 0; -} - - -static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv, - int ifindex, u8 *buf, size_t len) -{ - if (drv->ifindex == ifindex || drv->ifindex2 == ifindex) - return 1; - - if (drv->if_removed && wpa_driver_wext_own_ifname(drv, buf, len)) { - drv->ifindex = if_nametoindex(drv->ifname); - wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed " - "interface"); - wpa_driver_wext_finish_drv_init(drv); - return 1; - } - - return 0; -} - - -static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, - u8 *buf, size_t len) -{ - struct wpa_driver_wext_data *drv = ctx; - int attrlen, rta_len; - struct rtattr *attr; - char namebuf[IFNAMSIZ]; - - if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) { - wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d", - ifi->ifi_index); - return; - } - - wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x " - "(%s%s%s%s)", - drv->operstate, ifi->ifi_flags, - (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", - (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", - (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", - (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); - - if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { - wpa_printf(MSG_DEBUG, "WEXT: Interface down"); - drv->if_disabled = 1; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); - } - - if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) { - if (if_indextoname(ifi->ifi_index, namebuf) && - linux_iface_up(drv->ioctl_sock, drv->ifname) == 0) { - wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up " - "event since interface %s is down", - namebuf); - } else if (if_nametoindex(drv->ifname) == 0) { - wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up " - "event since interface %s does not exist", - drv->ifname); - } else if (drv->if_removed) { - wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up " - "event since interface %s is marked " - "removed", drv->ifname); - } else { - wpa_printf(MSG_DEBUG, "WEXT: Interface up"); - drv->if_disabled = 0; - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, - NULL); - } - } - - /* - * Some drivers send the association event before the operup event--in - * this case, lifting operstate in wpa_driver_wext_set_operstate() - * fails. This will hit us when wpa_supplicant does not need to do - * IEEE 802.1X authentication - */ - 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, - -1, IF_OPER_UP); - - attrlen = len; - attr = (struct rtattr *) buf; - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_WIRELESS) { - wpa_driver_wext_event_wireless( - drv, ((char *) attr) + rta_len, - attr->rta_len - rta_len); - } else if (attr->rta_type == IFLA_IFNAME) { - wpa_driver_wext_event_link(drv, - ((char *) attr) + rta_len, - attr->rta_len - rta_len, 0); - } - attr = RTA_NEXT(attr, attrlen); - } -} - - -static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi, - u8 *buf, size_t len) -{ - struct wpa_driver_wext_data *drv = ctx; - int attrlen, rta_len; - struct rtattr *attr; - - attrlen = len; - attr = (struct rtattr *) buf; - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_IFNAME) { - wpa_driver_wext_event_link(drv, - ((char *) attr) + rta_len, - attr->rta_len - rta_len, 1); - } - attr = RTA_NEXT(attr, attrlen); - } -} - - -static void wpa_driver_wext_rfkill_blocked(void *ctx) -{ - wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked"); - /* - * This may be for any interface; use ifdown event to disable - * interface. - */ -} - - -static void wpa_driver_wext_rfkill_unblocked(void *ctx) -{ - struct wpa_driver_wext_data *drv = ctx; - wpa_printf(MSG_DEBUG, "WEXT: RFKILL unblocked"); - if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) { - wpa_printf(MSG_DEBUG, "WEXT: Could not set interface UP " - "after rfkill unblock"); - return; - } - /* rtnetlink ifup handler will report interface as enabled */ -} - - -static void wext_get_phy_name(struct wpa_driver_wext_data *drv) -{ - /* Find phy (radio) to which this interface belongs */ - char buf[90], *pos; - int f, rv; - - drv->phyname[0] = '\0'; - snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name", - drv->ifname); - f = open(buf, O_RDONLY); - if (f < 0) { - wpa_printf(MSG_DEBUG, "Could not open file %s: %s", - buf, strerror(errno)); - return; - } - - rv = read(f, drv->phyname, sizeof(drv->phyname) - 1); - close(f); - if (rv < 0) { - wpa_printf(MSG_DEBUG, "Could not read file %s: %s", - buf, strerror(errno)); - return; - } - - drv->phyname[rv] = '\0'; - pos = os_strchr(drv->phyname, '\n'); - if (pos) - *pos = '\0'; - wpa_printf(MSG_DEBUG, "wext: interface %s phy: %s", - drv->ifname, drv->phyname); -} - - -/** - * wpa_driver_wext_init - Initialize WE driver interface - * @ctx: context to be used when calling wpa_supplicant functions, - * e.g., wpa_supplicant_event() - * @ifname: interface name, e.g., wlan0 - * Returns: Pointer to private data, %NULL on failure - */ -void * wpa_driver_wext_init(void *ctx, const char *ifname) -{ - struct wpa_driver_wext_data *drv; - struct netlink_config *cfg; - struct rfkill_config *rcfg; - char path[128]; - struct stat buf; - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - drv->ctx = ctx; - os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); - - os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname); - if (stat(path, &buf) == 0) { - wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected"); - drv->cfg80211 = 1; - wext_get_phy_name(drv); - } - - drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->ioctl_sock < 0) { - perror("socket(PF_INET,SOCK_DGRAM)"); - goto err1; - } - - cfg = os_zalloc(sizeof(*cfg)); - if (cfg == NULL) - goto err1; - cfg->ctx = drv; - cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink; - cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink; - drv->netlink = netlink_init(cfg); - if (drv->netlink == NULL) { - os_free(cfg); - goto err2; - } - - rcfg = os_zalloc(sizeof(*rcfg)); - if (rcfg == NULL) - goto err3; - rcfg->ctx = drv; - os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname)); - rcfg->blocked_cb = wpa_driver_wext_rfkill_blocked; - rcfg->unblocked_cb = wpa_driver_wext_rfkill_unblocked; - drv->rfkill = rfkill_init(rcfg); - if (drv->rfkill == NULL) { - wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available"); - os_free(rcfg); - } - - drv->mlme_sock = -1; - - if (wpa_driver_wext_finish_drv_init(drv) < 0) - goto err3; - - wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1); - - return drv; - -err3: - rfkill_deinit(drv->rfkill); - netlink_deinit(drv->netlink); -err2: - close(drv->ioctl_sock); -err1: - os_free(drv); - return NULL; -} - - -static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx) -{ - wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); -} - - -static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) -{ - int send_rfkill_event = 0; - - if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) { - if (rfkill_is_blocked(drv->rfkill)) { - wpa_printf(MSG_DEBUG, "WEXT: Could not yet enable " - "interface '%s' due to rfkill", - drv->ifname); - drv->if_disabled = 1; - send_rfkill_event = 1; - } else { - wpa_printf(MSG_ERROR, "WEXT: Could not set " - "interface '%s' UP", drv->ifname); - return -1; - } - } - - /* - * Make sure that the driver does not have any obsolete PMKID entries. - */ - wpa_driver_wext_flush_pmkid(drv); - - if (wpa_driver_wext_set_mode(drv, 0) < 0) { - wpa_printf(MSG_DEBUG, "Could not configure driver to use " - "managed mode"); - /* Try to use it anyway */ - } - - wpa_driver_wext_get_range(drv); - - /* - * Unlock the driver's BSSID and force to a random SSID to clear any - * previous association the driver might have when the supplicant - * starts up. - */ - wpa_driver_wext_disconnect(drv); - - drv->ifindex = if_nametoindex(drv->ifname); - - if (os_strncmp(drv->ifname, "wlan", 4) == 0) { - /* - * Host AP driver may use both wlan# and wifi# interface in - * wireless events. Since some of the versions included WE-18 - * support, let's add the alternative ifindex also from - * driver_wext.c for the time being. This may be removed at - * some point once it is believed that old versions of the - * driver are not in use anymore. - */ - char ifname2[IFNAMSIZ + 1]; - os_strlcpy(ifname2, drv->ifname, sizeof(ifname2)); - os_memcpy(ifname2, "wifi", 4); - wpa_driver_wext_alternative_ifindex(drv, ifname2); - } - - netlink_send_oper_ifla(drv->netlink, drv->ifindex, - 1, IF_OPER_DORMANT); - - if (send_rfkill_event) { - eloop_register_timeout(0, 0, wpa_driver_wext_send_rfkill, - drv, drv->ctx); - } - - return 0; -} - - -/** - * wpa_driver_wext_deinit - Deinitialize WE driver interface - * @priv: Pointer to private wext data from wpa_driver_wext_init() - * - * Shut down driver interface and processing of driver events. Free - * private data buffer if one was allocated in wpa_driver_wext_init(). - */ -void wpa_driver_wext_deinit(void *priv) -{ - struct wpa_driver_wext_data *drv = priv; - - wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0); - - eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); - - /* - * Clear possibly configured driver parameters in order to make it - * easier to use the driver after wpa_supplicant has been terminated. - */ - wpa_driver_wext_disconnect(drv); - - netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); - netlink_deinit(drv->netlink); - rfkill_deinit(drv->rfkill); - - if (drv->mlme_sock >= 0) - eloop_unregister_read_sock(drv->mlme_sock); - - (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); - - close(drv->ioctl_sock); - if (drv->mlme_sock >= 0) - close(drv->mlme_sock); - os_free(drv->assoc_req_ies); - os_free(drv->assoc_resp_ies); - os_free(drv); -} - - -/** - * wpa_driver_wext_scan_timeout - Scan timeout to report scan completion - * @eloop_ctx: Unused - * @timeout_ctx: ctx argument given to wpa_driver_wext_init() - * - * This function can be used as registered timeout when starting a scan to - * generate a scan completed event if the driver does not report this. - */ -void wpa_driver_wext_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); -} - - -/** - * wpa_driver_wext_scan - Request the driver to initiate scan - * @priv: Pointer to private wext data from wpa_driver_wext_init() - * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.) - * Returns: 0 on success, -1 on failure - */ -int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params) -{ - struct wpa_driver_wext_data *drv = priv; - struct iwreq iwr; - int ret = 0, timeout; - struct iw_scan_req req; - const u8 *ssid = params->ssids[0].ssid; - size_t ssid_len = params->ssids[0].ssid_len; - - if (ssid_len > IW_ESSID_MAX_SIZE) { - wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)", - __FUNCTION__, (unsigned long) ssid_len); - return -1; - } - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - - if (ssid && ssid_len) { - os_memset(&req, 0, sizeof(req)); - req.essid_len = ssid_len; - req.bssid.sa_family = ARPHRD_ETHER; - os_memset(req.bssid.sa_data, 0xff, ETH_ALEN); - os_memcpy(req.essid, ssid, ssid_len); - iwr.u.data.pointer = (caddr_t) &req; - iwr.u.data.length = sizeof(req); - iwr.u.data.flags = IW_SCAN_THIS_ESSID; - } - - 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. */ - timeout = 10; - if (drv->scan_complete_events) { - /* - * The driver seems to deliver SIOCGIWSCAN events to notify - * when scan is complete, so use longer timeout to avoid race - * conditions with scanning and following association request. - */ - timeout = 30; - } - wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " - "seconds", ret, timeout); - eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); - eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv, - drv->ctx); - - return ret; -} - - -static u8 * wpa_driver_wext_giwscan(struct wpa_driver_wext_data *drv, - size_t *len) -{ - struct iwreq iwr; - u8 *res_buf; - size_t res_buf_len; - - res_buf_len = IW_SCAN_MAX_DATA; - for (;;) { - res_buf = os_malloc(res_buf_len); - if (res_buf == NULL) - return NULL; - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = res_buf; - iwr.u.data.length = res_buf_len; - - if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0) - break; - - if (errno == E2BIG && res_buf_len < 65535) { - os_free(res_buf); - res_buf = NULL; - res_buf_len *= 2; - if (res_buf_len > 65535) - res_buf_len = 65535; /* 16-bit length field */ - wpa_printf(MSG_DEBUG, "Scan results did not fit - " - "trying larger buffer (%lu bytes)", - (unsigned long) res_buf_len); - } else { - perror("ioctl[SIOCGIWSCAN]"); - os_free(res_buf); - return NULL; - } - } - - if (iwr.u.data.length > res_buf_len) { - os_free(res_buf); - return NULL; - } - *len = iwr.u.data.length; - - return res_buf; -} - - -/* - * Data structure for collecting WEXT scan results. This is needed to allow - * the various methods of reporting IEs to be combined into a single IE buffer. - */ -struct wext_scan_data { - struct wpa_scan_res res; - u8 *ie; - size_t ie_len; - u8 ssid[32]; - size_t ssid_len; - int maxrate; -}; - - -static void wext_get_scan_mode(struct iw_event *iwe, - struct wext_scan_data *res) -{ - if (iwe->u.mode == IW_MODE_ADHOC) - res->res.caps |= IEEE80211_CAP_IBSS; - else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA) - res->res.caps |= IEEE80211_CAP_ESS; -} - - -static void wext_get_scan_ssid(struct iw_event *iwe, - struct wext_scan_data *res, char *custom, - char *end) -{ - int ssid_len = iwe->u.essid.length; - if (custom + ssid_len > end) - return; - if (iwe->u.essid.flags && - ssid_len > 0 && - ssid_len <= IW_ESSID_MAX_SIZE) { - os_memcpy(res->ssid, custom, ssid_len); - res->ssid_len = ssid_len; - } -} - - -static void wext_get_scan_freq(struct iw_event *iwe, - struct wext_scan_data *res) -{ - int divi = 1000000, i; - - if (iwe->u.freq.e == 0) { - /* - * Some drivers do not report frequency, but a channel. - * Try to map this to frequency by assuming they are using - * IEEE 802.11b/g. But don't overwrite a previously parsed - * frequency if the driver sends both frequency and channel, - * since the driver may be sending an A-band channel that we - * don't handle here. - */ - - if (res->res.freq) - return; - - if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) { - res->res.freq = 2407 + 5 * iwe->u.freq.m; - return; - } else if (iwe->u.freq.m == 14) { - res->res.freq = 2484; - return; - } - } - - if (iwe->u.freq.e > 6) { - wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID=" - MACSTR " m=%d e=%d)", - MAC2STR(res->res.bssid), iwe->u.freq.m, - iwe->u.freq.e); - return; - } - - for (i = 0; i < iwe->u.freq.e; i++) - divi /= 10; - res->res.freq = iwe->u.freq.m / divi; -} - - -static void wext_get_scan_qual(struct wpa_driver_wext_data *drv, - struct iw_event *iwe, - struct wext_scan_data *res) -{ - res->res.qual = iwe->u.qual.qual; - res->res.noise = iwe->u.qual.noise; - res->res.level = iwe->u.qual.level; - if (iwe->u.qual.updated & IW_QUAL_QUAL_INVALID) - res->res.flags |= WPA_SCAN_QUAL_INVALID; - if (iwe->u.qual.updated & IW_QUAL_LEVEL_INVALID) - res->res.flags |= WPA_SCAN_LEVEL_INVALID; - if (iwe->u.qual.updated & IW_QUAL_NOISE_INVALID) - res->res.flags |= WPA_SCAN_NOISE_INVALID; - if (iwe->u.qual.updated & IW_QUAL_DBM) - res->res.flags |= WPA_SCAN_LEVEL_DBM; - if ((iwe->u.qual.updated & IW_QUAL_DBM) || - ((iwe->u.qual.level != 0) && - (iwe->u.qual.level > drv->max_level))) { - if (iwe->u.qual.level >= 64) - res->res.level -= 0x100; - if (iwe->u.qual.noise >= 64) - res->res.noise -= 0x100; - } -} - - -static void wext_get_scan_encode(struct iw_event *iwe, - struct wext_scan_data *res) -{ - if (!(iwe->u.data.flags & IW_ENCODE_DISABLED)) - res->res.caps |= IEEE80211_CAP_PRIVACY; -} - - -static void wext_get_scan_rate(struct iw_event *iwe, - struct wext_scan_data *res, char *pos, - char *end) -{ - int maxrate; - char *custom = pos + IW_EV_LCP_LEN; - struct iw_param p; - size_t clen; - - clen = iwe->len; - if (custom + clen > end) - return; - maxrate = 0; - while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) { - /* Note: may be misaligned, make a local, aligned copy */ - os_memcpy(&p, custom, sizeof(struct iw_param)); - if (p.value > maxrate) - maxrate = p.value; - clen -= sizeof(struct iw_param); - custom += sizeof(struct iw_param); - } - - /* Convert the maxrate from WE-style (b/s units) to - * 802.11 rates (500000 b/s units). - */ - res->maxrate = maxrate / 500000; -} - - -static void wext_get_scan_iwevgenie(struct iw_event *iwe, - struct wext_scan_data *res, char *custom, - char *end) -{ - char *genie, *gpos, *gend; - u8 *tmp; - - if (iwe->u.data.length == 0) - return; - - gpos = genie = custom; - gend = genie + iwe->u.data.length; - if (gend > end) { - wpa_printf(MSG_INFO, "IWEVGENIE overflow"); - return; - } - - tmp = os_realloc(res->ie, res->ie_len + gend - gpos); - if (tmp == NULL) - return; - os_memcpy(tmp + res->ie_len, gpos, gend - gpos); - res->ie = tmp; - res->ie_len += gend - gpos; -} - - -static void wext_get_scan_custom(struct iw_event *iwe, - struct wext_scan_data *res, char *custom, - char *end) -{ - size_t clen; - u8 *tmp; - - clen = iwe->u.data.length; - if (custom + clen > end) - return; - - if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) { - char *spos; - int bytes; - spos = custom + 7; - bytes = custom + clen - spos; - if (bytes & 1 || bytes == 0) - return; - bytes /= 2; - tmp = os_realloc(res->ie, res->ie_len + bytes); - if (tmp == NULL) - return; - res->ie = tmp; - if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0) - return; - res->ie_len += bytes; - } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) { - char *spos; - int bytes; - spos = custom + 7; - bytes = custom + clen - spos; - if (bytes & 1 || bytes == 0) - return; - bytes /= 2; - tmp = os_realloc(res->ie, res->ie_len + bytes); - if (tmp == NULL) - return; - res->ie = tmp; - if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0) - return; - res->ie_len += bytes; - } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) { - char *spos; - int bytes; - u8 bin[8]; - spos = custom + 4; - bytes = custom + clen - spos; - if (bytes != 16) { - wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes); - return; - } - bytes /= 2; - if (hexstr2bin(spos, bin, bytes) < 0) { - wpa_printf(MSG_DEBUG, "WEXT: Invalid TSF value"); - return; - } - res->res.tsf += WPA_GET_BE64(bin); - } -} - - -static int wext_19_iw_point(struct wpa_driver_wext_data *drv, u16 cmd) -{ - return drv->we_version_compiled > 18 && - (cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE || - cmd == IWEVGENIE || cmd == IWEVCUSTOM); -} - - -static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res, - struct wext_scan_data *data) -{ - struct wpa_scan_res **tmp; - struct wpa_scan_res *r; - size_t extra_len; - u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL; - - /* Figure out whether we need to fake any IEs */ - pos = data->ie; - end = pos + data->ie_len; - while (pos && pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == WLAN_EID_SSID) - ssid_ie = pos; - else if (pos[0] == WLAN_EID_SUPP_RATES) - rate_ie = pos; - else if (pos[0] == WLAN_EID_EXT_SUPP_RATES) - rate_ie = pos; - pos += 2 + pos[1]; - } - - extra_len = 0; - if (ssid_ie == NULL) - extra_len += 2 + data->ssid_len; - if (rate_ie == NULL && data->maxrate) - extra_len += 3; - - r = os_zalloc(sizeof(*r) + extra_len + data->ie_len); - if (r == NULL) - return; - os_memcpy(r, &data->res, sizeof(*r)); - r->ie_len = extra_len + data->ie_len; - pos = (u8 *) (r + 1); - if (ssid_ie == NULL) { - /* - * Generate a fake SSID IE since the driver did not report - * a full IE list. - */ - *pos++ = WLAN_EID_SSID; - *pos++ = data->ssid_len; - os_memcpy(pos, data->ssid, data->ssid_len); - pos += data->ssid_len; - } - if (rate_ie == NULL && data->maxrate) { - /* - * Generate a fake Supported Rates IE since the driver did not - * report a full IE list. - */ - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = 1; - *pos++ = data->maxrate; - } - if (data->ie) - os_memcpy(pos, data->ie, data->ie_len); - - tmp = os_realloc_array(res->res, res->num + 1, - sizeof(struct wpa_scan_res *)); - if (tmp == NULL) { - os_free(r); - return; - } - tmp[res->num++] = r; - res->res = tmp; -} - - -/** - * wpa_driver_wext_get_scan_results - Fetch the latest scan results - * @priv: Pointer to private wext data from wpa_driver_wext_init() - * Returns: Scan results on success, -1 on failure - */ -struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv) -{ - struct wpa_driver_wext_data *drv = priv; - size_t len; - int first; - u8 *res_buf; - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end, *custom; - struct wpa_scan_results *res; - struct wext_scan_data data; - - res_buf = wpa_driver_wext_giwscan(drv, &len); - if (res_buf == NULL) - return NULL; - - first = 1; - - res = os_zalloc(sizeof(*res)); - if (res == NULL) { - os_free(res_buf); - return NULL; - } - - pos = (char *) res_buf; - end = (char *) res_buf + len; - os_memset(&data, 0, sizeof(data)); - - 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); - if (iwe->len <= IW_EV_LCP_LEN) - break; - - custom = pos + IW_EV_POINT_LEN; - if (wext_19_iw_point(drv, iwe->cmd)) { - /* 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 SIOCGIWAP: - if (!first) - wpa_driver_wext_add_scan_entry(res, &data); - first = 0; - os_free(data.ie); - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.res.bssid, - iwe->u.ap_addr.sa_data, ETH_ALEN); - break; - case SIOCGIWMODE: - wext_get_scan_mode(iwe, &data); - break; - case SIOCGIWESSID: - wext_get_scan_ssid(iwe, &data, custom, end); - break; - case SIOCGIWFREQ: - wext_get_scan_freq(iwe, &data); - break; - case IWEVQUAL: - wext_get_scan_qual(drv, iwe, &data); - break; - case SIOCGIWENCODE: - wext_get_scan_encode(iwe, &data); - break; - case SIOCGIWRATE: - wext_get_scan_rate(iwe, &data, pos, end); - break; - case IWEVGENIE: - wext_get_scan_iwevgenie(iwe, &data, custom, end); - break; - case IWEVCUSTOM: - wext_get_scan_custom(iwe, &data, custom, end); - break; - } - - pos += iwe->len; - } - os_free(res_buf); - res_buf = NULL; - if (!first) - wpa_driver_wext_add_scan_entry(res, &data); - os_free(data.ie); - - wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)", - (unsigned long) len, (unsigned long) res->num); - - return res; -} - - -static int wpa_driver_wext_get_range(void *priv) -{ - struct wpa_driver_wext_data *drv = priv; - struct iw_range *range; - struct iwreq iwr; - int minlen; - size_t buflen; - - /* - * Use larger buffer than struct iw_range in order to allow the - * structure to grow in the future. - */ - buflen = sizeof(struct iw_range) + 500; - range = os_zalloc(buflen); - if (range == NULL) - return -1; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) range; - iwr.u.data.length = buflen; - - minlen = ((char *) &range->enc_capa) - (char *) range + - sizeof(range->enc_capa); - - if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { - perror("ioctl[SIOCGIWRANGE]"); - os_free(range); - return -1; - } else if (iwr.u.data.length >= minlen && - range->we_version_compiled >= 18) { - wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " - "WE(source)=%d enc_capa=0x%x", - range->we_version_compiled, - range->we_version_source, - range->enc_capa); - drv->has_capability = 1; - drv->we_version_compiled = range->we_version_compiled; - if (range->enc_capa & IW_ENC_CAPA_WPA) { - drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA | - WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; - } - if (range->enc_capa & IW_ENC_CAPA_WPA2) { - drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; - } - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | - WPA_DRIVER_CAPA_ENC_WEP104; - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP128; - if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP) - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; - if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP) - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; - if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE) - drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE; - drv->capa.auth = WPA_DRIVER_AUTH_OPEN | - WPA_DRIVER_AUTH_SHARED | - WPA_DRIVER_AUTH_LEAP; - drv->capa.max_scan_ssids = 1; - - wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x " - "flags 0x%x", - drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags); - } else { - wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - " - "assuming WPA is not supported"); - } - - drv->max_level = range->max_qual.level; - - os_free(range); - return 0; -} - - -static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv, - const u8 *psk) -{ - struct iw_encode_ext *ext; - struct iwreq iwr; - int ret; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) - return 0; - - if (!psk) - return 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - - ext = os_zalloc(sizeof(*ext) + PMK_LEN); - if (ext == NULL) - return -1; - - iwr.u.encoding.pointer = (caddr_t) ext; - iwr.u.encoding.length = sizeof(*ext) + PMK_LEN; - ext->key_len = PMK_LEN; - os_memcpy(&ext->key, psk, ext->key_len); - ext->alg = IW_ENCODE_ALG_PMK; - - ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr); - if (ret < 0) - perror("ioctl[SIOCSIWENCODEEXT] PMK"); - os_free(ext); - - return ret; -} - - -static int wpa_driver_wext_set_key_ext(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_wext_data *drv = priv; - struct iwreq iwr; - int ret = 0; - struct iw_encode_ext *ext; - - if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) { - wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu", - __FUNCTION__, (unsigned long) seq_len); - return -1; - } - - ext = os_zalloc(sizeof(*ext) + key_len); - if (ext == NULL) - return -1; - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.encoding.flags = key_idx + 1; - iwr.u.encoding.flags |= IW_ENCODE_TEMP; - if (alg == WPA_ALG_NONE) - iwr.u.encoding.flags |= IW_ENCODE_DISABLED; - iwr.u.encoding.pointer = (caddr_t) ext; - iwr.u.encoding.length = sizeof(*ext) + key_len; - - if (addr == NULL || is_broadcast_ether_addr(addr)) - ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY; - if (set_tx) - ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY; - - ext->addr.sa_family = ARPHRD_ETHER; - if (addr) - os_memcpy(ext->addr.sa_data, addr, ETH_ALEN); - else - os_memset(ext->addr.sa_data, 0xff, ETH_ALEN); - if (key && key_len) { - os_memcpy(ext + 1, key, key_len); - ext->key_len = key_len; - } - switch (alg) { - case WPA_ALG_NONE: - ext->alg = IW_ENCODE_ALG_NONE; - break; - case WPA_ALG_WEP: - ext->alg = IW_ENCODE_ALG_WEP; - break; - case WPA_ALG_TKIP: - ext->alg = IW_ENCODE_ALG_TKIP; - break; - case WPA_ALG_CCMP: - ext->alg = IW_ENCODE_ALG_CCMP; - break; - case WPA_ALG_PMK: - ext->alg = IW_ENCODE_ALG_PMK; - break; -#ifdef CONFIG_IEEE80211W - case WPA_ALG_IGTK: - ext->alg = IW_ENCODE_ALG_AES_CMAC; - break; -#endif /* CONFIG_IEEE80211W */ - default: - wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d", - __FUNCTION__, alg); - os_free(ext); - return -1; - } - - if (seq && seq_len) { - ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID; - os_memcpy(ext->rx_seq, seq, seq_len); - } - - if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) { - ret = errno == EOPNOTSUPP ? -2 : -1; - if (errno == ENODEV) { - /* - * ndiswrapper seems to be returning incorrect error - * code.. */ - ret = -2; - } - - perror("ioctl[SIOCSIWENCODEEXT]"); - } - - os_free(ext); - return ret; -} - - -/** - * wpa_driver_wext_set_key - Configure encryption key - * @priv: Pointer to private wext data from wpa_driver_wext_init() - * @priv: Private driver interface data - * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, - * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key. - * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for - * broadcast/default keys - * @key_idx: key index (0..3), usually 0 for unicast keys - * @set_tx: Configure this key as the default Tx key (only used when - * driver does not support separate unicast/individual key - * @seq: Sequence number/packet number, seq_len octets, the next - * packet number to be used for in replay protection; configured - * for Rx keys (in most cases, this is only used with broadcast - * keys and set to zero for unicast keys) - * @seq_len: Length of the seq, depends on the algorithm: - * TKIP: 6 octets, CCMP: 6 octets - * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, - * 8-byte Rx Mic Key - * @key_len: Length of the key buffer in octets (WEP: 5 or 13, - * TKIP: 32, CCMP: 16) - * Returns: 0 on success, -1 on failure - * - * This function uses SIOCSIWENCODEEXT by default, but tries to use - * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key. - */ -int wpa_driver_wext_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_wext_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - 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); - - ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx, - seq, seq_len, key, key_len); - if (ret == 0) - return 0; - - if (ret == -2 && - (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) { - wpa_printf(MSG_DEBUG, "Driver did not support " - "SIOCSIWENCODEEXT, trying SIOCSIWENCODE"); - ret = 0; - } else { - wpa_printf(MSG_DEBUG, "Driver did not support " - "SIOCSIWENCODEEXT"); - return ret; - } - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.encoding.flags = key_idx + 1; - iwr.u.encoding.flags |= IW_ENCODE_TEMP; - if (alg == WPA_ALG_NONE) - iwr.u.encoding.flags |= IW_ENCODE_DISABLED; - iwr.u.encoding.pointer = (caddr_t) key; - iwr.u.encoding.length = key_len; - - if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { - perror("ioctl[SIOCSIWENCODE]"); - ret = -1; - } - - if (set_tx && alg != WPA_ALG_NONE) { - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.encoding.flags = key_idx + 1; - iwr.u.encoding.flags |= IW_ENCODE_TEMP; - iwr.u.encoding.pointer = (caddr_t) NULL; - iwr.u.encoding.length = 0; - if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { - perror("ioctl[SIOCSIWENCODE] (set_tx)"); - ret = -1; - } - } - - return ret; -} - - -static int wpa_driver_wext_set_countermeasures(void *priv, - int enabled) -{ - struct wpa_driver_wext_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - return wpa_driver_wext_set_auth_param(drv, - IW_AUTH_TKIP_COUNTERMEASURES, - enabled); -} - - -static int wpa_driver_wext_set_drop_unencrypted(void *priv, - int enabled) -{ - struct wpa_driver_wext_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - drv->use_crypt = enabled; - return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED, - enabled); -} - - -static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv, - const u8 *addr, int cmd, int reason_code) -{ - struct iwreq iwr; - struct iw_mlme mlme; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - os_memset(&mlme, 0, sizeof(mlme)); - mlme.cmd = cmd; - mlme.reason_code = reason_code; - mlme.addr.sa_family = ARPHRD_ETHER; - os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN); - iwr.u.data.pointer = (caddr_t) &mlme; - iwr.u.data.length = sizeof(mlme); - - if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) { - perror("ioctl[SIOCSIWMLME]"); - ret = -1; - } - - return ret; -} - - -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 }; - u8 ssid[32]; - int i; - - /* - * Only force-disconnect when the card is in infrastructure mode, - * otherwise the driver might interpret the cleared BSSID and random - * SSID as an attempt to create a new ad-hoc network. - */ - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) { - perror("ioctl[SIOCGIWMODE]"); - iwr.u.mode = IW_MODE_INFRA; - } - - 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"); - } - - if (drv->cfg80211) { - /* - * cfg80211 supports SIOCSIWMLME commands, so there is - * no need for the random SSID hack, but clear the - * SSID. - */ - if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { - wpa_printf(MSG_DEBUG, "WEXT: Failed to clear " - "SSID on disconnect"); - } - return; - } - - /* - * 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_ssid(drv, ssid, 32) < 0) { - wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus " - "SSID to disconnect"); - } - } -} - - -static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr, - int reason_code) -{ - struct wpa_driver_wext_data *drv = priv; - int ret; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code); - wpa_driver_wext_disconnect(drv); - return ret; -} - - -static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie, - size_t ie_len) -{ - struct wpa_driver_wext_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; - - if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) { - perror("ioctl[SIOCSIWGENIE]"); - ret = -1; - } - - return ret; -} - - -int wpa_driver_wext_cipher2wext(int cipher) -{ - switch (cipher) { - case WPA_CIPHER_NONE: - return IW_AUTH_CIPHER_NONE; - case WPA_CIPHER_WEP40: - return IW_AUTH_CIPHER_WEP40; - case WPA_CIPHER_TKIP: - return IW_AUTH_CIPHER_TKIP; - case WPA_CIPHER_CCMP: - return IW_AUTH_CIPHER_CCMP; - case WPA_CIPHER_WEP104: - return IW_AUTH_CIPHER_WEP104; - default: - return 0; - } -} - - -int wpa_driver_wext_keymgmt2wext(int keymgmt) -{ - switch (keymgmt) { - case WPA_KEY_MGMT_IEEE8021X: - case WPA_KEY_MGMT_IEEE8021X_NO_WPA: - return IW_AUTH_KEY_MGMT_802_1X; - case WPA_KEY_MGMT_PSK: - return IW_AUTH_KEY_MGMT_PSK; - default: - return 0; - } -} - - -static int -wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv, - struct wpa_driver_associate_params *params) -{ - struct iwreq iwr; - int ret = 0; - - wpa_printf(MSG_DEBUG, "WEXT: Driver did not support " - "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE"); - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - /* Just changing mode, not actual keys */ - iwr.u.encoding.flags = 0; - iwr.u.encoding.pointer = (caddr_t) NULL; - iwr.u.encoding.length = 0; - - /* - * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two - * different things. Here they are used to indicate Open System vs. - * Shared Key authentication algorithm. However, some drivers may use - * them to select between open/restricted WEP encrypted (open = allow - * both unencrypted and encrypted frames; restricted = only allow - * encrypted frames). - */ - - if (!drv->use_crypt) { - iwr.u.encoding.flags |= IW_ENCODE_DISABLED; - } else { - if (params->auth_alg & WPA_AUTH_ALG_OPEN) - iwr.u.encoding.flags |= IW_ENCODE_OPEN; - if (params->auth_alg & WPA_AUTH_ALG_SHARED) - iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED; - } - - if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { - perror("ioctl[SIOCSIWENCODE]"); - ret = -1; - } - - return ret; -} - - -int wpa_driver_wext_associate(void *priv, - struct wpa_driver_associate_params *params) -{ - struct wpa_driver_wext_data *drv = priv; - int ret = 0; - int allow_unencrypted_eapol; - int value; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (drv->cfg80211) { - /* - * Stop cfg80211 from trying to associate before we are done - * with all parameters. - */ - wpa_driver_wext_set_ssid(drv, (u8 *) "", 0); - } - - if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted) - < 0) - ret = -1; - if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0) - ret = -1; - if (wpa_driver_wext_set_mode(drv, params->mode) < 0) - ret = -1; - - /* - * If the driver did not support SIOCSIWAUTH, fallback to - * SIOCSIWENCODE here. - */ - if (drv->auth_alg_fallback && - wpa_driver_wext_auth_alg_fallback(drv, params) < 0) - ret = -1; - - if (!params->bssid && - wpa_driver_wext_set_bssid(drv, NULL) < 0) - ret = -1; - - /* TODO: should consider getting wpa version and cipher/key_mgmt suites - * from configuration, not from here, where only the selected suite is - * available */ - if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len) - < 0) - ret = -1; - if (params->wpa_ie == NULL || params->wpa_ie_len == 0) - value = IW_AUTH_WPA_VERSION_DISABLED; - else if (params->wpa_ie[0] == WLAN_EID_RSN) - value = IW_AUTH_WPA_VERSION_WPA2; - else - value = IW_AUTH_WPA_VERSION_WPA; - if (wpa_driver_wext_set_auth_param(drv, - IW_AUTH_WPA_VERSION, value) < 0) - ret = -1; - value = wpa_driver_wext_cipher2wext(params->pairwise_suite); - if (wpa_driver_wext_set_auth_param(drv, - IW_AUTH_CIPHER_PAIRWISE, value) < 0) - ret = -1; - value = wpa_driver_wext_cipher2wext(params->group_suite); - if (wpa_driver_wext_set_auth_param(drv, - IW_AUTH_CIPHER_GROUP, value) < 0) - ret = -1; - value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite); - if (wpa_driver_wext_set_auth_param(drv, - IW_AUTH_KEY_MGMT, value) < 0) - ret = -1; - value = params->key_mgmt_suite != WPA_KEY_MGMT_NONE || - params->pairwise_suite != WPA_CIPHER_NONE || - params->group_suite != WPA_CIPHER_NONE || - params->wpa_ie_len; - if (wpa_driver_wext_set_auth_param(drv, - IW_AUTH_PRIVACY_INVOKED, value) < 0) - ret = -1; - - /* 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 == WPA_KEY_MGMT_IEEE8021X || - params->key_mgmt_suite == WPA_KEY_MGMT_PSK) - allow_unencrypted_eapol = 0; - else - allow_unencrypted_eapol = 1; - - if (wpa_driver_wext_set_psk(drv, params->psk) < 0) - ret = -1; - if (wpa_driver_wext_set_auth_param(drv, - IW_AUTH_RX_UNENCRYPTED_EAPOL, - allow_unencrypted_eapol) < 0) - ret = -1; -#ifdef CONFIG_IEEE80211W - switch (params->mgmt_frame_protection) { - case NO_MGMT_FRAME_PROTECTION: - value = IW_AUTH_MFP_DISABLED; - break; - case MGMT_FRAME_PROTECTION_OPTIONAL: - value = IW_AUTH_MFP_OPTIONAL; - break; - case MGMT_FRAME_PROTECTION_REQUIRED: - value = IW_AUTH_MFP_REQUIRED; - break; - }; - if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0) - ret = -1; -#endif /* CONFIG_IEEE80211W */ - if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0) - ret = -1; - if (!drv->cfg80211 && - wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) - ret = -1; - if (params->bssid && - wpa_driver_wext_set_bssid(drv, params->bssid) < 0) - ret = -1; - if (drv->cfg80211 && - wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) - ret = -1; - - return ret; -} - - -static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg) -{ - struct wpa_driver_wext_data *drv = priv; - int algs = 0, res; - - if (auth_alg & WPA_AUTH_ALG_OPEN) - algs |= IW_AUTH_ALG_OPEN_SYSTEM; - if (auth_alg & WPA_AUTH_ALG_SHARED) - algs |= IW_AUTH_ALG_SHARED_KEY; - if (auth_alg & WPA_AUTH_ALG_LEAP) - algs |= IW_AUTH_ALG_LEAP; - if (algs == 0) { - /* at least one algorithm should be set */ - algs = IW_AUTH_ALG_OPEN_SYSTEM; - } - - res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG, - algs); - drv->auth_alg_fallback = res == -2; - return res; -} - - -/** - * wpa_driver_wext_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE - * @priv: Pointer to private wext data from wpa_driver_wext_init() - * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS - * Returns: 0 on success, -1 on failure - */ -int wpa_driver_wext_set_mode(void *priv, int mode) -{ - struct wpa_driver_wext_data *drv = priv; - struct iwreq iwr; - int ret = -1; - unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.mode = new_mode; - if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) { - ret = 0; - goto done; - } - - if (errno != EBUSY) { - perror("ioctl[SIOCSIWMODE]"); - goto done; - } - - /* mac80211 doesn't allow mode changes while the device is up, so if - * the device isn't in the mode we're about to change to, take device - * down, try to set the mode again, and bring it back up. - */ - if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) { - perror("ioctl[SIOCGIWMODE]"); - goto done; - } - - if (iwr.u.mode == new_mode) { - ret = 0; - goto done; - } - - if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) { - /* Try to set the mode again while the interface is down */ - iwr.u.mode = new_mode; - if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) - perror("ioctl[SIOCSIWMODE]"); - else - ret = 0; - - (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1); - } - -done: - return ret; -} - - -static int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv, - u32 cmd, const u8 *bssid, const u8 *pmkid) -{ - struct iwreq iwr; - struct iw_pmksa pmksa; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - os_memset(&pmksa, 0, sizeof(pmksa)); - pmksa.cmd = cmd; - pmksa.bssid.sa_family = ARPHRD_ETHER; - if (bssid) - os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN); - if (pmkid) - os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN); - iwr.u.data.pointer = (caddr_t) &pmksa; - iwr.u.data.length = sizeof(pmksa); - - if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) { - if (errno != EOPNOTSUPP) - perror("ioctl[SIOCSIWPMKSA]"); - ret = -1; - } - - return ret; -} - - -static int wpa_driver_wext_add_pmkid(void *priv, const u8 *bssid, - const u8 *pmkid) -{ - struct wpa_driver_wext_data *drv = priv; - return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid); -} - - -static int wpa_driver_wext_remove_pmkid(void *priv, const u8 *bssid, - const u8 *pmkid) -{ - struct wpa_driver_wext_data *drv = priv; - return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid); -} - - -static int wpa_driver_wext_flush_pmkid(void *priv) -{ - struct wpa_driver_wext_data *drv = priv; - return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL); -} - - -int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa) -{ - struct wpa_driver_wext_data *drv = priv; - if (!drv->has_capability) - return -1; - os_memcpy(capa, &drv->capa, sizeof(*capa)); - return 0; -} - - -int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv, - const char *ifname) -{ - if (ifname == NULL) { - drv->ifindex2 = -1; - return 0; - } - - drv->ifindex2 = if_nametoindex(ifname); - if (drv->ifindex2 <= 0) - return -1; - - wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for " - "wireless events", drv->ifindex2, ifname); - - return 0; -} - - -int wpa_driver_wext_set_operstate(void *priv, int state) -{ - struct wpa_driver_wext_data *drv = priv; - - 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, - state ? IF_OPER_UP : IF_OPER_DORMANT); -} - - -int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv) -{ - return drv->we_version_compiled; -} - - -static const char * wext_get_radio_name(void *priv) -{ - struct wpa_driver_wext_data *drv = priv; - return drv->phyname; -} - - -const struct wpa_driver_ops wpa_driver_wext_ops = { - .name = "wext", - .desc = "Linux wireless extensions (generic)", - .get_bssid = wpa_driver_wext_get_bssid, - .get_ssid = wpa_driver_wext_get_ssid, - .set_key = wpa_driver_wext_set_key, - .set_countermeasures = wpa_driver_wext_set_countermeasures, - .scan2 = wpa_driver_wext_scan, - .get_scan_results2 = wpa_driver_wext_get_scan_results, - .deauthenticate = wpa_driver_wext_deauthenticate, - .associate = wpa_driver_wext_associate, - .init = wpa_driver_wext_init, - .deinit = wpa_driver_wext_deinit, - .add_pmkid = wpa_driver_wext_add_pmkid, - .remove_pmkid = wpa_driver_wext_remove_pmkid, - .flush_pmkid = wpa_driver_wext_flush_pmkid, - .get_capa = wpa_driver_wext_get_capa, - .set_operstate = wpa_driver_wext_set_operstate, - .get_radio_name = wext_get_radio_name, -}; diff --git a/contrib/hostapd/src/drivers/driver_wext.h b/contrib/hostapd/src/drivers/driver_wext.h deleted file mode 100644 index b4b5960a77..0000000000 --- a/contrib/hostapd/src/drivers/driver_wext.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * WPA Supplicant - driver_wext exported functions - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef DRIVER_WEXT_H -#define DRIVER_WEXT_H - -#include - -struct wpa_driver_wext_data { - void *ctx; - struct netlink_data *netlink; - int ioctl_sock; - int mlme_sock; - char ifname[IFNAMSIZ + 1]; - char phyname[32]; - int ifindex; - int ifindex2; - int if_removed; - int if_disabled; - struct rfkill_data *rfkill; - u8 *assoc_req_ies; - size_t assoc_req_ies_len; - u8 *assoc_resp_ies; - size_t assoc_resp_ies_len; - struct wpa_driver_capa capa; - int has_capability; - int we_version_compiled; - - /* for set_auth_alg fallback */ - int use_crypt; - int auth_alg_fallback; - - int operstate; - - char mlmedev[IFNAMSIZ + 1]; - - int scan_complete_events; - - int cfg80211; /* whether driver is using cfg80211 */ - - u8 max_level; -}; - -int wpa_driver_wext_get_bssid(void *priv, u8 *bssid); -int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid); -int wpa_driver_wext_get_ssid(void *priv, u8 *ssid); -int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len); -int wpa_driver_wext_set_freq(void *priv, int freq); -int wpa_driver_wext_set_mode(void *priv, int mode); -int wpa_driver_wext_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); -int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params); -struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv); - -void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx); - -int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv, - const char *ifname); - -void * wpa_driver_wext_init(void *ctx, const char *ifname); -void wpa_driver_wext_deinit(void *priv); - -int wpa_driver_wext_set_operstate(void *priv, int state); -int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv); - -int wpa_driver_wext_associate(void *priv, - struct wpa_driver_associate_params *params); -int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa); -int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv, - int idx, u32 value); -int wpa_driver_wext_cipher2wext(int cipher); -int wpa_driver_wext_keymgmt2wext(int keymgmt); - -#endif /* DRIVER_WEXT_H */ diff --git a/contrib/hostapd/src/drivers/driver_wired.c b/contrib/hostapd/src/drivers/driver_wired.c deleted file mode 100644 index 21f5e4248f..0000000000 --- a/contrib/hostapd/src/drivers/driver_wired.c +++ /dev/null @@ -1,662 +0,0 @@ -/* - * Wired Ethernet driver interface - * Copyright (c) 2005-2009, Jouni Malinen - * Copyright (c) 2004, Gunter Burchardt - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include -#include -#ifdef __linux__ -#include -#include -#include -#endif /* __linux__ */ -#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) -#include -#include -#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */ -#ifdef __sun__ -#include -#endif /* __sun__ */ - -#include "common.h" -#include "eloop.h" -#include "driver.h" - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct ieee8023_hdr { - u8 dest[6]; - u8 src[6]; - u16 ethertype; -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - -static const u8 pae_group_addr[ETH_ALEN] = -{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; - - -struct wpa_driver_wired_data { - char ifname[IFNAMSIZ + 1]; - void *ctx; - - int sock; /* raw packet socket for driver access */ - int dhcp_sock; /* socket for dhcp packets */ - int use_pae_group_addr; - - int pf_sock; - int membership, multi, iff_allmulti, iff_up; -}; - - -/* TODO: detecting new devices should eventually be changed from using DHCP - * snooping to trigger on any packet from a new layer 2 MAC address, e.g., - * based on ebtables, etc. */ - -struct dhcp_message { - u_int8_t op; - u_int8_t htype; - u_int8_t hlen; - u_int8_t hops; - u_int32_t xid; - u_int16_t secs; - u_int16_t flags; - u_int32_t ciaddr; - u_int32_t yiaddr; - u_int32_t siaddr; - u_int32_t giaddr; - u_int8_t chaddr[16]; - u_int8_t sname[64]; - u_int8_t file[128]; - u_int32_t cookie; - u_int8_t options[308]; /* 312 - cookie */ -}; - - -static int wired_multicast_membership(int sock, int ifindex, - const u8 *addr, int add) -{ -#ifdef __linux__ - struct packet_mreq mreq; - - if (sock < 0) - return -1; - - os_memset(&mreq, 0, sizeof(mreq)); - mreq.mr_ifindex = ifindex; - mreq.mr_type = PACKET_MR_MULTICAST; - mreq.mr_alen = ETH_ALEN; - os_memcpy(mreq.mr_address, addr, ETH_ALEN); - - if (setsockopt(sock, SOL_PACKET, - add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, - &mreq, sizeof(mreq)) < 0) { - perror("setsockopt"); - return -1; - } - return 0; -#else /* __linux__ */ - return -1; -#endif /* __linux__ */ -} - - -#ifdef __linux__ -static void handle_data(void *ctx, unsigned char *buf, size_t len) -{ -#ifdef HOSTAPD - struct ieee8023_hdr *hdr; - u8 *pos, *sa; - size_t left; - union wpa_event_data event; - - /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest, - * 2 byte ethertype */ - if (len < 14) { - wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)", - (unsigned long) len); - return; - } - - hdr = (struct ieee8023_hdr *) buf; - - switch (ntohs(hdr->ethertype)) { - case ETH_P_PAE: - wpa_printf(MSG_MSGDUMP, "Received EAPOL packet"); - sa = hdr->src; - os_memset(&event, 0, sizeof(event)); - event.new_sta.addr = sa; - wpa_supplicant_event(ctx, EVENT_NEW_STA, &event); - - pos = (u8 *) (hdr + 1); - left = len - sizeof(*hdr); - drv_event_eapol_rx(ctx, sa, pos, left); - break; - - default: - wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame", - ntohs(hdr->ethertype)); - break; - } -#endif /* HOSTAPD */ -} - - -static void handle_read(int sock, void *eloop_ctx, void *sock_ctx) -{ - int len; - unsigned char buf[3000]; - - len = recv(sock, buf, sizeof(buf), 0); - if (len < 0) { - perror("recv"); - return; - } - - handle_data(eloop_ctx, buf, len); -} - - -static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx) -{ - int len; - unsigned char buf[3000]; - struct dhcp_message *msg; - u8 *mac_address; - union wpa_event_data event; - - len = recv(sock, buf, sizeof(buf), 0); - if (len < 0) { - perror("recv"); - return; - } - - /* must contain at least dhcp_message->chaddr */ - if (len < 44) { - wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len); - return; - } - - msg = (struct dhcp_message *) buf; - mac_address = (u8 *) &(msg->chaddr); - - wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR, - MAC2STR(mac_address)); - - os_memset(&event, 0, sizeof(event)); - event.new_sta.addr = mac_address; - wpa_supplicant_event(eloop_ctx, EVENT_NEW_STA, &event); -} -#endif /* __linux__ */ - - -static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr) -{ -#ifdef __linux__ - struct ifreq ifr; - struct sockaddr_ll addr; - struct sockaddr_in addr2; - int n = 1; - - drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE)); - if (drv->sock < 0) { - perror("socket[PF_PACKET,SOCK_RAW]"); - return -1; - } - - if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) { - printf("Could not register read socket\n"); - return -1; - } - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); - if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { - perror("ioctl(SIOCGIFINDEX)"); - return -1; - } - - os_memset(&addr, 0, sizeof(addr)); - addr.sll_family = AF_PACKET; - addr.sll_ifindex = ifr.ifr_ifindex; - wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", - addr.sll_ifindex); - - if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("bind"); - return -1; - } - - /* filter multicast address */ - if (wired_multicast_membership(drv->sock, ifr.ifr_ifindex, - pae_group_addr, 1) < 0) { - wpa_printf(MSG_ERROR, "wired: Failed to add multicast group " - "membership"); - return -1; - } - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); - if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) { - perror("ioctl(SIOCGIFHWADDR)"); - return -1; - } - - if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { - printf("Invalid HW-addr family 0x%04x\n", - ifr.ifr_hwaddr.sa_family); - return -1; - } - os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); - - /* setup dhcp listen socket for sta detection */ - if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - perror("socket call failed for dhcp"); - return -1; - } - - if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx, - NULL)) { - printf("Could not register read socket\n"); - return -1; - } - - os_memset(&addr2, 0, sizeof(addr2)); - addr2.sin_family = AF_INET; - addr2.sin_port = htons(67); - addr2.sin_addr.s_addr = INADDR_ANY; - - if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n, - sizeof(n)) == -1) { - perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]"); - return -1; - } - if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n, - sizeof(n)) == -1) { - perror("setsockopt[SOL_SOCKET,SO_BROADCAST]"); - return -1; - } - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ); - if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE, - (char *) &ifr, sizeof(ifr)) < 0) { - perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]"); - return -1; - } - - if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2, - sizeof(struct sockaddr)) == -1) { - perror("bind"); - return -1; - } - - return 0; -#else /* __linux__ */ - return -1; -#endif /* __linux__ */ -} - - -static int wired_send_eapol(void *priv, const u8 *addr, - const u8 *data, size_t data_len, int encrypt, - const u8 *own_addr, u32 flags) -{ - struct wpa_driver_wired_data *drv = priv; - struct ieee8023_hdr *hdr; - size_t len; - u8 *pos; - int res; - - len = sizeof(*hdr) + data_len; - hdr = os_zalloc(len); - if (hdr == NULL) { - printf("malloc() failed for wired_send_eapol(len=%lu)\n", - (unsigned long) len); - return -1; - } - - os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr, - ETH_ALEN); - os_memcpy(hdr->src, own_addr, ETH_ALEN); - hdr->ethertype = htons(ETH_P_PAE); - - pos = (u8 *) (hdr + 1); - os_memcpy(pos, data, data_len); - - res = send(drv->sock, (u8 *) hdr, len, 0); - os_free(hdr); - - if (res < 0) { - perror("wired_send_eapol: send"); - printf("wired_send_eapol - packet len: %lu - failed\n", - (unsigned long) len); - } - - return res; -} - - -static void * wired_driver_hapd_init(struct hostapd_data *hapd, - struct wpa_init_params *params) -{ - struct wpa_driver_wired_data *drv; - - drv = os_zalloc(sizeof(struct wpa_driver_wired_data)); - if (drv == NULL) { - printf("Could not allocate memory for wired driver data\n"); - return NULL; - } - - drv->ctx = hapd; - os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); - drv->use_pae_group_addr = params->use_pae_group_addr; - - if (wired_init_sockets(drv, params->own_addr)) { - os_free(drv); - return NULL; - } - - return drv; -} - - -static void wired_driver_hapd_deinit(void *priv) -{ - struct wpa_driver_wired_data *drv = priv; - - if (drv->sock >= 0) - close(drv->sock); - - if (drv->dhcp_sock >= 0) - close(drv->dhcp_sock); - - os_free(drv); -} - - -static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid) -{ - ssid[0] = 0; - return 0; -} - - -static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid) -{ - /* Report PAE group address as the "BSSID" for wired connection. */ - os_memcpy(bssid, pae_group_addr, ETH_ALEN); - return 0; -} - - -static int wpa_driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa) -{ - os_memset(capa, 0, sizeof(*capa)); - capa->flags = WPA_DRIVER_FLAGS_WIRED; - return 0; -} - - -static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags) -{ - struct ifreq ifr; - int s; - - s = socket(PF_INET, SOCK_DGRAM, 0); - if (s < 0) { - perror("socket"); - return -1; - } - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { - perror("ioctl[SIOCGIFFLAGS]"); - close(s); - return -1; - } - close(s); - *flags = ifr.ifr_flags & 0xffff; - return 0; -} - - -static int wpa_driver_wired_set_ifflags(const char *ifname, int flags) -{ - struct ifreq ifr; - int s; - - s = socket(PF_INET, SOCK_DGRAM, 0); - if (s < 0) { - perror("socket"); - return -1; - } - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - ifr.ifr_flags = flags & 0xffff; - if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { - perror("ioctl[SIOCSIFFLAGS]"); - close(s); - return -1; - } - close(s); - return 0; -} - - -#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) -static int wpa_driver_wired_get_ifstatus(const char *ifname, int *status) -{ - struct ifmediareq ifmr; - int s; - - s = socket(PF_INET, SOCK_DGRAM, 0); - if (s < 0) { - perror("socket"); - return -1; - } - - os_memset(&ifmr, 0, sizeof(ifmr)); - os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ); - if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) { - perror("ioctl[SIOCGIFMEDIA]"); - close(s); - return -1; - } - close(s); - *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) == - (IFM_ACTIVE | IFM_AVALID); - - return 0; -} -#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */ - - -static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add) -{ - struct ifreq ifr; - int s; - -#ifdef __sun__ - return -1; -#endif /* __sun__ */ - - s = socket(PF_INET, SOCK_DGRAM, 0); - if (s < 0) { - perror("socket"); - return -1; - } - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); -#ifdef __linux__ - ifr.ifr_hwaddr.sa_family = AF_UNSPEC; - os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN); -#endif /* __linux__ */ -#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) - { - struct sockaddr_dl *dlp; - dlp = (struct sockaddr_dl *) &ifr.ifr_addr; - dlp->sdl_len = sizeof(struct sockaddr_dl); - dlp->sdl_family = AF_LINK; - dlp->sdl_index = 0; - dlp->sdl_nlen = 0; - dlp->sdl_alen = ETH_ALEN; - dlp->sdl_slen = 0; - os_memcpy(LLADDR(dlp), addr, ETH_ALEN); - } -#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */ -#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) - { - struct sockaddr *sap; - sap = (struct sockaddr *) &ifr.ifr_addr; - sap->sa_len = sizeof(struct sockaddr); - sap->sa_family = AF_UNSPEC; - os_memcpy(sap->sa_data, addr, ETH_ALEN); - } -#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */ - - if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) { - perror("ioctl[SIOC{ADD/DEL}MULTI]"); - close(s); - return -1; - } - close(s); - return 0; -} - - -static void * wpa_driver_wired_init(void *ctx, const char *ifname) -{ - struct wpa_driver_wired_data *drv; - int flags; - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); - drv->ctx = ctx; - -#ifdef __linux__ - drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0); - if (drv->pf_sock < 0) - perror("socket(PF_PACKET)"); -#else /* __linux__ */ - drv->pf_sock = -1; -#endif /* __linux__ */ - - if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 && - !(flags & IFF_UP) && - wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) { - drv->iff_up = 1; - } - - if (wired_multicast_membership(drv->pf_sock, - if_nametoindex(drv->ifname), - pae_group_addr, 1) == 0) { - wpa_printf(MSG_DEBUG, "%s: Added multicast membership with " - "packet socket", __func__); - drv->membership = 1; - } else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) { - wpa_printf(MSG_DEBUG, "%s: Added multicast membership with " - "SIOCADDMULTI", __func__); - drv->multi = 1; - } else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) { - wpa_printf(MSG_INFO, "%s: Could not get interface " - "flags", __func__); - os_free(drv); - return NULL; - } else if (flags & IFF_ALLMULTI) { - wpa_printf(MSG_DEBUG, "%s: Interface is already configured " - "for multicast", __func__); - } else if (wpa_driver_wired_set_ifflags(ifname, - flags | IFF_ALLMULTI) < 0) { - wpa_printf(MSG_INFO, "%s: Failed to enable allmulti", - __func__); - os_free(drv); - return NULL; - } else { - wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode", - __func__); - drv->iff_allmulti = 1; - } -#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) - { - int status; - wpa_printf(MSG_DEBUG, "%s: waiting for link to become active", - __func__); - while (wpa_driver_wired_get_ifstatus(ifname, &status) == 0 && - status == 0) - sleep(1); - } -#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */ - - return drv; -} - - -static void wpa_driver_wired_deinit(void *priv) -{ - struct wpa_driver_wired_data *drv = priv; - int flags; - - if (drv->membership && - wired_multicast_membership(drv->pf_sock, - if_nametoindex(drv->ifname), - pae_group_addr, 0) < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast " - "group (PACKET)", __func__); - } - - if (drv->multi && - wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast " - "group (SIOCDELMULTI)", __func__); - } - - if (drv->iff_allmulti && - (wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 || - wpa_driver_wired_set_ifflags(drv->ifname, - flags & ~IFF_ALLMULTI) < 0)) { - wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode", - __func__); - } - - if (drv->iff_up && - wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 && - (flags & IFF_UP) && - wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down", - __func__); - } - - if (drv->pf_sock != -1) - close(drv->pf_sock); - - os_free(drv); -} - - -const struct wpa_driver_ops wpa_driver_wired_ops = { - .name = "wired", - .desc = "Wired Ethernet driver", - .hapd_init = wired_driver_hapd_init, - .hapd_deinit = wired_driver_hapd_deinit, - .hapd_send_eapol = wired_send_eapol, - .get_ssid = wpa_driver_wired_get_ssid, - .get_bssid = wpa_driver_wired_get_bssid, - .get_capa = wpa_driver_wired_get_capa, - .init = wpa_driver_wired_init, - .deinit = wpa_driver_wired_deinit, -}; diff --git a/contrib/hostapd/src/drivers/drivers.c b/contrib/hostapd/src/drivers/drivers.c deleted file mode 100644 index 446ab63926..0000000000 --- a/contrib/hostapd/src/drivers/drivers.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Driver interface list - * Copyright (c) 2004-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" -#include "utils/common.h" -#include "driver.h" - -#ifdef CONFIG_DRIVER_WEXT -extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */ -#endif /* CONFIG_DRIVER_WEXT */ -#ifdef CONFIG_DRIVER_NL80211 -extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */ -#endif /* CONFIG_DRIVER_NL80211 */ -#ifdef CONFIG_DRIVER_HOSTAP -extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */ -#endif /* CONFIG_DRIVER_HOSTAP */ -#ifdef CONFIG_DRIVER_MADWIFI -extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */ -#endif /* CONFIG_DRIVER_MADWIFI */ -#ifdef CONFIG_DRIVER_BSD -extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */ -#endif /* CONFIG_DRIVER_BSD */ -#ifdef CONFIG_DRIVER_OPENBSD -extern struct wpa_driver_ops wpa_driver_openbsd_ops; /* driver_openbsd.c */ -#endif /* CONFIG_DRIVER_OPENBSD */ -#ifdef CONFIG_DRIVER_NDIS -extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */ -#endif /* CONFIG_DRIVER_NDIS */ -#ifdef CONFIG_DRIVER_WIRED -extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */ -#endif /* CONFIG_DRIVER_WIRED */ -#ifdef CONFIG_DRIVER_TEST -extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */ -#endif /* CONFIG_DRIVER_TEST */ -#ifdef CONFIG_DRIVER_ROBOSWITCH -/* driver_roboswitch.c */ -extern struct wpa_driver_ops wpa_driver_roboswitch_ops; -#endif /* CONFIG_DRIVER_ROBOSWITCH */ -#ifdef CONFIG_DRIVER_ATHEROS -extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */ -#endif /* CONFIG_DRIVER_ATHEROS */ -#ifdef CONFIG_DRIVER_NONE -extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */ -#endif /* CONFIG_DRIVER_NONE */ - - -struct wpa_driver_ops *wpa_drivers[] = -{ -#ifdef CONFIG_DRIVER_NL80211 - &wpa_driver_nl80211_ops, -#endif /* CONFIG_DRIVER_NL80211 */ -#ifdef CONFIG_DRIVER_WEXT - &wpa_driver_wext_ops, -#endif /* CONFIG_DRIVER_WEXT */ -#ifdef CONFIG_DRIVER_HOSTAP - &wpa_driver_hostap_ops, -#endif /* CONFIG_DRIVER_HOSTAP */ -#ifdef CONFIG_DRIVER_MADWIFI - &wpa_driver_madwifi_ops, -#endif /* CONFIG_DRIVER_MADWIFI */ -#ifdef CONFIG_DRIVER_BSD - &wpa_driver_bsd_ops, -#endif /* CONFIG_DRIVER_BSD */ -#ifdef CONFIG_DRIVER_OPENBSD - &wpa_driver_openbsd_ops, -#endif /* CONFIG_DRIVER_OPENBSD */ -#ifdef CONFIG_DRIVER_NDIS - &wpa_driver_ndis_ops, -#endif /* CONFIG_DRIVER_NDIS */ -#ifdef CONFIG_DRIVER_WIRED - &wpa_driver_wired_ops, -#endif /* CONFIG_DRIVER_WIRED */ -#ifdef CONFIG_DRIVER_TEST - &wpa_driver_test_ops, -#endif /* CONFIG_DRIVER_TEST */ -#ifdef CONFIG_DRIVER_ROBOSWITCH - &wpa_driver_roboswitch_ops, -#endif /* CONFIG_DRIVER_ROBOSWITCH */ -#ifdef CONFIG_DRIVER_ATHEROS - &wpa_driver_atheros_ops, -#endif /* CONFIG_DRIVER_ATHEROS */ -#ifdef CONFIG_DRIVER_NONE - &wpa_driver_none_ops, -#endif /* CONFIG_DRIVER_NONE */ - NULL -}; diff --git a/contrib/hostapd/src/drivers/linux_ioctl.c b/contrib/hostapd/src/drivers/linux_ioctl.c deleted file mode 100644 index 837971d25c..0000000000 --- a/contrib/hostapd/src/drivers/linux_ioctl.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Linux ioctl helper functions for driver wrappers - * Copyright (c) 2002-2010, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" -#include -#include -#include - -#include "utils/common.h" -#include "linux_ioctl.h" - - -int linux_set_iface_flags(int sock, const char *ifname, int dev_up) -{ - 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; - } - - if (dev_up) { - if (ifr.ifr_flags & IFF_UP) - return 0; - ifr.ifr_flags |= IFF_UP; - } else { - if (!(ifr.ifr_flags & IFF_UP)) - return 0; - ifr.ifr_flags &= ~IFF_UP; - } - - if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) { - ret = errno ? -errno : -999; - wpa_printf(MSG_ERROR, "Could not set interface %s flags (%s): " - "%s", - ifname, dev_up ? "UP" : "DOWN", strerror(errno)); - 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; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - if (ioctl(sock, SIOCGIFHWADDR, &ifr)) { - wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s", - ifname, strerror(errno)); - return -1; - } - - if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { - wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x", - ifname, ifr.ifr_hwaddr.sa_family); - return -1; - } - os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); - - return 0; -} - - -int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr) -{ - struct ifreq ifr; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN); - ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; - - if (ioctl(sock, SIOCSIFHWADDR, &ifr)) { - wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s", - ifname, strerror(errno)); - return -1; - } - - return 0; -} - - -#ifndef SIOCBRADDBR -#define SIOCBRADDBR 0x89a0 -#endif -#ifndef SIOCBRDELBR -#define SIOCBRDELBR 0x89a1 -#endif -#ifndef SIOCBRADDIF -#define SIOCBRADDIF 0x89a2 -#endif -#ifndef SIOCBRDELIF -#define SIOCBRDELIF 0x89a3 -#endif - - -int linux_br_add(int sock, const char *brname) -{ - if (ioctl(sock, SIOCBRADDBR, brname) < 0) { - wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s", - brname, strerror(errno)); - return -1; - } - - return 0; -} - - -int linux_br_del(int sock, const char *brname) -{ - if (ioctl(sock, SIOCBRDELBR, brname) < 0) { - wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s", - brname, strerror(errno)); - return -1; - } - - return 0; -} - - -int linux_br_add_if(int sock, const char *brname, const char *ifname) -{ - struct ifreq ifr; - int ifindex; - - ifindex = if_nametoindex(ifname); - if (ifindex == 0) - return -1; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ); - ifr.ifr_ifindex = ifindex; - if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) { - wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge " - "%s: %s", ifname, brname, strerror(errno)); - return -1; - } - - return 0; -} - - -int linux_br_del_if(int sock, const char *brname, const char *ifname) -{ - struct ifreq ifr; - int ifindex; - - ifindex = if_nametoindex(ifname); - if (ifindex == 0) - return -1; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ); - ifr.ifr_ifindex = ifindex; - if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) { - wpa_printf(MSG_DEBUG, "Could not remove interface %s from " - "bridge %s: %s", ifname, brname, strerror(errno)); - return -1; - } - - return 0; -} - - -int linux_br_get(char *brname, const char *ifname) -{ - char path[128], brlink[128], *pos; - ssize_t res; - - os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge", - ifname); - res = readlink(path, brlink, sizeof(brlink)); - if (res < 0 || (size_t) res >= sizeof(brlink)) - return -1; - brlink[res] = '\0'; - pos = os_strrchr(brlink, '/'); - if (pos == NULL) - return -1; - pos++; - os_strlcpy(brname, pos, IFNAMSIZ); - return 0; -} diff --git a/contrib/hostapd/src/drivers/linux_ioctl.h b/contrib/hostapd/src/drivers/linux_ioctl.h deleted file mode 100644 index c03fe6e9a3..0000000000 --- a/contrib/hostapd/src/drivers/linux_ioctl.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Linux ioctl helper functions for driver wrappers - * Copyright (c) 2002-2010, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef LINUX_IOCTL_H -#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); -int linux_br_del(int sock, const char *brname); -int linux_br_add_if(int sock, const char *brname, const char *ifname); -int linux_br_del_if(int sock, const char *brname, const char *ifname); -int linux_br_get(char *brname, const char *ifname); - -#endif /* LINUX_IOCTL_H */ diff --git a/contrib/hostapd/src/drivers/linux_wext.h b/contrib/hostapd/src/drivers/linux_wext.h deleted file mode 100644 index 55cf955318..0000000000 --- a/contrib/hostapd/src/drivers/linux_wext.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Driver interaction with generic Linux Wireless Extensions - * Copyright (c) 2003-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README 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 -#include -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 - -#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/contrib/hostapd/src/drivers/ndis_events.c b/contrib/hostapd/src/drivers/ndis_events.c deleted file mode 100644 index 93673a3632..0000000000 --- a/contrib/hostapd/src/drivers/ndis_events.c +++ /dev/null @@ -1,802 +0,0 @@ -/* - * ndis_events - Receive NdisMIndicateStatus() events using WMI - * Copyright (c) 2004-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#define _WIN32_WINNT 0x0400 - -#include "includes.h" - -#ifndef COBJMACROS -#define COBJMACROS -#endif /* COBJMACROS */ -#include - -#include "common.h" - - -static int wmi_refcnt = 0; -static int wmi_first = 1; - -struct ndis_events_data { - IWbemObjectSink sink; - IWbemObjectSinkVtbl sink_vtbl; - - IWbemServices *pSvc; - IWbemLocator *pLoc; - - HANDLE read_pipe, write_pipe, event_avail; - UINT ref; - int terminating; - char *ifname; /* {GUID..} */ - WCHAR *adapter_desc; -}; - -#define BstrAlloc(x) (x) ? SysAllocString(x) : NULL -#define BstrFree(x) if (x) SysFreeString(x) - -/* WBEM / WMI wrapper functions, to perform in-place conversion of WCHARs to - * BSTRs */ -HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecQuery( - IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery, - long lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum) -{ - BSTR bsQueryLanguage, bsQuery; - HRESULT hr; - - bsQueryLanguage = BstrAlloc(strQueryLanguage); - bsQuery = BstrAlloc(strQuery); - - hr = IWbemServices_ExecQuery(pSvc, bsQueryLanguage, bsQuery, lFlags, - pCtx, ppEnum); - - BstrFree(bsQueryLanguage); - BstrFree(bsQuery); - - return hr; -} - - -HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecNotificationQueryAsync( - IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery, - long lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler) -{ - BSTR bsQueryLanguage, bsQuery; - HRESULT hr; - - bsQueryLanguage = BstrAlloc(strQueryLanguage); - bsQuery = BstrAlloc(strQuery); - - hr = IWbemServices_ExecNotificationQueryAsync(pSvc, bsQueryLanguage, - bsQuery, lFlags, pCtx, - pResponseHandler); - - BstrFree(bsQueryLanguage); - BstrFree(bsQuery); - - return hr; -} - - -HRESULT STDMETHODCALLTYPE call_IWbemLocator_ConnectServer( - IWbemLocator *pLoc, LPCWSTR strNetworkResource, LPCWSTR strUser, - LPCWSTR strPassword, LPCWSTR strLocale, long lSecurityFlags, - LPCWSTR strAuthority, IWbemContext *pCtx, IWbemServices **ppNamespace) -{ - BSTR bsNetworkResource, bsUser, bsPassword, bsLocale, bsAuthority; - HRESULT hr; - - bsNetworkResource = BstrAlloc(strNetworkResource); - bsUser = BstrAlloc(strUser); - bsPassword = BstrAlloc(strPassword); - bsLocale = BstrAlloc(strLocale); - bsAuthority = BstrAlloc(strAuthority); - - hr = IWbemLocator_ConnectServer(pLoc, bsNetworkResource, bsUser, - bsPassword, bsLocale, lSecurityFlags, - bsAuthority, pCtx, ppNamespace); - - BstrFree(bsNetworkResource); - BstrFree(bsUser); - BstrFree(bsPassword); - BstrFree(bsLocale); - BstrFree(bsAuthority); - - return hr; -} - - -enum event_types { EVENT_CONNECT, EVENT_DISCONNECT, EVENT_MEDIA_SPECIFIC, - EVENT_ADAPTER_ARRIVAL, EVENT_ADAPTER_REMOVAL }; - -static int ndis_events_get_adapter(struct ndis_events_data *events, - const char *ifname, const char *desc); - - -static int ndis_events_constructor(struct ndis_events_data *events) -{ - events->ref = 1; - - if (!CreatePipe(&events->read_pipe, &events->write_pipe, NULL, 512)) { - wpa_printf(MSG_ERROR, "CreatePipe() failed: %d", - (int) GetLastError()); - return -1; - } - events->event_avail = CreateEvent(NULL, TRUE, FALSE, NULL); - if (events->event_avail == NULL) { - wpa_printf(MSG_ERROR, "CreateEvent() failed: %d", - (int) GetLastError()); - CloseHandle(events->read_pipe); - CloseHandle(events->write_pipe); - return -1; - } - - return 0; -} - - -static void ndis_events_destructor(struct ndis_events_data *events) -{ - CloseHandle(events->read_pipe); - CloseHandle(events->write_pipe); - CloseHandle(events->event_avail); - IWbemServices_Release(events->pSvc); - IWbemLocator_Release(events->pLoc); - if (--wmi_refcnt == 0) - CoUninitialize(); -} - - -static HRESULT STDMETHODCALLTYPE -ndis_events_query_interface(IWbemObjectSink *this, REFIID riid, void **obj) -{ - *obj = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IWbemObjectSink)) { - *obj = this; - IWbemObjectSink_AddRef(this); - return NOERROR; - } - - return E_NOINTERFACE; -} - - -static ULONG STDMETHODCALLTYPE ndis_events_add_ref(IWbemObjectSink *this) -{ - struct ndis_events_data *events = (struct ndis_events_data *) this; - return ++events->ref; -} - - -static ULONG STDMETHODCALLTYPE ndis_events_release(IWbemObjectSink *this) -{ - struct ndis_events_data *events = (struct ndis_events_data *) this; - - if (--events->ref != 0) - return events->ref; - - ndis_events_destructor(events); - wpa_printf(MSG_DEBUG, "ndis_events: terminated"); - os_free(events->adapter_desc); - os_free(events->ifname); - os_free(events); - return 0; -} - - -static int ndis_events_send_event(struct ndis_events_data *events, - enum event_types type, - char *data, size_t data_len) -{ - char buf[512], *pos, *end; - int _type; - DWORD written; - - end = buf + sizeof(buf); - _type = (int) type; - os_memcpy(buf, &_type, sizeof(_type)); - pos = buf + sizeof(_type); - - if (data) { - if (2 + data_len > (size_t) (end - pos)) { - wpa_printf(MSG_DEBUG, "Not enough room for send_event " - "data (%d)", data_len); - return -1; - } - *pos++ = data_len >> 8; - *pos++ = data_len & 0xff; - os_memcpy(pos, data, data_len); - pos += data_len; - } - - if (WriteFile(events->write_pipe, buf, pos - buf, &written, NULL)) { - SetEvent(events->event_avail); - return 0; - } - wpa_printf(MSG_INFO, "WriteFile() failed: %d", (int) GetLastError()); - return -1; -} - - -static void ndis_events_media_connect(struct ndis_events_data *events) -{ - wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaConnect"); - ndis_events_send_event(events, EVENT_CONNECT, NULL, 0); -} - - -static void ndis_events_media_disconnect(struct ndis_events_data *events) -{ - wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaDisconnect"); - ndis_events_send_event(events, EVENT_DISCONNECT, NULL, 0); -} - - -static void ndis_events_media_specific(struct ndis_events_data *events, - IWbemClassObject *pObj) -{ - VARIANT vt; - HRESULT hr; - LONG lower, upper, k; - UCHAR ch; - char *data, *pos; - size_t data_len; - - wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaSpecificIndication"); - - /* This is the StatusBuffer from NdisMIndicateStatus() call */ - hr = IWbemClassObject_Get(pObj, L"NdisStatusMediaSpecificIndication", - 0, &vt, NULL, NULL); - if (FAILED(hr)) { - wpa_printf(MSG_DEBUG, "Could not get " - "NdisStatusMediaSpecificIndication from " - "the object?!"); - return; - } - - SafeArrayGetLBound(V_ARRAY(&vt), 1, &lower); - SafeArrayGetUBound(V_ARRAY(&vt), 1, &upper); - data_len = upper - lower + 1; - data = os_malloc(data_len); - if (data == NULL) { - wpa_printf(MSG_DEBUG, "Failed to allocate buffer for event " - "data"); - VariantClear(&vt); - return; - } - - pos = data; - for (k = lower; k <= upper; k++) { - SafeArrayGetElement(V_ARRAY(&vt), &k, &ch); - *pos++ = ch; - } - wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", (u8 *) data, data_len); - - VariantClear(&vt); - - ndis_events_send_event(events, EVENT_MEDIA_SPECIFIC, data, data_len); - - os_free(data); -} - - -static void ndis_events_adapter_arrival(struct ndis_events_data *events) -{ - wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterArrival"); - ndis_events_send_event(events, EVENT_ADAPTER_ARRIVAL, NULL, 0); -} - - -static void ndis_events_adapter_removal(struct ndis_events_data *events) -{ - wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterRemoval"); - ndis_events_send_event(events, EVENT_ADAPTER_REMOVAL, NULL, 0); -} - - -static HRESULT STDMETHODCALLTYPE -ndis_events_indicate(IWbemObjectSink *this, long lObjectCount, - IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray) -{ - struct ndis_events_data *events = (struct ndis_events_data *) this; - long i; - - if (events->terminating) { - wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore " - "indication - terminating"); - return WBEM_NO_ERROR; - } - /* wpa_printf(MSG_DEBUG, "Notification received - %d object(s)", - lObjectCount); */ - - for (i = 0; i < lObjectCount; i++) { - IWbemClassObject *pObj = ppObjArray[i]; - HRESULT hr; - VARIANT vtClass, vt; - - hr = IWbemClassObject_Get(pObj, L"__CLASS", 0, &vtClass, NULL, - NULL); - if (FAILED(hr)) { - wpa_printf(MSG_DEBUG, "Failed to get __CLASS from " - "event."); - break; - } - /* wpa_printf(MSG_DEBUG, "CLASS: '%S'", vtClass.bstrVal); */ - - hr = IWbemClassObject_Get(pObj, L"InstanceName", 0, &vt, NULL, - NULL); - if (FAILED(hr)) { - wpa_printf(MSG_DEBUG, "Failed to get InstanceName " - "from event."); - VariantClear(&vtClass); - break; - } - - if (wcscmp(vtClass.bstrVal, - L"MSNdis_NotifyAdapterArrival") == 0) { - wpa_printf(MSG_DEBUG, "ndis_events_indicate: Try to " - "update adapter description since it may " - "have changed with new adapter instance"); - ndis_events_get_adapter(events, events->ifname, NULL); - } - - if (wcscmp(events->adapter_desc, vt.bstrVal) != 0) { - wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore " - "indication for foreign adapter: " - "InstanceName: '%S' __CLASS: '%S'", - vt.bstrVal, vtClass.bstrVal); - VariantClear(&vtClass); - VariantClear(&vt); - continue; - } - VariantClear(&vt); - - if (wcscmp(vtClass.bstrVal, - L"MSNdis_StatusMediaSpecificIndication") == 0) { - ndis_events_media_specific(events, pObj); - } else if (wcscmp(vtClass.bstrVal, - L"MSNdis_StatusMediaConnect") == 0) { - ndis_events_media_connect(events); - } else if (wcscmp(vtClass.bstrVal, - L"MSNdis_StatusMediaDisconnect") == 0) { - ndis_events_media_disconnect(events); - } else if (wcscmp(vtClass.bstrVal, - L"MSNdis_NotifyAdapterArrival") == 0) { - ndis_events_adapter_arrival(events); - } else if (wcscmp(vtClass.bstrVal, - L"MSNdis_NotifyAdapterRemoval") == 0) { - ndis_events_adapter_removal(events); - } else { - wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: " - "'%S'", vtClass.bstrVal); - } - - VariantClear(&vtClass); - } - - return WBEM_NO_ERROR; -} - - -static HRESULT STDMETHODCALLTYPE -ndis_events_set_status(IWbemObjectSink *this, long lFlags, HRESULT hResult, - BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam) -{ - return WBEM_NO_ERROR; -} - - -static int notification_query(IWbemObjectSink *pDestSink, - IWbemServices *pSvc, const char *class_name) -{ - HRESULT hr; - WCHAR query[256]; - - _snwprintf(query, 256, - L"SELECT * FROM %S", class_name); - wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query); - hr = call_IWbemServices_ExecNotificationQueryAsync( - pSvc, L"WQL", query, 0, 0, pDestSink); - if (FAILED(hr)) { - wpa_printf(MSG_DEBUG, "ExecNotificationQueryAsync for %s " - "failed with hresult of 0x%x", - class_name, (int) hr); - return -1; - } - - return 0; -} - - -static int register_async_notification(IWbemObjectSink *pDestSink, - IWbemServices *pSvc) -{ - int i; - const char *class_list[] = { - "MSNdis_StatusMediaConnect", - "MSNdis_StatusMediaDisconnect", - "MSNdis_StatusMediaSpecificIndication", - "MSNdis_NotifyAdapterArrival", - "MSNdis_NotifyAdapterRemoval", - NULL - }; - - for (i = 0; class_list[i]; i++) { - if (notification_query(pDestSink, pSvc, class_list[i]) < 0) - return -1; - } - - return 0; -} - - -void ndis_events_deinit(struct ndis_events_data *events) -{ - events->terminating = 1; - IWbemServices_CancelAsyncCall(events->pSvc, &events->sink); - IWbemObjectSink_Release(&events->sink); - /* - * Rest of deinitialization is done in ndis_events_destructor() once - * all reference count drops to zero. - */ -} - - -static int ndis_events_use_desc(struct ndis_events_data *events, - const char *desc) -{ - char *tmp, *pos; - size_t len; - - if (desc == NULL) { - if (events->adapter_desc == NULL) - return -1; - /* Continue using old description */ - return 0; - } - - tmp = os_strdup(desc); - if (tmp == NULL) - return -1; - - pos = os_strstr(tmp, " (Microsoft's Packet Scheduler)"); - if (pos) - *pos = '\0'; - - len = os_strlen(tmp); - events->adapter_desc = os_malloc((len + 1) * sizeof(WCHAR)); - if (events->adapter_desc == NULL) { - os_free(tmp); - return -1; - } - _snwprintf(events->adapter_desc, len + 1, L"%S", tmp); - os_free(tmp); - return 0; -} - - -static int ndis_events_get_adapter(struct ndis_events_data *events, - const char *ifname, const char *desc) -{ - HRESULT hr; - IWbemServices *pSvc; -#define MAX_QUERY_LEN 256 - WCHAR query[MAX_QUERY_LEN]; - IEnumWbemClassObject *pEnumerator; - IWbemClassObject *pObj; - ULONG uReturned; - VARIANT vt; - int len, pos; - - /* - * Try to get adapter descriptor through WMI CIMv2 Win32_NetworkAdapter - * to have better probability of matching with InstanceName from - * MSNdis events. If this fails, use the provided description. - */ - - os_free(events->adapter_desc); - events->adapter_desc = NULL; - - hr = call_IWbemLocator_ConnectServer( - events->pLoc, L"ROOT\\CIMV2", NULL, NULL, 0, 0, 0, 0, &pSvc); - if (FAILED(hr)) { - wpa_printf(MSG_ERROR, "ndis_events: Could not connect to WMI " - "server (ROOT\\CIMV2) - error 0x%x", (int) hr); - return ndis_events_use_desc(events, desc); - } - wpa_printf(MSG_DEBUG, "ndis_events: Connected to ROOT\\CIMV2."); - - _snwprintf(query, MAX_QUERY_LEN, - L"SELECT Index FROM Win32_NetworkAdapterConfiguration " - L"WHERE SettingID='%S'", ifname); - wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query); - - hr = call_IWbemServices_ExecQuery( - pSvc, L"WQL", query, - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - NULL, &pEnumerator); - if (!SUCCEEDED(hr)) { - wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface " - "GUID from Win32_NetworkAdapterConfiguration: " - "0x%x", (int) hr); - IWbemServices_Release(pSvc); - return ndis_events_use_desc(events, desc); - } - - uReturned = 0; - hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1, - &pObj, &uReturned); - if (!SUCCEEDED(hr) || uReturned == 0) { - wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface " - "GUID from Win32_NetworkAdapterConfiguration: " - "0x%x", (int) hr); - IEnumWbemClassObject_Release(pEnumerator); - IWbemServices_Release(pSvc); - return ndis_events_use_desc(events, desc); - } - IEnumWbemClassObject_Release(pEnumerator); - - VariantInit(&vt); - hr = IWbemClassObject_Get(pObj, L"Index", 0, &vt, NULL, NULL); - if (!SUCCEEDED(hr)) { - wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Index from " - "Win32_NetworkAdapterConfiguration: 0x%x", - (int) hr); - IWbemServices_Release(pSvc); - return ndis_events_use_desc(events, desc); - } - - _snwprintf(query, MAX_QUERY_LEN, - L"SELECT Name,PNPDeviceID FROM Win32_NetworkAdapter WHERE " - L"Index=%d", - vt.uintVal); - wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query); - VariantClear(&vt); - IWbemClassObject_Release(pObj); - - hr = call_IWbemServices_ExecQuery( - pSvc, L"WQL", query, - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - NULL, &pEnumerator); - if (!SUCCEEDED(hr)) { - wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface " - "from Win32_NetworkAdapter: 0x%x", (int) hr); - IWbemServices_Release(pSvc); - return ndis_events_use_desc(events, desc); - } - - uReturned = 0; - hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1, - &pObj, &uReturned); - if (!SUCCEEDED(hr) || uReturned == 0) { - wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface " - "from Win32_NetworkAdapter: 0x%x", (int) hr); - IEnumWbemClassObject_Release(pEnumerator); - IWbemServices_Release(pSvc); - return ndis_events_use_desc(events, desc); - } - IEnumWbemClassObject_Release(pEnumerator); - - hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL); - if (!SUCCEEDED(hr)) { - wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from " - "Win32_NetworkAdapter: 0x%x", (int) hr); - IWbemClassObject_Release(pObj); - IWbemServices_Release(pSvc); - return ndis_events_use_desc(events, desc); - } - - wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::Name='%S'", - vt.bstrVal); - events->adapter_desc = _wcsdup(vt.bstrVal); - VariantClear(&vt); - - /* - * Try to get even better candidate for matching with InstanceName - * from Win32_PnPEntity. This is needed at least for some USB cards - * that can change the InstanceName whenever being unplugged and - * plugged again. - */ - - hr = IWbemClassObject_Get(pObj, L"PNPDeviceID", 0, &vt, NULL, NULL); - if (!SUCCEEDED(hr)) { - wpa_printf(MSG_DEBUG, "ndis_events: Failed to get PNPDeviceID " - "from Win32_NetworkAdapter: 0x%x", (int) hr); - IWbemClassObject_Release(pObj); - IWbemServices_Release(pSvc); - if (events->adapter_desc == NULL) - return ndis_events_use_desc(events, desc); - return 0; /* use Win32_NetworkAdapter::Name */ - } - - wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::PNPDeviceID=" - "'%S'", vt.bstrVal); - - len = _snwprintf(query, MAX_QUERY_LEN, - L"SELECT Name FROM Win32_PnPEntity WHERE DeviceID='"); - if (len < 0 || len >= MAX_QUERY_LEN - 1) { - VariantClear(&vt); - IWbemClassObject_Release(pObj); - IWbemServices_Release(pSvc); - if (events->adapter_desc == NULL) - return ndis_events_use_desc(events, desc); - return 0; /* use Win32_NetworkAdapter::Name */ - } - - /* Escape \ as \\ */ - for (pos = 0; vt.bstrVal[pos] && len < MAX_QUERY_LEN - 2; pos++) { - if (vt.bstrVal[pos] == '\\') { - if (len >= MAX_QUERY_LEN - 3) - break; - query[len++] = '\\'; - } - query[len++] = vt.bstrVal[pos]; - } - query[len++] = L'\''; - query[len] = L'\0'; - VariantClear(&vt); - IWbemClassObject_Release(pObj); - wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query); - - hr = call_IWbemServices_ExecQuery( - pSvc, L"WQL", query, - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - NULL, &pEnumerator); - if (!SUCCEEDED(hr)) { - wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface " - "Name from Win32_PnPEntity: 0x%x", (int) hr); - IWbemServices_Release(pSvc); - if (events->adapter_desc == NULL) - return ndis_events_use_desc(events, desc); - return 0; /* use Win32_NetworkAdapter::Name */ - } - - uReturned = 0; - hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1, - &pObj, &uReturned); - if (!SUCCEEDED(hr) || uReturned == 0) { - wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface " - "from Win32_PnPEntity: 0x%x", (int) hr); - IEnumWbemClassObject_Release(pEnumerator); - IWbemServices_Release(pSvc); - if (events->adapter_desc == NULL) - return ndis_events_use_desc(events, desc); - return 0; /* use Win32_NetworkAdapter::Name */ - } - IEnumWbemClassObject_Release(pEnumerator); - - hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL); - if (!SUCCEEDED(hr)) { - wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from " - "Win32_PnPEntity: 0x%x", (int) hr); - IWbemClassObject_Release(pObj); - IWbemServices_Release(pSvc); - if (events->adapter_desc == NULL) - return ndis_events_use_desc(events, desc); - return 0; /* use Win32_NetworkAdapter::Name */ - } - - wpa_printf(MSG_DEBUG, "ndis_events: Win32_PnPEntity::Name='%S'", - vt.bstrVal); - os_free(events->adapter_desc); - events->adapter_desc = _wcsdup(vt.bstrVal); - VariantClear(&vt); - - IWbemClassObject_Release(pObj); - - IWbemServices_Release(pSvc); - - if (events->adapter_desc == NULL) - return ndis_events_use_desc(events, desc); - - return 0; -} - - -struct ndis_events_data * -ndis_events_init(HANDLE *read_pipe, HANDLE *event_avail, - const char *ifname, const char *desc) -{ - HRESULT hr; - IWbemObjectSink *pSink; - struct ndis_events_data *events; - - events = os_zalloc(sizeof(*events)); - if (events == NULL) { - wpa_printf(MSG_ERROR, "Could not allocate sink for events."); - return NULL; - } - events->ifname = os_strdup(ifname); - if (events->ifname == NULL) { - os_free(events); - return NULL; - } - - if (wmi_refcnt++ == 0) { - hr = CoInitializeEx(0, COINIT_MULTITHREADED); - if (FAILED(hr)) { - wpa_printf(MSG_ERROR, "CoInitializeEx() failed - " - "returned 0x%x", (int) hr); - os_free(events); - return NULL; - } - } - - if (wmi_first) { - /* CoInitializeSecurity() must be called once and only once - * per process, so let's use wmi_first flag to protect against - * multiple calls. */ - wmi_first = 0; - - hr = CoInitializeSecurity(NULL, -1, NULL, NULL, - RPC_C_AUTHN_LEVEL_PKT_PRIVACY, - RPC_C_IMP_LEVEL_IMPERSONATE, - NULL, EOAC_SECURE_REFS, NULL); - if (FAILED(hr)) { - wpa_printf(MSG_ERROR, "CoInitializeSecurity() failed " - "- returned 0x%x", (int) hr); - os_free(events); - return NULL; - } - } - - hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, - &IID_IWbemLocator, - (LPVOID *) (void *) &events->pLoc); - if (FAILED(hr)) { - wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned " - "0x%x", (int) hr); - CoUninitialize(); - os_free(events); - return NULL; - } - - if (ndis_events_get_adapter(events, ifname, desc) < 0) { - CoUninitialize(); - os_free(events); - return NULL; - } - wpa_printf(MSG_DEBUG, "ndis_events: use adapter descriptor '%S'", - events->adapter_desc); - - hr = call_IWbemLocator_ConnectServer( - events->pLoc, L"ROOT\\WMI", NULL, NULL, - 0, 0, 0, 0, &events->pSvc); - if (FAILED(hr)) { - wpa_printf(MSG_ERROR, "Could not connect to server - error " - "0x%x", (int) hr); - CoUninitialize(); - os_free(events->adapter_desc); - os_free(events); - return NULL; - } - wpa_printf(MSG_DEBUG, "Connected to ROOT\\WMI."); - - ndis_events_constructor(events); - pSink = &events->sink; - pSink->lpVtbl = &events->sink_vtbl; - events->sink_vtbl.QueryInterface = ndis_events_query_interface; - events->sink_vtbl.AddRef = ndis_events_add_ref; - events->sink_vtbl.Release = ndis_events_release; - events->sink_vtbl.Indicate = ndis_events_indicate; - events->sink_vtbl.SetStatus = ndis_events_set_status; - - if (register_async_notification(pSink, events->pSvc) < 0) { - wpa_printf(MSG_DEBUG, "Failed to register async " - "notifications"); - ndis_events_destructor(events); - os_free(events->adapter_desc); - os_free(events); - return NULL; - } - - *read_pipe = events->read_pipe; - *event_avail = events->event_avail; - - return events; -} diff --git a/contrib/hostapd/src/drivers/netlink.c b/contrib/hostapd/src/drivers/netlink.c deleted file mode 100644 index 2fa20b1ebb..0000000000 --- a/contrib/hostapd/src/drivers/netlink.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Netlink helper functions for driver wrappers - * Copyright (c) 2002-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eloop.h" -#include "priv_netlink.h" -#include "netlink.h" - - -struct netlink_data { - struct netlink_config *cfg; - int sock; -}; - - -static void netlink_receive_link(struct netlink_data *netlink, - void (*cb)(void *ctx, struct ifinfomsg *ifi, - u8 *buf, size_t len), - struct nlmsghdr *h) -{ - if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg)) - return; - cb(netlink->cfg->ctx, NLMSG_DATA(h), - (u8 *) NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)), - NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg))); -} - - -static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct netlink_data *netlink = eloop_ctx; - char buf[8192]; - int left; - struct sockaddr_nl from; - socklen_t fromlen; - struct nlmsghdr *h; - int max_events = 10; - -try_again: - fromlen = sizeof(from); - left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, - (struct sockaddr *) &from, &fromlen); - if (left < 0) { - if (errno != EINTR && errno != EAGAIN) - wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s", - strerror(errno)); - return; - } - - h = (struct nlmsghdr *) buf; - while (NLMSG_OK(h, left)) { - switch (h->nlmsg_type) { - case RTM_NEWLINK: - netlink_receive_link(netlink, netlink->cfg->newlink_cb, - h); - break; - case RTM_DELLINK: - netlink_receive_link(netlink, netlink->cfg->dellink_cb, - h); - break; - } - - h = NLMSG_NEXT(h, left); - } - - if (left > 0) { - wpa_printf(MSG_DEBUG, "netlink: %d extra bytes in the end of " - "netlink message", left); - } - - if (--max_events > 0) { - /* - * Try to receive all events in one eloop call in order to - * limit race condition on cases where AssocInfo event, Assoc - * event, and EAPOL frames are received more or less at the - * same time. We want to process the event messages first - * before starting EAPOL processing. - */ - goto try_again; - } -} - - -struct netlink_data * netlink_init(struct netlink_config *cfg) -{ - struct netlink_data *netlink; - struct sockaddr_nl local; - - netlink = os_zalloc(sizeof(*netlink)); - if (netlink == NULL) - return NULL; - - netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (netlink->sock < 0) { - wpa_printf(MSG_ERROR, "netlink: Failed to open netlink " - "socket: %s", strerror(errno)); - netlink_deinit(netlink); - return NULL; - } - - os_memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0) - { - wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink " - "socket: %s", strerror(errno)); - netlink_deinit(netlink); - return NULL; - } - - eloop_register_read_sock(netlink->sock, netlink_receive, netlink, - NULL); - - netlink->cfg = cfg; - - return netlink; -} - - -void netlink_deinit(struct netlink_data *netlink) -{ - if (netlink == NULL) - return; - if (netlink->sock >= 0) { - eloop_unregister_read_sock(netlink->sock); - close(netlink->sock); - } - os_free(netlink->cfg); - os_free(netlink); -} - - -static const char * linkmode_str(int mode) -{ - switch (mode) { - case -1: - return "no change"; - case 0: - return "kernel-control"; - case 1: - return "userspace-control"; - } - return "?"; -} - - -static const char * operstate_str(int state) -{ - switch (state) { - case -1: - return "no change"; - case IF_OPER_DORMANT: - return "IF_OPER_DORMANT"; - case IF_OPER_UP: - return "IF_OPER_UP"; - } - return "?"; -} - - -int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, - int linkmode, int operstate) -{ - struct { - struct nlmsghdr hdr; - struct ifinfomsg ifinfo; - char opts[16]; - } req; - struct rtattr *rta; - static int nl_seq; - ssize_t ret; - - os_memset(&req, 0, sizeof(req)); - - req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.hdr.nlmsg_type = RTM_SETLINK; - req.hdr.nlmsg_flags = NLM_F_REQUEST; - req.hdr.nlmsg_seq = ++nl_seq; - req.hdr.nlmsg_pid = 0; - - req.ifinfo.ifi_family = AF_UNSPEC; - req.ifinfo.ifi_type = 0; - req.ifinfo.ifi_index = ifindex; - req.ifinfo.ifi_flags = 0; - req.ifinfo.ifi_change = 0; - - if (linkmode != -1) { - rta = aliasing_hide_typecast( - ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)), - struct rtattr); - rta->rta_type = IFLA_LINKMODE; - rta->rta_len = RTA_LENGTH(sizeof(char)); - *((char *) RTA_DATA(rta)) = linkmode; - req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + - RTA_LENGTH(sizeof(char)); - } - if (operstate != -1) { - rta = aliasing_hide_typecast( - ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)), - struct rtattr); - rta->rta_type = IFLA_OPERSTATE; - rta->rta_len = RTA_LENGTH(sizeof(char)); - *((char *) RTA_DATA(rta)) = operstate; - req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + - RTA_LENGTH(sizeof(char)); - } - - wpa_printf(MSG_DEBUG, "netlink: Operstate: ifindex=%d linkmode=%d (%s), operstate=%d (%s)", - ifindex, linkmode, linkmode_str(linkmode), - operstate, operstate_str(operstate)); - - ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA " - "failed: %s (assume operstate is not supported)", - strerror(errno)); - } - - return ret < 0 ? -1 : 0; -} diff --git a/contrib/hostapd/src/drivers/netlink.h b/contrib/hostapd/src/drivers/netlink.h deleted file mode 100644 index 3a7340e515..0000000000 --- a/contrib/hostapd/src/drivers/netlink.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Netlink helper functions for driver wrappers - * Copyright (c) 2002-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef NETLINK_H -#define NETLINK_H - -struct netlink_data; -struct ifinfomsg; - -struct netlink_config { - void *ctx; - void (*newlink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf, - size_t len); - void (*dellink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf, - size_t len); -}; - -struct netlink_data * netlink_init(struct netlink_config *cfg); -void netlink_deinit(struct netlink_data *netlink); -int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, - int linkmode, int operstate); - -#endif /* NETLINK_H */ diff --git a/contrib/hostapd/src/drivers/nl80211_copy.h b/contrib/hostapd/src/drivers/nl80211_copy.h deleted file mode 100644 index 91054fd660..0000000000 --- a/contrib/hostapd/src/drivers/nl80211_copy.h +++ /dev/null @@ -1,4040 +0,0 @@ -#ifndef __LINUX_NL80211_H -#define __LINUX_NL80211_H -/* - * 802.11 netlink interface public header - * - * Copyright 2006-2010 Johannes Berg - * Copyright 2008 Michael Wu - * Copyright 2008 Luis Carlos Cobo - * Copyright 2008 Michael Buesch - * Copyright 2008, 2009 Luis R. Rodriguez - * Copyright 2008 Jouni Malinen - * Copyright 2008 Colin McCabe - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include - -#define NL80211_GENL_NAME "nl80211" - -/** - * DOC: Station handling - * - * Stations are added per interface, but a special case exists with VLAN - * interfaces. When a station is bound to an AP interface, it may be moved - * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN). - * The station is still assumed to belong to the AP interface it was added - * to. - * - * Station handling varies per interface type and depending on the driver's - * capabilities. - * - * For drivers supporting TDLS with external setup (WIPHY_FLAG_SUPPORTS_TDLS - * and WIPHY_FLAG_TDLS_EXTERNAL_SETUP), the station lifetime is as follows: - * - a setup station entry is added, not yet authorized, without any rate - * or capability information, this just exists to avoid race conditions - * - when the TDLS setup is done, a single NL80211_CMD_SET_STATION is valid - * to add rate and capability information to the station and at the same - * time mark it authorized. - * - %NL80211_TDLS_ENABLE_LINK is then used - * - after this, the only valid operation is to remove it by tearing down - * the TDLS link (%NL80211_TDLS_DISABLE_LINK) - * - * TODO: need more info for other interface types - */ - -/** - * DOC: Frame transmission/registration support - * - * Frame transmission and registration support exists to allow userspace - * management entities such as wpa_supplicant react to management frames - * that are not being handled by the kernel. This includes, for example, - * certain classes of action frames that cannot be handled in the kernel - * for various reasons. - * - * Frame registration is done on a per-interface basis and registrations - * cannot be removed other than by closing the socket. It is possible to - * specify a registration filter to register, for example, only for a - * certain type of action frame. In particular with action frames, those - * that userspace registers for will not be returned as unhandled by the - * driver, so that the registered application has to take responsibility - * for doing that. - * - * The type of frame that can be registered for is also dependent on the - * driver and interface type. The frame types are advertised in wiphy - * attributes so applications know what to expect. - * - * NOTE: When an interface changes type while registrations are active, - * these registrations are ignored until the interface type is - * changed again. This means that changing the interface type can - * lead to a situation that couldn't otherwise be produced, but - * any such registrations will be dormant in the sense that they - * will not be serviced, i.e. they will not receive any frames. - * - * Frame transmission allows userspace to send for example the required - * responses to action frames. It is subject to some sanity checking, - * but many frames can be transmitted. When a frame was transmitted, its - * status is indicated to the sending socket. - * - * For more technical details, see the corresponding command descriptions - * below. - */ - -/** - * 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. - */ - -/** - * DOC: packet coalesce support - * - * In most cases, host that receives IPv4 and IPv6 multicast/broadcast - * packets does not do anything with these packets. Therefore the - * reception of these unwanted packets causes unnecessary processing - * and power consumption. - * - * Packet coalesce feature helps to reduce number of received interrupts - * to host by buffering these packets in firmware/hardware for some - * predefined time. Received interrupt will be generated when one of the - * following events occur. - * a) Expiration of hardware timer whose expiration time is set to maximum - * coalescing delay of matching coalesce rule. - * b) Coalescing buffer in hardware reaches it's limit. - * c) Packet doesn't match any of the configured coalesce rules. - * - * User needs to configure following parameters for creating a coalesce - * rule. - * a) Maximum coalescing delay - * b) List of packet patterns which needs to be matched - * c) Condition for coalescence. pattern 'match' or 'no match' - * Multiple such rules can be created. - */ - -/** - * enum nl80211_commands - supported nl80211 commands - * - * @NL80211_CMD_UNSPEC: unspecified command to catch errors - * - * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request - * to get a list of all present wiphys. - * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or - * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, - * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the - * attributes determining the channel width; this is used for setting - * monitor mode channel), %NL80211_ATTR_WIPHY_RETRY_SHORT, - * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, - * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD. - * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL - * instead, the support here is for backward compatibility only. - * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request - * or rename notification. Has attributes %NL80211_ATTR_WIPHY and - * %NL80211_ATTR_WIPHY_NAME. - * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes - * %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME. - * - * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration; - * either a dump request on a %NL80211_ATTR_WIPHY or a specific get - * on an %NL80211_ATTR_IFINDEX is supported. - * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires - * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE. - * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response - * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX, - * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also - * be sent from userspace to request creation of a new virtual interface, - * then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and - * %NL80211_ATTR_IFNAME. - * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes - * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from - * userspace to request deletion of a virtual interface, then requires - * attribute %NL80211_ATTR_IFINDEX. - * - * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified - * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. - * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT, - * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD. - * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, - * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER, - * and %NL80211_ATTR_KEY_SEQ attributes. - * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX - * or %NL80211_ATTR_MAC. - * - * @NL80211_CMD_GET_BEACON: (not used) - * @NL80211_CMD_SET_BEACON: change the beacon on an access point interface - * using the %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL - * attributes. For drivers that generate the beacon and probe responses - * internally, the following attributes must be provided: %NL80211_ATTR_IE, - * %NL80211_ATTR_IE_PROBE_RESP and %NL80211_ATTR_IE_ASSOC_RESP. - * @NL80211_CMD_START_AP: Start AP operation on an AP interface, parameters - * are like for %NL80211_CMD_SET_BEACON, and additionally parameters that - * do not change are used, these include %NL80211_ATTR_BEACON_INTERVAL, - * %NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID, - * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE, - * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS, - * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY, - * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_INACTIVITY_TIMEOUT, - * %NL80211_ATTR_ACL_POLICY and %NL80211_ATTR_MAC_ADDRS. - * The channel to use can be set on the interface or be given using the - * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width. - * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP - * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface - * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP - * - * @NL80211_CMD_GET_STATION: Get station attributes for station identified by - * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. - * @NL80211_CMD_SET_STATION: Set station attributes for station identified by - * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. - * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the - * the interface identified by %NL80211_ATTR_IFINDEX. - * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC - * or, if no MAC address given, all stations, on the interface identified - * by %NL80211_ATTR_IFINDEX. - * - * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to - * destination %NL80211_ATTR_MAC on the interface identified by - * %NL80211_ATTR_IFINDEX. - * @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 - * or, if no MAC address given, all mesh paths, on the interface identified - * by %NL80211_ATTR_IFINDEX. - * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by - * %NL80211_ATTR_IFINDEX. - * - * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set - * regulatory domain. - * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command - * after being queried by the kernel. CRDA replies by sending a regulatory - * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our - * current alpha2 if it found a match. It also provides - * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each - * regulatory rule is a nested set of attributes given by - * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and - * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by - * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and - * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP. - * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain - * 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_CONFIG: Get mesh networking properties for the - * interface identified by %NL80211_ATTR_IFINDEX - * - * @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 - * interface is identified with %NL80211_ATTR_IFINDEX and the management - * frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be - * added to the end of the specified management frame is specified with - * %NL80211_ATTR_IE. If the command succeeds, the requested data will be - * added to all specified management frames generated by - * kernel/firmware/driver. - * Note: This command has been removed and it is only reserved at this - * point to avoid re-using existing command number. The functionality this - * command was planned for has been provided with cleaner design with the - * option to specify additional IEs in NL80211_CMD_TRIGGER_SCAN, - * NL80211_CMD_AUTHENTICATE, NL80211_CMD_ASSOCIATE, - * NL80211_CMD_DEAUTHENTICATE, and NL80211_CMD_DISASSOCIATE. - * - * @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 - * NL80211_CMD_GET_SURVEY and on the "scan" multicast group) - * - * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC - * (for the BSSID) and %NL80211_ATTR_PMKID. - * @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC - * (for the BSSID) and %NL80211_ATTR_PMKID. - * @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries. - * - * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain - * has been changed and provides details of the request information - * that caused the change such as who initiated the regulatory request - * (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx - * (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if - * the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or - * %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain - * set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is - * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on - * to (%NL80211_ATTR_REG_ALPHA2). - * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon - * has been found while world roaming thus enabling active scan or - * any mode of operation that initiates TX (beacons) on a channel - * where we would not have been able to do either before. As an example - * if you are world roaming (regulatory domain set to world or if your - * driver is using a custom world roaming regulatory domain) and while - * doing a passive scan on the 5 GHz band you find an AP there (if not - * on a DFS channel) you will now be able to actively scan for that AP - * or use AP mode on your card on that same channel. Note that this will - * never be used for channels 1-11 on the 2 GHz band as they are always - * enabled world wide. This beacon hint is only sent if your device had - * either disabled active scanning or beaconing on a channel. We send to - * userspace the wiphy on which we removed a restriction from - * (%NL80211_ATTR_WIPHY) and the channel on which this occurred - * before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER) - * the beacon hint was processed. - * - * @NL80211_CMD_AUTHENTICATE: authentication request and notification. - * This command is used both as a command (request to authenticate) and - * as an event on the "mlme" multicast group indicating completion of the - * authentication process. - * When used as a command, %NL80211_ATTR_IFINDEX is used to identify the - * interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and - * BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify - * the SSID (mainly for association, but is included in authentication - * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used - * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE - * is used to specify the authentication type. %NL80211_ATTR_IE is used to - * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs) - * to be added to the frame. - * When used as an event, this reports reception of an Authentication - * frame in station and IBSS modes when the local MLME processed the - * frame, i.e., it was for the local STA and was received in correct - * state. This is similar to MLME-AUTHENTICATE.confirm primitive in the - * MLME SAP interface (kernel providing MLME, userspace SME). The - * included %NL80211_ATTR_FRAME attribute contains the management frame - * (including both the header and frame body, but not FCS). This event is - * also used to indicate if the authentication attempt timed out. In that - * case the %NL80211_ATTR_FRAME attribute is replaced with a - * %NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which - * pending authentication timed out). - * @NL80211_CMD_ASSOCIATE: association request and notification; like - * NL80211_CMD_AUTHENTICATE but for Association and Reassociation - * (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request, - * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives). - * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like - * NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to - * MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication - * primitives). - * @NL80211_CMD_DISASSOCIATE: disassociation request and notification; like - * NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to - * MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives). - * - * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael - * MIC (part of TKIP) failure; sent on the "mlme" multicast group; the - * event includes %NL80211_ATTR_MAC to describe the source MAC address of - * the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key - * type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and - * %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this - * event matches with MLME-MICHAELMICFAILURE.indication() primitive - * - * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a - * FREQ attribute (for the initial frequency if no peer can be found) - * and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those - * should be fixed rather than automatically determined. Can only be - * executed on a network interface that is UP, and fixed BSSID/FREQ - * may be rejected. Another optional parameter is the beacon interval, - * given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not - * given defaults to 100 TU (102.4ms). - * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is - * determined by the network interface. - * - * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute - * to identify the device, and the TESTDATA blob attribute to pass through - * to the driver. - * - * @NL80211_CMD_CONNECT: connection request and notification; this command - * requests to connect to a specified network but without separating - * auth and assoc steps. For this, you need to specify the SSID in a - * %NL80211_ATTR_SSID attribute, and can optionally specify the association - * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP, - * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, - * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and - * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT. - * Background scan period can optionally be - * specified in %NL80211_ATTR_BG_SCAN_PERIOD, - * if not specified default background scan configuration - * in driver is used and if period value is 0, bg scan will be disabled. - * This attribute is ignored if driver does not support roam scan. - * It is also sent as an event, with the BSSID and response IEs when the - * connection is established or failed to be established. This can be - * determined by the STATUS_CODE attribute. - * @NL80211_CMD_ROAM: request that the card roam (currently not implemented), - * sent as an event when the card/driver roamed by itself. - * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify - * userspace that a connection was dropped by the AP or due to other - * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and - * %NL80211_ATTR_REASON_CODE attributes are used. - * - * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices - * associated with this wiphy must be down and will follow. - * - * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified - * channel for the specified amount of time. This can be used to do - * off-channel operations like transmit a Public Action frame and wait for - * a response while being associated to an AP on another channel. - * %NL80211_ATTR_IFINDEX is used to specify which interface (and thus - * radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the - * frequency for the operation. - * %NL80211_ATTR_DURATION is used to specify the duration in milliseconds - * to remain on the channel. This command is also used as an event to - * notify when the requested duration starts (it may take a while for the - * driver to schedule this time due to other concurrent needs for the - * radio). - * When called, this operation returns a cookie (%NL80211_ATTR_COOKIE) - * that will be included with any events pertaining to this request; - * the cookie is also used to cancel the request. - * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a - * pending remain-on-channel duration if the desired operation has been - * completed prior to expiration of the originally requested duration. - * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the - * radio. The %NL80211_ATTR_COOKIE attribute must be given as well to - * uniquely identify the request. - * This command is also used as an event to notify when a requested - * remain-on-channel duration has expired. - * - * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX - * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface - * and @NL80211_ATTR_TX_RATES the set of allowed rates. - * - * @NL80211_CMD_REGISTER_FRAME: Register for receiving certain mgmt frames - * (via @NL80211_CMD_FRAME) for processing in userspace. This command - * requires an interface index, a frame type attribute (optional for - * backward compatibility reasons, if not given assumes action frames) - * and a match attribute containing the first few bytes of the frame - * that should match, e.g. a single byte for only a category match or - * four bytes for vendor frames including the OUI. The registration - * cannot be dropped, but is removed automatically when the netlink - * socket is closed. Multiple registrations can be made. - * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for - * backward compatibility - * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This - * command is used both as a request to transmit a management frame and - * as an event indicating reception of a frame that was not processed in - * kernel code, but is for us (i.e., which may need to be processed in a - * user space application). %NL80211_ATTR_FRAME is used to specify the - * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ is used - * to indicate on which channel the frame is to be transmitted or was - * received. If this channel is not the current channel (remain-on-channel - * or the operational channel) the device will switch to the given channel - * and transmit the frame, optionally waiting for a response for the time - * 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. - * @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility. - * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame - * transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies - * the TX command and %NL80211_ATTR_FRAME includes the contents of the - * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged - * the frame. - * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for - * backward compatibility. - * - * @NL80211_CMD_SET_POWER_SAVE: Set powersave, using %NL80211_ATTR_PS_STATE - * @NL80211_CMD_GET_POWER_SAVE: Get powersave status in %NL80211_ATTR_PS_STATE - * - * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command - * is used to configure connection quality monitoring notification trigger - * levels. - * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This - * command is used as an event to indicate the that a trigger level was - * reached. - * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ - * and the attributes determining channel width) the given interface - * (identifed by %NL80211_ATTR_IFINDEX) shall operate on. - * In case multiple channels are supported by the device, the mechanism - * with which it switches channels is implementation-defined. - * When a monitor interface is given, it can only switch channel while - * no other interfaces are operating to avoid disturbing the operation - * of any other interfaces, and other interfaces will again take - * precedence when they are used. - * - * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface. - * - * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial - * mesh config parameters may be given. - * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the - * network is determined by the network interface. - * - * @NL80211_CMD_UNPROT_DEAUTHENTICATE: Unprotected deauthentication frame - * notification. This event is used to indicate that an unprotected - * deauthentication frame was dropped when MFP is in use. - * @NL80211_CMD_UNPROT_DISASSOCIATE: Unprotected disassociation frame - * 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, - * @NL80211_MESH_SETUP_USERSPACE_AMPE, or - * @NL80211_MESH_SETUP_USERSPACE_MPM 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. - * The @NL80211_CMD_SET_WOWLAN command can also be used as a notification - * from the driver reporting the wakeup reason. In this case, the - * @NL80211_ATTR_WOWLAN_TRIGGERS attribute will contain the reason - * for the wakeup, if it was caused by wireless. If it is not present - * in the wakeup notification, the wireless device didn't cause the - * wakeup but reports that it was woken up. - * - * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver - * the necessary information for supporting GTK rekey offload. This - * 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). - * In addition, this can be used as an event to request userspace to take - * actions on TDLS links (set up a new link or tear down an existing one). - * In such events, %NL80211_ATTR_TDLS_OPERATION indicates the requested - * operation, %NL80211_ATTR_MAC contains the peer MAC address, and - * %NL80211_ATTR_REASON_CODE the reason code to be used (only with - * %NL80211_TDLS_TEARDOWN). - * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. The - * %NL80211_ATTR_TDLS_ACTION attribute determines the type of frame to be - * sent. Public Action codes (802.11-2012 8.1.5.1) will be sent as - * 802.11 management frames, while TDLS action codes (802.11-2012 - * 8.5.13.1) will be encapsulated and sent as data frames. The currently - * supported Public Action code is %WLAN_PUB_ACTION_TDLS_DISCOVER_RES - * and the currently supported TDLS actions codes are given in - * &enum ieee80211_tdls_actioncode. - * - * @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_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether - * No Acknowledgement Policy should be applied. - * - * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels - * independently of the userspace SME, send this event indicating - * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the - * attributes determining channel width. - * - * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by - * its %NL80211_ATTR_WDEV identifier. It must have been created with - * %NL80211_CMD_NEW_INTERFACE previously. After it has been started, the - * P2P Device can be used for P2P operations, e.g. remain-on-channel and - * public action frame TX. - * @NL80211_CMD_STOP_P2P_DEVICE: Stop the given P2P Device, identified by - * its %NL80211_ATTR_WDEV identifier. - * - * @NL80211_CMD_CONN_FAILED: connection request to an AP failed; used to - * notify userspace that AP has rejected the connection request from a - * station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON - * is used for this. - * - * @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames - * for IBSS or MESH vif. - * - * @NL80211_CMD_SET_MAC_ACL: sets ACL for MAC address based access control. - * This is to be used with the drivers advertising the support of MAC - * address based access control. List of MAC addresses is passed in - * %NL80211_ATTR_MAC_ADDRS and ACL policy is passed in - * %NL80211_ATTR_ACL_POLICY. Driver will enable ACL with this list, if it - * is not already done. The new list will replace any existing list. Driver - * will clear its ACL when the list of MAC addresses passed is empty. This - * command is used in AP/P2P GO mode. Driver has to make sure to clear its - * ACL list during %NL80211_CMD_STOP_AP. - * - * @NL80211_CMD_RADAR_DETECT: Start a Channel availability check (CAC). Once - * a radar is detected or the channel availability scan (CAC) has finished - * or was aborted, or a radar was detected, usermode will be notified with - * this event. This command is also used to notify userspace about radars - * while operating on this channel. - * %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the - * event. - * - * @NL80211_CMD_GET_PROTOCOL_FEATURES: Get global nl80211 protocol features, - * i.e. features for the nl80211 protocol rather than device features. - * Returns the features in the %NL80211_ATTR_PROTOCOL_FEATURES bitmap. - * - * @NL80211_CMD_UPDATE_FT_IES: Pass down the most up-to-date Fast Transition - * Information Element to the WLAN driver - * - * @NL80211_CMD_FT_EVENT: Send a Fast transition event from the WLAN driver - * to the supplicant. This will carry the target AP's MAC address along - * with the relevant Information Elements. This event is used to report - * received FT IEs (MDIE, FTIE, RSN IE, TIE, RICIE). - * - * @NL80211_CMD_CRIT_PROTOCOL_START: Indicates user-space will start running - * a critical protocol that needs more reliability in the connection to - * complete. - * - * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can - * return back to normal. - * - * @NL80211_CMD_GET_COALESCE: Get currently supported coalesce rules. - * @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules. - * - * @NL80211_CMD_CHANNEL_SWITCH: Perform a channel switch by announcing the - * the new channel information (Channel Switch Announcement - CSA) - * in the beacon for some time (as defined in the - * %NL80211_ATTR_CH_SWITCH_COUNT parameter) and then change to the - * new channel. Userspace provides the new channel information (using - * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel - * width). %NL80211_ATTR_CH_SWITCH_BLOCK_TX may be supplied to inform - * other station that transmission must be blocked until the channel - * switch is complete. - * - * @NL80211_CMD_VENDOR: Vendor-specified command/event. The command is specified - * by the %NL80211_ATTR_VENDOR_ID attribute and a sub-command in - * %NL80211_ATTR_VENDOR_SUBCMD. Parameter(s) can be transported in - * %NL80211_ATTR_VENDOR_DATA. - * For feature advertisement, the %NL80211_ATTR_VENDOR_DATA attribute is - * used in the wiphy data as a nested attribute containing descriptions - * (&struct nl80211_vendor_cmd_info) of the supported vendor commands. - * This may also be sent as an event with the same attributes. - * - * @NL80211_CMD_SET_QOS_MAP: Set Interworking QoS mapping for IP DSCP values. - * The QoS mapping information is included in %NL80211_ATTR_QOS_MAP. If - * that attribute is not included, QoS mapping is disabled. Since this - * QoS mapping is relevant for IP packets, it is only valid during an - * association. This is cleared on disassociation and AP restart. - * - * @NL80211_CMD_MAX: highest used command number - * @__NL80211_CMD_AFTER_LAST: internal use - */ -enum nl80211_commands { -/* don't change the order or add anything between, this is ABI! */ - NL80211_CMD_UNSPEC, - - NL80211_CMD_GET_WIPHY, /* can dump */ - NL80211_CMD_SET_WIPHY, - NL80211_CMD_NEW_WIPHY, - NL80211_CMD_DEL_WIPHY, - - NL80211_CMD_GET_INTERFACE, /* can dump */ - NL80211_CMD_SET_INTERFACE, - NL80211_CMD_NEW_INTERFACE, - NL80211_CMD_DEL_INTERFACE, - - NL80211_CMD_GET_KEY, - NL80211_CMD_SET_KEY, - NL80211_CMD_NEW_KEY, - NL80211_CMD_DEL_KEY, - - NL80211_CMD_GET_BEACON, - NL80211_CMD_SET_BEACON, - NL80211_CMD_START_AP, - NL80211_CMD_NEW_BEACON = NL80211_CMD_START_AP, - NL80211_CMD_STOP_AP, - NL80211_CMD_DEL_BEACON = NL80211_CMD_STOP_AP, - - NL80211_CMD_GET_STATION, - NL80211_CMD_SET_STATION, - NL80211_CMD_NEW_STATION, - NL80211_CMD_DEL_STATION, - - NL80211_CMD_GET_MPATH, - NL80211_CMD_SET_MPATH, - NL80211_CMD_NEW_MPATH, - NL80211_CMD_DEL_MPATH, - - NL80211_CMD_SET_BSS, - - NL80211_CMD_SET_REG, - NL80211_CMD_REQ_SET_REG, - - NL80211_CMD_GET_MESH_CONFIG, - NL80211_CMD_SET_MESH_CONFIG, - - NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */, - - NL80211_CMD_GET_REG, - - NL80211_CMD_GET_SCAN, - NL80211_CMD_TRIGGER_SCAN, - NL80211_CMD_NEW_SCAN_RESULTS, - NL80211_CMD_SCAN_ABORTED, - - NL80211_CMD_REG_CHANGE, - - NL80211_CMD_AUTHENTICATE, - NL80211_CMD_ASSOCIATE, - NL80211_CMD_DEAUTHENTICATE, - NL80211_CMD_DISASSOCIATE, - - NL80211_CMD_MICHAEL_MIC_FAILURE, - - NL80211_CMD_REG_BEACON_HINT, - - NL80211_CMD_JOIN_IBSS, - NL80211_CMD_LEAVE_IBSS, - - NL80211_CMD_TESTMODE, - - NL80211_CMD_CONNECT, - NL80211_CMD_ROAM, - NL80211_CMD_DISCONNECT, - - NL80211_CMD_SET_WIPHY_NETNS, - - NL80211_CMD_GET_SURVEY, - NL80211_CMD_NEW_SURVEY_RESULTS, - - NL80211_CMD_SET_PMKSA, - NL80211_CMD_DEL_PMKSA, - NL80211_CMD_FLUSH_PMKSA, - - NL80211_CMD_REMAIN_ON_CHANNEL, - NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, - - NL80211_CMD_SET_TX_BITRATE_MASK, - - NL80211_CMD_REGISTER_FRAME, - NL80211_CMD_REGISTER_ACTION = NL80211_CMD_REGISTER_FRAME, - NL80211_CMD_FRAME, - NL80211_CMD_ACTION = NL80211_CMD_FRAME, - NL80211_CMD_FRAME_TX_STATUS, - NL80211_CMD_ACTION_TX_STATUS = NL80211_CMD_FRAME_TX_STATUS, - - NL80211_CMD_SET_POWER_SAVE, - NL80211_CMD_GET_POWER_SAVE, - - NL80211_CMD_SET_CQM, - NL80211_CMD_NOTIFY_CQM, - - NL80211_CMD_SET_CHANNEL, - NL80211_CMD_SET_WDS_PEER, - - NL80211_CMD_FRAME_WAIT_CANCEL, - - NL80211_CMD_JOIN_MESH, - NL80211_CMD_LEAVE_MESH, - - 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, - - NL80211_CMD_SET_NOACK_MAP, - - NL80211_CMD_CH_SWITCH_NOTIFY, - - NL80211_CMD_START_P2P_DEVICE, - NL80211_CMD_STOP_P2P_DEVICE, - - NL80211_CMD_CONN_FAILED, - - NL80211_CMD_SET_MCAST_RATE, - - NL80211_CMD_SET_MAC_ACL, - - NL80211_CMD_RADAR_DETECT, - - NL80211_CMD_GET_PROTOCOL_FEATURES, - - NL80211_CMD_UPDATE_FT_IES, - NL80211_CMD_FT_EVENT, - - NL80211_CMD_CRIT_PROTOCOL_START, - NL80211_CMD_CRIT_PROTOCOL_STOP, - - NL80211_CMD_GET_COALESCE, - NL80211_CMD_SET_COALESCE, - - NL80211_CMD_CHANNEL_SWITCH, - - NL80211_CMD_VENDOR, - - NL80211_CMD_SET_QOS_MAP, - - /* add new commands above here */ - - /* used to define NL80211_CMD_MAX below */ - __NL80211_CMD_AFTER_LAST, - NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 -}; - -/* - * Allow user space programs to use #ifdef on new commands by defining them - * here - */ -#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS -#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE -#define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE -#define NL80211_CMD_AUTHENTICATE NL80211_CMD_AUTHENTICATE -#define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE -#define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE -#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 - * - * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors - * - * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf. - * /sys/class/ieee80211//index - * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) - * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters - * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz, - * defines the channel together with the (deprecated) - * %NL80211_ATTR_WIPHY_CHANNEL_TYPE attribute or the attributes - * %NL80211_ATTR_CHANNEL_WIDTH and if needed %NL80211_ATTR_CENTER_FREQ1 - * and %NL80211_ATTR_CENTER_FREQ2 - * @NL80211_ATTR_CHANNEL_WIDTH: u32 attribute containing one of the values - * of &enum nl80211_chan_width, describing the channel width. See the - * documentation of the enum for more information. - * @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the - * channel, used for anything but 20 MHz bandwidth - * @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the - * channel, used only for 80+80 MHz bandwidth - * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ - * if HT20 or HT40 are to be used (i.e., HT disabled if not included): - * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including - * this attribute) - * NL80211_CHAN_HT20 = HT20 only - * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel - * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel - * This attribute is now deprecated. - * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is - * less than or equal to the RTS threshold; allowed range: 1..255; - * dot11ShortRetryLimit; u8 - * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is - * greater than the RTS threshold; allowed range: 1..255; - * dot11ShortLongLimit; u8 - * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum - * length in octets for frames; allowed range: 256..8000, disable - * fragmentation with (u32)-1; dot11FragmentationThreshold; u32 - * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length - * larger than or equal to this use RTS/CTS handshake); allowed range: - * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32 - * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11 - * section 7.3.2.9; dot11CoverageClass; u8 - * - * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on - * @NL80211_ATTR_IFNAME: network interface name - * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype - * - * @NL80211_ATTR_WDEV: wireless device identifier, used for pseudo-devices - * that don't have a netdev (u64) - * - * @NL80211_ATTR_MAC: MAC address (various uses) - * - * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of - * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC - * keys - * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3) - * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 - * section 7.3.2.25.1, e.g. 0x000FAC04) - * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and - * CCMP keys, each six bytes in little endian - * @NL80211_ATTR_KEY_DEFAULT: Flag attribute indicating the key is default key - * @NL80211_ATTR_KEY_DEFAULT_MGMT: Flag attribute indicating the key is the - * default management key - * @NL80211_ATTR_CIPHER_SUITES_PAIRWISE: For crypto settings for connect or - * other commands, indicates which pairwise cipher suites are used - * @NL80211_ATTR_CIPHER_SUITE_GROUP: For crypto settings for connect or - * other commands, indicates which group cipher suite is used - * - * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU - * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing - * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE - * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE - * - * @NL80211_ATTR_STA_AID: Association ID for the station (u16) - * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of - * &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2) - * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by - * IEEE 802.11 7.3.1.6 (u16). - * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array 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_STA_VLAN: interface index of VLAN interface to move station - * to, or the AP interface the station was originally added to to. - * @NL80211_ATTR_STA_INFO: information about a station, part of station info - * given for %NL80211_CMD_GET_STATION, nested attribute containing - * info as possible, see &enum nl80211_sta_info. - * - * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, - * consisting of a nested array. - * - * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). - * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link - * (see &enum nl80211_plink_action). - * @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 - * &enum nl80211_mpath_info. - * - * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of - * &enum nl80211_mntr_flags. - * - * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the - * current regulatory domain should be set to or is already set to. - * For example, 'CR', for Costa Rica. This attribute is used by the kernel - * to query the CRDA to retrieve one regulatory domain. This attribute can - * also be used by userspace to query the kernel for the currently set - * regulatory domain. We chose an alpha2 as that is also used by the - * IEEE-802.11 country information element to identify a country. - * Users can also simply ask the wireless core to set regulatory domain - * to a specific alpha2. - * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory - * rules. - * - * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1) - * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled - * (u8, 0 or 1) - * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled - * (u8, 0 or 1) - * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic - * rates in format defined by IEEE 802.11 7.3.2.2 but without the length - * restriction (at most %NL80211_MAX_SUPP_RATES). - * - * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from - * association request when used with NL80211_CMD_NEW_STATION) - * - * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all - * supported interface types, each a flag attribute with the number - * of the interface mode. - * - * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for - * %NL80211_CMD_SET_MGMT_EXTRA_IE. - * - * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with - * %NL80211_CMD_SET_MGMT_EXTRA_IE). - * - * @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 - * scanning and include a zero-length SSID (wildcard) for wildcard scan - * @NL80211_ATTR_BSS: scan result BSS - * - * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain - * currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_* - * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently - * set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*) - * - * @NL80211_ATTR_SUPPORTED_COMMANDS: wiphy attribute that specifies - * an array of command numbers (i.e. a mapping index to command number) - * that the driver for the given wiphy supports. - * - * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header - * and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and - * NL80211_CMD_ASSOCIATE events - * @NL80211_ATTR_SSID: SSID (binary attribute, 0..32 octets) - * @NL80211_ATTR_AUTH_TYPE: AuthenticationType, see &enum nl80211_auth_type, - * represented as a u32 - * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and - * %NL80211_CMD_DISASSOCIATE, u16 - * - * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as - * a u32 - * - * @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change - * due to considerations from a beacon hint. This attribute reflects - * the state of the channel _before_ the beacon hint processing. This - * attributes consists of a nested attribute containing - * NL80211_FREQUENCY_ATTR_* - * @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change - * due to considerations from a beacon hint. This attribute reflects - * the state of the channel _after_ the beacon hint processing. This - * attributes consists of a nested attribute containing - * NL80211_FREQUENCY_ATTR_* - * - * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported - * cipher suites - * - * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look - * for other networks on different channels - * - * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this - * is used, e.g., with %NL80211_CMD_AUTHENTICATE event - * - * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is - * used for the association (&enum nl80211_mfp, represented as a u32); - * this attribute can be used - * with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests - * - * @NL80211_ATTR_STA_FLAGS2: Attribute containing a - * &struct nl80211_sta_flag_update. - * - * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls - * IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in - * station mode. If the flag is included in %NL80211_CMD_ASSOCIATE - * request, the driver will assume that the port is unauthorized until - * authorized by user space. Otherwise, port is marked authorized by - * default in station mode. - * @NL80211_ATTR_CONTROL_PORT_ETHERTYPE: A 16-bit value indicating the - * ethertype that will be used for key negotiation. It can be - * specified with the associate and connect commands. If it is not - * specified, the value defaults to 0x888E (PAE, 802.1X). This - * attribute is also used as a flag in the wiphy information to - * indicate that protocols other than PAE are supported. - * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with - * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom - * ethertype frames used for key negotiation must not be encrypted. - * - * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. - * We recommend using nested, driver-specific attributes within this. - * - * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT - * event was due to the AP disconnecting the station, and not due to - * a local disconnect request. - * @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. This is also used with NEW_BEACON to - * indicate that the BSS is to use protection. - * - * @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, 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, 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. - * @NL80211_ATTR_RESP_IE: (Re)association response information elements as - * sent by peer, for ROAM and successful CONNECT events. - * - * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE - * commands to specify using a reassociate frame - * - * @NL80211_ATTR_KEY: key information in a nested attribute with - * %NL80211_KEY_* sub-attributes - * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect() - * and join_ibss(), key information is in a nested attribute each - * with %NL80211_KEY_* sub-attributes - * - * @NL80211_ATTR_PID: Process ID of a network namespace. - * - * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for - * dumps. This number increases whenever the object list being - * dumped changes, and as such userspace can verify that it has - * obtained a complete and consistent snapshot by verifying that - * all dump messages contain the same generation number. If it - * changed then the list changed and the dump should be repeated - * completely from scratch. - * - * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface - * - * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of - * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute - * containing info as possible, see &enum survey_info. - * - * @NL80211_ATTR_PMKID: PMK material for PMKSA caching. - * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can - * cache, a wiphy attribute. - * - * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32. - * @NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION: Device attribute that - * specifies the maximum duration that can be requested with the - * remain-on-channel operation, in milliseconds, u32. - * - * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects. - * - * @NL80211_ATTR_TX_RATES: Nested set of attributes - * (enum nl80211_tx_rate_attributes) describing TX rates per band. The - * enum nl80211_band value is used as the index (nla_type() of the nested - * data. If a band is not included, it will be configured to allow all - * rates based on negotiated supported rates information. This attribute - * is used with %NL80211_CMD_SET_TX_BITRATE_MASK. - * - * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain - * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME. - * @NL80211_ATTR_FRAME_TYPE: A u16 indicating the frame type/subtype for the - * @NL80211_CMD_REGISTER_FRAME command. - * @NL80211_ATTR_TX_FRAME_TYPES: wiphy capability attribute, which is a - * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing - * information about which frame types can be transmitted with - * %NL80211_CMD_FRAME. - * @NL80211_ATTR_RX_FRAME_TYPES: wiphy capability attribute, which is a - * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing - * information about which frame types can be registered for RX. - * - * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was - * acknowledged by the recipient. - * - * @NL80211_ATTR_PS_STATE: powersave state, using &enum nl80211_ps_state values. - * - * @NL80211_ATTR_CQM: connection quality monitor configuration in a - * nested attribute with %NL80211_ATTR_CQM_* sub-attributes. - * - * @NL80211_ATTR_LOCAL_STATE_CHANGE: Flag attribute to indicate that a command - * is requesting a local authentication/association state change without - * invoking actual management frame exchange. This can be used with - * NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE, - * NL80211_CMD_DISASSOCIATE. - * - * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations - * connected to this BSS. - * - * @NL80211_ATTR_WIPHY_TX_POWER_SETTING: Transmit power setting type. See - * &enum nl80211_tx_power_setting for possible values. - * @NL80211_ATTR_WIPHY_TX_POWER_LEVEL: Transmit power level in signed mBm units. - * This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING - * for non-automatic settings. - * - * @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly - * means support for per-station GTKs. - * - * @NL80211_ATTR_WIPHY_ANTENNA_TX: Bitmap of allowed antennas for transmitting. - * This can be used to mask out antennas which are not attached or should - * not be used for transmitting. If an antenna is not selected in this - * bitmap the hardware is not allowed to transmit on this antenna. - * - * Each bit represents one antenna, starting with antenna 1 at the first - * bit. Depending on which antennas are selected in the bitmap, 802.11n - * drivers can derive which chainmasks to use (if all antennas belonging to - * a particular chain are disabled this chain should be disabled) and if - * a chain has diversity antennas wether diversity should be used or not. - * HT capabilities (STBC, TX Beamforming, Antenna selection) can be - * derived from the available chains after applying the antenna mask. - * Non-802.11n drivers can derive wether to use diversity or not. - * Drivers may reject configurations or RX/TX mask combinations they cannot - * support by returning -EINVAL. - * - * @NL80211_ATTR_WIPHY_ANTENNA_RX: Bitmap of allowed antennas for receiving. - * 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 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 - * - * @NL80211_ATTR_OFFCHANNEL_TX_OK: For management frame TX, the frame may be - * transmitted on another channel when the channel given doesn't match - * the current channel. If the current channel doesn't match and this - * flag isn't set, the frame will be rejected. This is also used as an - * nl80211 capability flag. - * - * @NL80211_ATTR_BSS_HT_OPMODE: HT operation mode (u16) - * - * @NL80211_ATTR_KEY_DEFAULT_TYPES: A nested attribute containing flags - * attributes, specifying what a key should be set as default as. - * 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 or - * @NL80211_MESH_SETUP_USERSPACE_MPM 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_DISABLE_HT: Force HT capable interfaces to disable - * this feature. Currently, only supported in mac80211 drivers. - * @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the - * ATTR_HT_CAPABILITY to which attention should be paid. - * Currently, only mac80211 NICs support this feature. - * The values that may be configured are: - * MCS rates, MAX-AMSDU, HT-20-40 and HT_CAP_SGI_40 - * AMPDU density and AMPDU factor. - * All values are treated as suggestions and may be ignored - * by the driver as required. The actual values may be seen in - * the station debugfs ht_caps file. - * - * @NL80211_ATTR_DFS_REGION: region for regulatory rules which this country - * abides to when initiating radiation on DFS channels. A country maps - * to one DFS region. - * - * @NL80211_ATTR_NOACK_MAP: This u16 bitmap contains the No Ack Policy of - * up to 16 TIDs. - * - * @NL80211_ATTR_INACTIVITY_TIMEOUT: timeout value in seconds, this can be - * used by the drivers which has MLME in firmware and does not have support - * to report per station tx/rx activity to free up the staion entry from - * the list. This needs to be used when the driver advertises the - * capability to timeout the stations. - * - * @NL80211_ATTR_RX_SIGNAL_DBM: signal strength in dBm (as a 32-bit int); - * this attribute is (depending on the driver capabilities) added to - * received frames indicated with %NL80211_CMD_FRAME. - * - * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds - * or 0 to disable background scan. - * - * @NL80211_ATTR_USER_REG_HINT_TYPE: type of regulatory hint passed from - * userspace. If unset it is assumed the hint comes directly from - * a user. If set code could specify exactly what type of source - * was used to provide the hint. For the different types of - * allowed user regulatory hints see nl80211_user_reg_hint_type. - * - * @NL80211_ATTR_CONN_FAILED_REASON: The reason for which AP has rejected - * the connection request from a station. nl80211_connect_failed_reason - * enum has different reasons of connection failure. - * - * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts - * with the Authentication transaction sequence number field. - * - * @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from - * association request when used with NL80211_CMD_NEW_STATION) - * - * @NL80211_ATTR_SCAN_FLAGS: scan request control flags (u32) - * - * @NL80211_ATTR_P2P_CTWINDOW: P2P GO Client Traffic Window (u8), used with - * the START_AP and SET_BSS commands - * @NL80211_ATTR_P2P_OPPPS: P2P GO opportunistic PS (u8), used with the - * START_AP and SET_BSS commands. This can have the values 0 or 1; - * if not given in START_AP 0 is assumed, if not given in SET_BSS - * no change is made. - * - * @NL80211_ATTR_LOCAL_MESH_POWER_MODE: local mesh STA link-specific power mode - * defined in &enum nl80211_mesh_power_mode. - * - * @NL80211_ATTR_ACL_POLICY: ACL policy, see &enum nl80211_acl_policy, - * carried in a u32 attribute - * - * @NL80211_ATTR_MAC_ADDRS: Array of nested MAC addresses, used for - * MAC ACL. - * - * @NL80211_ATTR_MAC_ACL_MAX: u32 attribute to advertise the maximum - * number of MAC addresses that a device can support for MAC - * ACL. - * - * @NL80211_ATTR_RADAR_EVENT: Type of radar event for notification to userspace, - * contains a value of enum nl80211_radar_event (u32). - * - * @NL80211_ATTR_EXT_CAPA: 802.11 extended capabilities that the kernel driver - * has and handles. The format is the same as the IE contents. See - * 802.11-2012 8.4.2.29 for more information. - * @NL80211_ATTR_EXT_CAPA_MASK: Extended capabilities that the kernel driver - * has set in the %NL80211_ATTR_EXT_CAPA value, for multibit fields. - * - * @NL80211_ATTR_STA_CAPABILITY: Station capabilities (u16) are advertised to - * the driver, e.g., to enable TDLS power save (PU-APSD). - * - * @NL80211_ATTR_STA_EXT_CAPABILITY: Station extended capabilities are - * advertised to the driver, e.g., to enable TDLS off channel operations - * and PU-APSD. - * - * @NL80211_ATTR_PROTOCOL_FEATURES: global nl80211 feature flags, see - * &enum nl80211_protocol_features, the attribute is a u32. - * - * @NL80211_ATTR_SPLIT_WIPHY_DUMP: flag attribute, userspace supports - * receiving the data for a single wiphy split across multiple - * messages, given with wiphy dump message - * - * @NL80211_ATTR_MDID: Mobility Domain Identifier - * - * @NL80211_ATTR_IE_RIC: Resource Information Container Information - * Element - * - * @NL80211_ATTR_CRIT_PROT_ID: critical protocol identifier requiring increased - * reliability, see &enum nl80211_crit_proto_id (u16). - * @NL80211_ATTR_MAX_CRIT_PROT_DURATION: duration in milliseconds in which - * the connection should have increased reliability (u16). - * - * @NL80211_ATTR_PEER_AID: Association ID for the peer TDLS station (u16). - * This is similar to @NL80211_ATTR_STA_AID but with a difference of being - * allowed to be used with the first @NL80211_CMD_SET_STATION command to - * update a TDLS peer STA entry. - * - * @NL80211_ATTR_COALESCE_RULE: Coalesce rule information. - * - * @NL80211_ATTR_CH_SWITCH_COUNT: u32 attribute specifying the number of TBTT's - * until the channel switch event. - * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission - * must be blocked on the current channel (before the channel switch - * operation). - * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information - * for the time while performing a channel switch. - * @NL80211_ATTR_CSA_C_OFF_BEACON: Offset of the channel switch counter - * field in the beacons tail (%NL80211_ATTR_BEACON_TAIL). - * @NL80211_ATTR_CSA_C_OFF_PRESP: Offset of the channel switch counter - * field in the probe response (%NL80211_ATTR_PROBE_RESP). - * - * @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32. - * As specified in the &enum nl80211_rxmgmt_flags. - * - * @NL80211_ATTR_STA_SUPPORTED_CHANNELS: array of supported channels. - * - * @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported - * supported operating classes. - * - * @NL80211_ATTR_HANDLE_DFS: A flag indicating whether user space - * controls DFS operation in IBSS mode. If the flag is included in - * %NL80211_CMD_JOIN_IBSS request, the driver will allow use of DFS - * channels and reports radar events to userspace. Userspace is required - * to react to radar events, e.g. initiate a channel switch or leave the - * IBSS network. - * - * @NL80211_ATTR_SUPPORT_5_MHZ: A flag indicating that the device supports - * 5 MHz channel bandwidth. - * @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports - * 10 MHz channel bandwidth. - * - * @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode - * Notification Element based on association request when used with - * %NL80211_CMD_NEW_STATION; u8 attribute. - * - * @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if - * %NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet) - * @NL80211_ATTR_VENDOR_SUBCMD: vendor sub-command - * @NL80211_ATTR_VENDOR_DATA: data for the vendor command, if any; this - * attribute is also used for vendor command feature advertisement - * @NL80211_ATTR_VENDOR_EVENTS: used for event list advertising in the wiphy - * info, containing a nested array of possible events - * - * @NL80211_ATTR_QOS_MAP: IP DSCP mapping for Interworking QoS mapping. This - * data is in the format defined for the payload of the QoS Map Set element - * in IEEE Std 802.11-2012, 8.4.2.97. - * - * @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 between, this is ABI! */ - NL80211_ATTR_UNSPEC, - - NL80211_ATTR_WIPHY, - NL80211_ATTR_WIPHY_NAME, - - NL80211_ATTR_IFINDEX, - NL80211_ATTR_IFNAME, - NL80211_ATTR_IFTYPE, - - NL80211_ATTR_MAC, - - NL80211_ATTR_KEY_DATA, - NL80211_ATTR_KEY_IDX, - NL80211_ATTR_KEY_CIPHER, - NL80211_ATTR_KEY_SEQ, - NL80211_ATTR_KEY_DEFAULT, - - NL80211_ATTR_BEACON_INTERVAL, - NL80211_ATTR_DTIM_PERIOD, - NL80211_ATTR_BEACON_HEAD, - NL80211_ATTR_BEACON_TAIL, - - NL80211_ATTR_STA_AID, - NL80211_ATTR_STA_FLAGS, - NL80211_ATTR_STA_LISTEN_INTERVAL, - NL80211_ATTR_STA_SUPPORTED_RATES, - NL80211_ATTR_STA_VLAN, - NL80211_ATTR_STA_INFO, - - NL80211_ATTR_WIPHY_BANDS, - - NL80211_ATTR_MNTR_FLAGS, - - NL80211_ATTR_MESH_ID, - NL80211_ATTR_STA_PLINK_ACTION, - NL80211_ATTR_MPATH_NEXT_HOP, - NL80211_ATTR_MPATH_INFO, - - NL80211_ATTR_BSS_CTS_PROT, - NL80211_ATTR_BSS_SHORT_PREAMBLE, - NL80211_ATTR_BSS_SHORT_SLOT_TIME, - - NL80211_ATTR_HT_CAPABILITY, - - NL80211_ATTR_SUPPORTED_IFTYPES, - - NL80211_ATTR_REG_ALPHA2, - NL80211_ATTR_REG_RULES, - - NL80211_ATTR_MESH_CONFIG, - - NL80211_ATTR_BSS_BASIC_RATES, - - NL80211_ATTR_WIPHY_TXQ_PARAMS, - NL80211_ATTR_WIPHY_FREQ, - NL80211_ATTR_WIPHY_CHANNEL_TYPE, - - NL80211_ATTR_KEY_DEFAULT_MGMT, - - NL80211_ATTR_MGMT_SUBTYPE, - NL80211_ATTR_IE, - - NL80211_ATTR_MAX_NUM_SCAN_SSIDS, - - NL80211_ATTR_SCAN_FREQUENCIES, - NL80211_ATTR_SCAN_SSIDS, - NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */ - NL80211_ATTR_BSS, - - NL80211_ATTR_REG_INITIATOR, - NL80211_ATTR_REG_TYPE, - - NL80211_ATTR_SUPPORTED_COMMANDS, - - NL80211_ATTR_FRAME, - NL80211_ATTR_SSID, - NL80211_ATTR_AUTH_TYPE, - NL80211_ATTR_REASON_CODE, - - NL80211_ATTR_KEY_TYPE, - - NL80211_ATTR_MAX_SCAN_IE_LEN, - NL80211_ATTR_CIPHER_SUITES, - - NL80211_ATTR_FREQ_BEFORE, - NL80211_ATTR_FREQ_AFTER, - - NL80211_ATTR_FREQ_FIXED, - - - NL80211_ATTR_WIPHY_RETRY_SHORT, - NL80211_ATTR_WIPHY_RETRY_LONG, - NL80211_ATTR_WIPHY_FRAG_THRESHOLD, - NL80211_ATTR_WIPHY_RTS_THRESHOLD, - - NL80211_ATTR_TIMED_OUT, - - NL80211_ATTR_USE_MFP, - - NL80211_ATTR_STA_FLAGS2, - - NL80211_ATTR_CONTROL_PORT, - - NL80211_ATTR_TESTDATA, - - NL80211_ATTR_PRIVACY, - - NL80211_ATTR_DISCONNECTED_BY_AP, - NL80211_ATTR_STATUS_CODE, - - NL80211_ATTR_CIPHER_SUITES_PAIRWISE, - NL80211_ATTR_CIPHER_SUITE_GROUP, - NL80211_ATTR_WPA_VERSIONS, - NL80211_ATTR_AKM_SUITES, - - NL80211_ATTR_REQ_IE, - NL80211_ATTR_RESP_IE, - - NL80211_ATTR_PREV_BSSID, - - NL80211_ATTR_KEY, - NL80211_ATTR_KEYS, - - NL80211_ATTR_PID, - - NL80211_ATTR_4ADDR, - - NL80211_ATTR_SURVEY_INFO, - - NL80211_ATTR_PMKID, - NL80211_ATTR_MAX_NUM_PMKIDS, - - NL80211_ATTR_DURATION, - - NL80211_ATTR_COOKIE, - - NL80211_ATTR_WIPHY_COVERAGE_CLASS, - - NL80211_ATTR_TX_RATES, - - NL80211_ATTR_FRAME_MATCH, - - NL80211_ATTR_ACK, - - NL80211_ATTR_PS_STATE, - - NL80211_ATTR_CQM, - - NL80211_ATTR_LOCAL_STATE_CHANGE, - - NL80211_ATTR_AP_ISOLATE, - - NL80211_ATTR_WIPHY_TX_POWER_SETTING, - NL80211_ATTR_WIPHY_TX_POWER_LEVEL, - - NL80211_ATTR_TX_FRAME_TYPES, - NL80211_ATTR_RX_FRAME_TYPES, - NL80211_ATTR_FRAME_TYPE, - - NL80211_ATTR_CONTROL_PORT_ETHERTYPE, - NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, - - NL80211_ATTR_SUPPORT_IBSS_RSN, - - NL80211_ATTR_WIPHY_ANTENNA_TX, - NL80211_ATTR_WIPHY_ANTENNA_RX, - - NL80211_ATTR_MCAST_RATE, - - NL80211_ATTR_OFFCHANNEL_TX_OK, - - NL80211_ATTR_BSS_HT_OPMODE, - - NL80211_ATTR_KEY_DEFAULT_TYPES, - - 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, - - NL80211_ATTR_DFS_REGION, - - NL80211_ATTR_DISABLE_HT, - NL80211_ATTR_HT_CAPABILITY_MASK, - - NL80211_ATTR_NOACK_MAP, - - NL80211_ATTR_INACTIVITY_TIMEOUT, - - NL80211_ATTR_RX_SIGNAL_DBM, - - NL80211_ATTR_BG_SCAN_PERIOD, - - NL80211_ATTR_WDEV, - - NL80211_ATTR_USER_REG_HINT_TYPE, - - NL80211_ATTR_CONN_FAILED_REASON, - - NL80211_ATTR_SAE_DATA, - - NL80211_ATTR_VHT_CAPABILITY, - - NL80211_ATTR_SCAN_FLAGS, - - NL80211_ATTR_CHANNEL_WIDTH, - NL80211_ATTR_CENTER_FREQ1, - NL80211_ATTR_CENTER_FREQ2, - - NL80211_ATTR_P2P_CTWINDOW, - NL80211_ATTR_P2P_OPPPS, - - NL80211_ATTR_LOCAL_MESH_POWER_MODE, - - NL80211_ATTR_ACL_POLICY, - - NL80211_ATTR_MAC_ADDRS, - - NL80211_ATTR_MAC_ACL_MAX, - - NL80211_ATTR_RADAR_EVENT, - - NL80211_ATTR_EXT_CAPA, - NL80211_ATTR_EXT_CAPA_MASK, - - NL80211_ATTR_STA_CAPABILITY, - NL80211_ATTR_STA_EXT_CAPABILITY, - - NL80211_ATTR_PROTOCOL_FEATURES, - NL80211_ATTR_SPLIT_WIPHY_DUMP, - - NL80211_ATTR_DISABLE_VHT, - NL80211_ATTR_VHT_CAPABILITY_MASK, - - NL80211_ATTR_MDID, - NL80211_ATTR_IE_RIC, - - NL80211_ATTR_CRIT_PROT_ID, - NL80211_ATTR_MAX_CRIT_PROT_DURATION, - - NL80211_ATTR_PEER_AID, - - NL80211_ATTR_COALESCE_RULE, - - NL80211_ATTR_CH_SWITCH_COUNT, - NL80211_ATTR_CH_SWITCH_BLOCK_TX, - NL80211_ATTR_CSA_IES, - NL80211_ATTR_CSA_C_OFF_BEACON, - NL80211_ATTR_CSA_C_OFF_PRESP, - - NL80211_ATTR_RXMGMT_FLAGS, - - NL80211_ATTR_STA_SUPPORTED_CHANNELS, - - NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES, - - NL80211_ATTR_HANDLE_DFS, - - NL80211_ATTR_SUPPORT_5_MHZ, - NL80211_ATTR_SUPPORT_10_MHZ, - - NL80211_ATTR_OPMODE_NOTIF, - - NL80211_ATTR_VENDOR_ID, - NL80211_ATTR_VENDOR_SUBCMD, - NL80211_ATTR_VENDOR_DATA, - NL80211_ATTR_VENDOR_EVENTS, - - NL80211_ATTR_QOS_MAP, - - /* add attributes here, update the policy in nl80211.c */ - - __NL80211_ATTR_AFTER_LAST, - NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 -}; - -/* 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 - * here - */ -#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT -#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY -#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES -#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS -#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ -#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE -#define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE -#define NL80211_ATTR_IE NL80211_ATTR_IE -#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR -#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE -#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME -#define NL80211_ATTR_SSID NL80211_ATTR_SSID -#define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE -#define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE -#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE -#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP -#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS -#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_HT_RATES 77 -#define NL80211_MAX_SUPP_REG_RULES 32 -#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 -#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 -#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 -#define NL80211_HT_CAPABILITY_LEN 26 -#define NL80211_VHT_CAPABILITY_LEN 12 - -#define NL80211_MAX_NR_CIPHER_SUITES 5 -#define NL80211_MAX_NR_AKM_SUITES 2 - -#define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10 - -/* default RSSI threshold for scan results if none specified. */ -#define NL80211_SCAN_RSSI_THOLD_OFF -300 - -#define NL80211_CQM_TXE_MAX_INTVL 1800 - -/** - * enum nl80211_iftype - (virtual) interface types - * - * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides - * @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; 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 - * @NL80211_IFTYPE_P2P_CLIENT: P2P client - * @NL80211_IFTYPE_P2P_GO: P2P group owner - * @NL80211_IFTYPE_P2P_DEVICE: P2P device interface type, this is not a netdev - * and therefore can't be created in the normal ways, use the - * %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE - * commands to create and destroy one - * @NL80211_IFTYPE_MAX: highest interface type number currently defined - * @NUM_NL80211_IFTYPES: number of defined interface types - * - * These values are used with the %NL80211_ATTR_IFTYPE - * to set the type of an interface. - * - */ -enum nl80211_iftype { - NL80211_IFTYPE_UNSPECIFIED, - NL80211_IFTYPE_ADHOC, - NL80211_IFTYPE_STATION, - NL80211_IFTYPE_AP, - NL80211_IFTYPE_AP_VLAN, - NL80211_IFTYPE_WDS, - NL80211_IFTYPE_MONITOR, - NL80211_IFTYPE_MESH_POINT, - NL80211_IFTYPE_P2P_CLIENT, - NL80211_IFTYPE_P2P_GO, - NL80211_IFTYPE_P2P_DEVICE, - - /* keep last */ - NUM_NL80211_IFTYPES, - NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1 -}; - -/** - * enum nl80211_sta_flags - station flags - * - * Station flags. When a station is added to an AP interface, it is - * assumed to be already associated (and hence authenticated.) - * - * @__NL80211_STA_FLAG_INVALID: attribute number 0 is reserved - * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X) - * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames - * 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 -- this flag should - * only be used in managed mode (even in the flags mask). Note that the - * flag can't be changed, it is only valid while adding a station, and - * attempts to change it will silently be ignored (rather than rejected - * as errors.) - * @NL80211_STA_FLAG_ASSOCIATED: station is associated; used with drivers - * that support %NL80211_FEATURE_FULL_AP_CLIENT_STATE to transition a - * previously added station into associated state - * @NL80211_STA_FLAG_MAX: highest station flag number currently defined - * @__NL80211_STA_FLAG_AFTER_LAST: internal use - */ -enum nl80211_sta_flags { - __NL80211_STA_FLAG_INVALID, - NL80211_STA_FLAG_AUTHORIZED, - NL80211_STA_FLAG_SHORT_PREAMBLE, - NL80211_STA_FLAG_WME, - NL80211_STA_FLAG_MFP, - NL80211_STA_FLAG_AUTHENTICATED, - NL80211_STA_FLAG_TDLS_PEER, - NL80211_STA_FLAG_ASSOCIATED, - - /* keep last */ - __NL80211_STA_FLAG_AFTER_LAST, - NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 -}; - -#define NL80211_STA_FLAG_MAX_OLD_API NL80211_STA_FLAG_TDLS_PEER - -/** - * struct nl80211_sta_flag_update - station flags mask/set - * @mask: mask of station flags to set - * @set: which values to set them to - * - * Both mask and set contain bits as per &enum nl80211_sta_flags. - */ -struct nl80211_sta_flag_update { - __u32 mask; - __u32 set; -} __attribute__((packed)); - -/** - * enum nl80211_rate_info - bitrate information - * - * These attribute types are used with %NL80211_STA_INFO_TXRATE - * when getting information about the bitrate of a station. - * There are 2 attributes for bitrate, a legacy one that represents - * a 16-bit value, and new one that represents a 32-bit value. - * If the rate value fits into 16 bit, both attributes are reported - * with the same value. If the rate is too high to fit into 16 bits - * (>6.5535Gbps) only 32-bit attribute is included. - * User space tools encouraged to use the 32-bit attribute and fall - * back to the 16-bit one for compatibility with older kernels. - * - * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved - * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) - * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) - * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 MHz dualchannel bitrate - * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval - * @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s) - * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined - * @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8) - * @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8) - * @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate - * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate - * @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate - * @__NL80211_RATE_INFO_AFTER_LAST: internal use - */ -enum nl80211_rate_info { - __NL80211_RATE_INFO_INVALID, - NL80211_RATE_INFO_BITRATE, - NL80211_RATE_INFO_MCS, - NL80211_RATE_INFO_40_MHZ_WIDTH, - NL80211_RATE_INFO_SHORT_GI, - NL80211_RATE_INFO_BITRATE32, - NL80211_RATE_INFO_VHT_MCS, - NL80211_RATE_INFO_VHT_NSS, - NL80211_RATE_INFO_80_MHZ_WIDTH, - NL80211_RATE_INFO_80P80_MHZ_WIDTH, - NL80211_RATE_INFO_160_MHZ_WIDTH, - - /* keep last */ - __NL80211_RATE_INFO_AFTER_LAST, - NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1 -}; - -/** - * 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 - * when getting information about a station. - * - * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved - * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) - * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) - * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) - * @NL80211_STA_INFO_RX_BYTES64: total received bytes (u64, from this station) - * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (u64, to this station) - * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) - * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute - * containing info as possible, see &enum nl80211_rate_info - * @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_BEACON_LOSS: count of times beacon loss was detected (u32) - * @NL80211_STA_INFO_T_OFFSET: timing offset with respect to this STA (s64) - * @NL80211_STA_INFO_LOCAL_PM: local mesh STA link-specific power mode - * @NL80211_STA_INFO_PEER_PM: peer mesh STA link-specific power mode - * @NL80211_STA_INFO_NONPEER_PM: neighbor mesh STA power save mode towards - * non-peer STA - * @NL80211_STA_INFO_CHAIN_SIGNAL: per-chain signal strength of last PPDU - * Contains a nested array of signal strength attributes (u8, dBm) - * @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average - * Same format as NL80211_STA_INFO_CHAIN_SIGNAL. - * @__NL80211_STA_INFO_AFTER_LAST: internal - * @NL80211_STA_INFO_MAX: highest possible station info attribute - */ -enum nl80211_sta_info { - __NL80211_STA_INFO_INVALID, - NL80211_STA_INFO_INACTIVE_TIME, - NL80211_STA_INFO_RX_BYTES, - NL80211_STA_INFO_TX_BYTES, - NL80211_STA_INFO_LLID, - NL80211_STA_INFO_PLID, - NL80211_STA_INFO_PLINK_STATE, - NL80211_STA_INFO_SIGNAL, - NL80211_STA_INFO_TX_BITRATE, - NL80211_STA_INFO_RX_PACKETS, - NL80211_STA_INFO_TX_PACKETS, - 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, - NL80211_STA_INFO_BEACON_LOSS, - NL80211_STA_INFO_T_OFFSET, - NL80211_STA_INFO_LOCAL_PM, - NL80211_STA_INFO_PEER_PM, - NL80211_STA_INFO_NONPEER_PM, - NL80211_STA_INFO_RX_BYTES64, - NL80211_STA_INFO_TX_BYTES64, - NL80211_STA_INFO_CHAIN_SIGNAL, - NL80211_STA_INFO_CHAIN_SIGNAL_AVG, - - /* keep last */ - __NL80211_STA_INFO_AFTER_LAST, - NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 -}; - -/** - * enum nl80211_mpath_flags - nl80211 mesh path flags - * - * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active - * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running - * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN - * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set - * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded - */ -enum nl80211_mpath_flags { - NL80211_MPATH_FLAG_ACTIVE = 1<<0, - NL80211_MPATH_FLAG_RESOLVING = 1<<1, - NL80211_MPATH_FLAG_SN_VALID = 1<<2, - NL80211_MPATH_FLAG_FIXED = 1<<3, - NL80211_MPATH_FLAG_RESOLVED = 1<<4, -}; - -/** - * enum nl80211_mpath_info - mesh path information - * - * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting - * information about a mesh path. - * - * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved - * @NL80211_MPATH_INFO_FRAME_QLEN: number of queued frames for this destination - * @NL80211_MPATH_INFO_SN: destination sequence number - * @NL80211_MPATH_INFO_METRIC: metric (cost) of this mesh path - * @NL80211_MPATH_INFO_EXPTIME: expiration time for the path, in msec from now - * @NL80211_MPATH_INFO_FLAGS: mesh path flags, enumerated in - * &enum nl80211_mpath_flags; - * @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec - * @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries - * @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number - * currently defind - * @__NL80211_MPATH_INFO_AFTER_LAST: internal use - */ -enum nl80211_mpath_info { - __NL80211_MPATH_INFO_INVALID, - NL80211_MPATH_INFO_FRAME_QLEN, - NL80211_MPATH_INFO_SN, - NL80211_MPATH_INFO_METRIC, - NL80211_MPATH_INFO_EXPTIME, - NL80211_MPATH_INFO_FLAGS, - NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, - NL80211_MPATH_INFO_DISCOVERY_RETRIES, - - /* keep last */ - __NL80211_MPATH_INFO_AFTER_LAST, - NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 -}; - -/** - * enum nl80211_band_attr - band attributes - * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved - * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band, - * an array of nested frequency attributes - * @NL80211_BAND_ATTR_RATES: supported bitrates in this band, - * an array of nested bitrate attributes - * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as - * defined in 802.11n - * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE - * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n - * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n - * @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as - * defined in 802.11ac - * @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE - * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined - * @__NL80211_BAND_ATTR_AFTER_LAST: internal use - */ -enum nl80211_band_attr { - __NL80211_BAND_ATTR_INVALID, - NL80211_BAND_ATTR_FREQS, - NL80211_BAND_ATTR_RATES, - - NL80211_BAND_ATTR_HT_MCS_SET, - NL80211_BAND_ATTR_HT_CAPA, - NL80211_BAND_ATTR_HT_AMPDU_FACTOR, - NL80211_BAND_ATTR_HT_AMPDU_DENSITY, - - NL80211_BAND_ATTR_VHT_MCS_SET, - NL80211_BAND_ATTR_VHT_CAPA, - - /* keep last */ - __NL80211_BAND_ATTR_AFTER_LAST, - NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 -}; - -#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA - -/** - * enum nl80211_frequency_attr - frequency attributes - * @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved - * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz - * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current - * regulatory domain. - * @NL80211_FREQUENCY_ATTR_NO_IR: no mechanisms that initiate radiation - * are permitted on this channel, this includes sending probe - * requests, or modes of operation that require beaconing. - * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory - * on this channel in current regulatory domain. - * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm - * (100 * dBm). - * @NL80211_FREQUENCY_ATTR_DFS_STATE: current state for DFS - * (enum nl80211_dfs_state) - * @NL80211_FREQUENCY_ATTR_DFS_TIME: time in miliseconds for how long - * this channel is in this DFS state. - * @NL80211_FREQUENCY_ATTR_NO_HT40_MINUS: HT40- isn't possible with this - * channel as the control channel - * @NL80211_FREQUENCY_ATTR_NO_HT40_PLUS: HT40+ isn't possible with this - * channel as the control channel - * @NL80211_FREQUENCY_ATTR_NO_80MHZ: any 80 MHz channel using this channel - * as the primary or any of the secondary channels isn't possible, - * this includes 80+80 channels - * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel - * using this channel as the primary or any of the secondary channels - * isn't possible - * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number - * currently defined - * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use - */ -enum nl80211_frequency_attr { - __NL80211_FREQUENCY_ATTR_INVALID, - NL80211_FREQUENCY_ATTR_FREQ, - NL80211_FREQUENCY_ATTR_DISABLED, - NL80211_FREQUENCY_ATTR_NO_IR, - __NL80211_FREQUENCY_ATTR_NO_IBSS, - NL80211_FREQUENCY_ATTR_RADAR, - NL80211_FREQUENCY_ATTR_MAX_TX_POWER, - NL80211_FREQUENCY_ATTR_DFS_STATE, - NL80211_FREQUENCY_ATTR_DFS_TIME, - NL80211_FREQUENCY_ATTR_NO_HT40_MINUS, - NL80211_FREQUENCY_ATTR_NO_HT40_PLUS, - NL80211_FREQUENCY_ATTR_NO_80MHZ, - NL80211_FREQUENCY_ATTR_NO_160MHZ, - - /* keep last */ - __NL80211_FREQUENCY_ATTR_AFTER_LAST, - NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1 -}; - -#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER -#define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN NL80211_FREQUENCY_ATTR_NO_IR -#define NL80211_FREQUENCY_ATTR_NO_IBSS NL80211_FREQUENCY_ATTR_NO_IR -#define NL80211_FREQUENCY_ATTR_NO_IR NL80211_FREQUENCY_ATTR_NO_IR - -/** - * enum nl80211_bitrate_attr - bitrate attributes - * @__NL80211_BITRATE_ATTR_INVALID: attribute number 0 is reserved - * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps - * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported - * in 2.4 GHz band. - * @NL80211_BITRATE_ATTR_MAX: highest bitrate attribute number - * currently defined - * @__NL80211_BITRATE_ATTR_AFTER_LAST: internal use - */ -enum nl80211_bitrate_attr { - __NL80211_BITRATE_ATTR_INVALID, - NL80211_BITRATE_ATTR_RATE, - NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE, - - /* keep last */ - __NL80211_BITRATE_ATTR_AFTER_LAST, - NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1 -}; - -/** - * enum nl80211_initiator - Indicates the initiator of a reg domain request - * @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world - * regulatory domain. - * @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the - * regulatory domain. - * @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the - * wireless core it thinks its knows the regulatory domain we should be in. - * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an - * 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 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. - */ -enum nl80211_reg_initiator { - NL80211_REGDOM_SET_BY_CORE, - NL80211_REGDOM_SET_BY_USER, - NL80211_REGDOM_SET_BY_DRIVER, - NL80211_REGDOM_SET_BY_COUNTRY_IE, -}; - -/** - * enum nl80211_reg_type - specifies the type of regulatory domain - * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains - * to a specific country. When this is set you can count on the - * ISO / IEC 3166 alpha2 country code being valid. - * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory - * domain. - * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom - * driver specific world regulatory domain. These do not apply system-wide - * and are only applicable to the individual devices which have requested - * them to be applied. - * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product - * of an intersection between two regulatory domains -- the previously - * set regulatory domain on the system and the last accepted regulatory - * domain request to be processed. - */ -enum nl80211_reg_type { - NL80211_REGDOM_TYPE_COUNTRY, - NL80211_REGDOM_TYPE_WORLD, - NL80211_REGDOM_TYPE_CUSTOM_WORLD, - NL80211_REGDOM_TYPE_INTERSECTION, -}; - -/** - * enum nl80211_reg_rule_attr - regulatory rule attributes - * @__NL80211_REG_RULE_ATTR_INVALID: attribute number 0 is reserved - * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional - * considerations for a given frequency range. These are the - * &enum nl80211_reg_rule_flags. - * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory - * rule in KHz. This is not a center of frequency but an actual regulatory - * band edge. - * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule - * in KHz. This is not a center a frequency but an actual regulatory - * band edge. - * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this - * frequency range, in KHz. - * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain - * for a given frequency range. The value is in mBi (100 * dBi). - * If you don't have one then don't send this. - * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for - * a given frequency range. The value is in mBm (100 * dBm). - * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number - * currently defined - * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use - */ -enum nl80211_reg_rule_attr { - __NL80211_REG_RULE_ATTR_INVALID, - NL80211_ATTR_REG_RULE_FLAGS, - - NL80211_ATTR_FREQ_RANGE_START, - NL80211_ATTR_FREQ_RANGE_END, - NL80211_ATTR_FREQ_RANGE_MAX_BW, - - NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, - NL80211_ATTR_POWER_RULE_MAX_EIRP, - - /* keep last */ - __NL80211_REG_RULE_ATTR_AFTER_LAST, - NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1 -}; - -/** - * 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_RSSI: RSSI threshold (in dBm) for reporting a - * BSS in scan results. Filtering is turned off if not specified. - * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter - * attribute number currently defined - * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use - */ -enum nl80211_sched_scan_match_attr { - __NL80211_SCHED_SCAN_MATCH_ATTR_INVALID, - - NL80211_SCHED_SCAN_MATCH_ATTR_SSID, - NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, - - /* keep last */ - __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST, - NL80211_SCHED_SCAN_MATCH_ATTR_MAX = - __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1 -}; - -/* only for backward compatibility */ -#define NL80211_ATTR_SCHED_SCAN_MATCH_SSID NL80211_SCHED_SCAN_MATCH_ATTR_SSID - -/** - * enum nl80211_reg_rule_flags - regulatory rule flags - * - * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed - * @NL80211_RRF_NO_CCK: CCK modulation not allowed - * @NL80211_RRF_NO_INDOOR: indoor operation not allowed - * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed - * @NL80211_RRF_DFS: DFS support is required to be used - * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links - * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links - * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed, - * this includes probe requests or modes of operation that require - * beaconing. - */ -enum nl80211_reg_rule_flags { - NL80211_RRF_NO_OFDM = 1<<0, - NL80211_RRF_NO_CCK = 1<<1, - NL80211_RRF_NO_INDOOR = 1<<2, - NL80211_RRF_NO_OUTDOOR = 1<<3, - NL80211_RRF_DFS = 1<<4, - NL80211_RRF_PTP_ONLY = 1<<5, - NL80211_RRF_PTMP_ONLY = 1<<6, - NL80211_RRF_NO_IR = 1<<7, - __NL80211_RRF_NO_IBSS = 1<<8, -}; - -#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR -#define NL80211_RRF_NO_IBSS NL80211_RRF_NO_IR -#define NL80211_RRF_NO_IR NL80211_RRF_NO_IR - -/* For backport compatibility with older userspace */ -#define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS) - -/** - * enum nl80211_dfs_regions - regulatory DFS regions - * - * @NL80211_DFS_UNSET: Country has no DFS master region specified - * @NL80211_DFS_FCC: Country follows DFS master rules from FCC - * @NL80211_DFS_ETSI: Country follows DFS master rules from ETSI - * @NL80211_DFS_JP: Country follows DFS master rules from JP/MKK/Telec - */ -enum nl80211_dfs_regions { - NL80211_DFS_UNSET = 0, - NL80211_DFS_FCC = 1, - NL80211_DFS_ETSI = 2, - NL80211_DFS_JP = 3, -}; - -/** - * enum nl80211_user_reg_hint_type - type of user regulatory hint - * - * @NL80211_USER_REG_HINT_USER: a user sent the hint. This is always - * assumed if the attribute is not set. - * @NL80211_USER_REG_HINT_CELL_BASE: the hint comes from a cellular - * base station. Device drivers that have been tested to work - * properly to support this type of hint can enable these hints - * by setting the NL80211_FEATURE_CELL_BASE_REG_HINTS feature - * capability on the struct wiphy. The wireless core will - * ignore all cell base station hints until at least one device - * present has been registered with the wireless core that - * has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a - * supported feature. - */ -enum nl80211_user_reg_hint_type { - NL80211_USER_REG_HINT_USER = 0, - NL80211_USER_REG_HINT_CELL_BASE = 1, -}; - -/** - * enum nl80211_survey_info - survey information - * - * These attribute types are used with %NL80211_ATTR_SURVEY_INFO - * when getting information about a survey. - * - * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved - * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel - * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) - * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used - * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio - * spent on this channel - * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary - * channel was sensed busy (either due to activity or energy detect) - * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension - * channel was sensed busy - * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent - * receiving data - * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent - * transmitting data - * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number - * currently defined - * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use - */ -enum nl80211_survey_info { - __NL80211_SURVEY_INFO_INVALID, - NL80211_SURVEY_INFO_FREQUENCY, - NL80211_SURVEY_INFO_NOISE, - NL80211_SURVEY_INFO_IN_USE, - NL80211_SURVEY_INFO_CHANNEL_TIME, - NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, - NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY, - NL80211_SURVEY_INFO_CHANNEL_TIME_RX, - NL80211_SURVEY_INFO_CHANNEL_TIME_TX, - - /* keep last */ - __NL80211_SURVEY_INFO_AFTER_LAST, - NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1 -}; - -/** - * enum nl80211_mntr_flags - monitor configuration flags - * - * Monitor configuration flags. - * - * @__NL80211_MNTR_FLAG_INVALID: reserved - * - * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS - * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP - * @NL80211_MNTR_FLAG_CONTROL: pass control frames - * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering - * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. - * overrides all other flags. - * @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address - * and ACK incoming unicast packets. - * - * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use - * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag - */ -enum nl80211_mntr_flags { - __NL80211_MNTR_FLAG_INVALID, - NL80211_MNTR_FLAG_FCSFAIL, - NL80211_MNTR_FLAG_PLCPFAIL, - NL80211_MNTR_FLAG_CONTROL, - NL80211_MNTR_FLAG_OTHER_BSS, - NL80211_MNTR_FLAG_COOK_FRAMES, - NL80211_MNTR_FLAG_ACTIVE, - - /* keep last */ - __NL80211_MNTR_FLAG_AFTER_LAST, - NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1 -}; - -/** - * enum nl80211_mesh_power_mode - mesh power save modes - * - * @NL80211_MESH_POWER_UNKNOWN: The mesh power mode of the mesh STA is - * not known or has not been set yet. - * @NL80211_MESH_POWER_ACTIVE: Active mesh power mode. The mesh STA is - * in Awake state all the time. - * @NL80211_MESH_POWER_LIGHT_SLEEP: Light sleep mode. The mesh STA will - * alternate between Active and Doze states, but will wake up for - * neighbor's beacons. - * @NL80211_MESH_POWER_DEEP_SLEEP: Deep sleep mode. The mesh STA will - * alternate between Active and Doze states, but may not wake up - * for neighbor's beacons. - * - * @__NL80211_MESH_POWER_AFTER_LAST - internal use - * @NL80211_MESH_POWER_MAX - highest possible power save level - */ - -enum nl80211_mesh_power_mode { - NL80211_MESH_POWER_UNKNOWN, - NL80211_MESH_POWER_ACTIVE, - NL80211_MESH_POWER_LIGHT_SLEEP, - NL80211_MESH_POWER_DEEP_SLEEP, - - __NL80211_MESH_POWER_AFTER_LAST, - NL80211_MESH_POWER_MAX = __NL80211_MESH_POWER_AFTER_LAST - 1 -}; - -/** - * enum nl80211_meshconf_params - mesh configuration parameters - * - * Mesh configuration parameters. These can be changed while the mesh is - * 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 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 - * millisecond units - * - * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed - * on this mesh interface - * - * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link - * open retries that can be sent to establish a new peer link instance in a - * mesh - * - * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh - * point. - * - * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically open - * peer links when we detect compatible mesh peers. Disabled if - * @NL80211_MESH_SETUP_USERSPACE_MPM or @NL80211_MESH_SETUP_USERSPACE_AMPE are - * set. - * - * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames - * containing a PREQ that an MP can send to a particular destination (path - * target) - * - * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths - * (in milliseconds) - * - * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait - * until giving up on a path discovery (in milliseconds) - * - * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh - * points receiving a PREQ shall consider the forwarding information from - * the root to be valid. (TU = time unit) - * - * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in - * TUs) during which an MP can send only one action frame containing a PREQ - * reference element - * - * @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_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_HWMP_PERR_MIN_INTERVAL: The minimum interval of time (in - * TUs) during which a mesh STA can send only one Action frame containing a - * PERR element. - * - * @NL80211_MESHCONF_FORWARDING: set Mesh STA as forwarding or non-forwarding - * or forwarding entity (default is TRUE - forwarding entity) - * - * @NL80211_MESHCONF_RSSI_THRESHOLD: RSSI threshold in dBm. This specifies the - * threshold for average signal strength of candidate station to establish - * a peer link. - * - * @NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR: maximum number of neighbors - * to synchronize to for 11s default synchronization method - * (see 11C.12.2.2) - * - * @NL80211_MESHCONF_HT_OPMODE: set mesh HT protection mode. - * - * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute - * - * @NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT: The time (in TUs) for - * which mesh STAs receiving a proactive PREQ shall consider the forwarding - * information to the root mesh STA to be valid. - * - * @NL80211_MESHCONF_HWMP_ROOT_INTERVAL: The interval of time (in TUs) between - * proactive PREQs are transmitted. - * - * @NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL: The minimum interval of time - * (in TUs) during which a mesh STA can send only one Action frame - * containing a PREQ element for root path confirmation. - * - * @NL80211_MESHCONF_POWER_MODE: Default mesh power mode for new peer links. - * type &enum nl80211_mesh_power_mode (u32) - * - * @NL80211_MESHCONF_AWAKE_WINDOW: awake window duration (in TUs) - * - * @NL80211_MESHCONF_PLINK_TIMEOUT: If no tx activity is seen from a STA we've - * established peering with for longer than this time (in seconds), then - * remove it from the STA's list of peers. Default is 30 minutes. - * - * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use - */ -enum nl80211_meshconf_params { - __NL80211_MESHCONF_INVALID, - NL80211_MESHCONF_RETRY_TIMEOUT, - NL80211_MESHCONF_CONFIRM_TIMEOUT, - NL80211_MESHCONF_HOLDING_TIMEOUT, - NL80211_MESHCONF_MAX_PEER_LINKS, - NL80211_MESHCONF_MAX_RETRIES, - NL80211_MESHCONF_TTL, - NL80211_MESHCONF_AUTO_OPEN_PLINKS, - NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, - NL80211_MESHCONF_PATH_REFRESH_TIME, - NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, - NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, - NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, - NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, - NL80211_MESHCONF_HWMP_ROOTMODE, - NL80211_MESHCONF_ELEMENT_TTL, - NL80211_MESHCONF_HWMP_RANN_INTERVAL, - NL80211_MESHCONF_GATE_ANNOUNCEMENTS, - NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, - NL80211_MESHCONF_FORWARDING, - NL80211_MESHCONF_RSSI_THRESHOLD, - NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, - NL80211_MESHCONF_HT_OPMODE, - NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, - NL80211_MESHCONF_HWMP_ROOT_INTERVAL, - NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, - NL80211_MESHCONF_POWER_MODE, - NL80211_MESHCONF_AWAKE_WINDOW, - NL80211_MESHCONF_PLINK_TIMEOUT, - - /* keep last */ - __NL80211_MESHCONF_ATTR_AFTER_LAST, - NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1 -}; - -/** - * 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_ENABLE_VENDOR_SYNC: Enable this option to use a - * vendor specific synchronization method or disable it to use the default - * neighbor offset synchronization - * - * @NL80211_MESH_SETUP_USERSPACE_MPM: Enable this option if userspace will - * implement an MPM which handles peer allocation and state. - * - * @NL80211_MESH_SETUP_AUTH_PROTOCOL: Inform the kernel of the authentication - * method (u8, as defined in IEEE 8.4.2.100.6, e.g. 0x1 for SAE). - * Default is no authentication method required. - * - * @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, - NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, - NL80211_MESH_SETUP_USERSPACE_MPM, - NL80211_MESH_SETUP_AUTH_PROTOCOL, - - /* 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_AC: AC identifier (NL80211_AC_*) - * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning - * disabled - * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form - * 2^n-1 in the range 1..32767] - * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form - * 2^n-1 in the range 1..32767] - * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255] - * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal - * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number - */ -enum nl80211_txq_attr { - __NL80211_TXQ_ATTR_INVALID, - NL80211_TXQ_ATTR_AC, - NL80211_TXQ_ATTR_TXOP, - NL80211_TXQ_ATTR_CWMIN, - NL80211_TXQ_ATTR_CWMAX, - NL80211_TXQ_ATTR_AIFS, - - /* keep last */ - __NL80211_TXQ_ATTR_AFTER_LAST, - NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1 -}; - -enum nl80211_ac { - NL80211_AC_VO, - NL80211_AC_VI, - NL80211_AC_BE, - NL80211_AC_BK, - NL80211_NUM_ACS -}; - -/* backward compat */ -#define NL80211_TXQ_ATTR_QUEUE NL80211_TXQ_ATTR_AC -#define NL80211_TXQ_Q_VO NL80211_AC_VO -#define NL80211_TXQ_Q_VI NL80211_AC_VI -#define NL80211_TXQ_Q_BE NL80211_AC_BE -#define NL80211_TXQ_Q_BK NL80211_AC_BK - -/** - * enum nl80211_channel_type - channel type - * @NL80211_CHAN_NO_HT: 20 MHz, non-HT channel - * @NL80211_CHAN_HT20: 20 MHz HT channel - * @NL80211_CHAN_HT40MINUS: HT40 channel, secondary channel - * below the control channel - * @NL80211_CHAN_HT40PLUS: HT40 channel, secondary channel - * above the control channel - */ -enum nl80211_channel_type { - NL80211_CHAN_NO_HT, - NL80211_CHAN_HT20, - NL80211_CHAN_HT40MINUS, - NL80211_CHAN_HT40PLUS -}; - -/** - * enum nl80211_chan_width - channel width definitions - * - * These values are used with the %NL80211_ATTR_CHANNEL_WIDTH - * attribute. - * - * @NL80211_CHAN_WIDTH_20_NOHT: 20 MHz, non-HT channel - * @NL80211_CHAN_WIDTH_20: 20 MHz HT channel - * @NL80211_CHAN_WIDTH_40: 40 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 - * attribute must be provided as well - * @NL80211_CHAN_WIDTH_80: 80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 - * attribute must be provided as well - * @NL80211_CHAN_WIDTH_80P80: 80+80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 - * and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well - * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 - * attribute must be provided as well - * @NL80211_CHAN_WIDTH_5: 5 MHz OFDM channel - * @NL80211_CHAN_WIDTH_10: 10 MHz OFDM channel - */ -enum nl80211_chan_width { - NL80211_CHAN_WIDTH_20_NOHT, - NL80211_CHAN_WIDTH_20, - NL80211_CHAN_WIDTH_40, - NL80211_CHAN_WIDTH_80, - NL80211_CHAN_WIDTH_80P80, - NL80211_CHAN_WIDTH_160, - NL80211_CHAN_WIDTH_5, - NL80211_CHAN_WIDTH_10, -}; - -/** - * enum nl80211_bss_scan_width - control channel width for a BSS - * - * These values are used with the %NL80211_BSS_CHAN_WIDTH attribute. - * - * @NL80211_BSS_CHAN_WIDTH_20: control channel is 20 MHz wide or compatible - * @NL80211_BSS_CHAN_WIDTH_10: control channel is 10 MHz wide - * @NL80211_BSS_CHAN_WIDTH_5: control channel is 5 MHz wide - */ -enum nl80211_bss_scan_width { - NL80211_BSS_CHAN_WIDTH_20, - NL80211_BSS_CHAN_WIDTH_10, - NL80211_BSS_CHAN_WIDTH_5, -}; - -/** - * enum nl80211_bss - netlink attributes for a BSS - * - * @__NL80211_BSS_INVALID: invalid - * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets) - * @NL80211_BSS_FREQUENCY: frequency in MHz (u32) - * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64) - * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16) - * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16) - * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the - * raw information elements from the probe response/beacon (bin); - * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are - * from a Probe Response frame; otherwise they are from a Beacon frame. - * However, if the driver does not indicate the source of the IEs, these - * IEs may be from either frame subtype. - * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon - * in mBm (100 * dBm) (s32) - * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon - * in unspecified units, scaled to 0..100 (u8) - * @NL80211_BSS_STATUS: status, if this BSS is "used" - * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms - * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information - * elements from a Beacon frame (bin); not present if no Beacon frame has - * yet been received - * @NL80211_BSS_CHAN_WIDTH: channel width of the control channel - * (u32, enum nl80211_bss_scan_width) - * @__NL80211_BSS_AFTER_LAST: internal - * @NL80211_BSS_MAX: highest BSS attribute - */ -enum nl80211_bss { - __NL80211_BSS_INVALID, - NL80211_BSS_BSSID, - NL80211_BSS_FREQUENCY, - NL80211_BSS_TSF, - NL80211_BSS_BEACON_INTERVAL, - NL80211_BSS_CAPABILITY, - NL80211_BSS_INFORMATION_ELEMENTS, - NL80211_BSS_SIGNAL_MBM, - NL80211_BSS_SIGNAL_UNSPEC, - NL80211_BSS_STATUS, - NL80211_BSS_SEEN_MS_AGO, - NL80211_BSS_BEACON_IES, - NL80211_BSS_CHAN_WIDTH, - - /* keep last */ - __NL80211_BSS_AFTER_LAST, - NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1 -}; - -/** - * enum nl80211_bss_status - BSS "status" - * @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS. - * @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS. - * @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS. - * - * The BSS status is a BSS attribute in scan dumps, which - * indicates the status the interface has wrt. this BSS. - */ -enum nl80211_bss_status { - NL80211_BSS_STATUS_AUTHENTICATED, - NL80211_BSS_STATUS_ASSOCIATED, - NL80211_BSS_STATUS_IBSS_JOINED, -}; - -/** - * enum nl80211_auth_type - AuthenticationType - * - * @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication - * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only) - * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r) - * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP) - * @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals - * @__NL80211_AUTHTYPE_NUM: internal - * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm - * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by - * trying multiple times); this is invalid in netlink -- leave out - * the attribute for this on CONNECT commands. - */ -enum nl80211_auth_type { - NL80211_AUTHTYPE_OPEN_SYSTEM, - NL80211_AUTHTYPE_SHARED_KEY, - NL80211_AUTHTYPE_FT, - NL80211_AUTHTYPE_NETWORK_EAP, - NL80211_AUTHTYPE_SAE, - - /* keep last */ - __NL80211_AUTHTYPE_NUM, - NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1, - NL80211_AUTHTYPE_AUTOMATIC -}; - -/** - * enum nl80211_key_type - Key Type - * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key - * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key - * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS) - * @NUM_NL80211_KEYTYPES: number of defined key types - */ -enum nl80211_key_type { - NL80211_KEYTYPE_GROUP, - NL80211_KEYTYPE_PAIRWISE, - NL80211_KEYTYPE_PEERKEY, - - NUM_NL80211_KEYTYPES -}; - -/** - * enum nl80211_mfp - Management frame protection state - * @NL80211_MFP_NO: Management frame protection not used - * @NL80211_MFP_REQUIRED: Management frame protection required - */ -enum nl80211_mfp { - NL80211_MFP_NO, - NL80211_MFP_REQUIRED, -}; - -enum nl80211_wpa_versions { - NL80211_WPA_VERSION_1 = 1 << 0, - NL80211_WPA_VERSION_2 = 1 << 1, -}; - -/** - * enum nl80211_key_default_types - key default types - * @__NL80211_KEY_DEFAULT_TYPE_INVALID: invalid - * @NL80211_KEY_DEFAULT_TYPE_UNICAST: key should be used as default - * unicast key - * @NL80211_KEY_DEFAULT_TYPE_MULTICAST: key should be used as default - * multicast key - * @NUM_NL80211_KEY_DEFAULT_TYPES: number of default types - */ -enum nl80211_key_default_types { - __NL80211_KEY_DEFAULT_TYPE_INVALID, - NL80211_KEY_DEFAULT_TYPE_UNICAST, - NL80211_KEY_DEFAULT_TYPE_MULTICAST, - - NUM_NL80211_KEY_DEFAULT_TYPES -}; - -/** - * enum nl80211_key_attributes - key attributes - * @__NL80211_KEY_INVALID: invalid - * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of - * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC - * keys - * @NL80211_KEY_IDX: key ID (u8, 0-3) - * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 - * section 7.3.2.25.1, e.g. 0x000FAC04) - * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and - * CCMP keys, each six bytes in little endian - * @NL80211_KEY_DEFAULT: flag indicating default key - * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key - * @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not - * specified the default depends on whether a MAC address was - * given with the command using the key or not (u32) - * @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags - * attributes, specifying what a key should be set as default as. - * See &enum nl80211_key_default_types. - * @__NL80211_KEY_AFTER_LAST: internal - * @NL80211_KEY_MAX: highest key attribute - */ -enum nl80211_key_attributes { - __NL80211_KEY_INVALID, - NL80211_KEY_DATA, - NL80211_KEY_IDX, - NL80211_KEY_CIPHER, - NL80211_KEY_SEQ, - NL80211_KEY_DEFAULT, - NL80211_KEY_DEFAULT_MGMT, - NL80211_KEY_TYPE, - NL80211_KEY_DEFAULT_TYPES, - - /* keep last */ - __NL80211_KEY_AFTER_LAST, - NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1 -}; - -/** - * enum nl80211_tx_rate_attributes - TX rate set attributes - * @__NL80211_TXRATE_INVALID: invalid - * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection - * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with - * 1 = 500 kbps) but without the IE length restriction (at most - * %NL80211_MAX_SUPP_RATES in a single array). - * @NL80211_TXRATE_HT: HT (MCS) rates allowed for TX rate selection - * in an array of MCS numbers. - * @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection, - * see &struct nl80211_txrate_vht - * @__NL80211_TXRATE_AFTER_LAST: internal - * @NL80211_TXRATE_MAX: highest TX rate attribute - */ -enum nl80211_tx_rate_attributes { - __NL80211_TXRATE_INVALID, - NL80211_TXRATE_LEGACY, - NL80211_TXRATE_HT, - NL80211_TXRATE_VHT, - - /* keep last */ - __NL80211_TXRATE_AFTER_LAST, - NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1 -}; - -#define NL80211_TXRATE_MCS NL80211_TXRATE_HT -#define NL80211_VHT_NSS_MAX 8 - -/** - * struct nl80211_txrate_vht - VHT MCS/NSS txrate bitmap - * @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.) - */ -struct nl80211_txrate_vht { - __u16 mcs[NL80211_VHT_NSS_MAX]; -}; - -/** - * enum nl80211_band - Frequency band - * @NL80211_BAND_2GHZ: 2.4 GHz ISM band - * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz) - * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz) - */ -enum nl80211_band { - NL80211_BAND_2GHZ, - NL80211_BAND_5GHZ, - NL80211_BAND_60GHZ, -}; - -/** - * enum nl80211_ps_state - powersave state - * @NL80211_PS_DISABLED: powersave is disabled - * @NL80211_PS_ENABLED: powersave is enabled - */ -enum nl80211_ps_state { - NL80211_PS_DISABLED, - NL80211_PS_ENABLED, -}; - -/** - * enum nl80211_attr_cqm - connection quality monitor attributes - * @__NL80211_ATTR_CQM_INVALID: invalid - * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies - * the threshold for the RSSI level at which an event will be sent. Zero - * to disable. - * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies - * the minimum amount the RSSI level must change after an event before a - * new event may be issued (to reduce effects of RSSI oscillation). - * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event - * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many - * consecutive packets were not acknowledged by the peer - * @NL80211_ATTR_CQM_TXE_RATE: TX error rate in %. Minimum % of TX failures - * during the given %NL80211_ATTR_CQM_TXE_INTVL before an - * %NL80211_CMD_NOTIFY_CQM with reported %NL80211_ATTR_CQM_TXE_RATE and - * %NL80211_ATTR_CQM_TXE_PKTS is generated. - * @NL80211_ATTR_CQM_TXE_PKTS: number of attempted packets in a given - * %NL80211_ATTR_CQM_TXE_INTVL before %NL80211_ATTR_CQM_TXE_RATE is - * checked. - * @NL80211_ATTR_CQM_TXE_INTVL: interval in seconds. Specifies the periodic - * interval in which %NL80211_ATTR_CQM_TXE_PKTS and - * %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an - * %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting. - * @__NL80211_ATTR_CQM_AFTER_LAST: internal - * @NL80211_ATTR_CQM_MAX: highest key attribute - */ -enum nl80211_attr_cqm { - __NL80211_ATTR_CQM_INVALID, - NL80211_ATTR_CQM_RSSI_THOLD, - NL80211_ATTR_CQM_RSSI_HYST, - NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, - NL80211_ATTR_CQM_PKT_LOSS_EVENT, - NL80211_ATTR_CQM_TXE_RATE, - NL80211_ATTR_CQM_TXE_PKTS, - NL80211_ATTR_CQM_TXE_INTVL, - - /* keep last */ - __NL80211_ATTR_CQM_AFTER_LAST, - NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1 -}; - -/** - * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event - * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: The RSSI level is lower than the - * configured threshold - * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the - * configured threshold - * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss. - * (Note that deauth/disassoc will still follow if the AP is not - * available. This event might get used as roaming event, etc.) - */ -enum nl80211_cqm_rssi_threshold_event { - NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, - NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, - NL80211_CQM_RSSI_BEACON_LOSS_EVENT, -}; - - -/** - * enum nl80211_tx_power_setting - TX power adjustment - * @NL80211_TX_POWER_AUTOMATIC: automatically determine transmit power - * @NL80211_TX_POWER_LIMITED: limit TX power by the mBm parameter - * @NL80211_TX_POWER_FIXED: fix TX power to the mBm parameter - */ -enum nl80211_tx_power_setting { - NL80211_TX_POWER_AUTOMATIC, - NL80211_TX_POWER_LIMITED, - NL80211_TX_POWER_FIXED, -}; - -/** - * enum nl80211_packet_pattern_attr - packet pattern attribute - * @__NL80211_PKTPAT_INVALID: invalid number for nested attribute - * @NL80211_PKTPAT_PATTERN: the pattern, values where the mask has - * a zero bit are ignored - * @NL80211_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,0x01". - * Note that the pattern matching is done as though frames were not - * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked - * first (including SNAP header unpacking) and then matched. - * @NL80211_PKTPAT_OFFSET: packet offset, pattern is matched after - * these fixed number of bytes of received packet - * @NUM_NL80211_PKTPAT: number of attributes - * @MAX_NL80211_PKTPAT: max attribute number - */ -enum nl80211_packet_pattern_attr { - __NL80211_PKTPAT_INVALID, - NL80211_PKTPAT_MASK, - NL80211_PKTPAT_PATTERN, - NL80211_PKTPAT_OFFSET, - - NUM_NL80211_PKTPAT, - MAX_NL80211_PKTPAT = NUM_NL80211_PKTPAT - 1, -}; - -/** - * struct nl80211_pattern_support - packet 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 - * @max_pkt_offset: maximum Rx packet offset - * - * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when - * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED or in - * %NL80211_ATTR_COALESCE_RULE_PKT_PATTERN when that is part of - * %NL80211_ATTR_COALESCE_RULE in the capability information given - * by the kernel to userspace. - */ -struct nl80211_pattern_support { - __u32 max_patterns; - __u32 min_pattern_len; - __u32 max_pattern_len; - __u32 max_pkt_offset; -} __attribute__((packed)); - -/* only for backward compatibility */ -#define __NL80211_WOWLAN_PKTPAT_INVALID __NL80211_PKTPAT_INVALID -#define NL80211_WOWLAN_PKTPAT_MASK NL80211_PKTPAT_MASK -#define NL80211_WOWLAN_PKTPAT_PATTERN NL80211_PKTPAT_PATTERN -#define NL80211_WOWLAN_PKTPAT_OFFSET NL80211_PKTPAT_OFFSET -#define NUM_NL80211_WOWLAN_PKTPAT NUM_NL80211_PKTPAT -#define MAX_NL80211_WOWLAN_PKTPAT MAX_NL80211_PKTPAT -#define nl80211_wowlan_pattern_support nl80211_pattern_support - -/** - * 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. Packet offset is associated with - * each pattern which is used while matching the pattern. The matching is - * done on the MSDU, i.e. as though the packet was an 802.3 packet, so the - * pattern matching is done after the packet is converted to the MSDU. - * - * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute - * carrying a &struct nl80211_pattern_support. - * - * When reporting wakeup. it is a u32 attribute containing the 0-based - * index of the pattern that caused the wakeup, in the patterns passed - * to the kernel when configuring. - * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be - * used when setting, used only to indicate that GTK rekeying is supported - * by the device (flag) - * @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) - * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211: For wakeup reporting only, contains - * the 802.11 packet that caused the wakeup, e.g. a deauth frame. The frame - * may be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN - * attribute contains the original length. - * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN: Original length of the 802.11 - * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211 - * attribute if the packet was truncated somewhere. - * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023: For wakeup reporting only, contains the - * 802.11 packet that caused the wakeup, e.g. a magic packet. The frame may - * be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN attribute - * contains the original length. - * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN: Original length of the 802.3 - * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023 - * attribute if the packet was truncated somewhere. - * @NL80211_WOWLAN_TRIG_TCP_CONNECTION: TCP connection wake, see DOC section - * "TCP connection wakeup" for more details. This is a nested attribute - * containing the exact information for establishing and keeping alive - * the TCP connection. - * @NL80211_WOWLAN_TRIG_TCP_WAKEUP_MATCH: For wakeup reporting only, the - * wakeup packet was received on the TCP connection - * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST: For wakeup reporting only, the - * TCP connection was lost or failed to be established - * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only, - * the TCP connection ran out of tokens to use for data to send to the - * service - * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers - * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number - * - * These nested attributes are used to configure the wakeup triggers and - * to report the wakeup reason(s). - */ -enum nl80211_wowlan_triggers { - __NL80211_WOWLAN_TRIG_INVALID, - 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, - NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211, - NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN, - NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023, - NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN, - NL80211_WOWLAN_TRIG_TCP_CONNECTION, - NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH, - NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST, - NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS, - - /* keep last */ - NUM_NL80211_WOWLAN_TRIG, - MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1 -}; - -/** - * DOC: TCP connection wakeup - * - * Some devices can establish a TCP connection in order to be woken up by a - * packet coming in from outside their network segment, or behind NAT. If - * configured, the device will establish a TCP connection to the given - * service, and periodically send data to that service. The first data - * packet is usually transmitted after SYN/ACK, also ACKing the SYN/ACK. - * The data packets can optionally include a (little endian) sequence - * number (in the TCP payload!) that is generated by the device, and, also - * optionally, a token from a list of tokens. This serves as a keep-alive - * with the service, and for NATed connections, etc. - * - * During this keep-alive period, the server doesn't send any data to the - * client. When receiving data, it is compared against the wakeup pattern - * (and mask) and if it matches, the host is woken up. Similarly, if the - * connection breaks or cannot be established to start with, the host is - * also woken up. - * - * Developer's note: ARP offload is required for this, otherwise TCP - * response packets might not go through correctly. - */ - -/** - * struct nl80211_wowlan_tcp_data_seq - WoWLAN TCP data sequence - * @start: starting value - * @offset: offset of sequence number in packet - * @len: length of the sequence value to write, 1 through 4 - * - * Note: don't confuse with the TCP sequence number(s), this is for the - * keepalive packet payload. The actual value is written into the packet - * in little endian. - */ -struct nl80211_wowlan_tcp_data_seq { - __u32 start, offset, len; -}; - -/** - * struct nl80211_wowlan_tcp_data_token - WoWLAN TCP data token config - * @offset: offset of token in packet - * @len: length of each token - * @token_stream: stream of data to be used for the tokens, the length must - * be a multiple of @len for this to make sense - */ -struct nl80211_wowlan_tcp_data_token { - __u32 offset, len; - __u8 token_stream[]; -}; - -/** - * struct nl80211_wowlan_tcp_data_token_feature - data token features - * @min_len: minimum token length - * @max_len: maximum token length - * @bufsize: total available token buffer size (max size of @token_stream) - */ -struct nl80211_wowlan_tcp_data_token_feature { - __u32 min_len, max_len, bufsize; -}; - -/** - * enum nl80211_wowlan_tcp_attrs - WoWLAN TCP connection parameters - * @__NL80211_WOWLAN_TCP_INVALID: invalid number for nested attributes - * @NL80211_WOWLAN_TCP_SRC_IPV4: source IPv4 address (in network byte order) - * @NL80211_WOWLAN_TCP_DST_IPV4: destination IPv4 address - * (in network byte order) - * @NL80211_WOWLAN_TCP_DST_MAC: destination MAC address, this is given because - * route lookup when configured might be invalid by the time we suspend, - * and doing a route lookup when suspending is no longer possible as it - * might require ARP querying. - * @NL80211_WOWLAN_TCP_SRC_PORT: source port (u16); optional, if not given a - * socket and port will be allocated - * @NL80211_WOWLAN_TCP_DST_PORT: destination port (u16) - * @NL80211_WOWLAN_TCP_DATA_PAYLOAD: data packet payload, at least one byte. - * For feature advertising, a u32 attribute holding the maximum length - * of the data payload. - * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ: data packet sequence configuration - * (if desired), a &struct nl80211_wowlan_tcp_data_seq. For feature - * advertising it is just a flag - * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN: data packet token configuration, - * see &struct nl80211_wowlan_tcp_data_token and for advertising see - * &struct nl80211_wowlan_tcp_data_token_feature. - * @NL80211_WOWLAN_TCP_DATA_INTERVAL: data interval in seconds, maximum - * interval in feature advertising (u32) - * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a - * u32 attribute holding the maximum length - * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for - * feature advertising. The mask works like @NL80211_PKTPAT_MASK - * but on the TCP payload only. - * @NUM_NL80211_WOWLAN_TCP: number of TCP attributes - * @MAX_NL80211_WOWLAN_TCP: highest attribute number - */ -enum nl80211_wowlan_tcp_attrs { - __NL80211_WOWLAN_TCP_INVALID, - NL80211_WOWLAN_TCP_SRC_IPV4, - NL80211_WOWLAN_TCP_DST_IPV4, - NL80211_WOWLAN_TCP_DST_MAC, - NL80211_WOWLAN_TCP_SRC_PORT, - NL80211_WOWLAN_TCP_DST_PORT, - NL80211_WOWLAN_TCP_DATA_PAYLOAD, - NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ, - NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, - NL80211_WOWLAN_TCP_DATA_INTERVAL, - NL80211_WOWLAN_TCP_WAKE_PAYLOAD, - NL80211_WOWLAN_TCP_WAKE_MASK, - - /* keep last */ - NUM_NL80211_WOWLAN_TCP, - MAX_NL80211_WOWLAN_TCP = NUM_NL80211_WOWLAN_TCP - 1 -}; - -/** - * struct nl80211_coalesce_rule_support - coalesce rule support information - * @max_rules: maximum number of rules supported - * @pat: packet pattern support information - * @max_delay: maximum supported coalescing delay in msecs - * - * This struct is carried in %NL80211_ATTR_COALESCE_RULE in the - * capability information given by the kernel to userspace. - */ -struct nl80211_coalesce_rule_support { - __u32 max_rules; - struct nl80211_pattern_support pat; - __u32 max_delay; -} __attribute__((packed)); - -/** - * enum nl80211_attr_coalesce_rule - coalesce rule attribute - * @__NL80211_COALESCE_RULE_INVALID: invalid number for nested attribute - * @NL80211_ATTR_COALESCE_RULE_DELAY: delay in msecs used for packet coalescing - * @NL80211_ATTR_COALESCE_RULE_CONDITION: condition for packet coalescence, - * see &enum nl80211_coalesce_condition. - * @NL80211_ATTR_COALESCE_RULE_PKT_PATTERN: packet offset, pattern is matched - * after these fixed number of bytes of received packet - * @NUM_NL80211_ATTR_COALESCE_RULE: number of attributes - * @NL80211_ATTR_COALESCE_RULE_MAX: max attribute number - */ -enum nl80211_attr_coalesce_rule { - __NL80211_COALESCE_RULE_INVALID, - NL80211_ATTR_COALESCE_RULE_DELAY, - NL80211_ATTR_COALESCE_RULE_CONDITION, - NL80211_ATTR_COALESCE_RULE_PKT_PATTERN, - - /* keep last */ - NUM_NL80211_ATTR_COALESCE_RULE, - NL80211_ATTR_COALESCE_RULE_MAX = NUM_NL80211_ATTR_COALESCE_RULE - 1 -}; - -/** - * enum nl80211_coalesce_condition - coalesce rule conditions - * @NL80211_COALESCE_CONDITION_MATCH: coalaesce Rx packets when patterns - * in a rule are matched. - * @NL80211_COALESCE_CONDITION_NO_MATCH: coalesce Rx packets when patterns - * in a rule are not matched. - */ -enum nl80211_coalesce_condition { - NL80211_COALESCE_CONDITION_MATCH, - NL80211_COALESCE_CONDITION_NO_MATCH -}; - -/** - * 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. - * @NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS: u32 attribute containing the bitmap - * of supported channel widths for radar detection. - * @NUM_NL80211_IFACE_COMB: number of attributes - * @MAX_NL80211_IFACE_COMB: highest attribute number - * - * 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 = [ #{} <= 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, - NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, - - /* 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 -}; - -/** - * enum nl80211_plink_action - actions to perform in mesh peers - * - * @NL80211_PLINK_ACTION_NO_ACTION: perform no action - * @NL80211_PLINK_ACTION_OPEN: start mesh peer link establishment - * @NL80211_PLINK_ACTION_BLOCK: block traffic from this mesh peer - * @NUM_NL80211_PLINK_ACTIONS: number of possible actions - */ -enum plink_actions { - NL80211_PLINK_ACTION_NO_ACTION, - NL80211_PLINK_ACTION_OPEN, - NL80211_PLINK_ACTION_BLOCK, - - NUM_NL80211_PLINK_ACTIONS, -}; - - -#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. - * @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates. - * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up - * the connected inactive stations in AP mode. - * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested - * to work properly to suppport receiving regulatory hints from - * cellular base stations. - * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: If this is set, an active - * P2P Device (%NL80211_IFTYPE_P2P_DEVICE) requires its own channel - * in the interface combinations, even when it's only used for scan - * and remain-on-channel. This could be due to, for example, the - * remain-on-channel implementation requiring a channel context. - * @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of - * equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station - * mode - * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan - * @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported - * @NL80211_FEATURE_AP_SCAN: Support scanning using an AP vif - * @NL80211_FEATURE_VIF_TXPOWER: The driver supports per-vif TX power setting - * @NL80211_FEATURE_NEED_OBSS_SCAN: The driver expects userspace to perform - * OBSS scans and generate 20/40 BSS coex reports. This flag is used only - * for drivers implementing the CONNECT API, for AUTH/ASSOC it is implied. - * @NL80211_FEATURE_P2P_GO_CTWIN: P2P GO implementation supports CT Window - * setting - * @NL80211_FEATURE_P2P_GO_OPPPS: P2P GO implementation supports opportunistic - * powersave - * @NL80211_FEATURE_FULL_AP_CLIENT_STATE: The driver supports full state - * transitions for AP clients. Without this flag (and if the driver - * doesn't have the AP SME in the device) the driver supports adding - * stations only when they're associated and adds them in associated - * state (to later be transitioned into authorized), with this flag - * they should be added before even sending the authentication reply - * and then transitioned into authenticated, associated and authorized - * states using station flags. - * Note that even for drivers that support this, the default is to add - * stations in authenticated/associated state, so to add unauthenticated - * stations the authenticated/associated bits have to be set in the mask. - * @NL80211_FEATURE_ADVERTISE_CHAN_LIMITS: cfg80211 advertises channel limits - * (HT40, VHT 80/160 MHz) if this flag is set - * @NL80211_FEATURE_USERSPACE_MPM: This driver supports a userspace Mesh - * Peering Management entity which may be implemented by registering for - * beacons or NL80211_CMD_NEW_PEER_CANDIDATE events. The mesh beacon is - * still generated by the driver. - * @NL80211_FEATURE_ACTIVE_MONITOR: This driver supports an active monitor - * interface. An active monitor interface behaves like a normal monitor - * interface, but gets added to the driver. It ensures that incoming - * unicast packets directed at the configured interface address get ACKed. - */ -enum nl80211_feature_flags { - NL80211_FEATURE_SK_TX_STATUS = 1 << 0, - NL80211_FEATURE_HT_IBSS = 1 << 1, - NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2, - NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3, - NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4, - NL80211_FEATURE_SAE = 1 << 5, - NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6, - NL80211_FEATURE_SCAN_FLUSH = 1 << 7, - NL80211_FEATURE_AP_SCAN = 1 << 8, - NL80211_FEATURE_VIF_TXPOWER = 1 << 9, - NL80211_FEATURE_NEED_OBSS_SCAN = 1 << 10, - NL80211_FEATURE_P2P_GO_CTWIN = 1 << 11, - NL80211_FEATURE_P2P_GO_OPPPS = 1 << 12, - /* bit 13 is reserved */ - NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14, - NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15, - NL80211_FEATURE_USERSPACE_MPM = 1 << 16, - NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17, -}; - -/** - * 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, -}; - -/** - * enum nl80211_connect_failed_reason - connection request failed reasons - * @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be - * handled by the AP is reached. - * @NL80211_CONN_FAIL_BLOCKED_CLIENT: Connection request is rejected due to ACL. - */ -enum nl80211_connect_failed_reason { - NL80211_CONN_FAIL_MAX_CLIENTS, - NL80211_CONN_FAIL_BLOCKED_CLIENT, -}; - -/** - * enum nl80211_scan_flags - scan request control flags - * - * Scan request control flags are used to control the handling - * of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN - * requests. - * - * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority - * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning - * @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured - * as AP and the beaconing has already been configured. This attribute is - * dangerous because will destroy stations performance as a lot of frames - * will be lost while scanning off-channel, therefore it must be used only - * when really needed - */ -enum nl80211_scan_flags { - NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, - NL80211_SCAN_FLAG_FLUSH = 1<<1, - NL80211_SCAN_FLAG_AP = 1<<2, -}; - -/** - * enum nl80211_acl_policy - access control policy - * - * Access control policy is applied on a MAC list set by - * %NL80211_CMD_START_AP and %NL80211_CMD_SET_MAC_ACL, to - * be used with %NL80211_ATTR_ACL_POLICY. - * - * @NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: Deny stations which are - * listed in ACL, i.e. allow all the stations which are not listed - * in ACL to authenticate. - * @NL80211_ACL_POLICY_DENY_UNLESS_LISTED: Allow the stations which are listed - * in ACL, i.e. deny all the stations which are not listed in ACL. - */ -enum nl80211_acl_policy { - NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED, - NL80211_ACL_POLICY_DENY_UNLESS_LISTED, -}; - -/** - * enum nl80211_radar_event - type of radar event for DFS operation - * - * Type of event to be used with NL80211_ATTR_RADAR_EVENT to inform userspace - * about detected radars or success of the channel available check (CAC) - * - * @NL80211_RADAR_DETECTED: A radar pattern has been detected. The channel is - * now unusable. - * @NL80211_RADAR_CAC_FINISHED: Channel Availability Check has been finished, - * the channel is now available. - * @NL80211_RADAR_CAC_ABORTED: Channel Availability Check has been aborted, no - * change to the channel status. - * @NL80211_RADAR_NOP_FINISHED: The Non-Occupancy Period for this channel is - * over, channel becomes usable. - */ -enum nl80211_radar_event { - NL80211_RADAR_DETECTED, - NL80211_RADAR_CAC_FINISHED, - NL80211_RADAR_CAC_ABORTED, - NL80211_RADAR_NOP_FINISHED, -}; - -/** - * enum nl80211_dfs_state - DFS states for channels - * - * Channel states used by the DFS code. - * - * @NL80211_DFS_USABLE: The channel can be used, but channel availability - * check (CAC) must be performed before using it for AP or IBSS. - * @NL80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it - * is therefore marked as not available. - * @NL80211_DFS_AVAILABLE: The channel has been CAC checked and is available. - */ -enum nl80211_dfs_state { - NL80211_DFS_USABLE, - NL80211_DFS_UNAVAILABLE, - NL80211_DFS_AVAILABLE, -}; - -/** - * enum enum nl80211_protocol_features - nl80211 protocol features - * @NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP: nl80211 supports splitting - * wiphy dumps (if requested by the application with the attribute - * %NL80211_ATTR_SPLIT_WIPHY_DUMP. Also supported is filtering the - * wiphy dump by %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFINDEX or - * %NL80211_ATTR_WDEV. - */ -enum nl80211_protocol_features { - NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP = 1 << 0, -}; - -/** - * enum nl80211_crit_proto_id - nl80211 critical protocol identifiers - * - * @NL80211_CRIT_PROTO_UNSPEC: protocol unspecified. - * @NL80211_CRIT_PROTO_DHCP: BOOTP or DHCPv6 protocol. - * @NL80211_CRIT_PROTO_EAPOL: EAPOL protocol. - * @NL80211_CRIT_PROTO_APIPA: APIPA protocol. - * @NUM_NL80211_CRIT_PROTO: must be kept last. - */ -enum nl80211_crit_proto_id { - NL80211_CRIT_PROTO_UNSPEC, - NL80211_CRIT_PROTO_DHCP, - NL80211_CRIT_PROTO_EAPOL, - NL80211_CRIT_PROTO_APIPA, - /* add other protocols before this one */ - NUM_NL80211_CRIT_PROTO -}; - -/* maximum duration for critical protocol measures */ -#define NL80211_CRIT_PROTO_MAX_DURATION 5000 /* msec */ - -/** - * enum nl80211_rxmgmt_flags - flags for received management frame. - * - * Used by cfg80211_rx_mgmt() - * - * @NL80211_RXMGMT_FLAG_ANSWERED: frame was answered by device/driver. - */ -enum nl80211_rxmgmt_flags { - NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0, -}; - -/* - * If this flag is unset, the lower 24 bits are an OUI, if set - * a Linux nl80211 vendor ID is used (no such IDs are allocated - * yet, so that's not valid so far) - */ -#define NL80211_VENDOR_ID_IS_LINUX 0x80000000 - -/** - * struct nl80211_vendor_cmd_info - vendor command data - * @vendor_id: If the %NL80211_VENDOR_ID_IS_LINUX flag is clear, then the - * value is a 24-bit OUI; if it is set then a separately allocated ID - * may be used, but no such IDs are allocated yet. New IDs should be - * added to this file when needed. - * @subcmd: sub-command ID for the command - */ -struct nl80211_vendor_cmd_info { - __u32 vendor_id; - __u32 subcmd; -}; - -#endif /* __LINUX_NL80211_H */ diff --git a/contrib/hostapd/src/drivers/priv_netlink.h b/contrib/hostapd/src/drivers/priv_netlink.h deleted file mode 100644 index 62320880c1..0000000000 --- a/contrib/hostapd/src/drivers/priv_netlink.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * wpa_supplicant - Private copy of Linux netlink/rtnetlink definitions. - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef PRIV_NETLINK_H -#define PRIV_NETLINK_H - -/* - * This should be replaced with user space header once one is available with C - * library, etc.. - */ - -#ifndef IFF_LOWER_UP -#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ -#endif -#ifndef IFF_DORMANT -#define IFF_DORMANT 0x20000 /* driver signals dormant */ -#endif - -#ifndef IFLA_IFNAME -#define IFLA_IFNAME 3 -#endif -#ifndef IFLA_WIRELESS -#define IFLA_WIRELESS 11 -#endif -#ifndef IFLA_OPERSTATE -#define IFLA_OPERSTATE 16 -#endif -#ifndef IFLA_LINKMODE -#define IFLA_LINKMODE 17 -#define IF_OPER_DORMANT 5 -#define IF_OPER_UP 6 -#endif - -#define NLM_F_REQUEST 1 - -#define NETLINK_ROUTE 0 -#define RTMGRP_LINK 1 -#define RTM_BASE 0x10 -#define RTM_NEWLINK (RTM_BASE + 0) -#define RTM_DELLINK (RTM_BASE + 1) -#define RTM_SETLINK (RTM_BASE + 3) - -#define NLMSG_ALIGNTO 4 -#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1)) -#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) -#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr))) -#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) -#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0))) -#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ - (struct nlmsghdr *) \ - (((char *)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) -#define NLMSG_OK(nlh,len) ((len) >= (int) sizeof(struct nlmsghdr) && \ - (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ - (int) (nlh)->nlmsg_len <= (len)) -#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) - -#define RTA_ALIGNTO 4 -#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1)) -#define RTA_OK(rta,len) \ -((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \ -(rta)->rta_len <= (len)) -#define RTA_NEXT(rta,attrlen) \ -((attrlen) -= RTA_ALIGN((rta)->rta_len), \ -(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len))) -#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len)) -#define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0))) -#define RTA_PAYLOAD(rta) ((int) ((rta)->rta_len) - RTA_LENGTH(0)) - - -struct sockaddr_nl -{ - sa_family_t nl_family; - unsigned short nl_pad; - u32 nl_pid; - u32 nl_groups; -}; - -struct nlmsghdr -{ - u32 nlmsg_len; - u16 nlmsg_type; - u16 nlmsg_flags; - u32 nlmsg_seq; - u32 nlmsg_pid; -}; - -struct ifinfomsg -{ - unsigned char ifi_family; - unsigned char __ifi_pad; - unsigned short ifi_type; - int ifi_index; - unsigned ifi_flags; - unsigned ifi_change; -}; - -struct rtattr -{ - unsigned short rta_len; - unsigned short rta_type; -}; - -#endif /* PRIV_NETLINK_H */ diff --git a/contrib/hostapd/src/drivers/rfkill.c b/contrib/hostapd/src/drivers/rfkill.c deleted file mode 100644 index 45b26c46b6..0000000000 --- a/contrib/hostapd/src/drivers/rfkill.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Linux rfkill helper functions for driver wrappers - * Copyright (c) 2010, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "utils/common.h" -#include "utils/eloop.h" -#include "rfkill.h" - -#define RFKILL_EVENT_SIZE_V1 8 - -struct rfkill_event { - u32 idx; - u8 type; - u8 op; - u8 soft; - u8 hard; -} STRUCT_PACKED; - -enum rfkill_operation { - RFKILL_OP_ADD = 0, - RFKILL_OP_DEL, - RFKILL_OP_CHANGE, - RFKILL_OP_CHANGE_ALL, -}; - -enum rfkill_type { - RFKILL_TYPE_ALL = 0, - RFKILL_TYPE_WLAN, - RFKILL_TYPE_BLUETOOTH, - RFKILL_TYPE_UWB, - RFKILL_TYPE_WIMAX, - RFKILL_TYPE_WWAN, - RFKILL_TYPE_GPS, - RFKILL_TYPE_FM, - NUM_RFKILL_TYPES, -}; - - -struct rfkill_data { - struct rfkill_config *cfg; - int fd; - int blocked; -}; - - -static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct rfkill_data *rfkill = eloop_ctx; - struct rfkill_event event; - ssize_t len; - int new_blocked; - - len = read(rfkill->fd, &event, sizeof(event)); - if (len < 0) { - wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s", - strerror(errno)); - return; - } - if (len != RFKILL_EVENT_SIZE_V1) { - wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size " - "%d (expected %d)", - (int) len, RFKILL_EVENT_SIZE_V1); - return; - } - wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d " - "op=%u soft=%u hard=%u", - event.idx, event.type, event.op, event.soft, - event.hard); - if (event.op != RFKILL_OP_CHANGE || event.type != RFKILL_TYPE_WLAN) - return; - - if (event.hard) { - wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); - new_blocked = 1; - } else if (event.soft) { - wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); - new_blocked = 1; - } else { - wpa_printf(MSG_INFO, "rfkill: WLAN unblocked"); - new_blocked = 0; - } - - if (new_blocked != rfkill->blocked) { - rfkill->blocked = new_blocked; - if (new_blocked) - rfkill->cfg->blocked_cb(rfkill->cfg->ctx); - else - rfkill->cfg->unblocked_cb(rfkill->cfg->ctx); - } -} - - -struct rfkill_data * rfkill_init(struct rfkill_config *cfg) -{ - struct rfkill_data *rfkill; - struct rfkill_event event; - ssize_t len; - - rfkill = os_zalloc(sizeof(*rfkill)); - if (rfkill == NULL) - return NULL; - - rfkill->cfg = cfg; - rfkill->fd = open("/dev/rfkill", O_RDONLY); - if (rfkill->fd < 0) { - wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control " - "device"); - goto fail; - } - - if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) { - wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: " - "%s", strerror(errno)); - goto fail2; - } - - for (;;) { - len = read(rfkill->fd, &event, sizeof(event)); - if (len < 0) { - if (errno == EAGAIN) - break; /* No more entries */ - wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s", - strerror(errno)); - break; - } - if (len != RFKILL_EVENT_SIZE_V1) { - wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size " - "%d (expected %d)", - (int) len, RFKILL_EVENT_SIZE_V1); - continue; - } - wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d " - "op=%u soft=%u hard=%u", - event.idx, event.type, event.op, event.soft, - event.hard); - if (event.op != RFKILL_OP_ADD || - event.type != RFKILL_TYPE_WLAN) - continue; - if (event.hard) { - wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); - rfkill->blocked = 1; - } else if (event.soft) { - wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); - rfkill->blocked = 1; - } - } - - eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL); - - return rfkill; - -fail2: - close(rfkill->fd); -fail: - os_free(rfkill); - return NULL; -} - - -void rfkill_deinit(struct rfkill_data *rfkill) -{ - if (rfkill == NULL) - return; - - if (rfkill->fd >= 0) { - eloop_unregister_read_sock(rfkill->fd); - close(rfkill->fd); - } - - os_free(rfkill->cfg); - os_free(rfkill); -} - - -int rfkill_is_blocked(struct rfkill_data *rfkill) -{ - if (rfkill == NULL) - return 0; - - return rfkill->blocked; -} diff --git a/contrib/hostapd/src/drivers/rfkill.h b/contrib/hostapd/src/drivers/rfkill.h deleted file mode 100644 index 0412ac3305..0000000000 --- a/contrib/hostapd/src/drivers/rfkill.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Linux rfkill helper functions for driver wrappers - * Copyright (c) 2010, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef RFKILL_H -#define RFKILL_H - -struct rfkill_data; - -struct rfkill_config { - void *ctx; - char ifname[IFNAMSIZ]; - void (*blocked_cb)(void *ctx); - void (*unblocked_cb)(void *ctx); -}; - -struct rfkill_data * rfkill_init(struct rfkill_config *cfg); -void rfkill_deinit(struct rfkill_data *rfkill); -int rfkill_is_blocked(struct rfkill_data *rfkill); - -#endif /* RFKILL_H */ diff --git a/contrib/hostapd/src/eap_common/chap.c b/contrib/hostapd/src/eap_common/chap.c deleted file mode 100644 index 820d18a416..0000000000 --- a/contrib/hostapd/src/eap_common/chap.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * CHAP-MD5 (RFC 1994) - * Copyright (c) 2007-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/crypto.h" -#include "chap.h" - -int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge, - size_t challenge_len, u8 *response) -{ - const u8 *addr[3]; - size_t len[3]; - - addr[0] = &id; - len[0] = 1; - addr[1] = secret; - len[1] = secret_len; - addr[2] = challenge; - len[2] = challenge_len; - return md5_vector(3, addr, len, response); -} diff --git a/contrib/hostapd/src/eap_common/chap.h b/contrib/hostapd/src/eap_common/chap.h deleted file mode 100644 index a791505f99..0000000000 --- a/contrib/hostapd/src/eap_common/chap.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * CHAP-MD5 (RFC 1994) - * Copyright (c) 2007-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef CHAP_H -#define CHAP_H - -#define CHAP_MD5_LEN 16 - -int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge, - size_t challenge_len, u8 *response); - -#endif /* CHAP_H */ diff --git a/contrib/hostapd/src/eap_common/eap_common.c b/contrib/hostapd/src/eap_common/eap_common.c deleted file mode 100644 index 7b077cb9f5..0000000000 --- a/contrib/hostapd/src/eap_common/eap_common.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * EAP common peer/server definitions - * Copyright (c) 2004-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_defs.h" -#include "eap_common.h" - -/** - * eap_hdr_len_valid - Validate EAP header length field - * @msg: EAP frame (starting with EAP header) - * @min_payload: Minimum payload length needed - * Returns: 1 for valid header, 0 for invalid - * - * This is a helper function that does minimal validation of EAP messages. The - * length field is verified to be large enough to include the header and not - * too large to go beyond the end of the buffer. - */ -int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload) -{ - const struct eap_hdr *hdr; - size_t len; - - if (msg == NULL) - return 0; - - hdr = wpabuf_head(msg); - - if (wpabuf_len(msg) < sizeof(*hdr)) { - wpa_printf(MSG_INFO, "EAP: Too short EAP frame"); - return 0; - } - - len = be_to_host16(hdr->length); - if (len < sizeof(*hdr) + min_payload || len > wpabuf_len(msg)) { - wpa_printf(MSG_INFO, "EAP: Invalid EAP length"); - return 0; - } - - return 1; -} - - -/** - * eap_hdr_validate - Validate EAP header - * @vendor: Expected EAP Vendor-Id (0 = IETF) - * @eap_type: Expected EAP type number - * @msg: EAP frame (starting with EAP header) - * @plen: Pointer to variable to contain the returned payload length - * Returns: Pointer to EAP payload (after type field), or %NULL on failure - * - * This is a helper function for EAP method implementations. This is usually - * called in the beginning of struct eap_method::process() function to verify - * that the received EAP request packet has a valid header. This function is - * able to process both legacy and expanded EAP headers and in most cases, the - * caller can just use the returned payload pointer (into *plen) for processing - * the payload regardless of whether the packet used the expanded EAP header or - * not. - */ -const u8 * eap_hdr_validate(int vendor, EapType eap_type, - const struct wpabuf *msg, size_t *plen) -{ - const struct eap_hdr *hdr; - const u8 *pos; - size_t len; - - if (!eap_hdr_len_valid(msg, 1)) - return NULL; - - hdr = wpabuf_head(msg); - len = be_to_host16(hdr->length); - pos = (const u8 *) (hdr + 1); - - if (*pos == EAP_TYPE_EXPANDED) { - int exp_vendor; - u32 exp_type; - if (len < sizeof(*hdr) + 8) { - wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP " - "length"); - return NULL; - } - pos++; - exp_vendor = WPA_GET_BE24(pos); - pos += 3; - exp_type = WPA_GET_BE32(pos); - pos += 4; - if (exp_vendor != vendor || exp_type != (u32) eap_type) { - wpa_printf(MSG_INFO, "EAP: Invalid expanded frame " - "type"); - return NULL; - } - - *plen = len - sizeof(*hdr) - 8; - return pos; - } else { - if (vendor != EAP_VENDOR_IETF || *pos != eap_type) { - wpa_printf(MSG_INFO, "EAP: Invalid frame type"); - return NULL; - } - *plen = len - sizeof(*hdr) - 1; - return pos + 1; - } -} - - -/** - * eap_msg_alloc - Allocate a buffer for an EAP message - * @vendor: Vendor-Id (0 = IETF) - * @type: EAP type - * @payload_len: Payload length in bytes (data after Type) - * @code: Message Code (EAP_CODE_*) - * @identifier: Identifier - * Returns: Pointer to the allocated message buffer or %NULL on error - * - * This function can be used to allocate a buffer for an EAP message and fill - * in the EAP header. This function is automatically using expanded EAP header - * if the selected Vendor-Id is not IETF. In other words, most EAP methods do - * not need to separately select which header type to use when using this - * function to allocate the message buffers. The returned buffer has room for - * payload_len bytes and has the EAP header and Type field already filled in. - */ -struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len, - u8 code, u8 identifier) -{ - struct wpabuf *buf; - struct eap_hdr *hdr; - size_t len; - - len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) + - payload_len; - buf = wpabuf_alloc(len); - if (buf == NULL) - return NULL; - - hdr = wpabuf_put(buf, sizeof(*hdr)); - hdr->code = code; - hdr->identifier = identifier; - hdr->length = host_to_be16(len); - - if (vendor == EAP_VENDOR_IETF) { - wpabuf_put_u8(buf, type); - } else { - wpabuf_put_u8(buf, EAP_TYPE_EXPANDED); - wpabuf_put_be24(buf, vendor); - wpabuf_put_be32(buf, type); - } - - return buf; -} - - -/** - * eap_update_len - Update EAP header length - * @msg: EAP message from eap_msg_alloc - * - * This function updates the length field in the EAP header to match with the - * current length for the buffer. This allows eap_msg_alloc() to be used to - * allocate a larger buffer than the exact message length (e.g., if exact - * message length is not yet known). - */ -void eap_update_len(struct wpabuf *msg) -{ - struct eap_hdr *hdr; - hdr = wpabuf_mhead(msg); - if (wpabuf_len(msg) < sizeof(*hdr)) - return; - hdr->length = host_to_be16(wpabuf_len(msg)); -} - - -/** - * eap_get_id - Get EAP Identifier from wpabuf - * @msg: Buffer starting with an EAP header - * Returns: The Identifier field from the EAP header - */ -u8 eap_get_id(const struct wpabuf *msg) -{ - const struct eap_hdr *eap; - - if (wpabuf_len(msg) < sizeof(*eap)) - return 0; - - eap = wpabuf_head(msg); - return eap->identifier; -} - - -/** - * eap_get_id - Get EAP Type from wpabuf - * @msg: Buffer starting with an EAP header - * Returns: The EAP Type after the EAP header - */ -EapType eap_get_type(const struct wpabuf *msg) -{ - if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1) - return EAP_TYPE_NONE; - - return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)]; -} diff --git a/contrib/hostapd/src/eap_common/eap_common.h b/contrib/hostapd/src/eap_common/eap_common.h deleted file mode 100644 index 8850c1fe55..0000000000 --- a/contrib/hostapd/src/eap_common/eap_common.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * EAP common peer/server definitions - * Copyright (c) 2004-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_COMMON_H -#define EAP_COMMON_H - -#include "wpabuf.h" - -int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload); -const u8 * eap_hdr_validate(int vendor, EapType eap_type, - const struct wpabuf *msg, size_t *plen); -struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len, - u8 code, u8 identifier); -void eap_update_len(struct wpabuf *msg); -u8 eap_get_id(const struct wpabuf *msg); -EapType eap_get_type(const struct wpabuf *msg); - -#endif /* EAP_COMMON_H */ diff --git a/contrib/hostapd/src/eap_common/eap_defs.h b/contrib/hostapd/src/eap_common/eap_defs.h deleted file mode 100644 index f5890bec27..0000000000 --- a/contrib/hostapd/src/eap_common/eap_defs.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * EAP server/peer: Shared EAP definitions - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_DEFS_H -#define EAP_DEFS_H - -/* RFC 3748 - Extensible Authentication Protocol (EAP) */ - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct eap_hdr { - u8 code; - u8 identifier; - be16 length; /* including code and identifier; network byte order */ - /* followed by length-4 octets of data */ -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - -enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3, - EAP_CODE_FAILURE = 4 }; - -/* EAP Request and Response data begins with one octet Type. Success and - * Failure do not have additional data. */ - -/* - * EAP Method Types as allocated by IANA: - * http://www.iana.org/assignments/eap-numbers - */ -typedef enum { - EAP_TYPE_NONE = 0, - EAP_TYPE_IDENTITY = 1 /* RFC 3748 */, - EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */, - EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */, - EAP_TYPE_MD5 = 4, /* RFC 3748 */ - EAP_TYPE_OTP = 5 /* RFC 3748 */, - EAP_TYPE_GTC = 6, /* RFC 3748 */ - EAP_TYPE_TLS = 13 /* RFC 2716 */, - EAP_TYPE_LEAP = 17 /* Cisco proprietary */, - EAP_TYPE_SIM = 18 /* RFC 4186 */, - EAP_TYPE_TTLS = 21 /* RFC 5281 */, - EAP_TYPE_AKA = 23 /* RFC 4187 */, - EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */, - EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */, - EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */, - EAP_TYPE_TNC = 38 /* TNC IF-T v1.0-r3; note: tentative assignment; - * type 38 has previously been allocated for - * EAP-HTTP Digest, (funk.com) */, - EAP_TYPE_FAST = 43 /* RFC 4851 */, - EAP_TYPE_PAX = 46 /* RFC 4746 */, - EAP_TYPE_PSK = 47 /* RFC 4764 */, - EAP_TYPE_SAKE = 48 /* RFC 4763 */, - EAP_TYPE_IKEV2 = 49 /* RFC 5106 */, - EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */, - EAP_TYPE_GPSK = 51 /* RFC 5433 */, - EAP_TYPE_PWD = 52 /* RFC 5931 */, - EAP_TYPE_EKE = 53 /* RFC 6124 */, - EAP_TYPE_EXPANDED = 254 /* RFC 3748 */ -} EapType; - - -/* SMI Network Management Private Enterprise Code for vendor specific types */ -enum { - EAP_VENDOR_IETF = 0, - EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */, - EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */, - EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */ -}; - -#define EAP_VENDOR_UNAUTH_TLS EAP_VENDOR_HOSTAP -#define EAP_VENDOR_TYPE_UNAUTH_TLS 1 - -#define EAP_MSK_LEN 64 -#define EAP_EMSK_LEN 64 - -#endif /* EAP_DEFS_H */ diff --git a/contrib/hostapd/src/eap_common/eap_eke_common.c b/contrib/hostapd/src/eap_common/eap_eke_common.c deleted file mode 100644 index a62ac8e046..0000000000 --- a/contrib/hostapd/src/eap_common/eap_eke_common.c +++ /dev/null @@ -1,768 +0,0 @@ -/* - * EAP server/peer: EAP-EKE shared routines - * Copyright (c) 2011-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/aes.h" -#include "crypto/aes_wrap.h" -#include "crypto/crypto.h" -#include "crypto/dh_groups.h" -#include "crypto/random.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "eap_common/eap_defs.h" -#include "eap_eke_common.h" - - -static int eap_eke_dh_len(u8 group) -{ - switch (group) { - case EAP_EKE_DHGROUP_EKE_2: - return 128; - case EAP_EKE_DHGROUP_EKE_5: - return 192; - case EAP_EKE_DHGROUP_EKE_14: - return 256; - case EAP_EKE_DHGROUP_EKE_15: - return 384; - case EAP_EKE_DHGROUP_EKE_16: - return 512; - } - - return -1; -} - - -static int eap_eke_dhcomp_len(u8 dhgroup, u8 encr) -{ - int dhlen; - - dhlen = eap_eke_dh_len(dhgroup); - if (dhlen < 0) - return -1; - if (encr != EAP_EKE_ENCR_AES128_CBC) - return -1; - return AES_BLOCK_SIZE + dhlen; -} - - -static const struct dh_group * eap_eke_dh_group(u8 group) -{ - switch (group) { - case EAP_EKE_DHGROUP_EKE_2: - return dh_groups_get(2); - case EAP_EKE_DHGROUP_EKE_5: - return dh_groups_get(5); - case EAP_EKE_DHGROUP_EKE_14: - return dh_groups_get(14); - case EAP_EKE_DHGROUP_EKE_15: - return dh_groups_get(15); - case EAP_EKE_DHGROUP_EKE_16: - return dh_groups_get(16); - } - - return NULL; -} - - -static int eap_eke_dh_generator(u8 group) -{ - switch (group) { - case EAP_EKE_DHGROUP_EKE_2: - return 5; - case EAP_EKE_DHGROUP_EKE_5: - return 31; - case EAP_EKE_DHGROUP_EKE_14: - return 11; - case EAP_EKE_DHGROUP_EKE_15: - return 5; - case EAP_EKE_DHGROUP_EKE_16: - return 5; - } - - return -1; -} - - -static int eap_eke_pnonce_len(u8 mac) -{ - int mac_len; - - if (mac == EAP_EKE_MAC_HMAC_SHA1) - mac_len = SHA1_MAC_LEN; - else if (mac == EAP_EKE_MAC_HMAC_SHA2_256) - mac_len = SHA256_MAC_LEN; - else - return -1; - - return AES_BLOCK_SIZE + 16 + mac_len; -} - - -static int eap_eke_pnonce_ps_len(u8 mac) -{ - int mac_len; - - if (mac == EAP_EKE_MAC_HMAC_SHA1) - mac_len = SHA1_MAC_LEN; - else if (mac == EAP_EKE_MAC_HMAC_SHA2_256) - mac_len = SHA256_MAC_LEN; - else - return -1; - - return AES_BLOCK_SIZE + 2 * 16 + mac_len; -} - - -static int eap_eke_prf_len(u8 prf) -{ - if (prf == EAP_EKE_PRF_HMAC_SHA1) - return 20; - if (prf == EAP_EKE_PRF_HMAC_SHA2_256) - return 32; - return -1; -} - - -static int eap_eke_nonce_len(u8 prf) -{ - int prf_len; - - prf_len = eap_eke_prf_len(prf); - if (prf_len < 0) - return -1; - - if (prf_len > 2 * 16) - return (prf_len + 1) / 2; - - return 16; -} - - -static int eap_eke_auth_len(u8 prf) -{ - switch (prf) { - case EAP_EKE_PRF_HMAC_SHA1: - return SHA1_MAC_LEN; - case EAP_EKE_PRF_HMAC_SHA2_256: - return SHA256_MAC_LEN; - } - - return -1; -} - - -int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub) -{ - int generator; - u8 gen; - const struct dh_group *dh; - size_t pub_len, i; - - generator = eap_eke_dh_generator(group); - if (generator < 0 || generator > 255) - return -1; - gen = generator; - - dh = eap_eke_dh_group(group); - if (dh == NULL) - return -1; - - /* x = random number 2 .. p-1 */ - if (random_get_bytes(ret_priv, dh->prime_len)) - return -1; - if (os_memcmp(ret_priv, dh->prime, dh->prime_len) > 0) { - /* Make sure private value is smaller than prime */ - ret_priv[0] = 0; - } - for (i = 0; i < dh->prime_len - 1; i++) { - if (ret_priv[i]) - break; - } - if (i == dh->prime_len - 1 && (ret_priv[i] == 0 || ret_priv[i] == 1)) - return -1; - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: DH private value", - ret_priv, dh->prime_len); - - /* y = g ^ x (mod p) */ - pub_len = dh->prime_len; - if (crypto_mod_exp(&gen, 1, ret_priv, dh->prime_len, - dh->prime, dh->prime_len, ret_pub, &pub_len) < 0) - return -1; - if (pub_len < dh->prime_len) { - size_t pad = dh->prime_len - pub_len; - os_memmove(ret_pub + pad, ret_pub, pub_len); - os_memset(ret_pub, 0, pad); - } - - wpa_hexdump(MSG_DEBUG, "EAP-EKE: DH public value", - ret_pub, dh->prime_len); - - return 0; -} - - -static int eap_eke_prf(u8 prf, const u8 *key, size_t key_len, const u8 *data, - size_t data_len, const u8 *data2, size_t data2_len, - u8 *res) -{ - const u8 *addr[2]; - size_t len[2]; - size_t num_elem = 1; - - addr[0] = data; - len[0] = data_len; - if (data2) { - num_elem++; - addr[1] = data2; - len[1] = data2_len; - } - - if (prf == EAP_EKE_PRF_HMAC_SHA1) - return hmac_sha1_vector(key, key_len, num_elem, addr, len, res); - if (prf == EAP_EKE_PRF_HMAC_SHA2_256) - return hmac_sha256_vector(key, key_len, num_elem, addr, len, - res); - return -1; -} - - -static int eap_eke_prf_hmac_sha1(const u8 *key, size_t key_len, const u8 *data, - size_t data_len, u8 *res, size_t len) -{ - u8 hash[SHA1_MAC_LEN]; - u8 idx; - const u8 *addr[3]; - size_t vlen[3]; - int ret; - - idx = 0; - addr[0] = hash; - vlen[0] = SHA1_MAC_LEN; - addr[1] = data; - vlen[1] = data_len; - addr[2] = &idx; - vlen[2] = 1; - - while (len > 0) { - idx++; - if (idx == 1) - ret = hmac_sha1_vector(key, key_len, 2, &addr[1], - &vlen[1], hash); - else - ret = hmac_sha1_vector(key, key_len, 3, addr, vlen, - hash); - if (ret < 0) - return -1; - if (len > SHA1_MAC_LEN) { - os_memcpy(res, hash, SHA1_MAC_LEN); - res += SHA1_MAC_LEN; - len -= SHA1_MAC_LEN; - } else { - os_memcpy(res, hash, len); - len = 0; - } - } - - return 0; -} - - -static int eap_eke_prf_hmac_sha256(const u8 *key, size_t key_len, const u8 *data, - size_t data_len, u8 *res, size_t len) -{ - u8 hash[SHA256_MAC_LEN]; - u8 idx; - const u8 *addr[3]; - size_t vlen[3]; - int ret; - - idx = 0; - addr[0] = hash; - vlen[0] = SHA256_MAC_LEN; - addr[1] = data; - vlen[1] = data_len; - addr[2] = &idx; - vlen[2] = 1; - - while (len > 0) { - idx++; - if (idx == 1) - ret = hmac_sha256_vector(key, key_len, 2, &addr[1], - &vlen[1], hash); - else - ret = hmac_sha256_vector(key, key_len, 3, addr, vlen, - hash); - if (ret < 0) - return -1; - if (len > SHA256_MAC_LEN) { - os_memcpy(res, hash, SHA256_MAC_LEN); - res += SHA256_MAC_LEN; - len -= SHA256_MAC_LEN; - } else { - os_memcpy(res, hash, len); - len = 0; - } - } - - return 0; -} - - -static int eap_eke_prfplus(u8 prf, const u8 *key, size_t key_len, - const u8 *data, size_t data_len, u8 *res, size_t len) -{ - if (prf == EAP_EKE_PRF_HMAC_SHA1) - return eap_eke_prf_hmac_sha1(key, key_len, data, data_len, res, - len); - if (prf == EAP_EKE_PRF_HMAC_SHA2_256) - return eap_eke_prf_hmac_sha256(key, key_len, data, data_len, - res, len); - return -1; -} - - -int eap_eke_derive_key(struct eap_eke_session *sess, - const u8 *password, size_t password_len, - const u8 *id_s, size_t id_s_len, const u8 *id_p, - size_t id_p_len, u8 *key) -{ - u8 zeros[EAP_EKE_MAX_HASH_LEN]; - u8 temp[EAP_EKE_MAX_HASH_LEN]; - size_t key_len = 16; /* Only AES-128-CBC is used here */ - u8 *id; - - /* temp = prf(0+, password) */ - os_memset(zeros, 0, sess->prf_len); - if (eap_eke_prf(sess->prf, zeros, sess->prf_len, - password, password_len, NULL, 0, temp) < 0) - return -1; - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: temp = prf(0+, password)", - temp, sess->prf_len); - - /* key = prf+(temp, ID_S | ID_P) */ - id = os_malloc(id_s_len + id_p_len); - if (id == NULL) - return -1; - os_memcpy(id, id_s, id_s_len); - os_memcpy(id + id_s_len, id_p, id_p_len); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: ID_S | ID_P", - id, id_s_len + id_p_len); - if (eap_eke_prfplus(sess->prf, temp, sess->prf_len, - id, id_s_len + id_p_len, key, key_len) < 0) { - os_free(id); - return -1; - } - os_free(id); - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: key = prf+(temp, ID_S | ID_P)", - key, key_len); - - return 0; -} - - -int eap_eke_dhcomp(struct eap_eke_session *sess, const u8 *key, const u8 *dhpub, - u8 *ret_dhcomp) -{ - u8 pub[EAP_EKE_MAX_DH_LEN]; - int dh_len; - u8 iv[AES_BLOCK_SIZE]; - - dh_len = eap_eke_dh_len(sess->dhgroup); - if (dh_len < 0) - return -1; - - /* - * DHComponent = Encr(key, y) - * - * All defined DH groups use primes that have length devisible by 16, so - * no need to do extra padding for y (= pub). - */ - if (sess->encr != EAP_EKE_ENCR_AES128_CBC) - return -1; - if (random_get_bytes(iv, AES_BLOCK_SIZE)) - return -1; - wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Encr(key, y)", - iv, AES_BLOCK_SIZE); - os_memcpy(pub, dhpub, dh_len); - if (aes_128_cbc_encrypt(key, iv, pub, dh_len) < 0) - return -1; - os_memcpy(ret_dhcomp, iv, AES_BLOCK_SIZE); - os_memcpy(ret_dhcomp + AES_BLOCK_SIZE, pub, dh_len); - wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent = Encr(key, y)", - ret_dhcomp, AES_BLOCK_SIZE + dh_len); - - return 0; -} - - -int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key, - const u8 *dhpriv, const u8 *peer_dhcomp) -{ - u8 zeros[EAP_EKE_MAX_HASH_LEN]; - u8 peer_pub[EAP_EKE_MAX_DH_LEN]; - u8 modexp[EAP_EKE_MAX_DH_LEN]; - size_t len; - const struct dh_group *dh; - - if (sess->encr != EAP_EKE_ENCR_AES128_CBC) - return -1; - - dh = eap_eke_dh_group(sess->dhgroup); - if (dh == NULL) - return -1; - - /* Decrypt peer DHComponent */ - os_memcpy(peer_pub, peer_dhcomp + AES_BLOCK_SIZE, dh->prime_len); - if (aes_128_cbc_decrypt(key, peer_dhcomp, peer_pub, dh->prime_len) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt DHComponent"); - return -1; - } - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted peer DH pubkey", - peer_pub, dh->prime_len); - - /* SharedSecret = prf(0+, g ^ (x_s * x_p) (mod p)) */ - len = dh->prime_len; - if (crypto_mod_exp(peer_pub, dh->prime_len, dhpriv, dh->prime_len, - dh->prime, dh->prime_len, modexp, &len) < 0) - return -1; - if (len < dh->prime_len) { - size_t pad = dh->prime_len - len; - os_memmove(modexp + pad, modexp, len); - os_memset(modexp, 0, pad); - } - - os_memset(zeros, 0, sess->auth_len); - if (eap_eke_prf(sess->prf, zeros, sess->auth_len, modexp, dh->prime_len, - NULL, 0, sess->shared_secret) < 0) - return -1; - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: SharedSecret", - sess->shared_secret, sess->auth_len); - - return 0; -} - - -int eap_eke_derive_ke_ki(struct eap_eke_session *sess, - const u8 *id_s, size_t id_s_len, - const u8 *id_p, size_t id_p_len) -{ - u8 buf[EAP_EKE_MAX_KE_LEN + EAP_EKE_MAX_KI_LEN]; - size_t ke_len, ki_len; - u8 *data; - size_t data_len; - const char *label = "EAP-EKE Keys"; - size_t label_len; - - /* - * Ke | Ki = prf+(SharedSecret, "EAP-EKE Keys" | ID_S | ID_P) - * Ke = encryption key - * Ki = integrity protection key - * Length of each key depends on the selected algorithms. - */ - - if (sess->encr == EAP_EKE_ENCR_AES128_CBC) - ke_len = 16; - else - return -1; - - if (sess->mac == EAP_EKE_PRF_HMAC_SHA1) - ki_len = 20; - else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256) - ki_len = 32; - else - return -1; - - label_len = os_strlen(label); - data_len = label_len + id_s_len + id_p_len; - data = os_malloc(data_len); - if (data == NULL) - return -1; - os_memcpy(data, label, label_len); - os_memcpy(data + label_len, id_s, id_s_len); - os_memcpy(data + label_len + id_s_len, id_p, id_p_len); - if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len, - data, data_len, buf, ke_len + ki_len) < 0) { - os_free(data); - return -1; - } - - os_memcpy(sess->ke, buf, ke_len); - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ke", sess->ke, ke_len); - os_memcpy(sess->ki, buf + ke_len, ki_len); - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ki", sess->ki, ki_len); - - os_free(data); - return 0; -} - - -int eap_eke_derive_ka(struct eap_eke_session *sess, - const u8 *id_s, size_t id_s_len, - const u8 *id_p, size_t id_p_len, - const u8 *nonce_p, const u8 *nonce_s) -{ - u8 *data, *pos; - size_t data_len; - const char *label = "EAP-EKE Ka"; - size_t label_len; - - /* - * Ka = prf+(SharedSecret, "EAP-EKE Ka" | ID_S | ID_P | Nonce_P | - * Nonce_S) - * Ka = authentication key - * Length of the key depends on the selected algorithms. - */ - - label_len = os_strlen(label); - data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len; - data = os_malloc(data_len); - if (data == NULL) - return -1; - pos = data; - os_memcpy(pos, label, label_len); - pos += label_len; - os_memcpy(pos, id_s, id_s_len); - pos += id_s_len; - os_memcpy(pos, id_p, id_p_len); - pos += id_p_len; - os_memcpy(pos, nonce_p, sess->nonce_len); - pos += sess->nonce_len; - os_memcpy(pos, nonce_s, sess->nonce_len); - if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len, - data, data_len, sess->ka, sess->prf_len) < 0) { - os_free(data); - return -1; - } - os_free(data); - - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka", sess->ka, sess->prf_len); - - return 0; -} - - -int eap_eke_derive_msk(struct eap_eke_session *sess, - const u8 *id_s, size_t id_s_len, - const u8 *id_p, size_t id_p_len, - const u8 *nonce_p, const u8 *nonce_s, - u8 *msk, u8 *emsk) -{ - u8 *data, *pos; - size_t data_len; - const char *label = "EAP-EKE Exported Keys"; - size_t label_len; - u8 buf[EAP_MSK_LEN + EAP_EMSK_LEN]; - - /* - * MSK | EMSK = prf+(SharedSecret, "EAP-EKE Exported Keys" | ID_S | - * ID_P | Nonce_P | Nonce_S) - */ - - label_len = os_strlen(label); - data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len; - data = os_malloc(data_len); - if (data == NULL) - return -1; - pos = data; - os_memcpy(pos, label, label_len); - pos += label_len; - os_memcpy(pos, id_s, id_s_len); - pos += id_s_len; - os_memcpy(pos, id_p, id_p_len); - pos += id_p_len; - os_memcpy(pos, nonce_p, sess->nonce_len); - pos += sess->nonce_len; - os_memcpy(pos, nonce_s, sess->nonce_len); - if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len, - data, data_len, buf, EAP_MSK_LEN + EAP_EMSK_LEN) < - 0) { - os_free(data); - return -1; - } - os_free(data); - - os_memcpy(msk, buf, EAP_MSK_LEN); - os_memcpy(emsk, buf + EAP_MSK_LEN, EAP_EMSK_LEN); - os_memset(buf, 0, sizeof(buf)); - - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: MSK", msk, EAP_MSK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: EMSK", msk, EAP_EMSK_LEN); - - return 0; -} - - -static int eap_eke_mac(u8 mac, const u8 *key, const u8 *data, size_t data_len, - u8 *res) -{ - if (mac == EAP_EKE_MAC_HMAC_SHA1) - return hmac_sha1(key, SHA1_MAC_LEN, data, data_len, res); - if (mac == EAP_EKE_MAC_HMAC_SHA2_256) - return hmac_sha256(key, SHA256_MAC_LEN, data, data_len, res); - return -1; -} - - -int eap_eke_prot(struct eap_eke_session *sess, - const u8 *data, size_t data_len, - u8 *prot, size_t *prot_len) -{ - size_t block_size, icv_len, pad; - u8 *pos, *iv, *e; - - if (sess->encr == EAP_EKE_ENCR_AES128_CBC) - block_size = AES_BLOCK_SIZE; - else - return -1; - - if (sess->mac == EAP_EKE_PRF_HMAC_SHA1) - icv_len = SHA1_MAC_LEN; - else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256) - icv_len = SHA256_MAC_LEN; - else - return -1; - - pad = data_len % block_size; - if (pad) - pad = block_size - pad; - - if (*prot_len < block_size + data_len + pad + icv_len) { - wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for Prot() data"); - } - pos = prot; - - if (random_get_bytes(pos, block_size)) - return -1; - iv = pos; - wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Prot()", iv, block_size); - pos += block_size; - - e = pos; - os_memcpy(pos, data, data_len); - pos += data_len; - if (pad) { - if (random_get_bytes(pos, pad)) - return -1; - pos += pad; - } - - if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0) - return -1; - - if (eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0) - return -1; - pos += icv_len; - - *prot_len = pos - prot; - return 0; -} - - -int eap_eke_decrypt_prot(struct eap_eke_session *sess, - const u8 *prot, size_t prot_len, - u8 *data, size_t *data_len) -{ - size_t block_size, icv_len; - u8 icv[EAP_EKE_MAX_HASH_LEN]; - - if (sess->encr == EAP_EKE_ENCR_AES128_CBC) - block_size = AES_BLOCK_SIZE; - else - return -1; - - if (sess->mac == EAP_EKE_PRF_HMAC_SHA1) - icv_len = SHA1_MAC_LEN; - else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256) - icv_len = SHA256_MAC_LEN; - else - return -1; - - if (prot_len < 2 * block_size + icv_len) - return -1; - if ((prot_len - icv_len) % block_size) - return -1; - - if (eap_eke_mac(sess->mac, sess->ki, prot + block_size, - prot_len - block_size - icv_len, icv) < 0) - return -1; - if (os_memcmp(icv, prot + prot_len - icv_len, icv_len) != 0) { - wpa_printf(MSG_INFO, "EAP-EKE: ICV mismatch in Prot() data"); - return -1; - } - - if (*data_len < prot_len - block_size - icv_len) { - wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for decrypted Prot() data"); - return -1; - } - - *data_len = prot_len - block_size - icv_len; - os_memcpy(data, prot + block_size, *data_len); - if (aes_128_cbc_decrypt(sess->ke, prot, data, *data_len) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt Prot() data"); - return -1; - } - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted Prot() data", - data, *data_len); - - return 0; -} - - -int eap_eke_auth(struct eap_eke_session *sess, const char *label, - const struct wpabuf *msgs, u8 *auth) -{ - wpa_printf(MSG_DEBUG, "EAP-EKE: Auth(%s)", label); - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka for Auth", - sess->ka, sess->auth_len); - wpa_hexdump_buf(MSG_MSGDUMP, "EAP-EKE: Messages for Auth", msgs); - return eap_eke_prf(sess->prf, sess->ka, sess->auth_len, - (const u8 *) label, os_strlen(label), - wpabuf_head(msgs), wpabuf_len(msgs), auth); -} - - -int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr, - u8 prf, u8 mac) -{ - sess->dhgroup = dhgroup; - sess->encr = encr; - sess->prf = prf; - sess->mac = mac; - - sess->prf_len = eap_eke_prf_len(prf); - if (sess->prf_len < 0) - return -1; - sess->nonce_len = eap_eke_nonce_len(prf); - if (sess->nonce_len < 0) - return -1; - sess->auth_len = eap_eke_auth_len(prf); - if (sess->auth_len < 0) - return -1; - sess->dhcomp_len = eap_eke_dhcomp_len(sess->dhgroup, sess->encr); - if (sess->dhcomp_len < 0) - return -1; - sess->pnonce_len = eap_eke_pnonce_len(sess->mac); - if (sess->pnonce_len < 0) - return -1; - sess->pnonce_ps_len = eap_eke_pnonce_ps_len(sess->mac); - if (sess->pnonce_ps_len < 0) - return -1; - - return 0; -} - - -void eap_eke_session_clean(struct eap_eke_session *sess) -{ - os_memset(sess->shared_secret, 0, EAP_EKE_MAX_HASH_LEN); - os_memset(sess->ke, 0, EAP_EKE_MAX_KE_LEN); - os_memset(sess->ki, 0, EAP_EKE_MAX_KI_LEN); - os_memset(sess->ka, 0, EAP_EKE_MAX_KA_LEN); -} diff --git a/contrib/hostapd/src/eap_common/eap_eke_common.h b/contrib/hostapd/src/eap_common/eap_eke_common.h deleted file mode 100644 index a4c042225d..0000000000 --- a/contrib/hostapd/src/eap_common/eap_eke_common.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * EAP server/peer: EAP-EKE shared routines - * Copyright (c) 2011-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_EKE_COMMON_H -#define EAP_EKE_COMMON_H - -/* EKE Exchange */ -#define EAP_EKE_ID 1 -#define EAP_EKE_COMMIT 2 -#define EAP_EKE_CONFIRM 3 -#define EAP_EKE_FAILURE 4 - -/* Diffie-Hellman Group Registry */ -#define EAP_EKE_DHGROUP_EKE_2 1 -#define EAP_EKE_DHGROUP_EKE_5 2 -#define EAP_EKE_DHGROUP_EKE_14 3 /* mandatory to implement */ -#define EAP_EKE_DHGROUP_EKE_15 4 -#define EAP_EKE_DHGROUP_EKE_16 5 - -/* Encryption Algorithm Registry */ -#define EAP_EKE_ENCR_AES128_CBC 1 /* mandatory to implement */ - -/* Pseudo Random Function Registry */ -#define EAP_EKE_PRF_HMAC_SHA1 1 /* mandatory to implement */ -#define EAP_EKE_PRF_HMAC_SHA2_256 2 - -/* Keyed Message Digest (MAC) Registry */ -#define EAP_EKE_MAC_HMAC_SHA1 1 /* mandatory to implement */ -#define EAP_EKE_MAC_HMAC_SHA2_256 2 - -/* Identity Type Registry */ -#define EAP_EKE_ID_OPAQUE 1 -#define EAP_EKE_ID_NAI 2 -#define EAP_EKE_ID_IPv4 3 -#define EAP_EKE_ID_IPv6 4 -#define EAP_EKE_ID_FQDN 5 -#define EAP_EKE_ID_DN 6 - -/* Failure-Code */ -#define EAP_EKE_FAIL_NO_ERROR 1 -#define EAP_EKE_FAIL_PROTO_ERROR 2 -#define EAP_EKE_FAIL_PASSWD_NOT_FOUND 3 -#define EAP_EKE_FAIL_AUTHENTICATION_FAIL 4 -#define EAP_EKE_FAIL_AUTHORIZATION_FAIL 5 -#define EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN 6 -#define EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR 0xffffffff - -#define EAP_EKE_MAX_DH_LEN 512 -#define EAP_EKE_MAX_HASH_LEN 32 -#define EAP_EKE_MAX_KEY_LEN 16 -#define EAP_EKE_MAX_KE_LEN 16 -#define EAP_EKE_MAX_KI_LEN 32 -#define EAP_EKE_MAX_KA_LEN 32 -#define EAP_EKE_MAX_NONCE_LEN 16 - -struct eap_eke_session { - /* Selected proposal */ - u8 dhgroup; - u8 encr; - u8 prf; - u8 mac; - - u8 shared_secret[EAP_EKE_MAX_HASH_LEN]; - u8 ke[EAP_EKE_MAX_KE_LEN]; - u8 ki[EAP_EKE_MAX_KI_LEN]; - u8 ka[EAP_EKE_MAX_KA_LEN]; - - int prf_len; - int nonce_len; - int auth_len; - int dhcomp_len; - int pnonce_len; - int pnonce_ps_len; -}; - -int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr, - u8 prf, u8 mac); -void eap_eke_session_clean(struct eap_eke_session *sess); -int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub); -int eap_eke_derive_key(struct eap_eke_session *sess, - const u8 *password, size_t password_len, - const u8 *id_s, size_t id_s_len, const u8 *id_p, - size_t id_p_len, u8 *key); -int eap_eke_dhcomp(struct eap_eke_session *sess, const u8 *key, const u8 *dhpub, - u8 *ret_dhcomp); -int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key, - const u8 *dhpriv, const u8 *peer_dhcomp); -int eap_eke_derive_ke_ki(struct eap_eke_session *sess, - const u8 *id_s, size_t id_s_len, - const u8 *id_p, size_t id_p_len); -int eap_eke_derive_ka(struct eap_eke_session *sess, - const u8 *id_s, size_t id_s_len, - const u8 *id_p, size_t id_p_len, - const u8 *nonce_p, const u8 *nonce_s); -int eap_eke_derive_msk(struct eap_eke_session *sess, - const u8 *id_s, size_t id_s_len, - const u8 *id_p, size_t id_p_len, - const u8 *nonce_p, const u8 *nonce_s, - u8 *msk, u8 *emsk); -int eap_eke_prot(struct eap_eke_session *sess, - const u8 *data, size_t data_len, - u8 *prot, size_t *prot_len); -int eap_eke_decrypt_prot(struct eap_eke_session *sess, - const u8 *prot, size_t prot_len, - u8 *data, size_t *data_len); -int eap_eke_auth(struct eap_eke_session *sess, const char *label, - const struct wpabuf *msgs, u8 *auth); - -#endif /* EAP_EKE_COMMON_H */ diff --git a/contrib/hostapd/src/eap_common/eap_fast_common.c b/contrib/hostapd/src/eap_common/eap_fast_common.c deleted file mode 100644 index 04b987d237..0000000000 --- a/contrib/hostapd/src/eap_common/eap_fast_common.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * EAP-FAST common helper functions (RFC 4851) - * Copyright (c) 2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha1.h" -#include "crypto/tls.h" -#include "eap_defs.h" -#include "eap_tlv_common.h" -#include "eap_fast_common.h" - - -void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len) -{ - struct pac_tlv_hdr hdr; - hdr.type = host_to_be16(type); - hdr.len = host_to_be16(len); - wpabuf_put_data(buf, &hdr, sizeof(hdr)); -} - - -void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data, - u16 len) -{ - eap_fast_put_tlv_hdr(buf, type, len); - wpabuf_put_data(buf, data, len); -} - - -void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type, - const struct wpabuf *data) -{ - eap_fast_put_tlv_hdr(buf, type, wpabuf_len(data)); - wpabuf_put_buf(buf, data); -} - - -struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf) -{ - struct wpabuf *e; - - if (buf == NULL) - return NULL; - - /* Encapsulate EAP packet in EAP-Payload TLV */ - wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV"); - e = wpabuf_alloc(sizeof(struct pac_tlv_hdr) + wpabuf_len(buf)); - if (e == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory " - "for TLV encapsulation"); - wpabuf_free(buf); - return NULL; - } - eap_fast_put_tlv_buf(e, - EAP_TLV_TYPE_MANDATORY | EAP_TLV_EAP_PAYLOAD_TLV, - buf); - wpabuf_free(buf); - return e; -} - - -void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random, - const u8 *client_random, u8 *master_secret) -{ -#define TLS_RANDOM_LEN 32 -#define TLS_MASTER_SECRET_LEN 48 - u8 seed[2 * TLS_RANDOM_LEN]; - - wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random", - client_random, TLS_RANDOM_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random", - server_random, TLS_RANDOM_LEN); - - /* - * RFC 4851, Section 5.1: - * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", - * server_random + client_random, 48) - */ - os_memcpy(seed, server_random, TLS_RANDOM_LEN); - os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN); - sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN, - "PAC to master secret label hash", - seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN); - - wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret", - master_secret, TLS_MASTER_SECRET_LEN); -} - - -u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, - const char *label, size_t len) -{ - struct tls_keys keys; - u8 *rnd = NULL, *out; - int block_size; - - block_size = tls_connection_get_keyblock_size(ssl_ctx, conn); - if (block_size < 0) - return NULL; - - out = os_malloc(block_size + len); - if (out == NULL) - return NULL; - - if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len) - == 0) { - os_memmove(out, out + block_size, len); - return out; - } - - if (tls_connection_get_keys(ssl_ctx, conn, &keys)) - goto fail; - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - if (rnd == NULL) - goto fail; - - os_memcpy(rnd, keys.server_random, keys.server_random_len); - os_memcpy(rnd + keys.server_random_len, keys.client_random, - keys.client_random_len); - - wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key " - "expansion", keys.master_key, keys.master_key_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); - return out; - -fail: - os_free(rnd); - os_free(out); - return NULL; -} - - -void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk) -{ - /* - * RFC 4851, Section 5.4: EAP Master Session Key Generation - * MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64) - */ - - sha1_t_prf(simck, EAP_FAST_SIMCK_LEN, - "Session Key Generating Function", (u8 *) "", 0, - msk, EAP_FAST_KEY_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)", - msk, EAP_FAST_KEY_LEN); -} - - -void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk) -{ - /* - * RFC 4851, Section 5.4: EAP Master Session Key Genreration - * EMSK = T-PRF(S-IMCK[j], - * "Extended Session Key Generating Function", 64) - */ - - sha1_t_prf(simck, EAP_FAST_SIMCK_LEN, - "Extended Session Key Generating Function", (u8 *) "", 0, - emsk, EAP_EMSK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)", - emsk, EAP_EMSK_LEN); -} - - -int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv, - int tlv_type, u8 *pos, int len) -{ - switch (tlv_type) { - case EAP_TLV_EAP_PAYLOAD_TLV: - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV", - pos, len); - if (tlv->eap_payload_tlv) { - wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " - "EAP-Payload TLV in the message"); - tlv->iresult = EAP_TLV_RESULT_FAILURE; - return -2; - } - tlv->eap_payload_tlv = pos; - tlv->eap_payload_tlv_len = len; - break; - case EAP_TLV_RESULT_TLV: - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len); - if (tlv->result) { - wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " - "Result TLV in the message"); - tlv->result = EAP_TLV_RESULT_FAILURE; - return -2; - } - if (len < 2) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " - "Result TLV"); - tlv->result = EAP_TLV_RESULT_FAILURE; - break; - } - tlv->result = WPA_GET_BE16(pos); - if (tlv->result != EAP_TLV_RESULT_SUCCESS && - tlv->result != EAP_TLV_RESULT_FAILURE) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d", - tlv->result); - tlv->result = EAP_TLV_RESULT_FAILURE; - } - wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s", - tlv->result == EAP_TLV_RESULT_SUCCESS ? - "Success" : "Failure"); - break; - case EAP_TLV_INTERMEDIATE_RESULT_TLV: - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV", - pos, len); - if (len < 2) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " - "Intermediate-Result TLV"); - tlv->iresult = EAP_TLV_RESULT_FAILURE; - break; - } - if (tlv->iresult) { - wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " - "Intermediate-Result TLV in the message"); - tlv->iresult = EAP_TLV_RESULT_FAILURE; - return -2; - } - tlv->iresult = WPA_GET_BE16(pos); - if (tlv->iresult != EAP_TLV_RESULT_SUCCESS && - tlv->iresult != EAP_TLV_RESULT_FAILURE) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate " - "Result %d", tlv->iresult); - tlv->iresult = EAP_TLV_RESULT_FAILURE; - } - wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s", - tlv->iresult == EAP_TLV_RESULT_SUCCESS ? - "Success" : "Failure"); - break; - case EAP_TLV_CRYPTO_BINDING_TLV: - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV", - pos, len); - if (tlv->crypto_binding) { - wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " - "Crypto-Binding TLV in the message"); - tlv->iresult = EAP_TLV_RESULT_FAILURE; - return -2; - } - tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len; - if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " - "Crypto-Binding TLV"); - tlv->iresult = EAP_TLV_RESULT_FAILURE; - return -2; - } - tlv->crypto_binding = (struct eap_tlv_crypto_binding_tlv *) - (pos - sizeof(struct eap_tlv_hdr)); - break; - case EAP_TLV_REQUEST_ACTION_TLV: - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV", - pos, len); - if (tlv->request_action) { - wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " - "Request-Action TLV in the message"); - tlv->iresult = EAP_TLV_RESULT_FAILURE; - return -2; - } - if (len < 2) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " - "Request-Action TLV"); - tlv->iresult = EAP_TLV_RESULT_FAILURE; - break; - } - tlv->request_action = WPA_GET_BE16(pos); - wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d", - tlv->request_action); - break; - case EAP_TLV_PAC_TLV: - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len); - if (tlv->pac) { - wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " - "PAC TLV in the message"); - tlv->iresult = EAP_TLV_RESULT_FAILURE; - return -2; - } - tlv->pac = pos; - tlv->pac_len = len; - break; - default: - /* Unknown TLV */ - return -1; - } - - return 0; -} diff --git a/contrib/hostapd/src/eap_common/eap_fast_common.h b/contrib/hostapd/src/eap_common/eap_fast_common.h deleted file mode 100644 index 895561747b..0000000000 --- a/contrib/hostapd/src/eap_common/eap_fast_common.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * EAP-FAST definitions (RFC 4851) - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_FAST_H -#define EAP_FAST_H - -#define EAP_FAST_VERSION 1 -#define EAP_FAST_KEY_LEN 64 -#define EAP_FAST_SIMCK_LEN 40 -#define EAP_FAST_SKS_LEN 40 -#define EAP_FAST_CMK_LEN 20 - -#define TLS_EXT_PAC_OPAQUE 35 - -/* - * RFC 5422: Section 4.2.1 - Formats for PAC TLV Attributes / Type Field - * Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined - * in the general PAC TLV format (Section 4.2). - */ -#define PAC_TYPE_PAC_KEY 1 -#define PAC_TYPE_PAC_OPAQUE 2 -#define PAC_TYPE_CRED_LIFETIME 3 -#define PAC_TYPE_A_ID 4 -#define PAC_TYPE_I_ID 5 -/* - * 6 was previous assigned for SERVER_PROTECTED_DATA, but - * draft-cam-winget-eap-fast-provisioning-02.txt changed this to Reserved. - */ -#define PAC_TYPE_A_ID_INFO 7 -#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8 -#define PAC_TYPE_PAC_INFO 9 -#define PAC_TYPE_PAC_TYPE 10 - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct pac_tlv_hdr { - be16 type; - be16 len; -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - - -#define EAP_FAST_PAC_KEY_LEN 32 - -/* RFC 5422: 4.2.6 PAC-Type TLV */ -#define PAC_TYPE_TUNNEL_PAC 1 -/* Application Specific Short Lived PACs (only in volatile storage) */ -/* User Authorization PAC */ -#define PAC_TYPE_USER_AUTHORIZATION 3 -/* Application Specific Long Lived PACs */ -/* Machine Authentication PAC */ -#define PAC_TYPE_MACHINE_AUTHENTICATION 2 - - -/* - * RFC 5422: - * Section 3.3 - Key Derivations Used in the EAP-FAST Provisioning Exchange - */ -struct eap_fast_key_block_provisioning { - /* Extra key material after TLS key_block */ - u8 session_key_seed[EAP_FAST_SKS_LEN]; - u8 server_challenge[16]; /* MSCHAPv2 ServerChallenge */ - u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */ -}; - - -struct wpabuf; -struct tls_connection; - -struct eap_fast_tlv_parse { - u8 *eap_payload_tlv; - size_t eap_payload_tlv_len; - struct eap_tlv_crypto_binding_tlv *crypto_binding; - size_t crypto_binding_len; - int iresult; - int result; - int request_action; - u8 *pac; - size_t pac_len; -}; - -void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len); -void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data, - u16 len); -void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type, - const struct wpabuf *data); -struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf); -void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random, - const u8 *client_random, u8 *master_secret); -u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, - const char *label, size_t len); -void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk); -void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk); -int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv, - int tlv_type, u8 *pos, int len); - -#endif /* EAP_FAST_H */ diff --git a/contrib/hostapd/src/eap_common/eap_gpsk_common.c b/contrib/hostapd/src/eap_common/eap_gpsk_common.c deleted file mode 100644 index 7a33215f9b..0000000000 --- a/contrib/hostapd/src/eap_common/eap_gpsk_common.c +++ /dev/null @@ -1,552 +0,0 @@ -/* - * EAP server/peer: EAP-GPSK shared routines - * Copyright (c) 2006-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/aes_wrap.h" -#include "crypto/sha256.h" -#include "eap_defs.h" -#include "eap_gpsk_common.h" - - -/** - * eap_gpsk_supported_ciphersuite - Check whether ciphersuite is supported - * @vendor: CSuite/Vendor - * @specifier: CSuite/Specifier - * Returns: 1 if ciphersuite is support, or 0 if not - */ -int eap_gpsk_supported_ciphersuite(int vendor, int specifier) -{ - if (vendor == EAP_GPSK_VENDOR_IETF && - specifier == EAP_GPSK_CIPHER_AES) - return 1; -#ifdef EAP_GPSK_SHA256 - if (vendor == EAP_GPSK_VENDOR_IETF && - specifier == EAP_GPSK_CIPHER_SHA256) - return 1; -#endif /* EAP_GPSK_SHA256 */ - return 0; -} - - -static int eap_gpsk_gkdf_cmac(const u8 *psk /* Y */, - const u8 *data /* Z */, size_t data_len, - u8 *buf, size_t len /* X */) -{ - u8 *opos; - size_t i, n, hashlen, left, clen; - u8 ibuf[2], hash[16]; - const u8 *addr[2]; - size_t vlen[2]; - - hashlen = sizeof(hash); - /* M_i = MAC_Y (i || Z); (MAC = AES-CMAC-128) */ - addr[0] = ibuf; - vlen[0] = sizeof(ibuf); - addr[1] = data; - vlen[1] = data_len; - - opos = buf; - left = len; - n = (len + hashlen - 1) / hashlen; - for (i = 1; i <= n; i++) { - WPA_PUT_BE16(ibuf, i); - if (omac1_aes_128_vector(psk, 2, addr, vlen, hash)) - return -1; - clen = left > hashlen ? hashlen : left; - os_memcpy(opos, hash, clen); - opos += clen; - left -= clen; - } - - return 0; -} - - -#ifdef EAP_GPSK_SHA256 -static int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */, - const u8 *data /* Z */, size_t data_len, - u8 *buf, size_t len /* X */) -{ - u8 *opos; - size_t i, n, hashlen, left, clen; - u8 ibuf[2], hash[SHA256_MAC_LEN]; - const u8 *addr[2]; - size_t vlen[2]; - - hashlen = SHA256_MAC_LEN; - /* M_i = MAC_Y (i || Z); (MAC = HMAC-SHA256) */ - addr[0] = ibuf; - vlen[0] = sizeof(ibuf); - addr[1] = data; - vlen[1] = data_len; - - opos = buf; - left = len; - n = (len + hashlen - 1) / hashlen; - for (i = 1; i <= n; i++) { - WPA_PUT_BE16(ibuf, i); - hmac_sha256_vector(psk, 32, 2, addr, vlen, hash); - clen = left > hashlen ? hashlen : left; - os_memcpy(opos, hash, clen); - opos += clen; - left -= clen; - } - - return 0; -} -#endif /* EAP_GPSK_SHA256 */ - - -static int eap_gpsk_derive_keys_helper(u32 csuite_specifier, - u8 *kdf_out, size_t kdf_out_len, - const u8 *psk, size_t psk_len, - const u8 *seed, size_t seed_len, - u8 *msk, u8 *emsk, - u8 *sk, size_t sk_len, - u8 *pk, size_t pk_len) -{ - u8 mk[32], *pos, *data; - size_t data_len, mk_len; - int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len, - u8 *buf, size_t len); - - gkdf = NULL; - switch (csuite_specifier) { - case EAP_GPSK_CIPHER_AES: - gkdf = eap_gpsk_gkdf_cmac; - mk_len = 16; - break; -#ifdef EAP_GPSK_SHA256 - case EAP_GPSK_CIPHER_SHA256: - gkdf = eap_gpsk_gkdf_sha256; - mk_len = SHA256_MAC_LEN; - break; -#endif /* EAP_GPSK_SHA256 */ - default: - return -1; - } - - if (psk_len < mk_len) - return -1; - - data_len = 2 + psk_len + 6 + seed_len; - data = os_malloc(data_len); - if (data == NULL) - return -1; - pos = data; - WPA_PUT_BE16(pos, psk_len); - pos += 2; - os_memcpy(pos, psk, psk_len); - pos += psk_len; - WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */ - pos += 4; - WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */ - pos += 2; - os_memcpy(pos, seed, seed_len); /* inputString */ - wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation", - data, data_len); - - if (gkdf(psk, data, data_len, mk, mk_len) < 0) { - os_free(data); - return -1; - } - os_free(data); - wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, mk_len); - - if (gkdf(mk, seed, seed_len, kdf_out, kdf_out_len) < 0) - return -1; - - pos = kdf_out; - wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN); - os_memcpy(msk, pos, EAP_MSK_LEN); - pos += EAP_MSK_LEN; - - wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN); - os_memcpy(emsk, pos, EAP_EMSK_LEN); - pos += EAP_EMSK_LEN; - - wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK", pos, sk_len); - os_memcpy(sk, pos, sk_len); - pos += sk_len; - - if (pk) { - wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK", pos, pk_len); - os_memcpy(pk, pos, pk_len); - } - - return 0; -} - - -static int eap_gpsk_derive_keys_aes(const u8 *psk, size_t psk_len, - const u8 *seed, size_t seed_len, - u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, - u8 *pk, size_t *pk_len) -{ -#define EAP_GPSK_SK_LEN_AES 16 -#define EAP_GPSK_PK_LEN_AES 16 - u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_AES + - EAP_GPSK_PK_LEN_AES]; - - /* - * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server - * (= seed) - * KS = 16, PL = psk_len, CSuite_Sel = 0x00000000 0x0001 - * MK = GKDF-16 (PSK[0..15], PL || PSK || CSuite_Sel || inputString) - * MSK = GKDF-160 (MK, inputString)[0..63] - * EMSK = GKDF-160 (MK, inputString)[64..127] - * SK = GKDF-160 (MK, inputString)[128..143] - * PK = GKDF-160 (MK, inputString)[144..159] - * zero = 0x00 || 0x00 || ... || 0x00 (16 times) - * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type || - * CSuite_Sel || inputString) - */ - - *sk_len = EAP_GPSK_SK_LEN_AES; - *pk_len = EAP_GPSK_PK_LEN_AES; - - return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_AES, - kdf_out, sizeof(kdf_out), - psk, psk_len, seed, seed_len, - msk, emsk, sk, *sk_len, - pk, *pk_len); -} - - -#ifdef EAP_GPSK_SHA256 -static int eap_gpsk_derive_keys_sha256(const u8 *psk, size_t psk_len, - const u8 *seed, size_t seed_len, - u8 *msk, u8 *emsk, - u8 *sk, size_t *sk_len) -{ -#define EAP_GPSK_SK_LEN_SHA256 SHA256_MAC_LEN -#define EAP_GPSK_PK_LEN_SHA256 SHA256_MAC_LEN - u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_SHA256 + - EAP_GPSK_PK_LEN_SHA256]; - - /* - * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server - * (= seed) - * KS = 32, PL = psk_len, CSuite_Sel = 0x00000000 0x0002 - * MK = GKDF-32 (PSK[0..31], PL || PSK || CSuite_Sel || inputString) - * MSK = GKDF-160 (MK, inputString)[0..63] - * EMSK = GKDF-160 (MK, inputString)[64..127] - * SK = GKDF-160 (MK, inputString)[128..159] - * zero = 0x00 || 0x00 || ... || 0x00 (32 times) - * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type || - * CSuite_Sel || inputString) - */ - - *sk_len = EAP_GPSK_SK_LEN_SHA256; - - return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_SHA256, - kdf_out, sizeof(kdf_out), - psk, psk_len, seed, seed_len, - msk, emsk, sk, *sk_len, - NULL, 0); -} -#endif /* EAP_GPSK_SHA256 */ - - -/** - * eap_gpsk_derive_keys - Derive EAP-GPSK keys - * @psk: Pre-shared key - * @psk_len: Length of psk in bytes - * @vendor: CSuite/Vendor - * @specifier: CSuite/Specifier - * @rand_peer: 32-byte RAND_Peer - * @rand_server: 32-byte RAND_Server - * @id_peer: ID_Peer - * @id_peer_len: Length of ID_Peer - * @id_server: ID_Server - * @id_server_len: Length of ID_Server - * @msk: Buffer for 64-byte MSK - * @emsk: Buffer for 64-byte EMSK - * @sk: Buffer for SK (at least EAP_GPSK_MAX_SK_LEN bytes) - * @sk_len: Buffer for returning length of SK - * @pk: Buffer for PK (at least EAP_GPSK_MAX_PK_LEN bytes) - * @pk_len: Buffer for returning length of PK - * Returns: 0 on success, -1 on failure - */ -int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor, - int specifier, - const u8 *rand_peer, const u8 *rand_server, - const u8 *id_peer, size_t id_peer_len, - const u8 *id_server, size_t id_server_len, - u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, - u8 *pk, size_t *pk_len) -{ - u8 *seed, *pos; - size_t seed_len; - int ret; - - wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)", - vendor, specifier); - - if (vendor != EAP_GPSK_VENDOR_IETF) - return -1; - - wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len); - - /* Seed = RAND_Peer || ID_Peer || RAND_Server || ID_Server */ - seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len; - seed = os_malloc(seed_len); - if (seed == NULL) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory " - "for key derivation"); - return -1; - } - - pos = seed; - os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN); - pos += EAP_GPSK_RAND_LEN; - os_memcpy(pos, id_peer, id_peer_len); - pos += id_peer_len; - os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN); - pos += EAP_GPSK_RAND_LEN; - os_memcpy(pos, id_server, id_server_len); - pos += id_server_len; - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len); - - switch (specifier) { - case EAP_GPSK_CIPHER_AES: - ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len, - msk, emsk, sk, sk_len, - pk, pk_len); - break; -#ifdef EAP_GPSK_SHA256 - case EAP_GPSK_CIPHER_SHA256: - ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len, - msk, emsk, sk, sk_len); - break; -#endif /* EAP_GPSK_SHA256 */ - default: - wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in " - "key derivation", vendor, specifier); - ret = -1; - break; - } - - os_free(seed); - - return ret; -} - - -static int eap_gpsk_derive_mid_helper(u32 csuite_specifier, - u8 *kdf_out, size_t kdf_out_len, - const u8 *psk, const u8 *seed, - size_t seed_len, u8 method_type) -{ - u8 *pos, *data; - size_t data_len; - int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len, - u8 *buf, size_t len); - - gkdf = NULL; - switch (csuite_specifier) { - case EAP_GPSK_CIPHER_AES: - gkdf = eap_gpsk_gkdf_cmac; - break; -#ifdef EAP_GPSK_SHA256 - case EAP_GPSK_CIPHER_SHA256: - gkdf = eap_gpsk_gkdf_sha256; - break; -#endif /* EAP_GPSK_SHA256 */ - default: - wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d used in " - "Session-Id derivation", csuite_specifier); - return -1; - } - -#define SID_LABEL "Method ID" - /* "Method ID" || EAP_Method_Type || CSuite_Sel || inputString */ - data_len = strlen(SID_LABEL) + 1 + 6 + seed_len; - data = os_malloc(data_len); - if (data == NULL) - return -1; - pos = data; - os_memcpy(pos, SID_LABEL, strlen(SID_LABEL)); - pos += strlen(SID_LABEL); -#undef SID_LABEL - os_memcpy(pos, &method_type, 1); - pos += 1; - WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */ - pos += 4; - WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */ - pos += 2; - os_memcpy(pos, seed, seed_len); /* inputString */ - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Data to Method ID derivation", - data, data_len); - - if (gkdf(psk, data, data_len, kdf_out, kdf_out_len) < 0) { - os_free(data); - return -1; - } - os_free(data); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Method ID", kdf_out, kdf_out_len); - - return 0; -} - - -/** - * eap_gpsk_session_id - Derive EAP-GPSK Session ID - * @psk: Pre-shared key - * @psk_len: Length of psk in bytes - * @vendor: CSuite/Vendor - * @specifier: CSuite/Specifier - * @rand_peer: 32-byte RAND_Peer - * @rand_server: 32-byte RAND_Server - * @id_peer: ID_Peer - * @id_peer_len: Length of ID_Peer - * @id_server: ID_Server - * @id_server_len: Length of ID_Server - * @method_type: EAP Authentication Method Type - * @sid: Buffer for 17-byte Session ID - * @sid_len: Buffer for returning length of Session ID - * Returns: 0 on success, -1 on failure - */ -int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor, - int specifier, - const u8 *rand_peer, const u8 *rand_server, - const u8 *id_peer, size_t id_peer_len, - const u8 *id_server, size_t id_server_len, - u8 method_type, u8 *sid, size_t *sid_len) -{ - u8 *seed, *pos; - u8 kdf_out[16]; - size_t seed_len; - int ret; - - wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving Session ID(%d:%d)", - vendor, specifier); - - if (vendor != EAP_GPSK_VENDOR_IETF) - return -1; - - wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len); - - /* - * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server - * (= seed) - * KS = 16, CSuite_Sel = 0x00000000 0x0001 - * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type || - * CSuite_Sel || inputString) - */ - seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len; - seed = os_malloc(seed_len); - if (seed == NULL) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory " - "for Session-Id derivation"); - return -1; - } - - pos = seed; - os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN); - pos += EAP_GPSK_RAND_LEN; - os_memcpy(pos, id_peer, id_peer_len); - pos += id_peer_len; - os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN); - pos += EAP_GPSK_RAND_LEN; - os_memcpy(pos, id_server, id_server_len); - pos += id_server_len; - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len); - - ret = eap_gpsk_derive_mid_helper(specifier, - kdf_out, sizeof(kdf_out), - psk, seed, seed_len, - method_type); - - sid[0] = method_type; - os_memcpy(sid + 1, kdf_out, sizeof(kdf_out)); - *sid_len = 1 + sizeof(kdf_out); - - os_free(seed); - - return ret; -} - - -/** - * eap_gpsk_mic_len - Get the length of the MIC - * @vendor: CSuite/Vendor - * @specifier: CSuite/Specifier - * Returns: MIC length in bytes - */ -size_t eap_gpsk_mic_len(int vendor, int specifier) -{ - if (vendor != EAP_GPSK_VENDOR_IETF) - return 0; - - switch (specifier) { - case EAP_GPSK_CIPHER_AES: - return 16; -#ifdef EAP_GPSK_SHA256 - case EAP_GPSK_CIPHER_SHA256: - return 32; -#endif /* EAP_GPSK_SHA256 */ - default: - return 0; - } -} - - -static int eap_gpsk_compute_mic_aes(const u8 *sk, size_t sk_len, - const u8 *data, size_t len, u8 *mic) -{ - if (sk_len != 16) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid SK length %lu for " - "AES-CMAC MIC", (unsigned long) sk_len); - return -1; - } - - return omac1_aes_128(sk, data, len, mic); -} - - -/** - * eap_gpsk_compute_mic - Compute EAP-GPSK MIC for an EAP packet - * @sk: Session key SK from eap_gpsk_derive_keys() - * @sk_len: SK length in bytes from eap_gpsk_derive_keys() - * @vendor: CSuite/Vendor - * @specifier: CSuite/Specifier - * @data: Input data to MIC - * @len: Input data length in bytes - * @mic: Buffer for the computed MIC, eap_gpsk_mic_len(cipher) bytes - * Returns: 0 on success, -1 on failure - */ -int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor, - int specifier, const u8 *data, size_t len, u8 *mic) -{ - int ret; - - if (vendor != EAP_GPSK_VENDOR_IETF) - return -1; - - switch (specifier) { - case EAP_GPSK_CIPHER_AES: - ret = eap_gpsk_compute_mic_aes(sk, sk_len, data, len, mic); - break; -#ifdef EAP_GPSK_SHA256 - case EAP_GPSK_CIPHER_SHA256: - hmac_sha256(sk, sk_len, data, len, mic); - ret = 0; - break; -#endif /* EAP_GPSK_SHA256 */ - default: - wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in " - "MIC computation", vendor, specifier); - ret = -1; - break; - } - - return ret; -} diff --git a/contrib/hostapd/src/eap_common/eap_gpsk_common.h b/contrib/hostapd/src/eap_common/eap_gpsk_common.h deleted file mode 100644 index fbcd54732b..0000000000 --- a/contrib/hostapd/src/eap_common/eap_gpsk_common.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * EAP server/peer: EAP-GPSK shared routines - * Copyright (c) 2006-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_GPSK_COMMON_H -#define EAP_GPSK_COMMON_H - -#define EAP_GPSK_OPCODE_GPSK_1 1 -#define EAP_GPSK_OPCODE_GPSK_2 2 -#define EAP_GPSK_OPCODE_GPSK_3 3 -#define EAP_GPSK_OPCODE_GPSK_4 4 -#define EAP_GPSK_OPCODE_FAIL 5 -#define EAP_GPSK_OPCODE_PROTECTED_FAIL 6 - -/* Failure-Code in GPSK-Fail and GPSK-Protected-Fail */ -#define EAP_GPSK_FAIL_PSK_NOT_FOUND 0x00000001 -#define EAP_GPSK_FAIL_AUTHENTICATION_FAILURE 0x00000002 -#define EAP_GPSK_FAIL_AUTHORIZATION_FAILURE 0x00000003 - -#define EAP_GPSK_RAND_LEN 32 -#define EAP_GPSK_MAX_SK_LEN 32 -#define EAP_GPSK_MAX_PK_LEN 32 -#define EAP_GPSK_MAX_MIC_LEN 32 - -#define EAP_GPSK_VENDOR_IETF 0x00000000 -#define EAP_GPSK_CIPHER_RESERVED 0x000000 -#define EAP_GPSK_CIPHER_AES 0x000001 -#define EAP_GPSK_CIPHER_SHA256 0x000002 - - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct eap_gpsk_csuite { - u8 vendor[4]; - u8 specifier[2]; -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - -int eap_gpsk_supported_ciphersuite(int vendor, int specifier); -int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor, - int specifier, - const u8 *rand_client, const u8 *rand_server, - const u8 *id_client, size_t id_client_len, - const u8 *id_server, size_t id_server_len, - u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, - u8 *pk, size_t *pk_len); -int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor, - int specifier, - const u8 *rand_peer, const u8 *rand_server, - const u8 *id_peer, size_t id_peer_len, - const u8 *id_server, size_t id_server_len, - u8 method_type, u8 *sid, size_t *sid_len); -size_t eap_gpsk_mic_len(int vendor, int specifier); -int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor, - int specifier, const u8 *data, size_t len, u8 *mic); - -#endif /* EAP_GPSK_COMMON_H */ diff --git a/contrib/hostapd/src/eap_common/eap_ikev2_common.c b/contrib/hostapd/src/eap_common/eap_ikev2_common.c deleted file mode 100644 index 6095fd8ad7..0000000000 --- a/contrib/hostapd/src/eap_common/eap_ikev2_common.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * EAP-IKEv2 common routines - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_defs.h" -#include "eap_common.h" -#include "ikev2_common.h" -#include "eap_ikev2_common.h" - - -int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys, - const u8 *i_nonce, size_t i_nonce_len, - const u8 *r_nonce, size_t r_nonce_len, - u8 *keymat) -{ - u8 *nonces; - size_t nlen; - - /* KEYMAT = prf+(SK_d, Ni | Nr) */ - if (keys->SK_d == NULL || i_nonce == NULL || r_nonce == NULL) - return -1; - - nlen = i_nonce_len + r_nonce_len; - nonces = os_malloc(nlen); - if (nonces == NULL) - return -1; - os_memcpy(nonces, i_nonce, i_nonce_len); - os_memcpy(nonces + i_nonce_len, r_nonce, r_nonce_len); - - if (ikev2_prf_plus(prf, keys->SK_d, keys->SK_d_len, nonces, nlen, - keymat, EAP_MSK_LEN + EAP_EMSK_LEN)) { - os_free(nonces); - return -1; - } - os_free(nonces); - - wpa_hexdump_key(MSG_DEBUG, "EAP-IKEV2: KEYMAT", - keymat, EAP_MSK_LEN + EAP_EMSK_LEN); - - return 0; -} - - -struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code) -{ - struct wpabuf *msg; - -#ifdef CCNS_PL - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory " - "for fragment ack"); - return NULL; - } - wpabuf_put_u8(msg, 0); /* Flags */ -#else /* CCNS_PL */ - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory " - "for fragment ack"); - return NULL; - } -#endif /* CCNS_PL */ - - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack"); - - return msg; -} - - -int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys, - int initiator, const struct wpabuf *msg, - const u8 *pos, const u8 *end) -{ - const struct ikev2_integ_alg *integ; - size_t icv_len; - u8 icv[IKEV2_MAX_HASH_LEN]; - const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; - - integ = ikev2_get_integ(integ_alg); - if (integ == NULL) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " - "transform / cannot validate ICV"); - return -1; - } - icv_len = integ->hash_len; - - if (end - pos < (int) icv_len) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Not enough room in the " - "message for Integrity Checksum Data"); - return -1; - } - - if (SK_a == NULL) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: No SK_a for ICV validation"); - return -1; - } - - if (ikev2_integ_hash(integ_alg, SK_a, keys->SK_integ_len, - wpabuf_head(msg), - wpabuf_len(msg) - icv_len, icv) < 0) { - wpa_printf(MSG_INFO, "EAP-IKEV2: Could not calculate ICV"); - return -1; - } - - if (os_memcmp(icv, end - icv_len, icv_len) != 0) { - wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV"); - wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV", - icv, icv_len); - wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Received ICV", - end - icv_len, icv_len); - return -1; - } - - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Valid Integrity Checksum Data in " - "the received message"); - - return icv_len; -} diff --git a/contrib/hostapd/src/eap_common/eap_ikev2_common.h b/contrib/hostapd/src/eap_common/eap_ikev2_common.h deleted file mode 100644 index 329ccc4d7a..0000000000 --- a/contrib/hostapd/src/eap_common/eap_ikev2_common.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * EAP-IKEv2 definitions - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_IKEV2_COMMON_H -#define EAP_IKEV2_COMMON_H - -#ifdef CCNS_PL -/* incorrect bit order */ -#define IKEV2_FLAGS_LENGTH_INCLUDED 0x01 -#define IKEV2_FLAGS_MORE_FRAGMENTS 0x02 -#define IKEV2_FLAGS_ICV_INCLUDED 0x04 -#else /* CCNS_PL */ -#define IKEV2_FLAGS_LENGTH_INCLUDED 0x80 -#define IKEV2_FLAGS_MORE_FRAGMENTS 0x40 -#define IKEV2_FLAGS_ICV_INCLUDED 0x20 -#endif /* CCNS_PL */ - -#define IKEV2_FRAGMENT_SIZE 1400 - -struct ikev2_keys; - -int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys, - const u8 *i_nonce, size_t i_nonce_len, - const u8 *r_nonce, size_t r_nonce_len, - u8 *keymat); -struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code); -int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys, - int initiator, const struct wpabuf *msg, - const u8 *pos, const u8 *end); - -#endif /* EAP_IKEV2_COMMON_H */ diff --git a/contrib/hostapd/src/eap_common/eap_pax_common.c b/contrib/hostapd/src/eap_common/eap_pax_common.c deleted file mode 100644 index b3bbacc63e..0000000000 --- a/contrib/hostapd/src/eap_common/eap_pax_common.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * EAP server/peer: EAP-PAX shared routines - * Copyright (c) 2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha1.h" -#include "eap_pax_common.h" - - -/** - * eap_pax_kdf - PAX Key Derivation Function - * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported - * @key: Secret key (X) - * @key_len: Length of the secret key in bytes - * @identifier: Public identifier for the key (Y) - * @entropy: Exchanged entropy to seed the KDF (Z) - * @entropy_len: Length of the entropy in bytes - * @output_len: Output len in bytes (W) - * @output: Buffer for the derived key - * Returns: 0 on success, -1 failed - * - * RFC 4746, Section 2.6: PAX-KDF-W(X, Y, Z) - */ -int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len, - const char *identifier, - const u8 *entropy, size_t entropy_len, - size_t output_len, u8 *output) -{ - u8 mac[SHA1_MAC_LEN]; - u8 counter, *pos; - const u8 *addr[3]; - size_t len[3]; - size_t num_blocks, left; - - num_blocks = (output_len + EAP_PAX_MAC_LEN - 1) / EAP_PAX_MAC_LEN; - if (identifier == NULL || num_blocks >= 255) - return -1; - - /* TODO: add support for EAP_PAX_HMAC_SHA256_128 */ - if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128) - return -1; - - addr[0] = (const u8 *) identifier; - len[0] = os_strlen(identifier); - addr[1] = entropy; - len[1] = entropy_len; - addr[2] = &counter; - len[2] = 1; - - pos = output; - left = output_len; - for (counter = 1; counter <= (u8) num_blocks; counter++) { - size_t clen = left > EAP_PAX_MAC_LEN ? EAP_PAX_MAC_LEN : left; - hmac_sha1_vector(key, key_len, 3, addr, len, mac); - os_memcpy(pos, mac, clen); - pos += clen; - left -= clen; - } - - return 0; -} - - -/** - * eap_pax_mac - EAP-PAX MAC - * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported - * @key: Secret key - * @key_len: Length of the secret key in bytes - * @data1: Optional data, first block; %NULL if not used - * @data1_len: Length of data1 in bytes - * @data2: Optional data, second block; %NULL if not used - * @data2_len: Length of data2 in bytes - * @data3: Optional data, third block; %NULL if not used - * @data3_len: Length of data3 in bytes - * @mac: Buffer for the MAC value (EAP_PAX_MAC_LEN = 16 bytes) - * Returns: 0 on success, -1 on failure - * - * Wrapper function to calculate EAP-PAX MAC. - */ -int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len, - const u8 *data1, size_t data1_len, - const u8 *data2, size_t data2_len, - const u8 *data3, size_t data3_len, - u8 *mac) -{ - u8 hash[SHA1_MAC_LEN]; - const u8 *addr[3]; - size_t len[3]; - size_t count; - - /* TODO: add support for EAP_PAX_HMAC_SHA256_128 */ - if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128) - return -1; - - addr[0] = data1; - len[0] = data1_len; - addr[1] = data2; - len[1] = data2_len; - addr[2] = data3; - len[2] = data3_len; - - count = (data1 ? 1 : 0) + (data2 ? 1 : 0) + (data3 ? 1 : 0); - hmac_sha1_vector(key, key_len, count, addr, len, hash); - os_memcpy(mac, hash, EAP_PAX_MAC_LEN); - - return 0; -} - - -/** - * eap_pax_initial_key_derivation - EAP-PAX initial key derivation - * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported - * @ak: Authentication Key - * @e: Entropy - * @mk: Buffer for the derived Master Key - * @ck: Buffer for the derived Confirmation Key - * @ick: Buffer for the derived Integrity Check Key - * Returns: 0 on success, -1 on failure - */ -int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e, - u8 *mk, u8 *ck, u8 *ick) -{ - wpa_printf(MSG_DEBUG, "EAP-PAX: initial key derivation"); - if (eap_pax_kdf(mac_id, ak, EAP_PAX_AK_LEN, "Master Key", - e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_MK_LEN, mk) || - eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Confirmation Key", - e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_CK_LEN, ck) || - eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Integrity Check Key", - e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_ICK_LEN, ick)) - return -1; - - wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: AK", ak, EAP_PAX_AK_LEN); - wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: MK", mk, EAP_PAX_MK_LEN); - wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: CK", ck, EAP_PAX_CK_LEN); - wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: ICK", ick, EAP_PAX_ICK_LEN); - - return 0; -} diff --git a/contrib/hostapd/src/eap_common/eap_pax_common.h b/contrib/hostapd/src/eap_common/eap_pax_common.h deleted file mode 100644 index fb03df253f..0000000000 --- a/contrib/hostapd/src/eap_common/eap_pax_common.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * EAP server/peer: EAP-PAX shared routines - * Copyright (c) 2005-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_PAX_COMMON_H -#define EAP_PAX_COMMON_H - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct eap_pax_hdr { - u8 op_code; - u8 flags; - u8 mac_id; - u8 dh_group_id; - u8 public_key_id; - /* Followed by variable length payload and ICV */ -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - - -/* op_code: */ -enum { - EAP_PAX_OP_STD_1 = 0x01, - EAP_PAX_OP_STD_2 = 0x02, - EAP_PAX_OP_STD_3 = 0x03, - EAP_PAX_OP_SEC_1 = 0x11, - EAP_PAX_OP_SEC_2 = 0x12, - EAP_PAX_OP_SEC_3 = 0x13, - EAP_PAX_OP_SEC_4 = 0x14, - EAP_PAX_OP_SEC_5 = 0x15, - EAP_PAX_OP_ACK = 0x21 -}; - -/* flags: */ -#define EAP_PAX_FLAGS_MF 0x01 -#define EAP_PAX_FLAGS_CE 0x02 -#define EAP_PAX_FLAGS_AI 0x04 - -/* mac_id: */ -#define EAP_PAX_MAC_HMAC_SHA1_128 0x01 -#define EAP_PAX_HMAC_SHA256_128 0x02 - -/* dh_group_id: */ -#define EAP_PAX_DH_GROUP_NONE 0x00 -#define EAP_PAX_DH_GROUP_2048_MODP 0x01 -#define EAP_PAX_DH_GROUP_3072_MODP 0x02 -#define EAP_PAX_DH_GROUP_NIST_ECC_P_256 0x03 - -/* public_key_id: */ -#define EAP_PAX_PUBLIC_KEY_NONE 0x00 -#define EAP_PAX_PUBLIC_KEY_RSAES_OAEP 0x01 -#define EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5 0x02 -#define EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC 0x03 - -/* ADE type: */ -#define EAP_PAX_ADE_VENDOR_SPECIFIC 0x01 -#define EAP_PAX_ADE_CLIENT_CHANNEL_BINDING 0x02 -#define EAP_PAX_ADE_SERVER_CHANNEL_BINDING 0x03 - - -#define EAP_PAX_RAND_LEN 32 -#define EAP_PAX_MAC_LEN 16 -#define EAP_PAX_ICV_LEN 16 -#define EAP_PAX_AK_LEN 16 -#define EAP_PAX_MK_LEN 16 -#define EAP_PAX_CK_LEN 16 -#define EAP_PAX_ICK_LEN 16 - - -int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len, - const char *identifier, - const u8 *entropy, size_t entropy_len, - size_t output_len, u8 *output); -int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len, - const u8 *data1, size_t data1_len, - const u8 *data2, size_t data2_len, - const u8 *data3, size_t data3_len, - u8 *mac); -int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e, - u8 *mk, u8 *ck, u8 *ick); - -#endif /* EAP_PAX_COMMON_H */ diff --git a/contrib/hostapd/src/eap_common/eap_peap_common.c b/contrib/hostapd/src/eap_common/eap_peap_common.c deleted file mode 100644 index 68b8878c93..0000000000 --- a/contrib/hostapd/src/eap_common/eap_peap_common.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * EAP-PEAP common routines - * Copyright (c) 2008-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha1.h" -#include "eap_peap_common.h" - -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; - u8 hash[SHA1_MAC_LEN]; - size_t label_len = os_strlen(label); - u8 extra[2]; - const unsigned char *addr[5]; - size_t len[5]; - - addr[0] = hash; - len[0] = 0; - addr[1] = (unsigned char *) label; - len[1] = label_len; - addr[2] = seed; - len[2] = seed_len; - - if (version == 0) { - /* - * PRF+(K, S, LEN) = T1 | T2 | ... | Tn - * T1 = HMAC-SHA1(K, S | 0x01 | 0x00 | 0x00) - * T2 = HMAC-SHA1(K, T1 | S | 0x02 | 0x00 | 0x00) - * ... - * Tn = HMAC-SHA1(K, Tn-1 | S | n | 0x00 | 0x00) - */ - - extra[0] = 0; - extra[1] = 0; - - addr[3] = &counter; - len[3] = 1; - addr[4] = extra; - len[4] = 2; - } else { - /* - * PRF (K,S,LEN) = T1 | T2 | T3 | T4 | ... where: - * T1 = HMAC-SHA1(K, S | LEN | 0x01) - * T2 = HMAC-SHA1 (K, T1 | S | LEN | 0x02) - * T3 = HMAC-SHA1 (K, T2 | S | LEN | 0x03) - * T4 = HMAC-SHA1 (K, T3 | S | LEN | 0x04) - * ... - */ - - extra[0] = buf_len & 0xff; - - addr[3] = extra; - len[3] = 1; - addr[4] = &counter; - len[4] = 1; - } - - pos = 0; - while (pos < buf_len) { - counter++; - plen = buf_len - pos; - 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; - } else { - os_memcpy(&buf[pos], hash, plen); - break; - } - len[0] = SHA1_MAC_LEN; - } - - return 0; -} diff --git a/contrib/hostapd/src/eap_common/eap_peap_common.h b/contrib/hostapd/src/eap_common/eap_peap_common.h deleted file mode 100644 index 7aad0dff78..0000000000 --- a/contrib/hostapd/src/eap_common/eap_peap_common.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * EAP-PEAP common routines - * Copyright (c) 2008-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_PEAP_COMMON_H -#define EAP_PEAP_COMMON_H - -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/contrib/hostapd/src/eap_common/eap_psk_common.c b/contrib/hostapd/src/eap_common/eap_psk_common.c deleted file mode 100644 index 638102ffee..0000000000 --- a/contrib/hostapd/src/eap_common/eap_psk_common.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * EAP server/peer: EAP-PSK shared routines - * Copyright (c) 2004-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/aes_wrap.h" -#include "eap_defs.h" -#include "eap_psk_common.h" - -#define aes_block_size 16 - - -int eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk) -{ - os_memset(ak, 0, aes_block_size); - if (aes_128_encrypt_block(psk, ak, ak)) - return -1; - os_memcpy(kdk, ak, aes_block_size); - ak[aes_block_size - 1] ^= 0x01; - kdk[aes_block_size - 1] ^= 0x02; - if (aes_128_encrypt_block(psk, ak, ak) || - aes_128_encrypt_block(psk, kdk, kdk)) - return -1; - return 0; -} - - -int eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk, - u8 *emsk) -{ - u8 hash[aes_block_size]; - u8 counter = 1; - int i; - - if (aes_128_encrypt_block(kdk, rand_p, hash)) - return -1; - - hash[aes_block_size - 1] ^= counter; - if (aes_128_encrypt_block(kdk, hash, tek)) - return -1; - hash[aes_block_size - 1] ^= counter; - counter++; - - for (i = 0; i < EAP_MSK_LEN / aes_block_size; i++) { - hash[aes_block_size - 1] ^= counter; - if (aes_128_encrypt_block(kdk, hash, &msk[i * aes_block_size])) - return -1; - hash[aes_block_size - 1] ^= counter; - counter++; - } - - for (i = 0; i < EAP_EMSK_LEN / aes_block_size; i++) { - hash[aes_block_size - 1] ^= counter; - if (aes_128_encrypt_block(kdk, hash, - &emsk[i * aes_block_size])) - return -1; - hash[aes_block_size - 1] ^= counter; - counter++; - } - - return 0; -} diff --git a/contrib/hostapd/src/eap_common/eap_psk_common.h b/contrib/hostapd/src/eap_common/eap_psk_common.h deleted file mode 100644 index 8bc2c3c4cf..0000000000 --- a/contrib/hostapd/src/eap_common/eap_psk_common.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * EAP server/peer: EAP-PSK shared routines - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_PSK_COMMON_H -#define EAP_PSK_COMMON_H - - -#define EAP_PSK_RAND_LEN 16 -#define EAP_PSK_MAC_LEN 16 -#define EAP_PSK_TEK_LEN 16 -#define EAP_PSK_PSK_LEN 16 -#define EAP_PSK_AK_LEN 16 -#define EAP_PSK_KDK_LEN 16 - -#define EAP_PSK_R_FLAG_CONT 1 -#define EAP_PSK_R_FLAG_DONE_SUCCESS 2 -#define EAP_PSK_R_FLAG_DONE_FAILURE 3 -#define EAP_PSK_E_FLAG 0x20 - -#define EAP_PSK_FLAGS_GET_T(flags) (((flags) & 0xc0) >> 6) -#define EAP_PSK_FLAGS_SET_T(t) ((u8) (t) << 6) - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -/* EAP-PSK First Message (AS -> Supplicant) */ -struct eap_psk_hdr_1 { - u8 flags; - u8 rand_s[EAP_PSK_RAND_LEN]; - /* Followed by variable length ID_S */ -} STRUCT_PACKED; - -/* EAP-PSK Second Message (Supplicant -> AS) */ -struct eap_psk_hdr_2 { - u8 flags; - u8 rand_s[EAP_PSK_RAND_LEN]; - u8 rand_p[EAP_PSK_RAND_LEN]; - u8 mac_p[EAP_PSK_MAC_LEN]; - /* Followed by variable length ID_P */ -} STRUCT_PACKED; - -/* EAP-PSK Third Message (AS -> Supplicant) */ -struct eap_psk_hdr_3 { - u8 flags; - u8 rand_s[EAP_PSK_RAND_LEN]; - u8 mac_s[EAP_PSK_MAC_LEN]; - /* Followed by variable length PCHANNEL */ -} STRUCT_PACKED; - -/* EAP-PSK Fourth Message (Supplicant -> AS) */ -struct eap_psk_hdr_4 { - u8 flags; - u8 rand_s[EAP_PSK_RAND_LEN]; - /* Followed by variable length PCHANNEL */ -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - - -int __must_check eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk); -int __must_check eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, - u8 *msk, u8 *emsk); - -#endif /* EAP_PSK_COMMON_H */ diff --git a/contrib/hostapd/src/eap_common/eap_pwd_common.c b/contrib/hostapd/src/eap_common/eap_pwd_common.c deleted file mode 100644 index 7d6e6b8898..0000000000 --- a/contrib/hostapd/src/eap_common/eap_pwd_common.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * EAP server/peer: EAP-pwd shared routines - * Copyright (c) 2010, Dan Harkins - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include "common.h" -#include "crypto/sha256.h" -#include "crypto/crypto.h" -#include "eap_defs.h" -#include "eap_pwd_common.h" - -/* The random function H(x) = HMAC-SHA256(0^32, x) */ -struct crypto_hash * eap_pwd_h_init(void) -{ - u8 allzero[SHA256_MAC_LEN]; - os_memset(allzero, 0, SHA256_MAC_LEN); - return crypto_hash_init(CRYPTO_HASH_ALG_HMAC_SHA256, allzero, - SHA256_MAC_LEN); -} - - -void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len) -{ - crypto_hash_update(hash, data, len); -} - - -void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest) -{ - size_t len = SHA256_MAC_LEN; - crypto_hash_finish(hash, digest, &len); -} - - -/* a counter-based KDF based on NIST SP800-108 */ -static int eap_pwd_kdf(const u8 *key, size_t keylen, const u8 *label, - size_t labellen, u8 *result, size_t resultbitlen) -{ - struct crypto_hash *hash; - u8 digest[SHA256_MAC_LEN]; - u16 i, ctr, L; - size_t resultbytelen, len = 0, mdlen; - - resultbytelen = (resultbitlen + 7) / 8; - ctr = 0; - L = htons(resultbitlen); - while (len < resultbytelen) { - ctr++; - i = htons(ctr); - hash = crypto_hash_init(CRYPTO_HASH_ALG_HMAC_SHA256, - key, keylen); - if (hash == NULL) - return -1; - if (ctr > 1) - crypto_hash_update(hash, digest, SHA256_MAC_LEN); - crypto_hash_update(hash, (u8 *) &i, sizeof(u16)); - crypto_hash_update(hash, label, labellen); - crypto_hash_update(hash, (u8 *) &L, sizeof(u16)); - mdlen = SHA256_MAC_LEN; - if (crypto_hash_finish(hash, digest, &mdlen) < 0) - return -1; - if ((len + mdlen) > resultbytelen) - os_memcpy(result + len, digest, resultbytelen - len); - else - os_memcpy(result + len, digest, mdlen); - len += mdlen; - } - - /* since we're expanding to a bit length, mask off the excess */ - if (resultbitlen % 8) { - u8 mask = 0xff; - mask <<= (8 - (resultbitlen % 8)); - result[resultbytelen - 1] &= mask; - } - - return 0; -} - - -/* - * compute a "random" secret point on an elliptic curve based - * on the password and identities. - */ -int compute_password_element(EAP_PWD_group *grp, u16 num, - u8 *password, int password_len, - u8 *id_server, int id_server_len, - u8 *id_peer, int id_peer_len, u8 *token) -{ - BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL; - struct crypto_hash *hash; - unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr; - int nid, is_odd, ret = 0; - size_t primebytelen, primebitlen; - - switch (num) { /* from IANA registry for IKE D-H groups */ - case 19: - nid = NID_X9_62_prime256v1; - break; - case 20: - nid = NID_secp384r1; - break; - case 21: - nid = NID_secp521r1; - break; - case 25: - nid = NID_X9_62_prime192v1; - break; - case 26: - nid = NID_secp224r1; - break; - default: - wpa_printf(MSG_INFO, "EAP-pwd: unsupported group %d", num); - return -1; - } - - grp->pwe = NULL; - grp->order = NULL; - grp->prime = NULL; - - if ((grp->group = EC_GROUP_new_by_curve_name(nid)) == NULL) { - wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC_GROUP"); - goto fail; - } - - if (((rnd = BN_new()) == NULL) || - ((cofactor = BN_new()) == NULL) || - ((grp->pwe = EC_POINT_new(grp->group)) == NULL) || - ((grp->order = BN_new()) == NULL) || - ((grp->prime = BN_new()) == NULL) || - ((x_candidate = BN_new()) == NULL)) { - wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums"); - goto fail; - } - - if (!EC_GROUP_get_curve_GFp(grp->group, grp->prime, NULL, NULL, NULL)) - { - wpa_printf(MSG_INFO, "EAP-pwd: unable to get prime for GFp " - "curve"); - goto fail; - } - if (!EC_GROUP_get_order(grp->group, grp->order, NULL)) { - wpa_printf(MSG_INFO, "EAP-pwd: unable to get order for curve"); - goto fail; - } - if (!EC_GROUP_get_cofactor(grp->group, cofactor, NULL)) { - wpa_printf(MSG_INFO, "EAP-pwd: unable to get cofactor for " - "curve"); - goto fail; - } - primebitlen = BN_num_bits(grp->prime); - primebytelen = BN_num_bytes(grp->prime); - if ((prfbuf = os_malloc(primebytelen)) == NULL) { - wpa_printf(MSG_INFO, "EAP-pwd: unable to malloc space for prf " - "buffer"); - goto fail; - } - os_memset(prfbuf, 0, primebytelen); - ctr = 0; - while (1) { - if (ctr > 30) { - wpa_printf(MSG_INFO, "EAP-pwd: unable to find random " - "point on curve for group %d, something's " - "fishy", num); - goto fail; - } - ctr++; - - /* - * compute counter-mode password value and stretch to prime - * pwd-seed = H(token | peer-id | server-id | password | - * counter) - */ - hash = eap_pwd_h_init(); - if (hash == NULL) - goto fail; - eap_pwd_h_update(hash, token, sizeof(u32)); - eap_pwd_h_update(hash, id_peer, id_peer_len); - eap_pwd_h_update(hash, id_server, id_server_len); - eap_pwd_h_update(hash, password, password_len); - eap_pwd_h_update(hash, &ctr, sizeof(ctr)); - eap_pwd_h_final(hash, pwe_digest); - - BN_bin2bn(pwe_digest, SHA256_MAC_LEN, rnd); - - if (eap_pwd_kdf(pwe_digest, SHA256_MAC_LEN, - (u8 *) "EAP-pwd Hunting And Pecking", - os_strlen("EAP-pwd Hunting And Pecking"), - prfbuf, primebitlen) < 0) - goto fail; - - BN_bin2bn(prfbuf, primebytelen, x_candidate); - - /* - * 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; - - wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate", - prfbuf, primebytelen); - - /* - * need to unambiguously identify the solution, if there is - * one... - */ - if (BN_is_odd(rnd)) - is_odd = 1; - else - is_odd = 0; - - /* - * solve the quadratic equation, if it's not solvable then we - * don't have a point - */ - if (!EC_POINT_set_compressed_coordinates_GFp(grp->group, - grp->pwe, - x_candidate, - is_odd, NULL)) - continue; - /* - * If there's a solution to the equation then the point must be - * on the curve so why check again explicitly? OpenSSL code - * says this is required by X9.62. We're not X9.62 but it can't - * hurt just to be sure. - */ - if (!EC_POINT_is_on_curve(grp->group, grp->pwe, NULL)) { - wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve"); - continue; - } - - if (BN_cmp(cofactor, BN_value_one())) { - /* make sure the point is not in a small sub-group */ - if (!EC_POINT_mul(grp->group, grp->pwe, NULL, grp->pwe, - cofactor, NULL)) { - wpa_printf(MSG_INFO, "EAP-pwd: cannot " - "multiply generator by order"); - continue; - } - if (EC_POINT_is_at_infinity(grp->group, grp->pwe)) { - wpa_printf(MSG_INFO, "EAP-pwd: point is at " - "infinity"); - continue; - } - } - /* if we got here then we have a new generator. */ - break; - } - wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %d tries", ctr); - grp->group_num = num; - if (0) { - fail: - EC_GROUP_free(grp->group); - grp->group = NULL; - EC_POINT_free(grp->pwe); - grp->pwe = NULL; - BN_free(grp->order); - grp->order = NULL; - BN_free(grp->prime); - grp->prime = NULL; - ret = 1; - } - /* cleanliness and order.... */ - BN_free(cofactor); - BN_free(x_candidate); - BN_free(rnd); - os_free(prfbuf); - - return ret; -} - - -int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k, - BIGNUM *peer_scalar, BIGNUM *server_scalar, - u8 *confirm_peer, u8 *confirm_server, - u32 *ciphersuite, u8 *msk, u8 *emsk) -{ - struct crypto_hash *hash; - u8 mk[SHA256_MAC_LEN], *cruft; - u8 session_id[SHA256_MAC_LEN + 1]; - u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN]; - int offset; - - if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL) - return -1; - - /* - * first compute the session-id = TypeCode | H(ciphersuite | scal_p | - * scal_s) - */ - session_id[0] = EAP_TYPE_PWD; - hash = eap_pwd_h_init(); - if (hash == NULL) { - os_free(cruft); - return -1; - } - eap_pwd_h_update(hash, (u8 *) ciphersuite, sizeof(u32)); - offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar); - os_memset(cruft, 0, BN_num_bytes(grp->prime)); - BN_bn2bin(peer_scalar, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order)); - offset = BN_num_bytes(grp->order) - BN_num_bytes(server_scalar); - os_memset(cruft, 0, BN_num_bytes(grp->prime)); - BN_bn2bin(server_scalar, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order)); - eap_pwd_h_final(hash, &session_id[1]); - - /* then compute MK = H(k | confirm-peer | confirm-server) */ - hash = eap_pwd_h_init(); - if (hash == NULL) { - os_free(cruft); - return -1; - } - offset = BN_num_bytes(grp->prime) - BN_num_bytes(k); - os_memset(cruft, 0, BN_num_bytes(grp->prime)); - BN_bn2bin(k, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->prime)); - os_free(cruft); - eap_pwd_h_update(hash, confirm_peer, SHA256_MAC_LEN); - eap_pwd_h_update(hash, confirm_server, SHA256_MAC_LEN); - eap_pwd_h_final(hash, mk); - - /* stretch the mk with the session-id to get MSK | EMSK */ - if (eap_pwd_kdf(mk, SHA256_MAC_LEN, - session_id, SHA256_MAC_LEN + 1, - msk_emsk, (EAP_MSK_LEN + EAP_EMSK_LEN) * 8) < 0) { - return -1; - } - - os_memcpy(msk, msk_emsk, EAP_MSK_LEN); - os_memcpy(emsk, msk_emsk + EAP_MSK_LEN, EAP_EMSK_LEN); - - return 1; -} diff --git a/contrib/hostapd/src/eap_common/eap_pwd_common.h b/contrib/hostapd/src/eap_common/eap_pwd_common.h deleted file mode 100644 index 816e58ccb3..0000000000 --- a/contrib/hostapd/src/eap_common/eap_pwd_common.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * EAP server/peer: EAP-pwd shared definitions - * Copyright (c) 2009, Dan Harkins - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_PWD_COMMON_H -#define EAP_PWD_COMMON_H - -#include -#include -#include - -/* - * definition of a finite cyclic group - * TODO: support one based on a prime field - */ -typedef struct group_definition_ { - u16 group_num; - EC_GROUP *group; - EC_POINT *pwe; - BIGNUM *order; - BIGNUM *prime; -} EAP_PWD_group; - -/* - * EAP-pwd header, included on all payloads - * L(1 bit) | M(1 bit) | exch(6 bits) | total_length(if L is set) - */ -#define EAP_PWD_HDR_SIZE 1 - -#define EAP_PWD_OPCODE_ID_EXCH 1 -#define EAP_PWD_OPCODE_COMMIT_EXCH 2 -#define EAP_PWD_OPCODE_CONFIRM_EXCH 3 -#define EAP_PWD_GET_LENGTH_BIT(x) ((x) & 0x80) -#define EAP_PWD_SET_LENGTH_BIT(x) ((x) |= 0x80) -#define EAP_PWD_GET_MORE_BIT(x) ((x) & 0x40) -#define EAP_PWD_SET_MORE_BIT(x) ((x) |= 0x40) -#define EAP_PWD_GET_EXCHANGE(x) ((x) & 0x3f) -#define EAP_PWD_SET_EXCHANGE(x,y) ((x) |= (y)) - -/* EAP-pwd-ID payload */ -struct eap_pwd_id { - be16 group_num; - u8 random_function; -#define EAP_PWD_DEFAULT_RAND_FUNC 1 - u8 prf; -#define EAP_PWD_DEFAULT_PRF 1 - u8 token[4]; - u8 prep; -#define EAP_PWD_PREP_NONE 0 -#define EAP_PWD_PREP_MS 1 - u8 identity[0]; /* length inferred from payload */ -} STRUCT_PACKED; - -/* common routines */ -int compute_password_element(EAP_PWD_group *, u16, u8 *, int, u8 *, int, u8 *, - int, u8 *); -int compute_keys(EAP_PWD_group *, BN_CTX *, BIGNUM *, BIGNUM *, BIGNUM *, - u8 *, u8 *, u32 *, u8 *, u8 *); -struct crypto_hash * eap_pwd_h_init(void); -void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len); -void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest); - -#endif /* EAP_PWD_COMMON_H */ diff --git a/contrib/hostapd/src/eap_common/eap_sake_common.c b/contrib/hostapd/src/eap_common/eap_sake_common.c deleted file mode 100644 index a76253d00f..0000000000 --- a/contrib/hostapd/src/eap_common/eap_sake_common.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * EAP server/peer: EAP-SAKE shared routines - * Copyright (c) 2006-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "wpabuf.h" -#include "crypto/sha1.h" -#include "eap_defs.h" -#include "eap_sake_common.h" - - -static int eap_sake_parse_add_attr(struct eap_sake_parse_attr *attr, - const u8 *pos) -{ - size_t i; - - switch (pos[0]) { - case EAP_SAKE_AT_RAND_S: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_S"); - if (pos[1] != 2 + EAP_SAKE_RAND_LEN) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_S with " - "invalid length %d", pos[1]); - return -1; - } - attr->rand_s = pos + 2; - break; - case EAP_SAKE_AT_RAND_P: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_P"); - if (pos[1] != 2 + EAP_SAKE_RAND_LEN) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_P with " - "invalid length %d", pos[1]); - return -1; - } - attr->rand_p = pos + 2; - break; - case EAP_SAKE_AT_MIC_S: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_S"); - if (pos[1] != 2 + EAP_SAKE_MIC_LEN) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_S with " - "invalid length %d", pos[1]); - return -1; - } - attr->mic_s = pos + 2; - break; - case EAP_SAKE_AT_MIC_P: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_P"); - if (pos[1] != 2 + EAP_SAKE_MIC_LEN) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_P with " - "invalid length %d", pos[1]); - return -1; - } - attr->mic_p = pos + 2; - break; - case EAP_SAKE_AT_SERVERID: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SERVERID"); - attr->serverid = pos + 2; - attr->serverid_len = pos[1] - 2; - break; - case EAP_SAKE_AT_PEERID: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PEERID"); - attr->peerid = pos + 2; - attr->peerid_len = pos[1] - 2; - break; - case EAP_SAKE_AT_SPI_S: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_S"); - attr->spi_s = pos + 2; - attr->spi_s_len = pos[1] - 2; - break; - case EAP_SAKE_AT_SPI_P: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_P"); - attr->spi_p = pos + 2; - attr->spi_p_len = pos[1] - 2; - break; - case EAP_SAKE_AT_ANY_ID_REQ: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ANY_ID_REQ"); - if (pos[1] != 4) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid AT_ANY_ID_REQ" - " length %d", pos[1]); - return -1; - } - attr->any_id_req = pos + 2; - break; - case EAP_SAKE_AT_PERM_ID_REQ: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PERM_ID_REQ"); - if (pos[1] != 4) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid " - "AT_PERM_ID_REQ length %d", pos[1]); - return -1; - } - attr->perm_id_req = pos + 2; - break; - case EAP_SAKE_AT_ENCR_DATA: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ENCR_DATA"); - attr->encr_data = pos + 2; - attr->encr_data_len = pos[1] - 2; - break; - case EAP_SAKE_AT_IV: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV"); - attr->iv = pos + 2; - attr->iv_len = pos[1] - 2; - break; - case EAP_SAKE_AT_PADDING: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PADDING"); - for (i = 2; i < pos[1]; i++) { - if (pos[i]) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_PADDING " - "with non-zero pad byte"); - return -1; - } - } - break; - case EAP_SAKE_AT_NEXT_TMPID: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_NEXT_TMPID"); - attr->next_tmpid = pos + 2; - attr->next_tmpid_len = pos[1] - 2; - break; - case EAP_SAKE_AT_MSK_LIFE: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV"); - if (pos[1] != 6) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid " - "AT_MSK_LIFE length %d", pos[1]); - return -1; - } - attr->msk_life = pos + 2; - break; - default: - if (pos[0] < 128) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown non-skippable" - " attribute %d", pos[0]); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring unknown skippable " - "attribute %d", pos[0]); - break; - } - - if (attr->iv && !attr->encr_data) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_IV included without " - "AT_ENCR_DATA"); - return -1; - } - - return 0; -} - - -/** - * eap_sake_parse_attributes - Parse EAP-SAKE attributes - * @buf: Packet payload (starting with the first attribute) - * @len: Payload length - * @attr: Structure to be filled with found attributes - * Returns: 0 on success or -1 on failure - */ -int eap_sake_parse_attributes(const u8 *buf, size_t len, - struct eap_sake_parse_attr *attr) -{ - const u8 *pos = buf, *end = buf + len; - - os_memset(attr, 0, sizeof(*attr)); - while (pos < end) { - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: Too short attribute"); - return -1; - } - - if (pos[1] < 2) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid attribute " - "length (%d)", pos[1]); - return -1; - } - - if (pos + pos[1] > end) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: Attribute underflow"); - return -1; - } - - if (eap_sake_parse_add_attr(attr, pos)) - return -1; - - pos += pos[1]; - } - - return 0; -} - - -/** - * eap_sake_kdf - EAP-SAKE Key Derivation Function (KDF) - * @key: Key for KDF - * @key_len: Length of the key in bytes - * @label: A unique label for each purpose of the KDF - * @data: Extra data (start) to bind into the key - * @data_len: Length of the data - * @data2: Extra data (end) to bind into the key - * @data2_len: Length of the data2 - * @buf: Buffer for the generated pseudo-random key - * @buf_len: Number of bytes of key to generate - * - * This function is used to derive new, cryptographically separate keys from a - * given key (e.g., SMS). This is identical to the PRF used in IEEE 802.11i. - */ -static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label, - const u8 *data, size_t data_len, - const u8 *data2, size_t data2_len, - u8 *buf, size_t buf_len) -{ - u8 counter = 0; - size_t pos, plen; - u8 hash[SHA1_MAC_LEN]; - size_t label_len = os_strlen(label) + 1; - const unsigned char *addr[4]; - size_t len[4]; - - addr[0] = (u8 *) label; /* Label | Y */ - len[0] = label_len; - addr[1] = data; /* Msg[start] */ - len[1] = data_len; - addr[2] = data2; /* Msg[end] */ - len[2] = data2_len; - addr[3] = &counter; /* Length */ - len[3] = 1; - - pos = 0; - while (pos < buf_len) { - plen = buf_len - pos; - if (plen >= SHA1_MAC_LEN) { - hmac_sha1_vector(key, key_len, 4, addr, len, - &buf[pos]); - pos += SHA1_MAC_LEN; - } else { - hmac_sha1_vector(key, key_len, 4, addr, len, - hash); - os_memcpy(&buf[pos], hash, plen); - break; - } - counter++; - } -} - - -/** - * eap_sake_derive_keys - Derive EAP-SAKE keys - * @root_secret_a: 16-byte Root-Secret-A - * @root_secret_b: 16-byte Root-Secret-B - * @rand_s: 16-byte RAND_S - * @rand_p: 16-byte RAND_P - * @tek: Buffer for Temporary EAK Keys (TEK-Auth[16] | TEK-Cipher[16]) - * @msk: Buffer for 64-byte MSK - * @emsk: Buffer for 64-byte EMSK - * - * This function derives EAP-SAKE keys as defined in RFC 4763, section 3.2.6. - */ -void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b, - const u8 *rand_s, const u8 *rand_p, u8 *tek, u8 *msk, - u8 *emsk) -{ - u8 sms_a[EAP_SAKE_SMS_LEN]; - u8 sms_b[EAP_SAKE_SMS_LEN]; - u8 key_buf[EAP_MSK_LEN + EAP_EMSK_LEN]; - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Deriving keys"); - - wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-A", - root_secret_a, EAP_SAKE_ROOT_SECRET_LEN); - eap_sake_kdf(root_secret_a, EAP_SAKE_ROOT_SECRET_LEN, - "SAKE Master Secret A", - rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN, - sms_a, EAP_SAKE_SMS_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-A", sms_a, EAP_SAKE_SMS_LEN); - eap_sake_kdf(sms_a, EAP_SAKE_SMS_LEN, "Transient EAP Key", - rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN, - tek, EAP_SAKE_TEK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Auth", - tek, EAP_SAKE_TEK_AUTH_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Cipher", - tek + EAP_SAKE_TEK_AUTH_LEN, EAP_SAKE_TEK_CIPHER_LEN); - - wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-B", - root_secret_b, EAP_SAKE_ROOT_SECRET_LEN); - eap_sake_kdf(root_secret_b, EAP_SAKE_ROOT_SECRET_LEN, - "SAKE Master Secret B", - rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN, - sms_b, EAP_SAKE_SMS_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-B", sms_b, EAP_SAKE_SMS_LEN); - eap_sake_kdf(sms_b, EAP_SAKE_SMS_LEN, "Master Session Key", - rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN, - key_buf, sizeof(key_buf)); - os_memcpy(msk, key_buf, EAP_MSK_LEN); - os_memcpy(emsk, key_buf + EAP_MSK_LEN, EAP_EMSK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: MSK", msk, EAP_MSK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: EMSK", emsk, EAP_EMSK_LEN); -} - - -/** - * eap_sake_compute_mic - Compute EAP-SAKE MIC for an EAP packet - * @tek_auth: 16-byte TEK-Auth - * @rand_s: 16-byte RAND_S - * @rand_p: 16-byte RAND_P - * @serverid: SERVERID - * @serverid_len: SERVERID length - * @peerid: PEERID - * @peerid_len: PEERID length - * @peer: MIC calculation for 0 = Server, 1 = Peer message - * @eap: EAP packet - * @eap_len: EAP packet length - * @mic_pos: MIC position in the EAP packet (must be [eap .. eap + eap_len]) - * @mic: Buffer for the computed 16-byte MIC - */ -int eap_sake_compute_mic(const u8 *tek_auth, - const u8 *rand_s, const u8 *rand_p, - const u8 *serverid, size_t serverid_len, - const u8 *peerid, size_t peerid_len, - int peer, const u8 *eap, size_t eap_len, - const u8 *mic_pos, u8 *mic) -{ - u8 _rand[2 * EAP_SAKE_RAND_LEN]; - u8 *tmp, *pos; - size_t tmplen; - - tmplen = serverid_len + 1 + peerid_len + 1 + eap_len; - tmp = os_malloc(tmplen); - if (tmp == NULL) - return -1; - pos = tmp; - if (peer) { - if (peerid) { - os_memcpy(pos, peerid, peerid_len); - pos += peerid_len; - } - *pos++ = 0x00; - if (serverid) { - os_memcpy(pos, serverid, serverid_len); - pos += serverid_len; - } - *pos++ = 0x00; - - os_memcpy(_rand, rand_s, EAP_SAKE_RAND_LEN); - os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_p, - EAP_SAKE_RAND_LEN); - } else { - if (serverid) { - os_memcpy(pos, serverid, serverid_len); - pos += serverid_len; - } - *pos++ = 0x00; - if (peerid) { - os_memcpy(pos, peerid, peerid_len); - pos += peerid_len; - } - *pos++ = 0x00; - - os_memcpy(_rand, rand_p, EAP_SAKE_RAND_LEN); - os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_s, - EAP_SAKE_RAND_LEN); - } - - os_memcpy(pos, eap, eap_len); - os_memset(pos + (mic_pos - eap), 0, EAP_SAKE_MIC_LEN); - - eap_sake_kdf(tek_auth, EAP_SAKE_TEK_AUTH_LEN, - peer ? "Peer MIC" : "Server MIC", - _rand, 2 * EAP_SAKE_RAND_LEN, tmp, tmplen, - mic, EAP_SAKE_MIC_LEN); - - os_free(tmp); - - return 0; -} - - -void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data, - size_t len) -{ - wpabuf_put_u8(buf, type); - wpabuf_put_u8(buf, 2 + len); /* Length; including attr header */ - if (data) - wpabuf_put_data(buf, data, len); - else - os_memset(wpabuf_put(buf, len), 0, len); -} diff --git a/contrib/hostapd/src/eap_common/eap_sake_common.h b/contrib/hostapd/src/eap_common/eap_sake_common.h deleted file mode 100644 index 9e1e75745a..0000000000 --- a/contrib/hostapd/src/eap_common/eap_sake_common.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * EAP server/peer: EAP-SAKE shared routines - * Copyright (c) 2006-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_SAKE_COMMON_H -#define EAP_SAKE_COMMON_H - -#define EAP_SAKE_VERSION 2 - -#define EAP_SAKE_SUBTYPE_CHALLENGE 1 -#define EAP_SAKE_SUBTYPE_CONFIRM 2 -#define EAP_SAKE_SUBTYPE_AUTH_REJECT 3 -#define EAP_SAKE_SUBTYPE_IDENTITY 4 - -#define EAP_SAKE_AT_RAND_S 1 -#define EAP_SAKE_AT_RAND_P 2 -#define EAP_SAKE_AT_MIC_S 3 -#define EAP_SAKE_AT_MIC_P 4 -#define EAP_SAKE_AT_SERVERID 5 -#define EAP_SAKE_AT_PEERID 6 -#define EAP_SAKE_AT_SPI_S 7 -#define EAP_SAKE_AT_SPI_P 8 -#define EAP_SAKE_AT_ANY_ID_REQ 9 -#define EAP_SAKE_AT_PERM_ID_REQ 10 -#define EAP_SAKE_AT_ENCR_DATA 128 -#define EAP_SAKE_AT_IV 129 -#define EAP_SAKE_AT_PADDING 130 -#define EAP_SAKE_AT_NEXT_TMPID 131 -#define EAP_SAKE_AT_MSK_LIFE 132 - -#define EAP_SAKE_RAND_LEN 16 -#define EAP_SAKE_MIC_LEN 16 -#define EAP_SAKE_ROOT_SECRET_LEN 16 -#define EAP_SAKE_SMS_LEN 16 -#define EAP_SAKE_TEK_AUTH_LEN 16 -#define EAP_SAKE_TEK_CIPHER_LEN 16 -#define EAP_SAKE_TEK_LEN (EAP_SAKE_TEK_AUTH_LEN + EAP_SAKE_TEK_CIPHER_LEN) - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct eap_sake_hdr { - u8 version; /* EAP_SAKE_VERSION */ - u8 session_id; - u8 subtype; -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - - -struct eap_sake_parse_attr { - const u8 *rand_s; - const u8 *rand_p; - const u8 *mic_s; - const u8 *mic_p; - const u8 *serverid; - size_t serverid_len; - const u8 *peerid; - size_t peerid_len; - const u8 *spi_s; - size_t spi_s_len; - const u8 *spi_p; - size_t spi_p_len; - const u8 *any_id_req; - const u8 *perm_id_req; - const u8 *encr_data; - size_t encr_data_len; - const u8 *iv; - size_t iv_len; - const u8 *next_tmpid; - size_t next_tmpid_len; - const u8 *msk_life; -}; - -int eap_sake_parse_attributes(const u8 *buf, size_t len, - struct eap_sake_parse_attr *attr); -void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b, - const u8 *rand_s, const u8 *rand_p, - u8 *tek, u8 *msk, u8 *emsk); -int eap_sake_compute_mic(const u8 *tek_auth, - const u8 *rand_s, const u8 *rand_p, - const u8 *serverid, size_t serverid_len, - const u8 *peerid, size_t peerid_len, - int peer, const u8 *eap, size_t eap_len, - const u8 *mic_pos, u8 *mic); -void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data, - size_t len); - -#endif /* EAP_SAKE_COMMON_H */ diff --git a/contrib/hostapd/src/eap_common/eap_sim_common.c b/contrib/hostapd/src/eap_common/eap_sim_common.c deleted file mode 100644 index e1773bf1ac..0000000000 --- a/contrib/hostapd/src/eap_common/eap_sim_common.c +++ /dev/null @@ -1,1209 +0,0 @@ -/* - * EAP peer/server: EAP-SIM/AKA/AKA' shared routines - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "wpabuf.h" -#include "crypto/aes_wrap.h" -#include "crypto/crypto.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "crypto/random.h" -#include "eap_common/eap_defs.h" -#include "eap_common/eap_sim_common.h" - - -static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen) -{ - return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen); -} - - -void eap_sim_derive_mk(const u8 *identity, size_t identity_len, - const u8 *nonce_mt, u16 selected_version, - const u8 *ver_list, size_t ver_list_len, - int num_chal, const u8 *kc, u8 *mk) -{ - u8 sel_ver[2]; - const unsigned char *addr[5]; - size_t len[5]; - - addr[0] = identity; - len[0] = identity_len; - addr[1] = kc; - len[1] = num_chal * EAP_SIM_KC_LEN; - addr[2] = nonce_mt; - len[2] = EAP_SIM_NONCE_MT_LEN; - addr[3] = ver_list; - len[3] = ver_list_len; - addr[4] = sel_ver; - len[4] = 2; - - WPA_PUT_BE16(sel_ver, selected_version); - - /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */ - sha1_vector(5, addr, len, mk); - wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN); -} - - -void eap_aka_derive_mk(const u8 *identity, size_t identity_len, - const u8 *ik, const u8 *ck, u8 *mk) -{ - const u8 *addr[3]; - size_t len[3]; - - addr[0] = identity; - len[0] = identity_len; - addr[1] = ik; - len[1] = EAP_AKA_IK_LEN; - addr[2] = ck; - len[2] = EAP_AKA_CK_LEN; - - /* MK = SHA1(Identity|IK|CK) */ - sha1_vector(3, addr, len, mk); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN); -} - - -int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk) -{ - u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN + - EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos; - if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) { - wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys"); - return -1; - } - pos = buf; - os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN); - pos += EAP_SIM_K_ENCR_LEN; - os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN); - pos += EAP_SIM_K_AUT_LEN; - os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN); - pos += EAP_SIM_KEYING_DATA_LEN; - os_memcpy(emsk, pos, EAP_EMSK_LEN); - - wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr", - k_encr, EAP_SIM_K_ENCR_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut", - k_aut, EAP_SIM_K_AUT_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)", - msk, EAP_SIM_KEYING_DATA_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN); - os_memset(buf, 0, sizeof(buf)); - - return 0; -} - - -int eap_sim_derive_keys_reauth(u16 _counter, - const u8 *identity, size_t identity_len, - const u8 *nonce_s, const u8 *mk, u8 *msk, - u8 *emsk) -{ - u8 xkey[SHA1_MAC_LEN]; - u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32]; - u8 counter[2]; - const u8 *addr[4]; - size_t len[4]; - - while (identity_len > 0 && identity[identity_len - 1] == 0) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop null " - "character from the end of identity"); - identity_len--; - } - addr[0] = identity; - len[0] = identity_len; - addr[1] = counter; - len[1] = 2; - addr[2] = nonce_s; - len[2] = EAP_SIM_NONCE_S_LEN; - addr[3] = mk; - len[3] = EAP_SIM_MK_LEN; - - WPA_PUT_BE16(counter, _counter); - - wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth"); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", - identity, identity_len); - wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2); - wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s, - EAP_SIM_NONCE_S_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN); - - /* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */ - sha1_vector(4, addr, len, xkey); - wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN); - - if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) { - wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys"); - return -1; - } - if (msk) { - os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)", - msk, EAP_SIM_KEYING_DATA_LEN); - } - if (emsk) { - os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN); - } - os_memset(buf, 0, sizeof(buf)); - - return 0; -} - - -int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req, - const u8 *mac, const u8 *extra, size_t extra_len) -{ - unsigned char hmac[SHA1_MAC_LEN]; - const u8 *addr[2]; - size_t len[2]; - u8 *tmp; - - if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN || - mac < wpabuf_head_u8(req) || - mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN) - return -1; - - tmp = os_malloc(wpabuf_len(req)); - if (tmp == NULL) - return -1; - - addr[0] = tmp; - len[0] = wpabuf_len(req); - addr[1] = extra; - len[1] = extra_len; - - /* HMAC-SHA1-128 */ - os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req)); - os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg", - tmp, wpabuf_len(req)); - wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data", - extra, extra_len); - wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut", - k_aut, EAP_SIM_K_AUT_LEN); - hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac); - wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC", - hmac, EAP_SIM_MAC_LEN); - os_free(tmp); - - return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1; -} - - -void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac, - const u8 *extra, size_t extra_len) -{ - unsigned char hmac[SHA1_MAC_LEN]; - const u8 *addr[2]; - size_t len[2]; - - addr[0] = msg; - len[0] = msg_len; - addr[1] = extra; - len[1] = extra_len; - - /* HMAC-SHA1-128 */ - os_memset(mac, 0, EAP_SIM_MAC_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len); - wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data", - extra, extra_len); - wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut", - k_aut, EAP_SIM_K_AUT_LEN); - hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac); - os_memcpy(mac, hmac, EAP_SIM_MAC_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC", - mac, EAP_SIM_MAC_LEN); -} - - -#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) -static void prf_prime(const u8 *k, const char *seed1, - const u8 *seed2, size_t seed2_len, - const u8 *seed3, size_t seed3_len, - u8 *res, size_t res_len) -{ - const u8 *addr[5]; - size_t len[5]; - u8 hash[SHA256_MAC_LEN]; - u8 iter; - - /* - * PRF'(K,S) = T1 | T2 | T3 | T4 | ... - * T1 = HMAC-SHA-256 (K, S | 0x01) - * T2 = HMAC-SHA-256 (K, T1 | S | 0x02) - * T3 = HMAC-SHA-256 (K, T2 | S | 0x03) - * T4 = HMAC-SHA-256 (K, T3 | S | 0x04) - * ... - */ - - addr[0] = hash; - len[0] = 0; - addr[1] = (const u8 *) seed1; - len[1] = os_strlen(seed1); - addr[2] = seed2; - len[2] = seed2_len; - addr[3] = seed3; - len[3] = seed3_len; - addr[4] = &iter; - len[4] = 1; - - iter = 0; - while (res_len) { - size_t hlen; - iter++; - hmac_sha256_vector(k, 32, 5, addr, len, hash); - len[0] = SHA256_MAC_LEN; - hlen = res_len > SHA256_MAC_LEN ? SHA256_MAC_LEN : res_len; - os_memcpy(res, hash, hlen); - res += hlen; - res_len -= hlen; - } -} - - -void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len, - const u8 *ik, const u8 *ck, u8 *k_encr, - u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk) -{ - u8 key[EAP_AKA_IK_LEN + EAP_AKA_CK_LEN]; - u8 keys[EAP_SIM_K_ENCR_LEN + EAP_AKA_PRIME_K_AUT_LEN + - EAP_AKA_PRIME_K_RE_LEN + EAP_MSK_LEN + EAP_EMSK_LEN]; - u8 *pos; - - /* - * MK = PRF'(IK'|CK',"EAP-AKA'"|Identity) - * K_encr = MK[0..127] - * K_aut = MK[128..383] - * K_re = MK[384..639] - * MSK = MK[640..1151] - * EMSK = MK[1152..1663] - */ - - os_memcpy(key, ik, EAP_AKA_IK_LEN); - os_memcpy(key + EAP_AKA_IK_LEN, ck, EAP_AKA_CK_LEN); - - prf_prime(key, "EAP-AKA'", identity, identity_len, NULL, 0, - keys, sizeof(keys)); - - pos = keys; - os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_encr", - k_encr, EAP_SIM_K_ENCR_LEN); - pos += EAP_SIM_K_ENCR_LEN; - - os_memcpy(k_aut, pos, EAP_AKA_PRIME_K_AUT_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_aut", - k_aut, EAP_AKA_PRIME_K_AUT_LEN); - pos += EAP_AKA_PRIME_K_AUT_LEN; - - os_memcpy(k_re, pos, EAP_AKA_PRIME_K_RE_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_re", - k_re, EAP_AKA_PRIME_K_RE_LEN); - pos += EAP_AKA_PRIME_K_RE_LEN; - - os_memcpy(msk, pos, EAP_MSK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN); - pos += EAP_MSK_LEN; - - os_memcpy(emsk, pos, EAP_EMSK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN); -} - - -int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter, - const u8 *identity, size_t identity_len, - const u8 *nonce_s, u8 *msk, u8 *emsk) -{ - u8 seed3[2 + EAP_SIM_NONCE_S_LEN]; - u8 keys[EAP_MSK_LEN + EAP_EMSK_LEN]; - u8 *pos; - - /* - * MK = PRF'(K_re,"EAP-AKA' re-auth"|Identity|counter|NONCE_S) - * MSK = MK[0..511] - * EMSK = MK[512..1023] - */ - - WPA_PUT_BE16(seed3, counter); - os_memcpy(seed3 + 2, nonce_s, EAP_SIM_NONCE_S_LEN); - - prf_prime(k_re, "EAP-AKA' re-auth", identity, identity_len, - seed3, sizeof(seed3), - keys, sizeof(keys)); - - pos = keys; - os_memcpy(msk, pos, EAP_MSK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN); - pos += EAP_MSK_LEN; - - os_memcpy(emsk, pos, EAP_EMSK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN); - - os_memset(keys, 0, sizeof(keys)); - - return 0; -} - - -int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req, - const u8 *mac, const u8 *extra, size_t extra_len) -{ - unsigned char hmac[SHA256_MAC_LEN]; - const u8 *addr[2]; - size_t len[2]; - u8 *tmp; - - if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN || - mac < wpabuf_head_u8(req) || - mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN) - return -1; - - tmp = os_malloc(wpabuf_len(req)); - if (tmp == NULL) - return -1; - - addr[0] = tmp; - len[0] = wpabuf_len(req); - addr[1] = extra; - len[1] = extra_len; - - /* HMAC-SHA-256-128 */ - os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req)); - os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - msg", - tmp, wpabuf_len(req)); - wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - extra data", - extra, extra_len); - wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Verify MAC - K_aut", - k_aut, EAP_AKA_PRIME_K_AUT_LEN); - hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac); - wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC: MAC", - hmac, EAP_SIM_MAC_LEN); - os_free(tmp); - - return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1; -} - - -void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len, - u8 *mac, const u8 *extra, size_t extra_len) -{ - unsigned char hmac[SHA256_MAC_LEN]; - const u8 *addr[2]; - size_t len[2]; - - addr[0] = msg; - len[0] = msg_len; - addr[1] = extra; - len[1] = extra_len; - - /* HMAC-SHA-256-128 */ - os_memset(mac, 0, EAP_SIM_MAC_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - msg", msg, msg_len); - wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - extra data", - extra, extra_len); - wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Add MAC - K_aut", - k_aut, EAP_AKA_PRIME_K_AUT_LEN); - hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac); - os_memcpy(mac, hmac, EAP_SIM_MAC_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC: MAC", - mac, EAP_SIM_MAC_LEN); -} - - -void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak, - const u8 *network_name, - size_t network_name_len) -{ - u8 key[EAP_AKA_CK_LEN + EAP_AKA_IK_LEN]; - u8 hash[SHA256_MAC_LEN]; - const u8 *addr[5]; - size_t len[5]; - u8 fc; - u8 l0[2], l1[2]; - - /* 3GPP TS 33.402 V8.0.0 - * (CK', IK') = F(CK, IK, ) - */ - /* TODO: CK', IK' generation should really be moved into the actual - * AKA procedure with network name passed in there and option to use - * AMF separation bit = 1 (3GPP TS 33.401). */ - - /* Change Request 33.402 CR 0033 to version 8.1.1 from - * 3GPP TSG-SA WG3 Meeting #53 in September 2008: - * - * CK' || IK' = HMAC-SHA-256(Key, S) - * S = FC || P0 || L0 || P1 || L1 || ... || Pn || Ln - * Key = CK || IK - * FC = 0x20 - * P0 = access network identity (3GPP TS 24.302) - * L0 = length of acceess network identity (2 octets, big endian) - * P1 = SQN xor AK (if AK is not used, AK is treaded as 000..0 - * L1 = 0x00 0x06 - */ - - fc = 0x20; - - wpa_printf(MSG_DEBUG, "EAP-AKA': Derive (CK',IK') from (CK,IK)"); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK", ck, EAP_AKA_CK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK", ik, EAP_AKA_IK_LEN); - wpa_printf(MSG_DEBUG, "EAP-AKA': FC = 0x%x", fc); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': P0 = Access network identity", - network_name, network_name_len); - wpa_hexdump(MSG_DEBUG, "EAP-AKA': P1 = SQN xor AK", sqn_ak, 6); - - os_memcpy(key, ck, EAP_AKA_CK_LEN); - os_memcpy(key + EAP_AKA_CK_LEN, ik, EAP_AKA_IK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': Key = CK || IK", - key, sizeof(key)); - - addr[0] = &fc; - len[0] = 1; - addr[1] = network_name; - len[1] = network_name_len; - WPA_PUT_BE16(l0, network_name_len); - addr[2] = l0; - len[2] = 2; - addr[3] = sqn_ak; - len[3] = 6; - WPA_PUT_BE16(l1, 6); - addr[4] = l1; - len[4] = 2; - - hmac_sha256_vector(key, sizeof(key), 5, addr, len, hash); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': KDF output (CK' || IK')", - hash, sizeof(hash)); - - os_memcpy(ck, hash, EAP_AKA_CK_LEN); - os_memcpy(ik, hash + EAP_AKA_CK_LEN, EAP_AKA_IK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK'", ck, EAP_AKA_CK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK'", ik, EAP_AKA_IK_LEN); -} -#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ - - -int eap_sim_parse_attr(const u8 *start, const u8 *end, - struct eap_sim_attrs *attr, int aka, int encr) -{ - const u8 *pos = start, *apos; - size_t alen, plen, i, list_len; - - os_memset(attr, 0, sizeof(*attr)); - attr->id_req = NO_ID_REQ; - attr->notification = -1; - attr->counter = -1; - attr->selected_version = -1; - attr->client_error_code = -1; - - while (pos < end) { - if (pos + 2 > end) { - wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)"); - return -1; - } - wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d", - pos[0], pos[1] * 4); - if (pos + pos[1] * 4 > end) { - wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow " - "(pos=%p len=%d end=%p)", - pos, pos[1] * 4, end); - return -1; - } - if (pos[1] == 0) { - wpa_printf(MSG_INFO, "EAP-SIM: Attribute underflow"); - return -1; - } - apos = pos + 2; - alen = pos[1] * 4 - 2; - wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data", - apos, alen); - - switch (pos[0]) { - case EAP_SIM_AT_RAND: - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND"); - apos += 2; - alen -= 2; - if ((!aka && (alen % GSM_RAND_LEN)) || - (aka && alen != EAP_AKA_RAND_LEN)) { - wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND" - " (len %lu)", - (unsigned long) alen); - return -1; - } - attr->rand = apos; - attr->num_chal = alen / GSM_RAND_LEN; - break; - case EAP_SIM_AT_AUTN: - wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN"); - if (!aka) { - wpa_printf(MSG_DEBUG, "EAP-SIM: " - "Unexpected AT_AUTN"); - return -1; - } - apos += 2; - alen -= 2; - if (alen != EAP_AKA_AUTN_LEN) { - wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN" - " (len %lu)", - (unsigned long) alen); - return -1; - } - attr->autn = apos; - break; - case EAP_SIM_AT_PADDING: - if (!encr) { - wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " - "AT_PADDING"); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING"); - for (i = 2; i < alen; i++) { - if (apos[i] != 0) { - wpa_printf(MSG_INFO, "EAP-SIM: (encr) " - "AT_PADDING used a non-zero" - " padding byte"); - wpa_hexdump(MSG_DEBUG, "EAP-SIM: " - "(encr) padding bytes", - apos + 2, alen - 2); - return -1; - } - } - break; - case EAP_SIM_AT_NONCE_MT: - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT"); - if (alen != 2 + EAP_SIM_NONCE_MT_LEN) { - wpa_printf(MSG_INFO, "EAP-SIM: Invalid " - "AT_NONCE_MT length"); - return -1; - } - attr->nonce_mt = apos + 2; - break; - case EAP_SIM_AT_PERMANENT_ID_REQ: - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ"); - attr->id_req = PERMANENT_ID; - break; - case EAP_SIM_AT_MAC: - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC"); - if (alen != 2 + EAP_SIM_MAC_LEN) { - wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC " - "length"); - return -1; - } - attr->mac = apos + 2; - break; - case EAP_SIM_AT_NOTIFICATION: - if (alen != 2) { - wpa_printf(MSG_INFO, "EAP-SIM: Invalid " - "AT_NOTIFICATION length %lu", - (unsigned long) alen); - return -1; - } - attr->notification = apos[0] * 256 + apos[1]; - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d", - attr->notification); - break; - case EAP_SIM_AT_ANY_ID_REQ: - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ"); - attr->id_req = ANY_ID; - break; - case EAP_SIM_AT_IDENTITY: - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY"); - plen = WPA_GET_BE16(apos); - apos += 2; - alen -= 2; - if (plen > alen) { - wpa_printf(MSG_INFO, "EAP-SIM: Invalid " - "AT_IDENTITY (Actual Length %lu, " - "remaining length %lu)", - (unsigned long) plen, - (unsigned long) alen); - return -1; - } - - attr->identity = apos; - attr->identity_len = plen; - break; - case EAP_SIM_AT_VERSION_LIST: - if (aka) { - wpa_printf(MSG_DEBUG, "EAP-AKA: " - "Unexpected AT_VERSION_LIST"); - return -1; - } - list_len = apos[0] * 256 + apos[1]; - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST"); - if (list_len < 2 || list_len > alen - 2) { - wpa_printf(MSG_WARNING, "EAP-SIM: Invalid " - "AT_VERSION_LIST (list_len=%lu " - "attr_len=%lu)", - (unsigned long) list_len, - (unsigned long) alen); - return -1; - } - attr->version_list = apos + 2; - attr->version_list_len = list_len; - break; - case EAP_SIM_AT_SELECTED_VERSION: - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION"); - if (alen != 2) { - wpa_printf(MSG_INFO, "EAP-SIM: Invalid " - "AT_SELECTED_VERSION length %lu", - (unsigned long) alen); - return -1; - } - attr->selected_version = apos[0] * 256 + apos[1]; - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION " - "%d", attr->selected_version); - break; - case EAP_SIM_AT_FULLAUTH_ID_REQ: - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ"); - attr->id_req = FULLAUTH_ID; - break; - case EAP_SIM_AT_COUNTER: - if (!encr) { - wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " - "AT_COUNTER"); - return -1; - } - if (alen != 2) { - wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid " - "AT_COUNTER (alen=%lu)", - (unsigned long) alen); - return -1; - } - attr->counter = apos[0] * 256 + apos[1]; - wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d", - attr->counter); - break; - case EAP_SIM_AT_COUNTER_TOO_SMALL: - if (!encr) { - wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " - "AT_COUNTER_TOO_SMALL"); - return -1; - } - if (alen != 2) { - wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid " - "AT_COUNTER_TOO_SMALL (alen=%lu)", - (unsigned long) alen); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) " - "AT_COUNTER_TOO_SMALL"); - attr->counter_too_small = 1; - break; - case EAP_SIM_AT_NONCE_S: - if (!encr) { - wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " - "AT_NONCE_S"); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) " - "AT_NONCE_S"); - if (alen != 2 + EAP_SIM_NONCE_S_LEN) { - wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid " - "AT_NONCE_S (alen=%lu)", - (unsigned long) alen); - return -1; - } - attr->nonce_s = apos + 2; - break; - case EAP_SIM_AT_CLIENT_ERROR_CODE: - if (alen != 2) { - wpa_printf(MSG_INFO, "EAP-SIM: Invalid " - "AT_CLIENT_ERROR_CODE length %lu", - (unsigned long) alen); - return -1; - } - attr->client_error_code = apos[0] * 256 + apos[1]; - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE " - "%d", attr->client_error_code); - break; - case EAP_SIM_AT_IV: - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV"); - if (alen != 2 + EAP_SIM_MAC_LEN) { - wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV " - "length %lu", (unsigned long) alen); - return -1; - } - attr->iv = apos + 2; - break; - case EAP_SIM_AT_ENCR_DATA: - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA"); - attr->encr_data = apos + 2; - attr->encr_data_len = alen - 2; - if (attr->encr_data_len % 16) { - wpa_printf(MSG_INFO, "EAP-SIM: Invalid " - "AT_ENCR_DATA length %lu", - (unsigned long) - attr->encr_data_len); - return -1; - } - break; - case EAP_SIM_AT_NEXT_PSEUDONYM: - if (!encr) { - wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " - "AT_NEXT_PSEUDONYM"); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) " - "AT_NEXT_PSEUDONYM"); - plen = apos[0] * 256 + apos[1]; - if (plen > alen - 2) { - wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid" - " AT_NEXT_PSEUDONYM (actual" - " len %lu, attr len %lu)", - (unsigned long) plen, - (unsigned long) alen); - return -1; - } - attr->next_pseudonym = pos + 4; - attr->next_pseudonym_len = plen; - break; - case EAP_SIM_AT_NEXT_REAUTH_ID: - if (!encr) { - wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " - "AT_NEXT_REAUTH_ID"); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) " - "AT_NEXT_REAUTH_ID"); - plen = apos[0] * 256 + apos[1]; - if (plen > alen - 2) { - wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid" - " AT_NEXT_REAUTH_ID (actual" - " len %lu, attr len %lu)", - (unsigned long) plen, - (unsigned long) alen); - return -1; - } - attr->next_reauth_id = pos + 4; - attr->next_reauth_id_len = plen; - break; - case EAP_SIM_AT_RES: - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES"); - attr->res_len_bits = WPA_GET_BE16(apos); - apos += 2; - alen -= 2; - if (!aka || alen < EAP_AKA_MIN_RES_LEN || - alen > EAP_AKA_MAX_RES_LEN) { - wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES " - "(len %lu)", - (unsigned long) alen); - return -1; - } - attr->res = apos; - attr->res_len = alen; - break; - case EAP_SIM_AT_AUTS: - wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS"); - if (!aka) { - wpa_printf(MSG_DEBUG, "EAP-SIM: " - "Unexpected AT_AUTS"); - return -1; - } - if (alen != EAP_AKA_AUTS_LEN) { - wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS" - " (len %lu)", - (unsigned long) alen); - return -1; - } - attr->auts = apos; - break; - case EAP_SIM_AT_CHECKCODE: - wpa_printf(MSG_DEBUG, "EAP-AKA: AT_CHECKCODE"); - if (!aka) { - wpa_printf(MSG_DEBUG, "EAP-SIM: " - "Unexpected AT_CHECKCODE"); - return -1; - } - apos += 2; - alen -= 2; - if (alen != 0 && alen != EAP_AKA_CHECKCODE_LEN && - alen != EAP_AKA_PRIME_CHECKCODE_LEN) { - wpa_printf(MSG_INFO, "EAP-AKA: Invalid " - "AT_CHECKCODE (len %lu)", - (unsigned long) alen); - return -1; - } - attr->checkcode = apos; - attr->checkcode_len = alen; - break; - case EAP_SIM_AT_RESULT_IND: - if (encr) { - wpa_printf(MSG_ERROR, "EAP-SIM: Encrypted " - "AT_RESULT_IND"); - return -1; - } - if (alen != 2) { - wpa_printf(MSG_INFO, "EAP-SIM: Invalid " - "AT_RESULT_IND (alen=%lu)", - (unsigned long) alen); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RESULT_IND"); - attr->result_ind = 1; - break; -#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) - case EAP_SIM_AT_KDF_INPUT: - if (aka != 2) { - wpa_printf(MSG_INFO, "EAP-AKA: Unexpected " - "AT_KDF_INPUT"); - return -1; - } - - wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF_INPUT"); - plen = WPA_GET_BE16(apos); - apos += 2; - alen -= 2; - if (plen > alen) { - wpa_printf(MSG_INFO, "EAP-AKA': Invalid " - "AT_KDF_INPUT (Actual Length %lu, " - "remaining length %lu)", - (unsigned long) plen, - (unsigned long) alen); - return -1; - } - attr->kdf_input = apos; - attr->kdf_input_len = plen; - break; - case EAP_SIM_AT_KDF: - if (aka != 2) { - wpa_printf(MSG_INFO, "EAP-AKA: Unexpected " - "AT_KDF"); - return -1; - } - - wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF"); - if (alen != 2) { - wpa_printf(MSG_INFO, "EAP-AKA': Invalid " - "AT_KDF (len %lu)", - (unsigned long) alen); - return -1; - } - if (attr->kdf_count == EAP_AKA_PRIME_KDF_MAX) { - wpa_printf(MSG_DEBUG, "EAP-AKA': Too many " - "AT_KDF attributes - ignore this"); - continue; - } - attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos); - attr->kdf_count++; - break; - case EAP_SIM_AT_BIDDING: - wpa_printf(MSG_DEBUG, "EAP-AKA: AT_BIDDING"); - if (alen != 2) { - wpa_printf(MSG_INFO, "EAP-AKA: Invalid " - "AT_BIDDING (len %lu)", - (unsigned long) alen); - return -1; - } - attr->bidding = apos; - break; -#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ - default: - if (pos[0] < 128) { - wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized " - "non-skippable attribute %d", - pos[0]); - return -1; - } - - wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable" - " attribute %d ignored", pos[0]); - break; - } - - pos += pos[1] * 4; - } - - wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully " - "(aka=%d encr=%d)", aka, encr); - - return 0; -} - - -u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data, - size_t encr_data_len, const u8 *iv, - struct eap_sim_attrs *attr, int aka) -{ - u8 *decrypted; - - if (!iv) { - wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV"); - return NULL; - } - - decrypted = os_malloc(encr_data_len); - if (decrypted == NULL) - return NULL; - os_memcpy(decrypted, encr_data, encr_data_len); - - if (aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len)) { - os_free(decrypted); - return NULL; - } - wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA", - decrypted, encr_data_len); - - if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr, - aka, 1)) { - wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse " - "decrypted AT_ENCR_DATA"); - os_free(decrypted); - return NULL; - } - - return decrypted; -} - - -#define EAP_SIM_INIT_LEN 128 - -struct eap_sim_msg { - struct wpabuf *buf; - size_t mac, iv, encr; /* index from buf */ - int type; -}; - - -struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype) -{ - struct eap_sim_msg *msg; - struct eap_hdr *eap; - u8 *pos; - - msg = os_zalloc(sizeof(*msg)); - if (msg == NULL) - return NULL; - - msg->type = type; - msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN); - if (msg->buf == NULL) { - os_free(msg); - return NULL; - } - eap = wpabuf_put(msg->buf, sizeof(*eap)); - eap->code = code; - eap->identifier = id; - - pos = wpabuf_put(msg->buf, 4); - *pos++ = type; - *pos++ = subtype; - *pos++ = 0; /* Reserved */ - *pos++ = 0; /* Reserved */ - - return msg; -} - - -struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut, - const u8 *extra, size_t extra_len) -{ - struct eap_hdr *eap; - struct wpabuf *buf; - - if (msg == NULL) - return NULL; - - eap = wpabuf_mhead(msg->buf); - eap->length = host_to_be16(wpabuf_len(msg->buf)); - -#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) - if (k_aut && msg->mac && msg->type == EAP_TYPE_AKA_PRIME) { - eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf), - wpabuf_len(msg->buf), - (u8 *) wpabuf_mhead(msg->buf) + - msg->mac, extra, extra_len); - } else -#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ - if (k_aut && msg->mac) { - eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf), - wpabuf_len(msg->buf), - (u8 *) wpabuf_mhead(msg->buf) + msg->mac, - extra, extra_len); - } - - buf = msg->buf; - os_free(msg); - return buf; -} - - -void eap_sim_msg_free(struct eap_sim_msg *msg) -{ - if (msg) { - wpabuf_free(msg->buf); - os_free(msg); - } -} - - -u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr, - const u8 *data, size_t len) -{ - int attr_len = 2 + len; - int pad_len; - u8 *start; - - if (msg == NULL) - return NULL; - - pad_len = (4 - attr_len % 4) % 4; - attr_len += pad_len; - if (wpabuf_resize(&msg->buf, attr_len)) - return NULL; - start = wpabuf_put(msg->buf, 0); - wpabuf_put_u8(msg->buf, attr); - wpabuf_put_u8(msg->buf, attr_len / 4); - wpabuf_put_data(msg->buf, data, len); - if (pad_len) - os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len); - return start; -} - - -u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value, - const u8 *data, size_t len) -{ - int attr_len = 4 + len; - int pad_len; - u8 *start; - - if (msg == NULL) - return NULL; - - pad_len = (4 - attr_len % 4) % 4; - attr_len += pad_len; - if (wpabuf_resize(&msg->buf, attr_len)) - return NULL; - start = wpabuf_put(msg->buf, 0); - wpabuf_put_u8(msg->buf, attr); - wpabuf_put_u8(msg->buf, attr_len / 4); - wpabuf_put_be16(msg->buf, value); - if (data) - wpabuf_put_data(msg->buf, data, len); - else - wpabuf_put(msg->buf, len); - if (pad_len) - os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len); - return start; -} - - -u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr) -{ - u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN); - if (pos) - msg->mac = (pos - wpabuf_head_u8(msg->buf)) + 4; - return pos; -} - - -int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv, - u8 attr_encr) -{ - u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN); - if (pos == NULL) - return -1; - msg->iv = (pos - wpabuf_head_u8(msg->buf)) + 4; - if (random_get_bytes(wpabuf_mhead_u8(msg->buf) + msg->iv, - EAP_SIM_IV_LEN)) { - msg->iv = 0; - return -1; - } - - pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0); - if (pos == NULL) { - msg->iv = 0; - return -1; - } - msg->encr = pos - wpabuf_head_u8(msg->buf); - - return 0; -} - - -int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad) -{ - size_t encr_len; - - if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0) - return -1; - - encr_len = wpabuf_len(msg->buf) - msg->encr - 4; - if (encr_len % 16) { - u8 *pos; - int pad_len = 16 - (encr_len % 16); - if (pad_len < 4) { - wpa_printf(MSG_WARNING, "EAP-SIM: " - "eap_sim_msg_add_encr_end - invalid pad_len" - " %d", pad_len); - return -1; - } - wpa_printf(MSG_DEBUG, " *AT_PADDING"); - pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4); - if (pos == NULL) - return -1; - os_memset(pos + 4, 0, pad_len - 4); - encr_len += pad_len; - } - wpa_printf(MSG_DEBUG, " (AT_ENCR_DATA data len %lu)", - (unsigned long) encr_len); - wpabuf_mhead_u8(msg->buf)[msg->encr + 1] = encr_len / 4 + 1; - return aes_128_cbc_encrypt(k_encr, wpabuf_head_u8(msg->buf) + msg->iv, - wpabuf_mhead_u8(msg->buf) + msg->encr + 4, - encr_len); -} - - -void eap_sim_report_notification(void *msg_ctx, int notification, int aka) -{ -#ifndef CONFIG_NO_STDOUT_DEBUG - const char *type = aka ? "AKA" : "SIM"; -#endif /* CONFIG_NO_STDOUT_DEBUG */ - - switch (notification) { - case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH: - wpa_printf(MSG_WARNING, "EAP-%s: General failure " - "notification (after authentication)", type); - break; - case EAP_SIM_TEMPORARILY_DENIED: - wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: " - "User has been temporarily denied access to the " - "requested service", type); - break; - case EAP_SIM_NOT_SUBSCRIBED: - wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: " - "User has not subscribed to the requested service", - type); - break; - case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH: - wpa_printf(MSG_WARNING, "EAP-%s: General failure " - "notification (before authentication)", type); - break; - case EAP_SIM_SUCCESS: - wpa_printf(MSG_INFO, "EAP-%s: Successful authentication " - "notification", type); - break; - default: - if (notification >= 32768) { - wpa_printf(MSG_INFO, "EAP-%s: Unrecognized " - "non-failure notification %d", - type, notification); - } else { - wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized " - "failure notification %d", - type, notification); - } - } -} diff --git a/contrib/hostapd/src/eap_common/eap_sim_common.h b/contrib/hostapd/src/eap_common/eap_sim_common.h deleted file mode 100644 index 6021bd2e2b..0000000000 --- a/contrib/hostapd/src/eap_common/eap_sim_common.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * EAP peer/server: EAP-SIM/AKA/AKA' shared routines - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_SIM_COMMON_H -#define EAP_SIM_COMMON_H - -#define EAP_SIM_NONCE_S_LEN 16 -#define EAP_SIM_NONCE_MT_LEN 16 -#define EAP_SIM_MAC_LEN 16 -#define EAP_SIM_MK_LEN 20 -#define EAP_SIM_K_AUT_LEN 16 -#define EAP_SIM_K_ENCR_LEN 16 -#define EAP_SIM_KEYING_DATA_LEN 64 -#define EAP_SIM_IV_LEN 16 -#define EAP_SIM_KC_LEN 8 -#define EAP_SIM_SRES_LEN 4 - -#define GSM_RAND_LEN 16 - -#define EAP_SIM_VERSION 1 - -/* EAP-SIM Subtypes */ -#define EAP_SIM_SUBTYPE_START 10 -#define EAP_SIM_SUBTYPE_CHALLENGE 11 -#define EAP_SIM_SUBTYPE_NOTIFICATION 12 -#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13 -#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14 - -/* AT_CLIENT_ERROR_CODE error codes */ -#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0 -#define EAP_SIM_UNSUPPORTED_VERSION 1 -#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2 -#define EAP_SIM_RAND_NOT_FRESH 3 - -#define EAP_SIM_MAX_FAST_REAUTHS 1000 - -#define EAP_SIM_MAX_CHAL 3 - - -/* EAP-AKA Subtypes */ -#define EAP_AKA_SUBTYPE_CHALLENGE 1 -#define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2 -#define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4 -#define EAP_AKA_SUBTYPE_IDENTITY 5 -#define EAP_AKA_SUBTYPE_NOTIFICATION 12 -#define EAP_AKA_SUBTYPE_REAUTHENTICATION 13 -#define EAP_AKA_SUBTYPE_CLIENT_ERROR 14 - -/* AT_CLIENT_ERROR_CODE error codes */ -#define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0 - -#define EAP_AKA_RAND_LEN 16 -#define EAP_AKA_AUTN_LEN 16 -#define EAP_AKA_AUTS_LEN 14 -#define EAP_AKA_RES_MAX_LEN 16 -#define EAP_AKA_IK_LEN 16 -#define EAP_AKA_CK_LEN 16 -#define EAP_AKA_MAX_FAST_REAUTHS 1000 -#define EAP_AKA_MIN_RES_LEN 4 -#define EAP_AKA_MAX_RES_LEN 16 -#define EAP_AKA_CHECKCODE_LEN 20 - -#define EAP_AKA_PRIME_K_AUT_LEN 32 -#define EAP_AKA_PRIME_CHECKCODE_LEN 32 -#define EAP_AKA_PRIME_K_RE_LEN 32 - -struct wpabuf; - -void eap_sim_derive_mk(const u8 *identity, size_t identity_len, - const u8 *nonce_mt, u16 selected_version, - const u8 *ver_list, size_t ver_list_len, - int num_chal, const u8 *kc, u8 *mk); -void eap_aka_derive_mk(const u8 *identity, size_t identity_len, - const u8 *ik, const u8 *ck, u8 *mk); -int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, - u8 *emsk); -int eap_sim_derive_keys_reauth(u16 _counter, - const u8 *identity, size_t identity_len, - const u8 *nonce_s, const u8 *mk, u8 *msk, - u8 *emsk); -int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req, - const u8 *mac, const u8 *extra, size_t extra_len); -void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac, - const u8 *extra, size_t extra_len); - -#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) -void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len, - const u8 *ik, const u8 *ck, u8 *k_encr, - u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk); -int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter, - const u8 *identity, size_t identity_len, - const u8 *nonce_s, u8 *msk, u8 *emsk); -int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req, - const u8 *mac, const u8 *extra, - size_t extra_len); -void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len, - u8 *mac, const u8 *extra, size_t extra_len); - -void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak, - const u8 *network_name, - size_t network_name_len); -#else /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ -static inline void eap_aka_prime_derive_keys(const u8 *identity, - size_t identity_len, - const u8 *ik, const u8 *ck, - u8 *k_encr, u8 *k_aut, u8 *k_re, - u8 *msk, u8 *emsk) -{ -} - -static inline int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter, - const u8 *identity, - size_t identity_len, - const u8 *nonce_s, u8 *msk, - u8 *emsk) -{ - return -1; -} - -static inline int eap_sim_verify_mac_sha256(const u8 *k_aut, - const struct wpabuf *req, - const u8 *mac, const u8 *extra, - size_t extra_len) -{ - return -1; -} -#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ - - -/* EAP-SIM/AKA Attributes (0..127 non-skippable) */ -#define EAP_SIM_AT_RAND 1 -#define EAP_SIM_AT_AUTN 2 /* only AKA */ -#define EAP_SIM_AT_RES 3 /* only AKA, only peer->server */ -#define EAP_SIM_AT_AUTS 4 /* only AKA, only peer->server */ -#define EAP_SIM_AT_PADDING 6 /* only encrypted */ -#define EAP_SIM_AT_NONCE_MT 7 /* only SIM, only send */ -#define EAP_SIM_AT_PERMANENT_ID_REQ 10 -#define EAP_SIM_AT_MAC 11 -#define EAP_SIM_AT_NOTIFICATION 12 -#define EAP_SIM_AT_ANY_ID_REQ 13 -#define EAP_SIM_AT_IDENTITY 14 /* only send */ -#define EAP_SIM_AT_VERSION_LIST 15 /* only SIM */ -#define EAP_SIM_AT_SELECTED_VERSION 16 /* only SIM */ -#define EAP_SIM_AT_FULLAUTH_ID_REQ 17 -#define EAP_SIM_AT_COUNTER 19 /* only encrypted */ -#define EAP_SIM_AT_COUNTER_TOO_SMALL 20 /* only encrypted */ -#define EAP_SIM_AT_NONCE_S 21 /* only encrypted */ -#define EAP_SIM_AT_CLIENT_ERROR_CODE 22 /* only send */ -#define EAP_SIM_AT_KDF_INPUT 23 /* only AKA' */ -#define EAP_SIM_AT_KDF 24 /* only AKA' */ -#define EAP_SIM_AT_IV 129 -#define EAP_SIM_AT_ENCR_DATA 130 -#define EAP_SIM_AT_NEXT_PSEUDONYM 132 /* only encrypted */ -#define EAP_SIM_AT_NEXT_REAUTH_ID 133 /* only encrypted */ -#define EAP_SIM_AT_CHECKCODE 134 /* only AKA */ -#define EAP_SIM_AT_RESULT_IND 135 -#define EAP_SIM_AT_BIDDING 136 - -/* AT_NOTIFICATION notification code values */ -#define EAP_SIM_GENERAL_FAILURE_AFTER_AUTH 0 -#define EAP_SIM_TEMPORARILY_DENIED 1026 -#define EAP_SIM_NOT_SUBSCRIBED 1031 -#define EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH 16384 -#define EAP_SIM_SUCCESS 32768 - -/* EAP-AKA' AT_KDF Key Derivation Function values */ -#define EAP_AKA_PRIME_KDF 1 - -/* AT_BIDDING flags */ -#define EAP_AKA_BIDDING_FLAG_D 0x8000 - - -enum eap_sim_id_req { - NO_ID_REQ, ANY_ID, FULLAUTH_ID, PERMANENT_ID -}; - - -struct eap_sim_attrs { - const u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s; - const u8 *next_pseudonym, *next_reauth_id; - const u8 *nonce_mt, *identity, *res, *auts; - const u8 *checkcode; - const u8 *kdf_input; - const u8 *bidding; - size_t num_chal, version_list_len, encr_data_len; - size_t next_pseudonym_len, next_reauth_id_len, identity_len, res_len; - size_t res_len_bits; - size_t checkcode_len; - size_t kdf_input_len; - enum eap_sim_id_req id_req; - int notification, counter, selected_version, client_error_code; - int counter_too_small; - int result_ind; -#define EAP_AKA_PRIME_KDF_MAX 10 - u16 kdf[EAP_AKA_PRIME_KDF_MAX]; - size_t kdf_count; -}; - -int eap_sim_parse_attr(const u8 *start, const u8 *end, - struct eap_sim_attrs *attr, int aka, int encr); -u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data, - size_t encr_data_len, const u8 *iv, - struct eap_sim_attrs *attr, int aka); - - -struct eap_sim_msg; - -struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype); -struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut, - const u8 *extra, size_t extra_len); -void eap_sim_msg_free(struct eap_sim_msg *msg); -u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr, - const u8 *data, size_t len); -u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, - u16 value, const u8 *data, size_t len); -u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr); -int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv, - u8 attr_encr); -int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, - int attr_pad); - -void eap_sim_report_notification(void *msg_ctx, int notification, int aka); - -#endif /* EAP_SIM_COMMON_H */ diff --git a/contrib/hostapd/src/eap_common/eap_tlv_common.h b/contrib/hostapd/src/eap_common/eap_tlv_common.h deleted file mode 100644 index 3286055ab7..0000000000 --- a/contrib/hostapd/src/eap_common/eap_tlv_common.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-10.txt) - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_TLV_COMMON_H -#define EAP_TLV_COMMON_H - -/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-10.txt) */ -#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */ -#define EAP_TLV_NAK_TLV 4 -#define EAP_TLV_ERROR_CODE_TLV 5 -#define EAP_TLV_CONNECTION_BINDING_TLV 6 -#define EAP_TLV_VENDOR_SPECIFIC_TLV 7 -#define EAP_TLV_URI_TLV 8 -#define EAP_TLV_EAP_PAYLOAD_TLV 9 -#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10 -#define EAP_TLV_PAC_TLV 11 /* RFC 5422, Section 4.2 */ -#define EAP_TLV_CRYPTO_BINDING_TLV 12 -#define EAP_TLV_CALLING_STATION_ID_TLV 13 -#define EAP_TLV_CALLED_STATION_ID_TLV 14 -#define EAP_TLV_NAS_PORT_TYPE_TLV 15 -#define EAP_TLV_SERVER_IDENTIFIER_TLV 16 -#define EAP_TLV_IDENTITY_TYPE_TLV 17 -#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18 -#define EAP_TLV_REQUEST_ACTION_TLV 19 -#define EAP_TLV_PKCS7_TLV 20 - -#define EAP_TLV_RESULT_SUCCESS 1 -#define EAP_TLV_RESULT_FAILURE 2 - -#define EAP_TLV_TYPE_MANDATORY 0x8000 -#define EAP_TLV_TYPE_MASK 0x3fff - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct eap_tlv_hdr { - be16 tlv_type; - be16 length; -} STRUCT_PACKED; - -struct eap_tlv_nak_tlv { - be16 tlv_type; - be16 length; - be32 vendor_id; - be16 nak_type; -} STRUCT_PACKED; - -struct eap_tlv_result_tlv { - be16 tlv_type; - be16 length; - be16 status; -} STRUCT_PACKED; - -/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */ -struct eap_tlv_intermediate_result_tlv { - be16 tlv_type; - be16 length; - be16 status; - /* Followed by optional TLVs */ -} STRUCT_PACKED; - -/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */ -struct eap_tlv_crypto_binding_tlv { - be16 tlv_type; - be16 length; - u8 reserved; - u8 version; - u8 received_version; - u8 subtype; - u8 nonce[32]; - u8 compound_mac[20]; -} STRUCT_PACKED; - -struct eap_tlv_pac_ack_tlv { - be16 tlv_type; - be16 length; - be16 pac_type; - be16 pac_len; - be16 result; -} STRUCT_PACKED; - -/* RFC 4851, Section 4.2.9 - Request-Action TLV */ -struct eap_tlv_request_action_tlv { - be16 tlv_type; - be16 length; - be16 action; -} STRUCT_PACKED; - -/* RFC 5422, Section 4.2.6 - PAC-Type TLV */ -struct eap_tlv_pac_type_tlv { - be16 tlv_type; /* PAC_TYPE_PAC_TYPE */ - be16 length; - be16 pac_type; -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - -#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0 -#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1 - -#define EAP_TLV_ACTION_PROCESS_TLV 1 -#define EAP_TLV_ACTION_NEGOTIATE_EAP 2 - -#endif /* EAP_TLV_COMMON_H */ diff --git a/contrib/hostapd/src/eap_common/eap_ttls.h b/contrib/hostapd/src/eap_common/eap_ttls.h deleted file mode 100644 index 17901d42db..0000000000 --- a/contrib/hostapd/src/eap_common/eap_ttls.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * EAP server/peer: EAP-TTLS (RFC 5281) - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_TTLS_H -#define EAP_TTLS_H - -struct ttls_avp { - be32 avp_code; - be32 avp_length; /* 8-bit flags, 24-bit length; - * length includes AVP header */ - /* optional 32-bit Vendor-ID */ - /* Data */ -}; - -struct ttls_avp_vendor { - be32 avp_code; - be32 avp_length; /* 8-bit flags, 24-bit length; - * length includes AVP header */ - be32 vendor_id; - /* Data */ -}; - -#define AVP_FLAGS_VENDOR 0x80 -#define AVP_FLAGS_MANDATORY 0x40 - -#define AVP_PAD(start, pos) \ -do { \ - int __pad; \ - __pad = (4 - (((pos) - (start)) & 3)) & 3; \ - os_memset((pos), 0, __pad); \ - pos += __pad; \ -} while (0) - - -/* RFC 2865 */ -#define RADIUS_ATTR_USER_NAME 1 -#define RADIUS_ATTR_USER_PASSWORD 2 -#define RADIUS_ATTR_CHAP_PASSWORD 3 -#define RADIUS_ATTR_REPLY_MESSAGE 18 -#define RADIUS_ATTR_CHAP_CHALLENGE 60 -#define RADIUS_ATTR_EAP_MESSAGE 79 - -/* RFC 2548 */ -#define RADIUS_VENDOR_ID_MICROSOFT 311 -#define RADIUS_ATTR_MS_CHAP_RESPONSE 1 -#define RADIUS_ATTR_MS_CHAP_ERROR 2 -#define RADIUS_ATTR_MS_CHAP_NT_ENC_PW 6 -#define RADIUS_ATTR_MS_CHAP_CHALLENGE 11 -#define RADIUS_ATTR_MS_CHAP2_RESPONSE 25 -#define RADIUS_ATTR_MS_CHAP2_SUCCESS 26 -#define RADIUS_ATTR_MS_CHAP2_CPW 27 - -#define EAP_TTLS_MSCHAPV2_CHALLENGE_LEN 16 -#define EAP_TTLS_MSCHAPV2_RESPONSE_LEN 50 -#define EAP_TTLS_MSCHAP_CHALLENGE_LEN 8 -#define EAP_TTLS_MSCHAP_RESPONSE_LEN 50 -#define EAP_TTLS_CHAP_CHALLENGE_LEN 16 -#define EAP_TTLS_CHAP_PASSWORD_LEN 16 - -#endif /* EAP_TTLS_H */ diff --git a/contrib/hostapd/src/eap_common/eap_wsc_common.c b/contrib/hostapd/src/eap_common/eap_wsc_common.c deleted file mode 100644 index 7c1496ec33..0000000000 --- a/contrib/hostapd/src/eap_common/eap_wsc_common.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * EAP-WSC common routines for Wi-Fi Protected Setup - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_defs.h" -#include "eap_common.h" -#include "wps/wps.h" -#include "eap_wsc_common.h" - -struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code) -{ - struct wpabuf *msg; - - msg = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2, code, id); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for " - "FRAG_ACK"); - return NULL; - } - - wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/FRAG_ACK"); - wpabuf_put_u8(msg, WSC_FRAG_ACK); /* Op-Code */ - wpabuf_put_u8(msg, 0); /* Flags */ - - return msg; -} diff --git a/contrib/hostapd/src/eap_common/eap_wsc_common.h b/contrib/hostapd/src/eap_common/eap_wsc_common.h deleted file mode 100644 index 0e7b653081..0000000000 --- a/contrib/hostapd/src/eap_common/eap_wsc_common.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * EAP-WSC definitions for Wi-Fi Protected Setup - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_WSC_COMMON_H -#define EAP_WSC_COMMON_H - -#define EAP_VENDOR_TYPE_WSC 1 - -#define WSC_FLAGS_MF 0x01 -#define WSC_FLAGS_LF 0x02 - -#define WSC_ID_REGISTRAR "WFA-SimpleConfig-Registrar-1-0" -#define WSC_ID_REGISTRAR_LEN 30 -#define WSC_ID_ENROLLEE "WFA-SimpleConfig-Enrollee-1-0" -#define WSC_ID_ENROLLEE_LEN 29 - -#define WSC_FRAGMENT_SIZE 1400 - - -struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code); - -#endif /* EAP_WSC_COMMON_H */ diff --git a/contrib/hostapd/src/eap_common/ikev2_common.c b/contrib/hostapd/src/eap_common/ikev2_common.c deleted file mode 100644 index f061866ae2..0000000000 --- a/contrib/hostapd/src/eap_common/ikev2_common.c +++ /dev/null @@ -1,791 +0,0 @@ -/* - * IKEv2 common routines for initiator and responder - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/crypto.h" -#include "crypto/md5.h" -#include "crypto/sha1.h" -#include "crypto/random.h" -#include "ikev2_common.h" - - -static struct ikev2_integ_alg ikev2_integ_algs[] = { - { AUTH_HMAC_SHA1_96, 20, 12 }, - { AUTH_HMAC_MD5_96, 16, 12 } -}; - -#define NUM_INTEG_ALGS ARRAY_SIZE(ikev2_integ_algs) - - -static struct ikev2_prf_alg ikev2_prf_algs[] = { - { PRF_HMAC_SHA1, 20, 20 }, - { PRF_HMAC_MD5, 16, 16 } -}; - -#define NUM_PRF_ALGS ARRAY_SIZE(ikev2_prf_algs) - - -static struct ikev2_encr_alg ikev2_encr_algs[] = { - { ENCR_AES_CBC, 16, 16 }, /* only 128-bit keys supported for now */ - { ENCR_3DES, 24, 8 } -}; - -#define NUM_ENCR_ALGS ARRAY_SIZE(ikev2_encr_algs) - - -const struct ikev2_integ_alg * ikev2_get_integ(int id) -{ - size_t i; - - for (i = 0; i < NUM_INTEG_ALGS; i++) { - if (ikev2_integ_algs[i].id == id) - return &ikev2_integ_algs[i]; - } - - return NULL; -} - - -int ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data, - size_t data_len, u8 *hash) -{ - u8 tmphash[IKEV2_MAX_HASH_LEN]; - - switch (alg) { - case AUTH_HMAC_SHA1_96: - if (key_len != 20) - return -1; - hmac_sha1(key, key_len, data, data_len, tmphash); - os_memcpy(hash, tmphash, 12); - break; - case AUTH_HMAC_MD5_96: - if (key_len != 16) - return -1; - hmac_md5(key, key_len, data, data_len, tmphash); - os_memcpy(hash, tmphash, 12); - break; - default: - return -1; - } - - return 0; -} - - -const struct ikev2_prf_alg * ikev2_get_prf(int id) -{ - size_t i; - - for (i = 0; i < NUM_PRF_ALGS; i++) { - if (ikev2_prf_algs[i].id == id) - return &ikev2_prf_algs[i]; - } - - return NULL; -} - - -int ikev2_prf_hash(int alg, const u8 *key, size_t key_len, - size_t num_elem, const u8 *addr[], const size_t *len, - u8 *hash) -{ - switch (alg) { - case PRF_HMAC_SHA1: - hmac_sha1_vector(key, key_len, num_elem, addr, len, hash); - break; - case PRF_HMAC_MD5: - hmac_md5_vector(key, key_len, num_elem, addr, len, hash); - break; - default: - return -1; - } - - return 0; -} - - -int ikev2_prf_plus(int alg, const u8 *key, size_t key_len, - const u8 *data, size_t data_len, - u8 *out, size_t out_len) -{ - u8 hash[IKEV2_MAX_HASH_LEN]; - size_t hash_len; - u8 iter, *pos, *end; - const u8 *addr[3]; - size_t len[3]; - const struct ikev2_prf_alg *prf; - int res; - - prf = ikev2_get_prf(alg); - if (prf == NULL) - return -1; - hash_len = prf->hash_len; - - addr[0] = hash; - len[0] = hash_len; - addr[1] = data; - len[1] = data_len; - addr[2] = &iter; - len[2] = 1; - - pos = out; - end = out + out_len; - iter = 1; - while (pos < end) { - size_t clen; - if (iter == 1) - res = ikev2_prf_hash(alg, key, key_len, 2, &addr[1], - &len[1], hash); - else - res = ikev2_prf_hash(alg, key, key_len, 3, addr, len, - hash); - if (res < 0) - return -1; - clen = hash_len; - if ((int) clen > end - pos) - clen = end - pos; - os_memcpy(pos, hash, clen); - pos += clen; - iter++; - } - - return 0; -} - - -const struct ikev2_encr_alg * ikev2_get_encr(int id) -{ - size_t i; - - for (i = 0; i < NUM_ENCR_ALGS; i++) { - if (ikev2_encr_algs[i].id == id) - return &ikev2_encr_algs[i]; - } - - return NULL; -} - - -#ifdef CCNS_PL -/* from des.c */ -struct des3_key_s { - u32 ek[3][32]; - u32 dk[3][32]; -}; - -void des3_key_setup(const u8 *key, struct des3_key_s *dkey); -void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt); -void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain); -#endif /* CCNS_PL */ - - -int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, - const u8 *plain, u8 *crypt, size_t len) -{ - struct crypto_cipher *cipher; - int encr_alg; - -#ifdef CCNS_PL - if (alg == ENCR_3DES) { - struct des3_key_s des3key; - size_t i, blocks; - u8 *pos; - - /* ECB mode is used incorrectly for 3DES!? */ - if (key_len != 24) { - wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length"); - return -1; - } - des3_key_setup(key, &des3key); - - blocks = len / 8; - pos = crypt; - for (i = 0; i < blocks; i++) { - des3_encrypt(pos, &des3key, pos); - pos += 8; - } - } else { -#endif /* CCNS_PL */ - switch (alg) { - case ENCR_3DES: - encr_alg = CRYPTO_CIPHER_ALG_3DES; - break; - case ENCR_AES_CBC: - encr_alg = CRYPTO_CIPHER_ALG_AES; - break; - default: - wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); - return -1; - } - - cipher = crypto_cipher_init(encr_alg, iv, key, key_len); - if (cipher == NULL) { - wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); - return -1; - } - - if (crypto_cipher_encrypt(cipher, plain, crypt, len) < 0) { - wpa_printf(MSG_INFO, "IKEV2: Encryption failed"); - crypto_cipher_deinit(cipher); - return -1; - } - crypto_cipher_deinit(cipher); -#ifdef CCNS_PL - } -#endif /* CCNS_PL */ - - return 0; -} - - -int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, - const u8 *crypt, u8 *plain, size_t len) -{ - struct crypto_cipher *cipher; - int encr_alg; - -#ifdef CCNS_PL - if (alg == ENCR_3DES) { - struct des3_key_s des3key; - size_t i, blocks; - - /* ECB mode is used incorrectly for 3DES!? */ - if (key_len != 24) { - wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length"); - return -1; - } - des3_key_setup(key, &des3key); - - if (len % 8) { - wpa_printf(MSG_INFO, "IKEV2: Invalid encrypted " - "length"); - return -1; - } - blocks = len / 8; - for (i = 0; i < blocks; i++) { - des3_decrypt(crypt, &des3key, plain); - plain += 8; - crypt += 8; - } - } else { -#endif /* CCNS_PL */ - switch (alg) { - case ENCR_3DES: - encr_alg = CRYPTO_CIPHER_ALG_3DES; - break; - case ENCR_AES_CBC: - encr_alg = CRYPTO_CIPHER_ALG_AES; - break; - default: - wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); - return -1; - } - - cipher = crypto_cipher_init(encr_alg, iv, key, key_len); - if (cipher == NULL) { - wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); - return -1; - } - - if (crypto_cipher_decrypt(cipher, crypt, plain, len) < 0) { - wpa_printf(MSG_INFO, "IKEV2: Decryption failed"); - crypto_cipher_deinit(cipher); - return -1; - } - crypto_cipher_deinit(cipher); -#ifdef CCNS_PL - } -#endif /* CCNS_PL */ - - return 0; -} - - -int ikev2_parse_payloads(struct ikev2_payloads *payloads, - u8 next_payload, const u8 *pos, const u8 *end) -{ - const struct ikev2_payload_hdr *phdr; - - os_memset(payloads, 0, sizeof(*payloads)); - - while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) { - int plen, pdatalen; - const u8 *pdata; - wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u", - next_payload); - if (end - pos < (int) sizeof(*phdr)) { - wpa_printf(MSG_INFO, "IKEV2: Too short message for " - "payload header (left=%ld)", - (long) (end - pos)); - } - phdr = (const struct ikev2_payload_hdr *) pos; - plen = WPA_GET_BE16(phdr->payload_length); - if (plen < (int) sizeof(*phdr) || pos + plen > end) { - wpa_printf(MSG_INFO, "IKEV2: Invalid payload header " - "length %d", plen); - return -1; - } - - wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Flags: 0x%x" - " Payload Length: %d", - phdr->next_payload, phdr->flags, plen); - - pdata = (const u8 *) (phdr + 1); - pdatalen = plen - sizeof(*phdr); - - switch (next_payload) { - case IKEV2_PAYLOAD_SA: - wpa_printf(MSG_DEBUG, "IKEV2: Payload: Security " - "Association"); - payloads->sa = pdata; - payloads->sa_len = pdatalen; - break; - case IKEV2_PAYLOAD_KEY_EXCHANGE: - wpa_printf(MSG_DEBUG, "IKEV2: Payload: Key " - "Exchange"); - payloads->ke = pdata; - payloads->ke_len = pdatalen; - break; - case IKEV2_PAYLOAD_IDi: - wpa_printf(MSG_DEBUG, "IKEV2: Payload: IDi"); - payloads->idi = pdata; - payloads->idi_len = pdatalen; - break; - case IKEV2_PAYLOAD_IDr: - wpa_printf(MSG_DEBUG, "IKEV2: Payload: IDr"); - payloads->idr = pdata; - payloads->idr_len = pdatalen; - break; - case IKEV2_PAYLOAD_CERTIFICATE: - wpa_printf(MSG_DEBUG, "IKEV2: Payload: Certificate"); - payloads->cert = pdata; - payloads->cert_len = pdatalen; - break; - case IKEV2_PAYLOAD_AUTHENTICATION: - wpa_printf(MSG_DEBUG, "IKEV2: Payload: " - "Authentication"); - payloads->auth = pdata; - payloads->auth_len = pdatalen; - break; - case IKEV2_PAYLOAD_NONCE: - wpa_printf(MSG_DEBUG, "IKEV2: Payload: Nonce"); - payloads->nonce = pdata; - payloads->nonce_len = pdatalen; - break; - case IKEV2_PAYLOAD_ENCRYPTED: - wpa_printf(MSG_DEBUG, "IKEV2: Payload: Encrypted"); - payloads->encrypted = pdata; - payloads->encrypted_len = pdatalen; - break; - case IKEV2_PAYLOAD_NOTIFICATION: - wpa_printf(MSG_DEBUG, "IKEV2: Payload: " - "Notification"); - payloads->notification = pdata; - payloads->notification_len = pdatalen; - break; - default: - if (phdr->flags & IKEV2_PAYLOAD_FLAGS_CRITICAL) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported " - "critical payload %u - reject the " - "entire message", next_payload); - return -1; - } else { - wpa_printf(MSG_DEBUG, "IKEV2: Skipped " - "unsupported payload %u", - next_payload); - } - } - - if (next_payload == IKEV2_PAYLOAD_ENCRYPTED && - pos + plen == end) { - /* - * Next Payload in the case of Encrypted Payload is - * actually the payload type for the first embedded - * payload. - */ - payloads->encr_next_payload = phdr->next_payload; - next_payload = IKEV2_PAYLOAD_NO_NEXT_PAYLOAD; - } else - next_payload = phdr->next_payload; - - pos += plen; - } - - if (pos != end) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected extra data after " - "payloads"); - return -1; - } - - return 0; -} - - -int ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg, - const u8 *ID, size_t ID_len, u8 ID_type, - struct ikev2_keys *keys, int initiator, - const u8 *shared_secret, size_t shared_secret_len, - const u8 *nonce, size_t nonce_len, - const u8 *key_pad, size_t key_pad_len, - u8 *auth_data) -{ - size_t sign_len, buf_len; - u8 *sign_data, *pos, *buf, hash[IKEV2_MAX_HASH_LEN]; - const struct ikev2_prf_alg *prf; - const u8 *SK_p = initiator ? keys->SK_pi : keys->SK_pr; - - prf = ikev2_get_prf(prf_alg); - if (sign_msg == NULL || ID == NULL || SK_p == NULL || - shared_secret == NULL || nonce == NULL || prf == NULL) - return -1; - - /* prf(SK_pi/r,IDi/r') */ - buf_len = 4 + ID_len; - buf = os_zalloc(buf_len); - if (buf == NULL) - return -1; - buf[0] = ID_type; - os_memcpy(buf + 4, ID, ID_len); - if (ikev2_prf_hash(prf->id, SK_p, keys->SK_prf_len, - 1, (const u8 **) &buf, &buf_len, hash) < 0) { - os_free(buf); - return -1; - } - os_free(buf); - - /* sign_data = msg | Nr/i | prf(SK_pi/r,IDi/r') */ - sign_len = wpabuf_len(sign_msg) + nonce_len + prf->hash_len; - sign_data = os_malloc(sign_len); - if (sign_data == NULL) - return -1; - pos = sign_data; - os_memcpy(pos, wpabuf_head(sign_msg), wpabuf_len(sign_msg)); - pos += wpabuf_len(sign_msg); - os_memcpy(pos, nonce, nonce_len); - pos += nonce_len; - os_memcpy(pos, hash, prf->hash_len); - - /* AUTH = prf(prf(Shared Secret, key pad, sign_data) */ - if (ikev2_prf_hash(prf->id, shared_secret, shared_secret_len, 1, - &key_pad, &key_pad_len, hash) < 0 || - ikev2_prf_hash(prf->id, hash, prf->hash_len, 1, - (const u8 **) &sign_data, &sign_len, auth_data) < 0) - { - os_free(sign_data); - return -1; - } - os_free(sign_data); - - return 0; -} - - -u8 * ikev2_decrypt_payload(int encr_id, int integ_id, - struct ikev2_keys *keys, int initiator, - const struct ikev2_hdr *hdr, - const u8 *encrypted, size_t encrypted_len, - size_t *res_len) -{ - size_t iv_len; - const u8 *pos, *end, *iv, *integ; - u8 hash[IKEV2_MAX_HASH_LEN], *decrypted; - size_t decrypted_len, pad_len; - const struct ikev2_integ_alg *integ_alg; - const struct ikev2_encr_alg *encr_alg; - const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er; - const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; - - if (encrypted == NULL) { - wpa_printf(MSG_INFO, "IKEV2: No Encrypted payload in SA_AUTH"); - return NULL; - } - - encr_alg = ikev2_get_encr(encr_id); - if (encr_alg == NULL) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type"); - return NULL; - } - iv_len = encr_alg->block_size; - - integ_alg = ikev2_get_integ(integ_id); - if (integ_alg == NULL) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type"); - return NULL; - } - - if (encrypted_len < iv_len + 1 + integ_alg->hash_len) { - wpa_printf(MSG_INFO, "IKEV2: No room for IV or Integrity " - "Checksum"); - return NULL; - } - - iv = encrypted; - pos = iv + iv_len; - end = encrypted + encrypted_len; - integ = end - integ_alg->hash_len; - - if (SK_a == NULL) { - wpa_printf(MSG_INFO, "IKEV2: No SK_a available"); - return NULL; - } - if (ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len, - (const u8 *) hdr, - integ - (const u8 *) hdr, hash) < 0) { - wpa_printf(MSG_INFO, "IKEV2: Failed to calculate integrity " - "hash"); - return NULL; - } - if (os_memcmp(integ, hash, integ_alg->hash_len) != 0) { - wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum " - "Data"); - return NULL; - } - - if (SK_e == NULL) { - wpa_printf(MSG_INFO, "IKEV2: No SK_e available"); - return NULL; - } - - decrypted_len = integ - pos; - decrypted = os_malloc(decrypted_len); - if (decrypted == NULL) - return NULL; - - if (ikev2_encr_decrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, pos, - decrypted, decrypted_len) < 0) { - os_free(decrypted); - return NULL; - } - - pad_len = decrypted[decrypted_len - 1]; - if (decrypted_len < pad_len + 1) { - wpa_printf(MSG_INFO, "IKEV2: Invalid padding in encrypted " - "payload"); - os_free(decrypted); - return NULL; - } - - decrypted_len -= pad_len + 1; - - *res_len = decrypted_len; - return decrypted; -} - - -void ikev2_update_hdr(struct wpabuf *msg) -{ - struct ikev2_hdr *hdr; - - /* Update lenth field in HDR */ - hdr = wpabuf_mhead(msg); - WPA_PUT_BE32(hdr->length, wpabuf_len(msg)); -} - - -int ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys, - int initiator, struct wpabuf *msg, - struct wpabuf *plain, u8 next_payload) -{ - struct ikev2_payload_hdr *phdr; - size_t plen; - size_t iv_len, pad_len; - u8 *icv, *iv; - const struct ikev2_integ_alg *integ_alg; - const struct ikev2_encr_alg *encr_alg; - const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er; - const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding Encrypted payload"); - - /* Encr - RFC 4306, Sect. 3.14 */ - - encr_alg = ikev2_get_encr(encr_id); - if (encr_alg == NULL) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type"); - return -1; - } - iv_len = encr_alg->block_size; - - integ_alg = ikev2_get_integ(integ_id); - if (integ_alg == NULL) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type"); - return -1; - } - - if (SK_e == NULL) { - wpa_printf(MSG_INFO, "IKEV2: No SK_e available"); - return -1; - } - - if (SK_a == NULL) { - wpa_printf(MSG_INFO, "IKEV2: No SK_a available"); - return -1; - } - - phdr = wpabuf_put(msg, sizeof(*phdr)); - phdr->next_payload = next_payload; - phdr->flags = 0; - - iv = wpabuf_put(msg, iv_len); - if (random_get_bytes(iv, iv_len)) { - wpa_printf(MSG_INFO, "IKEV2: Could not generate IV"); - return -1; - } - - pad_len = iv_len - (wpabuf_len(plain) + 1) % iv_len; - if (pad_len == iv_len) - pad_len = 0; - wpabuf_put(plain, pad_len); - wpabuf_put_u8(plain, pad_len); - - if (ikev2_encr_encrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, - wpabuf_head(plain), wpabuf_mhead(plain), - wpabuf_len(plain)) < 0) - return -1; - - wpabuf_put_buf(msg, plain); - - /* Need to update all headers (Length fields) prior to hash func */ - icv = wpabuf_put(msg, integ_alg->hash_len); - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; - WPA_PUT_BE16(phdr->payload_length, plen); - - ikev2_update_hdr(msg); - - return ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len, - wpabuf_head(msg), - wpabuf_len(msg) - integ_alg->hash_len, icv); - - return 0; -} - - -int ikev2_keys_set(struct ikev2_keys *keys) -{ - return keys->SK_d && keys->SK_ai && keys->SK_ar && keys->SK_ei && - keys->SK_er && keys->SK_pi && keys->SK_pr; -} - - -void ikev2_free_keys(struct ikev2_keys *keys) -{ - os_free(keys->SK_d); - os_free(keys->SK_ai); - os_free(keys->SK_ar); - os_free(keys->SK_ei); - os_free(keys->SK_er); - os_free(keys->SK_pi); - os_free(keys->SK_pr); - keys->SK_d = keys->SK_ai = keys->SK_ar = keys->SK_ei = keys->SK_er = - keys->SK_pi = keys->SK_pr = NULL; -} - - -int ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf, - const struct ikev2_integ_alg *integ, - const struct ikev2_encr_alg *encr, - const u8 *skeyseed, const u8 *data, size_t data_len, - struct ikev2_keys *keys) -{ - u8 *keybuf, *pos; - size_t keybuf_len; - - /* - * {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } = - * prf+(SKEYSEED, Ni | Nr | SPIi | SPIr ) - */ - ikev2_free_keys(keys); - keys->SK_d_len = prf->key_len; - keys->SK_integ_len = integ->key_len; - keys->SK_encr_len = encr->key_len; - keys->SK_prf_len = prf->key_len; -#ifdef CCNS_PL - /* Uses encryption key length for SK_d; should be PRF length */ - keys->SK_d_len = keys->SK_encr_len; -#endif /* CCNS_PL */ - - keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len + - 2 * keys->SK_encr_len + 2 * keys->SK_prf_len; - keybuf = os_malloc(keybuf_len); - if (keybuf == NULL) - return -1; - - if (ikev2_prf_plus(prf->id, skeyseed, prf->hash_len, - data, data_len, keybuf, keybuf_len)) { - os_free(keybuf); - return -1; - } - - pos = keybuf; - - keys->SK_d = os_malloc(keys->SK_d_len); - if (keys->SK_d) { - os_memcpy(keys->SK_d, pos, keys->SK_d_len); - wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_d", - keys->SK_d, keys->SK_d_len); - } - pos += keys->SK_d_len; - - keys->SK_ai = os_malloc(keys->SK_integ_len); - if (keys->SK_ai) { - os_memcpy(keys->SK_ai, pos, keys->SK_integ_len); - wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ai", - keys->SK_ai, keys->SK_integ_len); - } - pos += keys->SK_integ_len; - - keys->SK_ar = os_malloc(keys->SK_integ_len); - if (keys->SK_ar) { - os_memcpy(keys->SK_ar, pos, keys->SK_integ_len); - wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ar", - keys->SK_ar, keys->SK_integ_len); - } - pos += keys->SK_integ_len; - - keys->SK_ei = os_malloc(keys->SK_encr_len); - if (keys->SK_ei) { - os_memcpy(keys->SK_ei, pos, keys->SK_encr_len); - wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ei", - keys->SK_ei, keys->SK_encr_len); - } - pos += keys->SK_encr_len; - - keys->SK_er = os_malloc(keys->SK_encr_len); - if (keys->SK_er) { - os_memcpy(keys->SK_er, pos, keys->SK_encr_len); - wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_er", - keys->SK_er, keys->SK_encr_len); - } - pos += keys->SK_encr_len; - - keys->SK_pi = os_malloc(keys->SK_prf_len); - if (keys->SK_pi) { - os_memcpy(keys->SK_pi, pos, keys->SK_prf_len); - wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pi", - keys->SK_pi, keys->SK_prf_len); - } - pos += keys->SK_prf_len; - - keys->SK_pr = os_malloc(keys->SK_prf_len); - if (keys->SK_pr) { - os_memcpy(keys->SK_pr, pos, keys->SK_prf_len); - wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pr", - keys->SK_pr, keys->SK_prf_len); - } - - os_free(keybuf); - - if (!ikev2_keys_set(keys)) { - ikev2_free_keys(keys); - return -1; - } - - return 0; -} diff --git a/contrib/hostapd/src/eap_common/ikev2_common.h b/contrib/hostapd/src/eap_common/ikev2_common.h deleted file mode 100644 index 45c970b608..0000000000 --- a/contrib/hostapd/src/eap_common/ikev2_common.h +++ /dev/null @@ -1,338 +0,0 @@ -/* - * IKEv2 definitions - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef IKEV2_COMMON_H -#define IKEV2_COMMON_H - -/* - * Nonce length must be at least 16 octets. It must also be at least half the - * key size of the negotiated PRF. - */ -#define IKEV2_NONCE_MIN_LEN 16 -#define IKEV2_NONCE_MAX_LEN 256 - -/* IKE Header - RFC 4306, Sect. 3.1 */ -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -#define IKEV2_SPI_LEN 8 - -struct ikev2_hdr { - u8 i_spi[IKEV2_SPI_LEN]; /* IKE_SA Initiator's SPI */ - u8 r_spi[IKEV2_SPI_LEN]; /* IKE_SA Responder's SPI */ - u8 next_payload; - u8 version; /* MjVer | MnVer */ - u8 exchange_type; - u8 flags; - u8 message_id[4]; - u8 length[4]; /* total length of HDR + payloads */ -} STRUCT_PACKED; - -struct ikev2_payload_hdr { - u8 next_payload; - u8 flags; - u8 payload_length[2]; /* this payload, including the payload header */ -} STRUCT_PACKED; - -struct ikev2_proposal { - u8 type; /* 0 (last) or 2 (more) */ - u8 reserved; - u8 proposal_length[2]; /* including all transform and attributes */ - u8 proposal_num; - u8 protocol_id; /* IKEV2_PROTOCOL_* */ - u8 spi_size; - u8 num_transforms; - /* SPI of spi_size octets */ - /* Transforms */ -} STRUCT_PACKED; - -struct ikev2_transform { - u8 type; /* 0 (last) or 3 (more) */ - u8 reserved; - u8 transform_length[2]; /* including Header and Attributes */ - u8 transform_type; - u8 reserved2; - u8 transform_id[2]; - /* Transform Attributes */ -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - - -/* Current IKEv2 version from RFC 4306 */ -#define IKEV2_MjVer 2 -#define IKEV2_MnVer 0 -#ifdef CCNS_PL -#define IKEV2_VERSION ((IKEV2_MjVer) | ((IKEV2_MnVer) << 4)) -#else /* CCNS_PL */ -#define IKEV2_VERSION (((IKEV2_MjVer) << 4) | (IKEV2_MnVer)) -#endif /* CCNS_PL */ - -/* IKEv2 Exchange Types */ -enum { - /* 0-33 RESERVED */ - IKE_SA_INIT = 34, - IKE_SA_AUTH = 35, - CREATE_CHILD_SA = 36, - INFORMATION = 37 - /* 38-239 RESERVED TO IANA */ - /* 240-255 Reserved for private use */ -}; - -/* IKEv2 Flags */ -#define IKEV2_HDR_INITIATOR 0x08 -#define IKEV2_HDR_VERSION 0x10 -#define IKEV2_HDR_RESPONSE 0x20 - -/* Payload Header Flags */ -#define IKEV2_PAYLOAD_FLAGS_CRITICAL 0x01 - - -/* EAP-IKEv2 Payload Types (in Next Payload Type field) - * http://www.iana.org/assignments/eap-ikev2-payloads */ -enum { - IKEV2_PAYLOAD_NO_NEXT_PAYLOAD = 0, - IKEV2_PAYLOAD_SA = 33, - IKEV2_PAYLOAD_KEY_EXCHANGE = 34, - IKEV2_PAYLOAD_IDi = 35, - IKEV2_PAYLOAD_IDr = 36, - IKEV2_PAYLOAD_CERTIFICATE = 37, - IKEV2_PAYLOAD_CERT_REQ = 38, - IKEV2_PAYLOAD_AUTHENTICATION = 39, - IKEV2_PAYLOAD_NONCE = 40, - IKEV2_PAYLOAD_NOTIFICATION = 41, - IKEV2_PAYLOAD_VENDOD_ID = 43, - IKEV2_PAYLOAD_ENCRYPTED = 46, - IKEV2_PAYLOAD_NEXT_FAST_ID = 121 -}; - - -/* IKEv2 Proposal - Protocol ID */ -enum { - IKEV2_PROTOCOL_RESERVED = 0, - IKEV2_PROTOCOL_IKE = 1, /* IKE is the only one allowed for EAP-IKEv2 */ - IKEV2_PROTOCOL_AH = 2, - IKEV2_PROTOCOL_ESP = 3 -}; - - -/* IKEv2 Transform Types */ -enum { - IKEV2_TRANSFORM_ENCR = 1, - IKEV2_TRANSFORM_PRF = 2, - IKEV2_TRANSFORM_INTEG = 3, - IKEV2_TRANSFORM_DH = 4, - IKEV2_TRANSFORM_ESN = 5 -}; - -/* IKEv2 Transform Type 1 (Encryption Algorithm) */ -enum { - ENCR_DES_IV64 = 1, - ENCR_DES = 2, - ENCR_3DES = 3, - ENCR_RC5 = 4, - ENCR_IDEA = 5, - ENCR_CAST = 6, - ENCR_BLOWFISH = 7, - ENCR_3IDEA = 8, - ENCR_DES_IV32 = 9, - ENCR_NULL = 11, - ENCR_AES_CBC = 12, - ENCR_AES_CTR = 13 -}; - -/* IKEv2 Transform Type 2 (Pseudo-random Function) */ -enum { - PRF_HMAC_MD5 = 1, - PRF_HMAC_SHA1 = 2, - PRF_HMAC_TIGER = 3, - PRF_AES128_XCBC = 4 -}; - -/* IKEv2 Transform Type 3 (Integrity Algorithm) */ -enum { - AUTH_HMAC_MD5_96 = 1, - AUTH_HMAC_SHA1_96 = 2, - AUTH_DES_MAC = 3, - AUTH_KPDK_MD5 = 4, - AUTH_AES_XCBC_96 = 5 -}; - -/* IKEv2 Transform Type 4 (Diffie-Hellman Group) */ -enum { - DH_GROUP1_768BIT_MODP = 1, /* RFC 4306 */ - DH_GROUP2_1024BIT_MODP = 2, /* RFC 4306 */ - DH_GROUP5_1536BIT_MODP = 5, /* RFC 3526 */ - DH_GROUP5_2048BIT_MODP = 14, /* RFC 3526 */ - DH_GROUP5_3072BIT_MODP = 15, /* RFC 3526 */ - DH_GROUP5_4096BIT_MODP = 16, /* RFC 3526 */ - DH_GROUP5_6144BIT_MODP = 17, /* RFC 3526 */ - DH_GROUP5_8192BIT_MODP = 18 /* RFC 3526 */ -}; - - -/* Identification Data Types (RFC 4306, Sect. 3.5) */ -enum { - ID_IPV4_ADDR = 1, - ID_FQDN = 2, - ID_RFC822_ADDR = 3, - ID_IPV6_ADDR = 5, - ID_DER_ASN1_DN = 9, - ID_DER_ASN1_GN= 10, - ID_KEY_ID = 11 -}; - - -/* Certificate Encoding (RFC 4306, Sect. 3.6) */ -enum { - CERT_ENCODING_PKCS7_X509 = 1, - CERT_ENCODING_PGP_CERT = 2, - CERT_ENCODING_DNS_SIGNED_KEY = 3, - /* X.509 Certificate - Signature: DER encoded X.509 certificate whose - * public key is used to validate the sender's AUTH payload */ - CERT_ENCODING_X509_CERT_SIGN = 4, - CERT_ENCODING_KERBEROS_TOKEN = 6, - /* DER encoded X.509 certificate revocation list */ - CERT_ENCODING_CRL = 7, - CERT_ENCODING_ARL = 8, - CERT_ENCODING_SPKI_CERT = 9, - CERT_ENCODING_X509_CERT_ATTR = 10, - /* PKCS #1 encoded RSA key */ - CERT_ENCODING_RAW_RSA_KEY = 11, - CERT_ENCODING_HASH_AND_URL_X509_CERT = 12, - CERT_ENCODING_HASH_AND_URL_X509_BUNDLE = 13 -}; - - -/* Authentication Method (RFC 4306, Sect. 3.8) */ -enum { - AUTH_RSA_SIGN = 1, - AUTH_SHARED_KEY_MIC = 2, - AUTH_DSS_SIGN = 3 -}; - - -/* Notify Message Types (RFC 4306, Sect. 3.10.1) */ -enum { - UNSUPPORTED_CRITICAL_PAYLOAD = 1, - INVALID_IKE_SPI = 4, - INVALID_MAJOR_VERSION = 5, - INVALID_SYNTAX = 7, - INVALID_MESSAGE_ID = 9, - INVALID_SPI = 11, - NO_PROPOSAL_CHOSEN = 14, - INVALID_KE_PAYLOAD = 17, - AUTHENTICATION_FAILED = 24, - SINGLE_PAIR_REQUIRED = 34, - NO_ADDITIONAL_SAS = 35, - INTERNAL_ADDRESS_FAILURE = 36, - FAILED_CP_REQUIRED = 37, - TS_UNACCEPTABLE = 38, - INVALID_SELECTORS = 39 -}; - - -struct ikev2_keys { - u8 *SK_d, *SK_ai, *SK_ar, *SK_ei, *SK_er, *SK_pi, *SK_pr; - size_t SK_d_len, SK_integ_len, SK_encr_len, SK_prf_len; -}; - - -int ikev2_keys_set(struct ikev2_keys *keys); -void ikev2_free_keys(struct ikev2_keys *keys); - - -/* Maximum hash length for supported hash algorithms */ -#define IKEV2_MAX_HASH_LEN 20 - -struct ikev2_integ_alg { - int id; - size_t key_len; - size_t hash_len; -}; - -struct ikev2_prf_alg { - int id; - size_t key_len; - size_t hash_len; -}; - -struct ikev2_encr_alg { - int id; - size_t key_len; - size_t block_size; -}; - -const struct ikev2_integ_alg * ikev2_get_integ(int id); -int ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data, - size_t data_len, u8 *hash); -const struct ikev2_prf_alg * ikev2_get_prf(int id); -int ikev2_prf_hash(int alg, const u8 *key, size_t key_len, - size_t num_elem, const u8 *addr[], const size_t *len, - u8 *hash); -int ikev2_prf_plus(int alg, const u8 *key, size_t key_len, - const u8 *data, size_t data_len, - u8 *out, size_t out_len); -const struct ikev2_encr_alg * ikev2_get_encr(int id); -int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, - const u8 *plain, u8 *crypt, size_t len); -int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, - const u8 *crypt, u8 *plain, size_t len); - -int ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg, - const u8 *ID, size_t ID_len, u8 ID_type, - struct ikev2_keys *keys, int initiator, - const u8 *shared_secret, size_t shared_secret_len, - const u8 *nonce, size_t nonce_len, - const u8 *key_pad, size_t key_pad_len, - u8 *auth_data); - - -struct ikev2_payloads { - const u8 *sa; - size_t sa_len; - const u8 *ke; - size_t ke_len; - const u8 *idi; - size_t idi_len; - const u8 *idr; - size_t idr_len; - const u8 *cert; - size_t cert_len; - const u8 *auth; - size_t auth_len; - const u8 *nonce; - size_t nonce_len; - const u8 *encrypted; - size_t encrypted_len; - u8 encr_next_payload; - const u8 *notification; - size_t notification_len; -}; - -int ikev2_parse_payloads(struct ikev2_payloads *payloads, - u8 next_payload, const u8 *pos, const u8 *end); - -u8 * ikev2_decrypt_payload(int encr_id, int integ_id, struct ikev2_keys *keys, - int initiator, const struct ikev2_hdr *hdr, - const u8 *encrypted, size_t encrypted_len, - size_t *res_len); -void ikev2_update_hdr(struct wpabuf *msg); -int ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys, - int initiator, struct wpabuf *msg, - struct wpabuf *plain, u8 next_payload); -int ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf, - const struct ikev2_integ_alg *integ, - const struct ikev2_encr_alg *encr, - const u8 *skeyseed, const u8 *data, size_t data_len, - struct ikev2_keys *keys); - -#endif /* IKEV2_COMMON_H */ diff --git a/contrib/hostapd/src/eap_peer/eap.c b/contrib/hostapd/src/eap_peer/eap.c deleted file mode 100644 index 47cbbeed13..0000000000 --- a/contrib/hostapd/src/eap_peer/eap.c +++ /dev/null @@ -1,2426 +0,0 @@ -/* - * EAP peer state machines (RFC 4137) - * Copyright (c) 2004-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file implements the Peer State Machine as defined in RFC 4137. The used - * states and state transitions match mostly with the RFC. However, there are - * couple of additional transitions for working around small issues noticed - * during testing. These exceptions are explained in comments within the - * functions in this file. The method functions, m.func(), are similar to the - * ones used in RFC 4137, but some small changes have used here to optimize - * operations and to add functionality needed for fast re-authentication - * (session resumption). - */ - -#include "includes.h" - -#include "common.h" -#include "pcsc_funcs.h" -#include "state_machine.h" -#include "ext_password.h" -#include "crypto/crypto.h" -#include "crypto/tls.h" -#include "common/wpa_ctrl.h" -#include "eap_common/eap_wsc_common.h" -#include "eap_i.h" -#include "eap_config.h" - -#define STATE_MACHINE_DATA struct eap_sm -#define STATE_MACHINE_DEBUG_PREFIX "EAP" - -#define EAP_MAX_AUTH_ROUNDS 50 -#define EAP_CLIENT_TIMEOUT_DEFAULT 60 - - -static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor, - EapType method); -static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id); -static void eap_sm_processIdentity(struct eap_sm *sm, - const struct wpabuf *req); -static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req); -static struct wpabuf * eap_sm_buildNotify(int id); -static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req); -#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) -static const char * eap_sm_method_state_txt(EapMethodState state); -static const char * eap_sm_decision_txt(EapDecision decision); -#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ - - - -static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var) -{ - return sm->eapol_cb->get_bool(sm->eapol_ctx, var); -} - - -static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var, - Boolean value) -{ - sm->eapol_cb->set_bool(sm->eapol_ctx, var, value); -} - - -static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var) -{ - return sm->eapol_cb->get_int(sm->eapol_ctx, var); -} - - -static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var, - unsigned int value) -{ - sm->eapol_cb->set_int(sm->eapol_ctx, var, value); -} - - -static struct wpabuf * eapol_get_eapReqData(struct eap_sm *sm) -{ - return sm->eapol_cb->get_eapReqData(sm->eapol_ctx); -} - - -static void eap_notify_status(struct eap_sm *sm, const char *status, - const char *parameter) -{ - wpa_printf(MSG_DEBUG, "EAP: Status notification: %s (param=%s)", - status, parameter); - if (sm->eapol_cb->notify_status) - sm->eapol_cb->notify_status(sm->eapol_ctx, status, parameter); -} - - -static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt) -{ - ext_password_free(sm->ext_pw_buf); - sm->ext_pw_buf = NULL; - - if (sm->m == NULL || sm->eap_method_priv == NULL) - return; - - wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method " - "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt); - sm->m->deinit(sm, sm->eap_method_priv); - sm->eap_method_priv = NULL; - sm->m = NULL; -} - - -/** - * eap_allowed_method - Check whether EAP method is allowed - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types - * @method: EAP type - * Returns: 1 = allowed EAP method, 0 = not allowed - */ -int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method) -{ - struct eap_peer_config *config = eap_get_config(sm); - int i; - struct eap_method_type *m; - - if (config == NULL || config->eap_methods == NULL) - return 1; - - m = config->eap_methods; - for (i = 0; m[i].vendor != EAP_VENDOR_IETF || - m[i].method != EAP_TYPE_NONE; i++) { - if (m[i].vendor == vendor && m[i].method == method) - return 1; - } - return 0; -} - - -/* - * This state initializes state machine variables when the machine is - * activated (portEnabled = TRUE). This is also used when re-starting - * authentication (eapRestart == TRUE). - */ -SM_STATE(EAP, INITIALIZE) -{ - SM_ENTRY(EAP, INITIALIZE); - if (sm->fast_reauth && sm->m && sm->m->has_reauth_data && - sm->m->has_reauth_data(sm, sm->eap_method_priv) && - !sm->prev_failure) { - wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for " - "fast reauthentication"); - sm->m->deinit_for_reauth(sm, sm->eap_method_priv); - } else { - eap_deinit_prev_method(sm, "INITIALIZE"); - } - sm->selectedMethod = EAP_TYPE_NONE; - 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); - os_free(sm->eapKeyData); - sm->eapKeyData = NULL; - os_free(sm->eapSessionId); - sm->eapSessionId = NULL; - sm->eapKeyAvailable = FALSE; - eapol_set_bool(sm, EAPOL_eapRestart, FALSE); - sm->lastId = -1; /* new session - make sure this does not match with - * the first EAP-Packet */ - /* - * RFC 4137 does not reset eapResp and eapNoResp here. However, this - * seemed to be able to trigger cases where both were set and if EAPOL - * state machine uses eapNoResp first, it may end up not sending a real - * reply correctly. This occurred when the workaround in FAIL state set - * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do - * something else(?) - */ - eapol_set_bool(sm, EAPOL_eapResp, FALSE); - eapol_set_bool(sm, EAPOL_eapNoResp, FALSE); - sm->num_rounds = 0; - sm->prev_failure = 0; - sm->expected_failure = 0; -} - - -/* - * This state is reached whenever service from the lower layer is interrupted - * or unavailable (portEnabled == FALSE). Immediate transition to INITIALIZE - * occurs when the port becomes enabled. - */ -SM_STATE(EAP, DISABLED) -{ - SM_ENTRY(EAP, DISABLED); - sm->num_rounds = 0; - /* - * RFC 4137 does not describe clearing of idleWhile here, but doing so - * allows the timer tick to be stopped more quickly when EAP is not in - * use. - */ - eapol_set_int(sm, EAPOL_idleWhile, 0); -} - - -/* - * The state machine spends most of its time here, waiting for something to - * happen. This state is entered unconditionally from INITIALIZE, DISCARD, and - * SEND_RESPONSE states. - */ -SM_STATE(EAP, IDLE) -{ - SM_ENTRY(EAP, IDLE); -} - - -/* - * This state is entered when an EAP packet is received (eapReq == TRUE) to - * parse the packet header. - */ -SM_STATE(EAP, RECEIVED) -{ - const struct wpabuf *eapReqData; - - SM_ENTRY(EAP, RECEIVED); - eapReqData = eapol_get_eapReqData(sm); - /* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */ - eap_sm_parseEapReq(sm, eapReqData); - sm->num_rounds++; -} - - -/* - * This state is entered when a request for a new type comes in. Either the - * correct method is started, or a Nak response is built. - */ -SM_STATE(EAP, GET_METHOD) -{ - int reinit; - EapType method; - const struct eap_method *eap_method; - - SM_ENTRY(EAP, GET_METHOD); - - if (sm->reqMethod == EAP_TYPE_EXPANDED) - method = sm->reqVendorMethod; - else - method = sm->reqMethod; - - eap_method = eap_peer_get_eap_method(sm->reqVendor, method); - - if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) { - wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed", - sm->reqVendor, method); - wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD - "vendor=%u method=%u -> NAK", - sm->reqVendor, method); - eap_notify_status(sm, "refuse proposed method", - eap_method ? eap_method->name : "unknown"); - goto nak; - } - - wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD - "vendor=%u method=%u", sm->reqVendor, method); - - eap_notify_status(sm, "accept proposed method", - eap_method ? eap_method->name : "unknown"); - /* - * RFC 4137 does not define specific operation for fast - * re-authentication (session resumption). The design here is to allow - * the previously used method data to be maintained for - * re-authentication if the method support session resumption. - * Otherwise, the previously used method data is freed and a new method - * is allocated here. - */ - if (sm->fast_reauth && - sm->m && sm->m->vendor == sm->reqVendor && - sm->m->method == method && - sm->m->has_reauth_data && - sm->m->has_reauth_data(sm, sm->eap_method_priv)) { - wpa_printf(MSG_DEBUG, "EAP: Using previous method data" - " for fast re-authentication"); - reinit = 1; - } else { - eap_deinit_prev_method(sm, "GET_METHOD"); - reinit = 0; - } - - sm->selectedMethod = sm->reqMethod; - if (sm->m == NULL) - sm->m = eap_method; - if (!sm->m) { - wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: " - "vendor %d method %d", - sm->reqVendor, method); - goto nak; - } - - sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT; - - wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: " - "vendor %u method %u (%s)", - sm->reqVendor, method, sm->m->name); - if (reinit) - sm->eap_method_priv = sm->m->init_for_reauth( - sm, sm->eap_method_priv); - else - sm->eap_method_priv = sm->m->init(sm); - - if (sm->eap_method_priv == NULL) { - struct eap_peer_config *config = eap_get_config(sm); - wpa_msg(sm->msg_ctx, MSG_INFO, - "EAP: Failed to initialize EAP method: vendor %u " - "method %u (%s)", - sm->reqVendor, method, sm->m->name); - sm->m = NULL; - sm->methodState = METHOD_NONE; - sm->selectedMethod = EAP_TYPE_NONE; - if (sm->reqMethod == EAP_TYPE_TLS && config && - (config->pending_req_pin || - config->pending_req_passphrase)) { - /* - * Return without generating Nak in order to allow - * entering of PIN code or passphrase to retry the - * current EAP packet. - */ - wpa_printf(MSG_DEBUG, "EAP: Pending PIN/passphrase " - "request - skip Nak"); - return; - } - - goto nak; - } - - sm->methodState = METHOD_INIT; - wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_METHOD - "EAP vendor %u method %u (%s) selected", - sm->reqVendor, method, sm->m->name); - return; - -nak: - wpabuf_free(sm->eapRespData); - sm->eapRespData = NULL; - sm->eapRespData = eap_sm_buildNak(sm, sm->reqId); -} - - -/* - * The method processing happens here. The request from the authenticator is - * processed, and an appropriate response packet is built. - */ -SM_STATE(EAP, METHOD) -{ - struct wpabuf *eapReqData; - struct eap_method_ret ret; - int min_len = 1; - - SM_ENTRY(EAP, METHOD); - if (sm->m == NULL) { - wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected"); - return; - } - - eapReqData = eapol_get_eapReqData(sm); - if (sm->m->vendor == EAP_VENDOR_IETF && sm->m->method == EAP_TYPE_LEAP) - min_len = 0; /* LEAP uses EAP-Success without payload */ - if (!eap_hdr_len_valid(eapReqData, min_len)) - return; - - /* - * Get ignore, methodState, decision, allowNotifications, and - * eapRespData. RFC 4137 uses three separate method procedure (check, - * process, and buildResp) in this state. These have been combined into - * a single function call to m->process() in order to optimize EAP - * method implementation interface a bit. These procedures are only - * used from within this METHOD state, so there is no need to keep - * these as separate C functions. - * - * The RFC 4137 procedures return values as follows: - * ignore = m.check(eapReqData) - * (methodState, decision, allowNotifications) = m.process(eapReqData) - * eapRespData = m.buildResp(reqId) - */ - os_memset(&ret, 0, sizeof(ret)); - ret.ignore = sm->ignore; - ret.methodState = sm->methodState; - ret.decision = sm->decision; - ret.allowNotifications = sm->allowNotifications; - wpabuf_free(sm->eapRespData); - sm->eapRespData = NULL; - sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret, - eapReqData); - wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s " - "methodState=%s decision=%s eapRespData=%p", - ret.ignore ? "TRUE" : "FALSE", - eap_sm_method_state_txt(ret.methodState), - eap_sm_decision_txt(ret.decision), - sm->eapRespData); - - sm->ignore = ret.ignore; - if (sm->ignore) - return; - sm->methodState = ret.methodState; - sm->decision = ret.decision; - sm->allowNotifications = ret.allowNotifications; - - if (sm->m->isKeyAvailable && sm->m->getKey && - sm->m->isKeyAvailable(sm, sm->eap_method_priv)) { - os_free(sm->eapKeyData); - sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv, - &sm->eapKeyDataLen); - os_free(sm->eapSessionId); - sm->eapSessionId = NULL; - if (sm->m->getSessionId) { - sm->eapSessionId = sm->m->getSessionId( - sm, sm->eap_method_priv, - &sm->eapSessionIdLen); - wpa_hexdump(MSG_DEBUG, "EAP: Session-Id", - sm->eapSessionId, sm->eapSessionIdLen); - } - } -} - - -/* - * This state signals the lower layer that a response packet is ready to be - * sent. - */ -SM_STATE(EAP, SEND_RESPONSE) -{ - SM_ENTRY(EAP, SEND_RESPONSE); - wpabuf_free(sm->lastRespData); - if (sm->eapRespData) { - if (sm->workaround) - os_memcpy(sm->last_md5, sm->req_md5, 16); - sm->lastId = sm->reqId; - sm->lastRespData = wpabuf_dup(sm->eapRespData); - eapol_set_bool(sm, EAPOL_eapResp, TRUE); - } else { - wpa_printf(MSG_DEBUG, "EAP: No eapRespData available"); - sm->lastRespData = NULL; - } - eapol_set_bool(sm, EAPOL_eapReq, FALSE); - eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout); -} - - -/* - * This state signals the lower layer that the request was discarded, and no - * response packet will be sent at this time. - */ -SM_STATE(EAP, DISCARD) -{ - SM_ENTRY(EAP, DISCARD); - eapol_set_bool(sm, EAPOL_eapReq, FALSE); - eapol_set_bool(sm, EAPOL_eapNoResp, TRUE); -} - - -/* - * Handles requests for Identity method and builds a response. - */ -SM_STATE(EAP, IDENTITY) -{ - const struct wpabuf *eapReqData; - - SM_ENTRY(EAP, IDENTITY); - eapReqData = eapol_get_eapReqData(sm); - if (!eap_hdr_len_valid(eapReqData, 1)) - return; - eap_sm_processIdentity(sm, eapReqData); - wpabuf_free(sm->eapRespData); - sm->eapRespData = NULL; - sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId, 0); -} - - -/* - * Handles requests for Notification method and builds a response. - */ -SM_STATE(EAP, NOTIFICATION) -{ - const struct wpabuf *eapReqData; - - SM_ENTRY(EAP, NOTIFICATION); - eapReqData = eapol_get_eapReqData(sm); - if (!eap_hdr_len_valid(eapReqData, 1)) - return; - eap_sm_processNotify(sm, eapReqData); - wpabuf_free(sm->eapRespData); - sm->eapRespData = NULL; - sm->eapRespData = eap_sm_buildNotify(sm->reqId); -} - - -/* - * This state retransmits the previous response packet. - */ -SM_STATE(EAP, RETRANSMIT) -{ - SM_ENTRY(EAP, RETRANSMIT); - wpabuf_free(sm->eapRespData); - if (sm->lastRespData) - sm->eapRespData = wpabuf_dup(sm->lastRespData); - else - sm->eapRespData = NULL; -} - - -/* - * This state is entered in case of a successful completion of authentication - * and state machine waits here until port is disabled or EAP authentication is - * restarted. - */ -SM_STATE(EAP, SUCCESS) -{ - SM_ENTRY(EAP, SUCCESS); - if (sm->eapKeyData != NULL) - sm->eapKeyAvailable = TRUE; - eapol_set_bool(sm, EAPOL_eapSuccess, TRUE); - - /* - * RFC 4137 does not clear eapReq here, but this seems to be required - * to avoid processing the same request twice when state machine is - * initialized. - */ - eapol_set_bool(sm, EAPOL_eapReq, FALSE); - - /* - * RFC 4137 does not set eapNoResp here, but this seems to be required - * to get EAPOL Supplicant backend state machine into SUCCESS state. In - * addition, either eapResp or eapNoResp is required to be set after - * processing the received EAP frame. - */ - eapol_set_bool(sm, EAPOL_eapNoResp, TRUE); - - wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS - "EAP authentication completed successfully"); -} - - -/* - * This state is entered in case of a failure and state machine waits here - * until port is disabled or EAP authentication is restarted. - */ -SM_STATE(EAP, FAILURE) -{ - SM_ENTRY(EAP, FAILURE); - eapol_set_bool(sm, EAPOL_eapFail, TRUE); - - /* - * RFC 4137 does not clear eapReq here, but this seems to be required - * to avoid processing the same request twice when state machine is - * initialized. - */ - eapol_set_bool(sm, EAPOL_eapReq, FALSE); - - /* - * RFC 4137 does not set eapNoResp here. However, either eapResp or - * eapNoResp is required to be set after processing the received EAP - * frame. - */ - eapol_set_bool(sm, EAPOL_eapNoResp, TRUE); - - wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE - "EAP authentication failed"); - - sm->prev_failure = 1; -} - - -static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId) -{ - /* - * At least Microsoft IAS and Meetinghouse Aegis seem to be sending - * EAP-Success/Failure with lastId + 1 even though RFC 3748 and - * RFC 4137 require that reqId == lastId. In addition, it looks like - * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success. - * - * Accept this kind of Id if EAP workarounds are enabled. These are - * unauthenticated plaintext messages, so this should have minimal - * security implications (bit easier to fake EAP-Success/Failure). - */ - if (sm->workaround && (reqId == ((lastId + 1) & 0xff) || - reqId == ((lastId + 2) & 0xff))) { - wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected " - "identifier field in EAP Success: " - "reqId=%d lastId=%d (these are supposed to be " - "same)", reqId, lastId); - return 1; - } - wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d " - "lastId=%d", reqId, lastId); - return 0; -} - - -/* - * RFC 4137 - Appendix A.1: EAP Peer State Machine - State transitions - */ - -static void eap_peer_sm_step_idle(struct eap_sm *sm) -{ - /* - * The first three transitions are from RFC 4137. The last two are - * local additions to handle special cases with LEAP and PEAP server - * not sending EAP-Success in some cases. - */ - if (eapol_get_bool(sm, EAPOL_eapReq)) - SM_ENTER(EAP, RECEIVED); - else if ((eapol_get_bool(sm, EAPOL_altAccept) && - sm->decision != DECISION_FAIL) || - (eapol_get_int(sm, EAPOL_idleWhile) == 0 && - sm->decision == DECISION_UNCOND_SUCC)) - SM_ENTER(EAP, SUCCESS); - else if (eapol_get_bool(sm, EAPOL_altReject) || - (eapol_get_int(sm, EAPOL_idleWhile) == 0 && - sm->decision != DECISION_UNCOND_SUCC) || - (eapol_get_bool(sm, EAPOL_altAccept) && - sm->methodState != METHOD_CONT && - sm->decision == DECISION_FAIL)) - SM_ENTER(EAP, FAILURE); - else if (sm->selectedMethod == EAP_TYPE_LEAP && - sm->leap_done && sm->decision != DECISION_FAIL && - sm->methodState == METHOD_DONE) - SM_ENTER(EAP, SUCCESS); - else if (sm->selectedMethod == EAP_TYPE_PEAP && - sm->peap_done && sm->decision != DECISION_FAIL && - sm->methodState == METHOD_DONE) - SM_ENTER(EAP, SUCCESS); -} - - -static int eap_peer_req_is_duplicate(struct eap_sm *sm) -{ - int duplicate; - - duplicate = (sm->reqId == sm->lastId) && sm->rxReq; - if (sm->workaround && duplicate && - os_memcmp(sm->req_md5, sm->last_md5, 16) != 0) { - /* - * RFC 4137 uses (reqId == lastId) as the only verification for - * duplicate EAP requests. However, this misses cases where the - * AS is incorrectly using the same id again; and - * unfortunately, such implementations exist. Use MD5 hash as - * an extra verification for the packets being duplicate to - * workaround these issues. - */ - wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again, but " - "EAP packets were not identical"); - wpa_printf(MSG_DEBUG, "EAP: workaround - assume this is not a " - "duplicate packet"); - duplicate = 0; - } - - return duplicate; -} - - -static void eap_peer_sm_step_received(struct eap_sm *sm) -{ - int duplicate = eap_peer_req_is_duplicate(sm); - - /* - * Two special cases below for LEAP are local additions to work around - * odd LEAP behavior (EAP-Success in the middle of authentication and - * then swapped roles). Other transitions are based on RFC 4137. - */ - if (sm->rxSuccess && sm->decision != DECISION_FAIL && - (sm->reqId == sm->lastId || - eap_success_workaround(sm, sm->reqId, sm->lastId))) - SM_ENTER(EAP, SUCCESS); - else if (sm->methodState != METHOD_CONT && - ((sm->rxFailure && - sm->decision != DECISION_UNCOND_SUCC) || - (sm->rxSuccess && sm->decision == DECISION_FAIL && - (sm->selectedMethod != EAP_TYPE_LEAP || - sm->methodState != METHOD_MAY_CONT))) && - (sm->reqId == sm->lastId || - eap_success_workaround(sm, sm->reqId, sm->lastId))) - SM_ENTER(EAP, FAILURE); - else if (sm->rxReq && duplicate) - SM_ENTER(EAP, RETRANSMIT); - else if (sm->rxReq && !duplicate && - sm->reqMethod == EAP_TYPE_NOTIFICATION && - sm->allowNotifications) - SM_ENTER(EAP, NOTIFICATION); - else if (sm->rxReq && !duplicate && - sm->selectedMethod == EAP_TYPE_NONE && - sm->reqMethod == EAP_TYPE_IDENTITY) - SM_ENTER(EAP, IDENTITY); - else if (sm->rxReq && !duplicate && - sm->selectedMethod == EAP_TYPE_NONE && - sm->reqMethod != EAP_TYPE_IDENTITY && - sm->reqMethod != EAP_TYPE_NOTIFICATION) - SM_ENTER(EAP, GET_METHOD); - else if (sm->rxReq && !duplicate && - sm->reqMethod == sm->selectedMethod && - sm->methodState != METHOD_DONE) - SM_ENTER(EAP, METHOD); - else if (sm->selectedMethod == EAP_TYPE_LEAP && - (sm->rxSuccess || sm->rxResp)) - SM_ENTER(EAP, METHOD); - else - SM_ENTER(EAP, DISCARD); -} - - -static void eap_peer_sm_step_local(struct eap_sm *sm) -{ - switch (sm->EAP_state) { - case EAP_INITIALIZE: - SM_ENTER(EAP, IDLE); - break; - case EAP_DISABLED: - if (eapol_get_bool(sm, EAPOL_portEnabled) && - !sm->force_disabled) - SM_ENTER(EAP, INITIALIZE); - break; - case EAP_IDLE: - eap_peer_sm_step_idle(sm); - break; - case EAP_RECEIVED: - eap_peer_sm_step_received(sm); - break; - case EAP_GET_METHOD: - if (sm->selectedMethod == sm->reqMethod) - SM_ENTER(EAP, METHOD); - else - SM_ENTER(EAP, SEND_RESPONSE); - break; - case EAP_METHOD: - /* - * Note: RFC 4137 uses methodState == DONE && decision == FAIL - * as the condition. eapRespData == NULL here is used to allow - * final EAP method response to be sent without having to change - * all methods to either use methodState MAY_CONT or leaving - * decision to something else than FAIL in cases where the only - * expected response is EAP-Failure. - */ - if (sm->ignore) - SM_ENTER(EAP, DISCARD); - else if (sm->methodState == METHOD_DONE && - sm->decision == DECISION_FAIL && !sm->eapRespData) - SM_ENTER(EAP, FAILURE); - else - SM_ENTER(EAP, SEND_RESPONSE); - break; - case EAP_SEND_RESPONSE: - SM_ENTER(EAP, IDLE); - break; - case EAP_DISCARD: - SM_ENTER(EAP, IDLE); - break; - case EAP_IDENTITY: - SM_ENTER(EAP, SEND_RESPONSE); - break; - case EAP_NOTIFICATION: - SM_ENTER(EAP, SEND_RESPONSE); - break; - case EAP_RETRANSMIT: - SM_ENTER(EAP, SEND_RESPONSE); - break; - case EAP_SUCCESS: - break; - case EAP_FAILURE: - break; - } -} - - -SM_STEP(EAP) -{ - /* Global transitions */ - if (eapol_get_bool(sm, EAPOL_eapRestart) && - eapol_get_bool(sm, EAPOL_portEnabled)) - SM_ENTER_GLOBAL(EAP, INITIALIZE); - else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled) - SM_ENTER_GLOBAL(EAP, DISABLED); - else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) { - /* RFC 4137 does not place any limit on number of EAP messages - * in an authentication session. However, some error cases have - * ended up in a state were EAP messages were sent between the - * peer and server in a loop (e.g., TLS ACK frame in both - * direction). Since this is quite undesired outcome, limit the - * total number of EAP round-trips and abort authentication if - * this limit is exceeded. - */ - if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) { - wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d " - "authentication rounds - abort", - EAP_MAX_AUTH_ROUNDS); - sm->num_rounds++; - SM_ENTER_GLOBAL(EAP, FAILURE); - } - } else { - /* Local transitions */ - eap_peer_sm_step_local(sm); - } -} - - -static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor, - EapType method) -{ - if (!eap_allowed_method(sm, vendor, method)) { - wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: " - "vendor %u method %u", vendor, method); - return FALSE; - } - if (eap_peer_get_eap_method(vendor, method)) - return TRUE; - wpa_printf(MSG_DEBUG, "EAP: not included in build: " - "vendor %u method %u", vendor, method); - return FALSE; -} - - -static struct wpabuf * eap_sm_build_expanded_nak( - struct eap_sm *sm, int id, const struct eap_method *methods, - size_t count) -{ - struct wpabuf *resp; - int found = 0; - const struct eap_method *m; - - wpa_printf(MSG_DEBUG, "EAP: Building expanded EAP-Nak"); - - /* RFC 3748 - 5.3.2: Expanded Nak */ - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EXPANDED, - 8 + 8 * (count + 1), EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - - wpabuf_put_be24(resp, EAP_VENDOR_IETF); - wpabuf_put_be32(resp, EAP_TYPE_NAK); - - for (m = methods; m; m = m->next) { - if (sm->reqVendor == m->vendor && - sm->reqVendorMethod == m->method) - continue; /* do not allow the current method again */ - if (eap_allowed_method(sm, m->vendor, m->method)) { - wpa_printf(MSG_DEBUG, "EAP: allowed type: " - "vendor=%u method=%u", - m->vendor, m->method); - wpabuf_put_u8(resp, EAP_TYPE_EXPANDED); - wpabuf_put_be24(resp, m->vendor); - wpabuf_put_be32(resp, m->method); - - found++; - } - } - if (!found) { - wpa_printf(MSG_DEBUG, "EAP: no more allowed methods"); - wpabuf_put_u8(resp, EAP_TYPE_EXPANDED); - wpabuf_put_be24(resp, EAP_VENDOR_IETF); - wpabuf_put_be32(resp, EAP_TYPE_NONE); - } - - eap_update_len(resp); - - return resp; -} - - -static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id) -{ - struct wpabuf *resp; - u8 *start; - int found = 0, expanded_found = 0; - size_t count; - const struct eap_method *methods, *m; - - wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %u " - "vendor=%u method=%u not allowed)", sm->reqMethod, - sm->reqVendor, sm->reqVendorMethod); - methods = eap_peer_get_methods(&count); - if (methods == NULL) - return NULL; - if (sm->reqMethod == EAP_TYPE_EXPANDED) - return eap_sm_build_expanded_nak(sm, id, methods, count); - - /* RFC 3748 - 5.3.1: Legacy Nak */ - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, - sizeof(struct eap_hdr) + 1 + count + 1, - EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - - start = wpabuf_put(resp, 0); - for (m = methods; m; m = m->next) { - if (m->vendor == EAP_VENDOR_IETF && m->method == sm->reqMethod) - continue; /* do not allow the current method again */ - if (eap_allowed_method(sm, m->vendor, m->method)) { - if (m->vendor != EAP_VENDOR_IETF) { - if (expanded_found) - continue; - expanded_found = 1; - wpabuf_put_u8(resp, EAP_TYPE_EXPANDED); - } else - wpabuf_put_u8(resp, m->method); - found++; - } - } - if (!found) - wpabuf_put_u8(resp, EAP_TYPE_NONE); - wpa_hexdump(MSG_DEBUG, "EAP: allowed methods", start, found); - - eap_update_len(resp); - - return resp; -} - - -static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req) -{ - const u8 *pos; - size_t msg_len; - - wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED - "EAP authentication started"); - eap_notify_status(sm, "started", ""); - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req, - &msg_len); - if (pos == NULL) - return; - - /* - * RFC 3748 - 5.1: Identity - * Data field may contain a displayable message in UTF-8. If this - * includes NUL-character, only the data before that should be - * displayed. Some EAP implementasitons may piggy-back additional - * options after the NUL. - */ - /* TODO: could save displayable message so that it can be shown to the - * user in case of interaction is required */ - wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data", - pos, msg_len); -} - - -#ifdef PCSC_FUNCS - -/* - * Rules for figuring out MNC length based on IMSI for SIM cards that do not - * include MNC length field. - */ -static int mnc_len_from_imsi(const char *imsi) -{ - char mcc_str[4]; - unsigned int mcc; - - os_memcpy(mcc_str, imsi, 3); - mcc_str[3] = '\0'; - mcc = atoi(mcc_str); - - if (mcc == 228) - return 2; /* Networks in Switzerland use 2-digit MNC */ - if (mcc == 244) - return 2; /* Networks in Finland use 2-digit MNC */ - - return -1; -} - - -static int eap_sm_append_3gpp_realm(struct eap_sm *sm, char *imsi, - size_t max_len, size_t *imsi_len) -{ - int mnc_len; - char *pos, mnc[4]; - - if (*imsi_len + 36 > max_len) { - wpa_printf(MSG_WARNING, "No room for realm in IMSI buffer"); - return -1; - } - - /* MNC (2 or 3 digits) */ - mnc_len = scard_get_mnc_len(sm->scard_ctx); - if (mnc_len < 0) - mnc_len = mnc_len_from_imsi(imsi); - if (mnc_len < 0) { - wpa_printf(MSG_INFO, "Failed to get MNC length from (U)SIM " - "assuming 3"); - mnc_len = 3; - } - - if (mnc_len == 2) { - mnc[0] = '0'; - mnc[1] = imsi[3]; - mnc[2] = imsi[4]; - } else if (mnc_len == 3) { - mnc[0] = imsi[3]; - mnc[1] = imsi[4]; - mnc[2] = imsi[5]; - } - mnc[3] = '\0'; - - pos = imsi + *imsi_len; - pos += os_snprintf(pos, imsi + max_len - pos, - "@wlan.mnc%s.mcc%c%c%c.3gppnetwork.org", - mnc, imsi[0], imsi[1], imsi[2]); - *imsi_len = pos - imsi; - - return 0; -} - - -static int eap_sm_imsi_identity(struct eap_sm *sm, - struct eap_peer_config *conf) -{ - enum { EAP_SM_SIM, EAP_SM_AKA, EAP_SM_AKA_PRIME } method = EAP_SM_SIM; - char imsi[100]; - size_t imsi_len; - struct eap_method_type *m = conf->eap_methods; - int i; - - imsi_len = sizeof(imsi); - if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) { - wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM"); - return -1; - } - - wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len); - - if (imsi_len < 7) { - wpa_printf(MSG_WARNING, "Too short IMSI for SIM identity"); - return -1; - } - - if (eap_sm_append_3gpp_realm(sm, imsi, sizeof(imsi), &imsi_len) < 0) { - wpa_printf(MSG_WARNING, "Could not add realm to SIM identity"); - return -1; - } - wpa_hexdump_ascii(MSG_DEBUG, "IMSI + realm", (u8 *) imsi, imsi_len); - - for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF || - m[i].method != EAP_TYPE_NONE); i++) { - if (m[i].vendor == EAP_VENDOR_IETF && - m[i].method == EAP_TYPE_AKA_PRIME) { - method = EAP_SM_AKA_PRIME; - break; - } - - if (m[i].vendor == EAP_VENDOR_IETF && - m[i].method == EAP_TYPE_AKA) { - method = EAP_SM_AKA; - break; - } - } - - os_free(conf->identity); - conf->identity = os_malloc(1 + imsi_len); - if (conf->identity == NULL) { - wpa_printf(MSG_WARNING, "Failed to allocate buffer for " - "IMSI-based identity"); - return -1; - } - - switch (method) { - case EAP_SM_SIM: - conf->identity[0] = '1'; - break; - case EAP_SM_AKA: - conf->identity[0] = '0'; - break; - case EAP_SM_AKA_PRIME: - conf->identity[0] = '6'; - break; - } - os_memcpy(conf->identity + 1, imsi, imsi_len); - conf->identity_len = 1 + imsi_len; - - return 0; -} - -#endif /* PCSC_FUNCS */ - - -static int eap_sm_set_scard_pin(struct eap_sm *sm, - struct eap_peer_config *conf) -{ -#ifdef PCSC_FUNCS - if (scard_set_pin(sm->scard_ctx, conf->pin)) { - /* - * Make sure the same PIN is not tried again in order to avoid - * blocking SIM. - */ - os_free(conf->pin); - conf->pin = NULL; - - wpa_printf(MSG_WARNING, "PIN validation failed"); - eap_sm_request_pin(sm); - return -1; - } - return 0; -#else /* PCSC_FUNCS */ - return -1; -#endif /* PCSC_FUNCS */ -} - -static int eap_sm_get_scard_identity(struct eap_sm *sm, - struct eap_peer_config *conf) -{ -#ifdef PCSC_FUNCS - if (eap_sm_set_scard_pin(sm, conf)) - return -1; - - return eap_sm_imsi_identity(sm, conf); -#else /* PCSC_FUNCS */ - return -1; -#endif /* PCSC_FUNCS */ -} - - -/** - * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @id: EAP identifier for the packet - * @encrypted: Whether the packet is for encrypted tunnel (EAP phase 2) - * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on - * failure - * - * This function allocates and builds an EAP-Identity/Response packet for the - * current network. The caller is responsible for freeing the returned data. - */ -struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted) -{ - struct eap_peer_config *config = eap_get_config(sm); - struct wpabuf *resp; - const u8 *identity; - size_t identity_len; - - if (config == NULL) { - wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration " - "was not available"); - return NULL; - } - - if (sm->m && sm->m->get_identity && - (identity = sm->m->get_identity(sm, sm->eap_method_priv, - &identity_len)) != NULL) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth " - "identity", identity, identity_len); - } else if (!encrypted && config->anonymous_identity) { - identity = config->anonymous_identity; - identity_len = config->anonymous_identity_len; - wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity", - identity, identity_len); - } else { - identity = config->identity; - identity_len = config->identity_len; - wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity", - identity, identity_len); - } - - if (identity == NULL) { - wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity " - "configuration was not available"); - if (config->pcsc) { - if (eap_sm_get_scard_identity(sm, config) < 0) - return NULL; - identity = config->identity; - identity_len = config->identity_len; - wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from " - "IMSI", identity, identity_len); - } else { - eap_sm_request_identity(sm); - return NULL; - } - } else if (config->pcsc) { - if (eap_sm_set_scard_pin(sm, config) < 0) - return NULL; - } - - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len, - EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - - wpabuf_put_data(resp, identity, identity_len); - - return resp; -} - - -static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req) -{ - const u8 *pos; - char *msg; - size_t i, msg_len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, req, - &msg_len); - if (pos == NULL) - return; - wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data", - pos, msg_len); - - msg = os_malloc(msg_len + 1); - if (msg == NULL) - return; - for (i = 0; i < msg_len; i++) - msg[i] = isprint(pos[i]) ? (char) pos[i] : '_'; - msg[msg_len] = '\0'; - wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s", - WPA_EVENT_EAP_NOTIFICATION, msg); - os_free(msg); -} - - -static struct wpabuf * eap_sm_buildNotify(int id) -{ - struct wpabuf *resp; - - wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification"); - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0, - EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - - return resp; -} - - -static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req) -{ - const struct eap_hdr *hdr; - size_t plen; - const u8 *pos; - - sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE; - sm->reqId = 0; - sm->reqMethod = EAP_TYPE_NONE; - sm->reqVendor = EAP_VENDOR_IETF; - sm->reqVendorMethod = EAP_TYPE_NONE; - - if (req == NULL || wpabuf_len(req) < sizeof(*hdr)) - return; - - hdr = wpabuf_head(req); - plen = be_to_host16(hdr->length); - if (plen > wpabuf_len(req)) { - wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet " - "(len=%lu plen=%lu)", - (unsigned long) wpabuf_len(req), - (unsigned long) plen); - return; - } - - sm->reqId = hdr->identifier; - - if (sm->workaround) { - const u8 *addr[1]; - addr[0] = wpabuf_head(req); - md5_vector(1, addr, &plen, sm->req_md5); - } - - switch (hdr->code) { - case EAP_CODE_REQUEST: - if (plen < sizeof(*hdr) + 1) { - wpa_printf(MSG_DEBUG, "EAP: Too short EAP-Request - " - "no Type field"); - return; - } - sm->rxReq = TRUE; - pos = (const u8 *) (hdr + 1); - sm->reqMethod = *pos++; - if (sm->reqMethod == EAP_TYPE_EXPANDED) { - if (plen < sizeof(*hdr) + 8) { - wpa_printf(MSG_DEBUG, "EAP: Ignored truncated " - "expanded EAP-Packet (plen=%lu)", - (unsigned long) plen); - return; - } - sm->reqVendor = WPA_GET_BE24(pos); - pos += 3; - sm->reqVendorMethod = WPA_GET_BE32(pos); - } - wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request id=%d " - "method=%u vendor=%u vendorMethod=%u", - sm->reqId, sm->reqMethod, sm->reqVendor, - sm->reqVendorMethod); - break; - case EAP_CODE_RESPONSE: - if (sm->selectedMethod == EAP_TYPE_LEAP) { - /* - * LEAP differs from RFC 4137 by using reversed roles - * for mutual authentication and because of this, we - * need to accept EAP-Response frames if LEAP is used. - */ - if (plen < sizeof(*hdr) + 1) { - wpa_printf(MSG_DEBUG, "EAP: Too short " - "EAP-Response - no Type field"); - return; - } - sm->rxResp = TRUE; - pos = (const u8 *) (hdr + 1); - sm->reqMethod = *pos; - wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for " - "LEAP method=%d id=%d", - sm->reqMethod, sm->reqId); - break; - } - wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response"); - break; - case EAP_CODE_SUCCESS: - wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success"); - eap_notify_status(sm, "completion", "success"); - sm->rxSuccess = TRUE; - break; - case EAP_CODE_FAILURE: - wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure"); - eap_notify_status(sm, "completion", "failure"); - sm->rxFailure = TRUE; - break; - default: - wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown " - "code %d", hdr->code); - break; - } -} - - -static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev, - union tls_event_data *data) -{ - struct eap_sm *sm = ctx; - char *hash_hex = NULL; - - switch (ev) { - case TLS_CERT_CHAIN_SUCCESS: - eap_notify_status(sm, "remote certificate verification", - "success"); - break; - case TLS_CERT_CHAIN_FAILURE: - wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR - "reason=%d depth=%d subject='%s' err='%s'", - data->cert_fail.reason, - data->cert_fail.depth, - data->cert_fail.subject, - data->cert_fail.reason_txt); - eap_notify_status(sm, "remote certificate verification", - data->cert_fail.reason_txt); - break; - case TLS_PEER_CERTIFICATE: - if (!sm->eapol_cb->notify_cert) - break; - - if (data->peer_cert.hash) { - size_t len = data->peer_cert.hash_len * 2 + 1; - hash_hex = os_malloc(len); - if (hash_hex) { - wpa_snprintf_hex(hash_hex, len, - data->peer_cert.hash, - data->peer_cert.hash_len); - } - } - - sm->eapol_cb->notify_cert(sm->eapol_ctx, - data->peer_cert.depth, - data->peer_cert.subject, - hash_hex, data->peer_cert.cert); - break; - case TLS_ALERT: - if (data->alert.is_local) - eap_notify_status(sm, "local TLS alert", - data->alert.description); - else - eap_notify_status(sm, "remote TLS alert", - data->alert.description); - break; - } - - os_free(hash_hex); -} - - -/** - * eap_peer_sm_init - Allocate and initialize EAP peer state machine - * @eapol_ctx: Context data to be used with eapol_cb calls - * @eapol_cb: Pointer to EAPOL callback functions - * @msg_ctx: Context data for wpa_msg() calls - * @conf: EAP configuration - * Returns: Pointer to the allocated EAP state machine or %NULL on failure - * - * This function allocates and initializes an EAP state machine. In addition, - * this initializes TLS library for the new EAP state machine. eapol_cb pointer - * will be in use until eap_peer_sm_deinit() is used to deinitialize this EAP - * state machine. Consequently, the caller must make sure that this data - * structure remains alive while the EAP state machine is active. - */ -struct eap_sm * eap_peer_sm_init(void *eapol_ctx, - struct eapol_callbacks *eapol_cb, - void *msg_ctx, struct eap_config *conf) -{ - struct eap_sm *sm; - struct tls_config tlsconf; - - sm = os_zalloc(sizeof(*sm)); - if (sm == NULL) - return NULL; - sm->eapol_ctx = eapol_ctx; - sm->eapol_cb = eapol_cb; - sm->msg_ctx = msg_ctx; - sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT; - sm->wps = conf->wps; - - os_memset(&tlsconf, 0, sizeof(tlsconf)); - tlsconf.opensc_engine_path = conf->opensc_engine_path; - tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path; - tlsconf.pkcs11_module_path = conf->pkcs11_module_path; -#ifdef CONFIG_FIPS - tlsconf.fips_mode = 1; -#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 " - "context."); - os_free(sm); - return NULL; - } - - sm->ssl_ctx2 = tls_init(&tlsconf); - if (sm->ssl_ctx2 == NULL) { - wpa_printf(MSG_INFO, "SSL: Failed to initialize TLS " - "context (2)."); - /* Run without separate TLS context within TLS tunnel */ - } - - return sm; -} - - -/** - * eap_peer_sm_deinit - Deinitialize and free an EAP peer state machine - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * - * This function deinitializes EAP state machine and frees all allocated - * resources. - */ -void eap_peer_sm_deinit(struct eap_sm *sm) -{ - if (sm == NULL) - return; - eap_deinit_prev_method(sm, "EAP deinit"); - eap_sm_abort(sm); - if (sm->ssl_ctx2) - tls_deinit(sm->ssl_ctx2); - tls_deinit(sm->ssl_ctx); - os_free(sm); -} - - -/** - * eap_peer_sm_step - Step EAP peer state machine - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * Returns: 1 if EAP state was changed or 0 if not - * - * This function advances EAP state machine to a new state to match with the - * current variables. This should be called whenever variables used by the EAP - * state machine have changed. - */ -int eap_peer_sm_step(struct eap_sm *sm) -{ - int res = 0; - do { - sm->changed = FALSE; - SM_STEP_RUN(EAP); - if (sm->changed) - res = 1; - } while (sm->changed); - return res; -} - - -/** - * eap_sm_abort - Abort EAP authentication - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * - * Release system resources that have been allocated for the authentication - * session without fully deinitializing the EAP state machine. - */ -void eap_sm_abort(struct eap_sm *sm) -{ - wpabuf_free(sm->lastRespData); - sm->lastRespData = NULL; - wpabuf_free(sm->eapRespData); - sm->eapRespData = NULL; - os_free(sm->eapKeyData); - sm->eapKeyData = NULL; - os_free(sm->eapSessionId); - sm->eapSessionId = NULL; - - /* This is not clearly specified in the EAP statemachines draft, but - * it seems necessary to make sure that some of the EAPOL variables get - * cleared for the next authentication. */ - eapol_set_bool(sm, EAPOL_eapSuccess, FALSE); -} - - -#ifdef CONFIG_CTRL_IFACE -static const char * eap_sm_state_txt(int state) -{ - switch (state) { - case EAP_INITIALIZE: - return "INITIALIZE"; - case EAP_DISABLED: - return "DISABLED"; - case EAP_IDLE: - return "IDLE"; - case EAP_RECEIVED: - return "RECEIVED"; - case EAP_GET_METHOD: - return "GET_METHOD"; - case EAP_METHOD: - return "METHOD"; - case EAP_SEND_RESPONSE: - return "SEND_RESPONSE"; - case EAP_DISCARD: - return "DISCARD"; - case EAP_IDENTITY: - return "IDENTITY"; - case EAP_NOTIFICATION: - return "NOTIFICATION"; - case EAP_RETRANSMIT: - return "RETRANSMIT"; - case EAP_SUCCESS: - return "SUCCESS"; - case EAP_FAILURE: - return "FAILURE"; - default: - return "UNKNOWN"; - } -} -#endif /* CONFIG_CTRL_IFACE */ - - -#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) -static const char * eap_sm_method_state_txt(EapMethodState state) -{ - switch (state) { - case METHOD_NONE: - return "NONE"; - case METHOD_INIT: - return "INIT"; - case METHOD_CONT: - return "CONT"; - case METHOD_MAY_CONT: - return "MAY_CONT"; - case METHOD_DONE: - return "DONE"; - default: - return "UNKNOWN"; - } -} - - -static const char * eap_sm_decision_txt(EapDecision decision) -{ - switch (decision) { - case DECISION_FAIL: - return "FAIL"; - case DECISION_COND_SUCC: - return "COND_SUCC"; - case DECISION_UNCOND_SUCC: - return "UNCOND_SUCC"; - default: - return "UNKNOWN"; - } -} -#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ - - -#ifdef CONFIG_CTRL_IFACE - -/** - * eap_sm_get_status - Get EAP state machine status - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @buf: Buffer for status information - * @buflen: Maximum buffer length - * @verbose: Whether to include verbose status information - * Returns: Number of bytes written to buf. - * - * Query EAP state machine for status information. This function fills in a - * text area with current status information from the EAPOL state machine. If - * the buffer (buf) is not large enough, status information will be truncated - * to fit the buffer. - */ -int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose) -{ - int len, ret; - - if (sm == NULL) - return 0; - - len = os_snprintf(buf, buflen, - "EAP state=%s\n", - eap_sm_state_txt(sm->EAP_state)); - if (len < 0 || (size_t) len >= buflen) - return 0; - - if (sm->selectedMethod != EAP_TYPE_NONE) { - const char *name; - if (sm->m) { - name = sm->m->name; - } else { - const struct eap_method *m = - eap_peer_get_eap_method(EAP_VENDOR_IETF, - sm->selectedMethod); - if (m) - name = m->name; - else - name = "?"; - } - ret = os_snprintf(buf + len, buflen - len, - "selectedMethod=%d (EAP-%s)\n", - sm->selectedMethod, name); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - if (sm->m && sm->m->get_status) { - len += sm->m->get_status(sm, sm->eap_method_priv, - buf + len, buflen - len, - verbose); - } - } - - if (verbose) { - ret = os_snprintf(buf + len, buflen - len, - "reqMethod=%d\n" - "methodState=%s\n" - "decision=%s\n" - "ClientTimeout=%d\n", - sm->reqMethod, - eap_sm_method_state_txt(sm->methodState), - eap_sm_decision_txt(sm->decision), - sm->ClientTimeout); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - } - - return len; -} -#endif /* CONFIG_CTRL_IFACE */ - - -#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) -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; - const char *txt = NULL; - char *tmp; - - if (sm == NULL) - return; - config = eap_get_config(sm); - if (config == NULL) - return; - - switch (field) { - case WPA_CTRL_REQ_EAP_IDENTITY: - config->pending_req_identity++; - break; - case WPA_CTRL_REQ_EAP_PASSWORD: - config->pending_req_password++; - break; - case WPA_CTRL_REQ_EAP_NEW_PASSWORD: - config->pending_req_new_password++; - break; - case WPA_CTRL_REQ_EAP_PIN: - config->pending_req_pin++; - break; - case WPA_CTRL_REQ_EAP_OTP: - if (msg) { - tmp = os_malloc(msglen + 3); - if (tmp == NULL) - return; - tmp[0] = '['; - os_memcpy(tmp + 1, msg, msglen); - tmp[msglen + 1] = ']'; - tmp[msglen + 2] = '\0'; - txt = tmp; - os_free(config->pending_req_otp); - config->pending_req_otp = tmp; - config->pending_req_otp_len = msglen + 3; - } else { - if (config->pending_req_otp == NULL) - return; - txt = config->pending_req_otp; - } - break; - case WPA_CTRL_REQ_EAP_PASSPHRASE: - config->pending_req_passphrase++; - break; - case WPA_CTRL_REQ_SIM: - txt = msg; - break; - default: - return; - } - - if (sm->eapol_cb->eap_param_needed) - sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt); -} -#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ -#define eap_sm_request(sm, type, msg, msglen) do { } while (0) -#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ - -const char * eap_sm_get_method_name(struct eap_sm *sm) -{ - if (sm->m == NULL) - return "UNKNOWN"; - return sm->m->name; -} - - -/** - * eap_sm_request_identity - Request identity from user (ctrl_iface) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * - * EAP methods can call this function to request identity information for the - * current network. This is normally called when the identity is not included - * in the network configuration. The request will be sent to monitor programs - * through the control interface. - */ -void eap_sm_request_identity(struct eap_sm *sm) -{ - eap_sm_request(sm, WPA_CTRL_REQ_EAP_IDENTITY, NULL, 0); -} - - -/** - * eap_sm_request_password - Request password from user (ctrl_iface) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * - * EAP methods can call this function to request password information for the - * current network. This is normally called when the password is not included - * in the network configuration. The request will be sent to monitor programs - * through the control interface. - */ -void eap_sm_request_password(struct eap_sm *sm) -{ - eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSWORD, NULL, 0); -} - - -/** - * eap_sm_request_new_password - Request new password from user (ctrl_iface) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * - * EAP methods can call this function to request new password information for - * the current network. This is normally called when the EAP method indicates - * that the current password has expired and password change is required. The - * request will be sent to monitor programs through the control interface. - */ -void eap_sm_request_new_password(struct eap_sm *sm) -{ - eap_sm_request(sm, WPA_CTRL_REQ_EAP_NEW_PASSWORD, NULL, 0); -} - - -/** - * eap_sm_request_pin - Request SIM or smart card PIN from user (ctrl_iface) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * - * EAP methods can call this function to request SIM or smart card PIN - * information for the current network. This is normally called when the PIN is - * not included in the network configuration. The request will be sent to - * monitor programs through the control interface. - */ -void eap_sm_request_pin(struct eap_sm *sm) -{ - eap_sm_request(sm, WPA_CTRL_REQ_EAP_PIN, NULL, 0); -} - - -/** - * eap_sm_request_otp - Request one time password from user (ctrl_iface) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @msg: Message to be displayed to the user when asking for OTP - * @msg_len: Length of the user displayable message - * - * EAP methods can call this function to request open time password (OTP) for - * the current network. The request will be sent to monitor programs through - * the control interface. - */ -void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len) -{ - eap_sm_request(sm, WPA_CTRL_REQ_EAP_OTP, msg, msg_len); -} - - -/** - * eap_sm_request_passphrase - Request passphrase from user (ctrl_iface) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * - * EAP methods can call this function to request passphrase for a private key - * for the current network. This is normally called when the passphrase is not - * included in the network configuration. The request will be sent to monitor - * programs through the control interface. - */ -void eap_sm_request_passphrase(struct eap_sm *sm) -{ - eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSPHRASE, NULL, 0); -} - - -/** - * eap_sm_request_sim - Request external SIM processing - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @req: EAP method specific request - */ -void eap_sm_request_sim(struct eap_sm *sm, const char *req) -{ - eap_sm_request(sm, WPA_CTRL_REQ_SIM, req, os_strlen(req)); -} - - -/** - * eap_sm_notify_ctrl_attached - Notification of attached monitor - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * - * Notify EAP state machines that a monitor was attached to the control - * interface to trigger re-sending of pending requests for user input. - */ -void eap_sm_notify_ctrl_attached(struct eap_sm *sm) -{ - struct eap_peer_config *config = eap_get_config(sm); - - if (config == NULL) - return; - - /* Re-send any pending requests for user data since a new control - * interface was added. This handles cases where the EAP authentication - * starts immediately after system startup when the user interface is - * not yet running. */ - if (config->pending_req_identity) - eap_sm_request_identity(sm); - if (config->pending_req_password) - eap_sm_request_password(sm); - if (config->pending_req_new_password) - eap_sm_request_new_password(sm); - if (config->pending_req_otp) - eap_sm_request_otp(sm, NULL, 0); - if (config->pending_req_pin) - eap_sm_request_pin(sm); - if (config->pending_req_passphrase) - eap_sm_request_passphrase(sm); -} - - -static int eap_allowed_phase2_type(int vendor, int type) -{ - if (vendor != EAP_VENDOR_IETF) - return 0; - return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS && - type != EAP_TYPE_FAST; -} - - -/** - * eap_get_phase2_type - Get EAP type for the given EAP phase 2 method name - * @name: EAP method name, e.g., MD5 - * @vendor: Buffer for returning EAP Vendor-Id - * Returns: EAP method type or %EAP_TYPE_NONE if not found - * - * This function maps EAP type names into EAP type numbers that are allowed for - * Phase 2, i.e., for tunneled authentication. Phase 2 is used, e.g., with - * EAP-PEAP, EAP-TTLS, and EAP-FAST. - */ -u32 eap_get_phase2_type(const char *name, int *vendor) -{ - int v; - u8 type = eap_peer_get_type(name, &v); - if (eap_allowed_phase2_type(v, type)) { - *vendor = v; - return type; - } - *vendor = EAP_VENDOR_IETF; - return EAP_TYPE_NONE; -} - - -/** - * eap_get_phase2_types - Get list of allowed EAP phase 2 types - * @config: Pointer to a network configuration - * @count: Pointer to a variable to be filled with number of returned EAP types - * Returns: Pointer to allocated type list or %NULL on failure - * - * This function generates an array of allowed EAP phase 2 (tunneled) types for - * the given network configuration. - */ -struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config, - size_t *count) -{ - struct eap_method_type *buf; - u32 method; - int vendor; - size_t mcount; - const struct eap_method *methods, *m; - - methods = eap_peer_get_methods(&mcount); - if (methods == NULL) - return NULL; - *count = 0; - buf = os_malloc(mcount * sizeof(struct eap_method_type)); - if (buf == NULL) - return NULL; - - for (m = methods; m; m = m->next) { - vendor = m->vendor; - method = m->method; - if (eap_allowed_phase2_type(vendor, method)) { - if (vendor == EAP_VENDOR_IETF && - method == EAP_TYPE_TLS && config && - config->private_key2 == NULL) - continue; - buf[*count].vendor = vendor; - buf[*count].method = method; - (*count)++; - } - } - - return buf; -} - - -/** - * eap_set_fast_reauth - Update fast_reauth setting - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @enabled: 1 = Fast reauthentication is enabled, 0 = Disabled - */ -void eap_set_fast_reauth(struct eap_sm *sm, int enabled) -{ - sm->fast_reauth = enabled; -} - - -/** - * eap_set_workaround - Update EAP workarounds setting - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @workaround: 1 = Enable EAP workarounds, 0 = Disable EAP workarounds - */ -void eap_set_workaround(struct eap_sm *sm, unsigned int workaround) -{ - sm->workaround = workaround; -} - - -/** - * eap_get_config - Get current network configuration - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * Returns: Pointer to the current network configuration or %NULL if not found - * - * EAP peer methods should avoid using this function if they can use other - * access functions, like eap_get_config_identity() and - * eap_get_config_password(), that do not require direct access to - * struct eap_peer_config. - */ -struct eap_peer_config * eap_get_config(struct eap_sm *sm) -{ - return sm->eapol_cb->get_config(sm->eapol_ctx); -} - - -/** - * eap_get_config_identity - Get identity from the network configuration - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @len: Buffer for the length of the identity - * Returns: Pointer to the identity or %NULL if not found - */ -const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len) -{ - struct eap_peer_config *config = eap_get_config(sm); - if (config == NULL) - return NULL; - *len = config->identity_len; - return config->identity; -} - - -static int eap_get_ext_password(struct eap_sm *sm, - struct eap_peer_config *config) -{ - char *name; - - if (config->password == NULL) - return -1; - - name = os_zalloc(config->password_len + 1); - if (name == NULL) - return -1; - os_memcpy(name, config->password, config->password_len); - - ext_password_free(sm->ext_pw_buf); - sm->ext_pw_buf = ext_password_get(sm->ext_pw, name); - os_free(name); - - return sm->ext_pw_buf == NULL ? -1 : 0; -} - - -/** - * eap_get_config_password - Get password from the network configuration - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @len: Buffer for the length of the password - * Returns: Pointer to the password or %NULL if not found - */ -const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len) -{ - struct eap_peer_config *config = eap_get_config(sm); - if (config == NULL) - return NULL; - - if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { - if (eap_get_ext_password(sm, config) < 0) - return NULL; - *len = wpabuf_len(sm->ext_pw_buf); - return wpabuf_head(sm->ext_pw_buf); - } - - *len = config->password_len; - return config->password; -} - - -/** - * eap_get_config_password2 - Get password from the network configuration - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @len: Buffer for the length of the password - * @hash: Buffer for returning whether the password is stored as a - * NtPasswordHash instead of plaintext password; can be %NULL if this - * information is not needed - * Returns: Pointer to the password or %NULL if not found - */ -const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash) -{ - struct eap_peer_config *config = eap_get_config(sm); - if (config == NULL) - return NULL; - - if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { - if (eap_get_ext_password(sm, config) < 0) - return NULL; - if (hash) - *hash = 0; - *len = wpabuf_len(sm->ext_pw_buf); - return wpabuf_head(sm->ext_pw_buf); - } - - *len = config->password_len; - if (hash) - *hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH); - return config->password; -} - - -/** - * eap_get_config_new_password - Get new password from network configuration - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @len: Buffer for the length of the new password - * Returns: Pointer to the new password or %NULL if not found - */ -const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len) -{ - struct eap_peer_config *config = eap_get_config(sm); - if (config == NULL) - return NULL; - *len = config->new_password_len; - return config->new_password; -} - - -/** - * eap_get_config_otp - Get one-time password from the network configuration - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @len: Buffer for the length of the one-time password - * Returns: Pointer to the one-time password or %NULL if not found - */ -const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len) -{ - struct eap_peer_config *config = eap_get_config(sm); - if (config == NULL) - return NULL; - *len = config->otp_len; - return config->otp; -} - - -/** - * eap_clear_config_otp - Clear used one-time password - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * - * This function clears a used one-time password (OTP) from the current network - * configuration. This should be called when the OTP has been used and is not - * needed anymore. - */ -void eap_clear_config_otp(struct eap_sm *sm) -{ - struct eap_peer_config *config = eap_get_config(sm); - if (config == NULL) - return; - os_memset(config->otp, 0, config->otp_len); - os_free(config->otp); - config->otp = NULL; - config->otp_len = 0; -} - - -/** - * eap_get_config_phase1 - Get phase1 data from the network configuration - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * Returns: Pointer to the phase1 data or %NULL if not found - */ -const char * eap_get_config_phase1(struct eap_sm *sm) -{ - struct eap_peer_config *config = eap_get_config(sm); - if (config == NULL) - return NULL; - return config->phase1; -} - - -/** - * eap_get_config_phase2 - Get phase2 data from the network configuration - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * Returns: Pointer to the phase1 data or %NULL if not found - */ -const char * eap_get_config_phase2(struct eap_sm *sm) -{ - struct eap_peer_config *config = eap_get_config(sm); - if (config == NULL) - return NULL; - return config->phase2; -} - - -int eap_get_config_fragment_size(struct eap_sm *sm) -{ - struct eap_peer_config *config = eap_get_config(sm); - if (config == NULL) - return -1; - return config->fragment_size; -} - - -/** - * eap_key_available - Get key availability (eapKeyAvailable variable) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * Returns: 1 if EAP keying material is available, 0 if not - */ -int eap_key_available(struct eap_sm *sm) -{ - return sm ? sm->eapKeyAvailable : 0; -} - - -/** - * eap_notify_success - Notify EAP state machine about external success trigger - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * - * This function is called when external event, e.g., successful completion of - * WPA-PSK key handshake, is indicating that EAP state machine should move to - * success state. This is mainly used with security modes that do not use EAP - * state machine (e.g., WPA-PSK). - */ -void eap_notify_success(struct eap_sm *sm) -{ - if (sm) { - sm->decision = DECISION_COND_SUCC; - sm->EAP_state = EAP_SUCCESS; - } -} - - -/** - * eap_notify_lower_layer_success - Notification of lower layer success - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * - * Notify EAP state machines that a lower layer has detected a successful - * authentication. This is used to recover from dropped EAP-Success messages. - */ -void eap_notify_lower_layer_success(struct eap_sm *sm) -{ - if (sm == NULL) - return; - - if (eapol_get_bool(sm, EAPOL_eapSuccess) || - sm->decision == DECISION_FAIL || - (sm->methodState != METHOD_MAY_CONT && - sm->methodState != METHOD_DONE)) - return; - - if (sm->eapKeyData != NULL) - sm->eapKeyAvailable = TRUE; - eapol_set_bool(sm, EAPOL_eapSuccess, TRUE); - wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS - "EAP authentication completed successfully (based on lower " - "layer success)"); -} - - -/** - * eap_get_eapSessionId - Get Session-Id from EAP state machine - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @len: Pointer to variable that will be set to number of bytes in the session - * Returns: Pointer to the EAP Session-Id or %NULL on failure - * - * Fetch EAP Session-Id from the EAP state machine. The Session-Id is available - * only after a successful authentication. EAP state machine continues to manage - * the Session-Id and the caller must not change or free the returned data. - */ -const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len) -{ - if (sm == NULL || sm->eapSessionId == NULL) { - *len = 0; - return NULL; - } - - *len = sm->eapSessionIdLen; - return sm->eapSessionId; -} - - -/** - * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @len: Pointer to variable that will be set to number of bytes in the key - * Returns: Pointer to the EAP keying data or %NULL on failure - * - * Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The - * key is available only after a successful authentication. EAP state machine - * continues to manage the key data and the caller must not change or free the - * returned data. - */ -const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len) -{ - if (sm == NULL || sm->eapKeyData == NULL) { - *len = 0; - return NULL; - } - - *len = sm->eapKeyDataLen; - return sm->eapKeyData; -} - - -/** - * eap_get_eapKeyData - Get EAP response data - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * Returns: Pointer to the EAP response (eapRespData) or %NULL on failure - * - * Fetch EAP response (eapRespData) from the EAP state machine. This data is - * available when EAP state machine has processed an incoming EAP request. The - * EAP state machine does not maintain a reference to the response after this - * function is called and the caller is responsible for freeing the data. - */ -struct wpabuf * eap_get_eapRespData(struct eap_sm *sm) -{ - struct wpabuf *resp; - - if (sm == NULL || sm->eapRespData == NULL) - return NULL; - - resp = sm->eapRespData; - sm->eapRespData = NULL; - - return resp; -} - - -/** - * eap_sm_register_scard_ctx - Notification of smart card context - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @ctx: Context data for smart card operations - * - * Notify EAP state machines of context data for smart card operations. This - * context data will be used as a parameter for scard_*() functions. - */ -void eap_register_scard_ctx(struct eap_sm *sm, void *ctx) -{ - if (sm) - sm->scard_ctx = ctx; -} - - -/** - * eap_set_config_blob - Set or add a named configuration blob - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @blob: New value for the blob - * - * Adds a new configuration blob or replaces the current value of an existing - * blob. - */ -void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob) -{ -#ifndef CONFIG_NO_CONFIG_BLOBS - sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob); -#endif /* CONFIG_NO_CONFIG_BLOBS */ -} - - -/** - * eap_get_config_blob - Get a named configuration blob - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @name: Name of the blob - * Returns: Pointer to blob data or %NULL if not found - */ -const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm, - const char *name) -{ -#ifndef CONFIG_NO_CONFIG_BLOBS - return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name); -#else /* CONFIG_NO_CONFIG_BLOBS */ - return NULL; -#endif /* CONFIG_NO_CONFIG_BLOBS */ -} - - -/** - * eap_set_force_disabled - Set force_disabled flag - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @disabled: 1 = EAP disabled, 0 = EAP enabled - * - * This function is used to force EAP state machine to be disabled when it is - * not in use (e.g., with WPA-PSK or plaintext connections). - */ -void eap_set_force_disabled(struct eap_sm *sm, int disabled) -{ - sm->force_disabled = disabled; -} - - -/** - * eap_set_external_sim - Set external_sim flag - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @external_sim: Whether external SIM/USIM processing is used - */ -void eap_set_external_sim(struct eap_sm *sm, int external_sim) -{ - sm->external_sim = external_sim; -} - - - /** - * eap_notify_pending - Notify that EAP method is ready to re-process a request - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * - * An EAP method can perform a pending operation (e.g., to get a response from - * an external process). Once the response is available, this function can be - * used to request EAPOL state machine to retry delivering the previously - * received (and still unanswered) EAP request to EAP state machine. - */ -void eap_notify_pending(struct eap_sm *sm) -{ - sm->eapol_cb->notify_pending(sm->eapol_ctx); -} - - -/** - * eap_invalidate_cached_session - Mark cached session data invalid - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - */ -void eap_invalidate_cached_session(struct eap_sm *sm) -{ - if (sm) - eap_deinit_prev_method(sm, "invalidate"); -} - - -int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf) -{ - if (conf->identity_len != WSC_ID_ENROLLEE_LEN || - os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)) - return 0; /* Not a WPS Enrollee */ - - if (conf->phase1 == NULL || os_strstr(conf->phase1, "pbc=1") == NULL) - return 0; /* Not using PBC */ - - return 1; -} - - -int eap_is_wps_pin_enrollee(struct eap_peer_config *conf) -{ - if (conf->identity_len != WSC_ID_ENROLLEE_LEN || - os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)) - return 0; /* Not a WPS Enrollee */ - - if (conf->phase1 == NULL || os_strstr(conf->phase1, "pin=") == NULL) - return 0; /* Not using PIN */ - - return 1; -} - - -void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext) -{ - ext_password_free(sm->ext_pw_buf); - sm->ext_pw_buf = NULL; - sm->ext_pw = ext; -} - - -/** - * eap_set_anon_id - Set or add anonymous identity - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear - * @len: Length of anonymous identity in octets - */ -void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len) -{ - if (sm->eapol_cb->set_anon_id) - sm->eapol_cb->set_anon_id(sm->eapol_ctx, id, len); -} - - -int eap_peer_was_failure_expected(struct eap_sm *sm) -{ - return sm->expected_failure; -} diff --git a/contrib/hostapd/src/eap_peer/eap.h b/contrib/hostapd/src/eap_peer/eap.h deleted file mode 100644 index 712e929dcb..0000000000 --- a/contrib/hostapd/src/eap_peer/eap.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - * EAP peer state machine functions (RFC 4137) - * Copyright (c) 2004-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_H -#define EAP_H - -#include "common/defs.h" -#include "eap_common/eap_defs.h" -#include "eap_peer/eap_methods.h" - -struct eap_sm; -struct wpa_config_blob; -struct wpabuf; - -struct eap_method_type { - int vendor; - u32 method; -}; - -#ifdef IEEE8021X_EAPOL - -/** - * enum eapol_bool_var - EAPOL boolean state variables for EAP state machine - * - * These variables are used in the interface between EAP peer state machine and - * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is - * expected to maintain these variables and register a callback functions for - * EAP state machine to get and set the variables. - */ -enum eapol_bool_var { - /** - * EAPOL_eapSuccess - EAP SUCCESS state reached - * - * EAP state machine reads and writes this value. - */ - EAPOL_eapSuccess, - - /** - * EAPOL_eapRestart - Lower layer request to restart authentication - * - * Set to TRUE in lower layer, FALSE in EAP state machine. - */ - EAPOL_eapRestart, - - /** - * EAPOL_eapFail - EAP FAILURE state reached - * - * EAP state machine writes this value. - */ - EAPOL_eapFail, - - /** - * EAPOL_eapResp - Response to send - * - * Set to TRUE in EAP state machine, FALSE in lower layer. - */ - EAPOL_eapResp, - - /** - * EAPOL_eapNoResp - Request has been process; no response to send - * - * Set to TRUE in EAP state machine, FALSE in lower layer. - */ - EAPOL_eapNoResp, - - /** - * EAPOL_eapReq - EAP request available from lower layer - * - * Set to TRUE in lower layer, FALSE in EAP state machine. - */ - EAPOL_eapReq, - - /** - * EAPOL_portEnabled - Lower layer is ready for communication - * - * EAP state machines reads this value. - */ - EAPOL_portEnabled, - - /** - * EAPOL_altAccept - Alternate indication of success (RFC3748) - * - * EAP state machines reads this value. - */ - EAPOL_altAccept, - - /** - * EAPOL_altReject - Alternate indication of failure (RFC3748) - * - * EAP state machines reads this value. - */ - EAPOL_altReject -}; - -/** - * enum eapol_int_var - EAPOL integer state variables for EAP state machine - * - * These variables are used in the interface between EAP peer state machine and - * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is - * expected to maintain these variables and register a callback functions for - * EAP state machine to get and set the variables. - */ -enum eapol_int_var { - /** - * EAPOL_idleWhile - Outside time for EAP peer timeout - * - * This integer variable is used to provide an outside timer that the - * external (to EAP state machine) code must decrement by one every - * second until the value reaches zero. This is used in the same way as - * EAPOL state machine timers. EAP state machine reads and writes this - * value. - */ - EAPOL_idleWhile -}; - -/** - * struct eapol_callbacks - Callback functions from EAP to lower layer - * - * This structure defines the callback functions that EAP state machine - * requires from the lower layer (usually EAPOL state machine) for updating - * state variables and requesting information. eapol_ctx from - * eap_peer_sm_init() call will be used as the ctx parameter for these - * callback functions. - */ -struct eapol_callbacks { - /** - * get_config - Get pointer to the current network configuration - * @ctx: eapol_ctx from eap_peer_sm_init() call - */ - struct eap_peer_config * (*get_config)(void *ctx); - - /** - * get_bool - Get a boolean EAPOL state variable - * @variable: EAPOL boolean variable to get - * Returns: Value of the EAPOL variable - */ - Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable); - - /** - * set_bool - Set a boolean EAPOL state variable - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @variable: EAPOL boolean variable to set - * @value: Value for the EAPOL variable - */ - void (*set_bool)(void *ctx, enum eapol_bool_var variable, - Boolean value); - - /** - * get_int - Get an integer EAPOL state variable - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @variable: EAPOL integer variable to get - * Returns: Value of the EAPOL variable - */ - unsigned int (*get_int)(void *ctx, enum eapol_int_var variable); - - /** - * set_int - Set an integer EAPOL state variable - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @variable: EAPOL integer variable to set - * @value: Value for the EAPOL variable - */ - void (*set_int)(void *ctx, enum eapol_int_var variable, - unsigned int value); - - /** - * get_eapReqData - Get EAP-Request data - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @len: Pointer to variable that will be set to eapReqDataLen - * Returns: Reference to eapReqData (EAP state machine will not free - * this) or %NULL if eapReqData not available. - */ - struct wpabuf * (*get_eapReqData)(void *ctx); - - /** - * set_config_blob - Set named configuration blob - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @blob: New value for the blob - * - * Adds a new configuration blob or replaces the current value of an - * existing blob. - */ - void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob); - - /** - * get_config_blob - Get a named configuration blob - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @name: Name of the blob - * Returns: Pointer to blob data or %NULL if not found - */ - const struct wpa_config_blob * (*get_config_blob)(void *ctx, - const char *name); - - /** - * notify_pending - Notify that a pending request can be retried - * @ctx: eapol_ctx from eap_peer_sm_init() call - * - * An EAP method can perform a pending operation (e.g., to get a - * response from an external process). Once the response is available, - * this callback function can be used to request EAPOL state machine to - * retry delivering the previously received (and still unanswered) EAP - * request to EAP state machine. - */ - void (*notify_pending)(void *ctx); - - /** - * eap_param_needed - Notify that EAP parameter is needed - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY) - * @txt: User readable text describing the required parameter - */ - void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field, - const char *txt); - - /** - * notify_cert - Notification of a peer certificate - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @depth: Depth in certificate chain (0 = server) - * @subject: Subject of the peer certificate - * @cert_hash: SHA-256 hash of the certificate - * @cert: Peer certificate - */ - void (*notify_cert)(void *ctx, int depth, const char *subject, - const char *cert_hash, const struct wpabuf *cert); - - /** - * notify_status - Notification of the current EAP state - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @status: Step in the process of EAP authentication - * @parameter: Step-specific parameter, e.g., EAP method name - */ - void (*notify_status)(void *ctx, const char *status, - const char *parameter); - - /** - * set_anon_id - Set or add anonymous identity - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear - * @len: Length of anonymous identity in octets - */ - void (*set_anon_id)(void *ctx, const u8 *id, size_t len); -}; - -/** - * struct eap_config - Configuration for EAP state machine - */ -struct eap_config { - /** - * opensc_engine_path - OpenSC engine for OpenSSL engine support - * - * Usually, path to engine_opensc.so. - */ - const char *opensc_engine_path; - /** - * pkcs11_engine_path - PKCS#11 engine for OpenSSL engine support - * - * Usually, path to engine_pkcs11.so. - */ - const char *pkcs11_engine_path; - /** - * pkcs11_module_path - OpenSC PKCS#11 module for OpenSSL engine - * - * Usually, path to opensc-pkcs11.so. - */ - const char *pkcs11_module_path; - /** - * wps - WPS context data - * - * 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, - struct eapol_callbacks *eapol_cb, - void *msg_ctx, struct eap_config *conf); -void eap_peer_sm_deinit(struct eap_sm *sm); -int eap_peer_sm_step(struct eap_sm *sm); -void eap_sm_abort(struct eap_sm *sm); -int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, - int verbose); -const char * eap_sm_get_method_name(struct eap_sm *sm); -struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted); -void eap_sm_request_identity(struct eap_sm *sm); -void eap_sm_request_password(struct eap_sm *sm); -void eap_sm_request_new_password(struct eap_sm *sm); -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); -void eap_sm_request_passphrase(struct eap_sm *sm); -void eap_sm_request_sim(struct eap_sm *sm, const char *req); -void eap_sm_notify_ctrl_attached(struct eap_sm *sm); -u32 eap_get_phase2_type(const char *name, int *vendor); -struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config, - size_t *count); -void eap_set_fast_reauth(struct eap_sm *sm, int enabled); -void eap_set_workaround(struct eap_sm *sm, unsigned int workaround); -void eap_set_force_disabled(struct eap_sm *sm, int disabled); -void eap_set_external_sim(struct eap_sm *sm, int external_sim); -int eap_key_available(struct eap_sm *sm); -void eap_notify_success(struct eap_sm *sm); -void eap_notify_lower_layer_success(struct eap_sm *sm); -const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len); -const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len); -struct wpabuf * eap_get_eapRespData(struct eap_sm *sm); -void eap_register_scard_ctx(struct eap_sm *sm, void *ctx); -void eap_invalidate_cached_session(struct eap_sm *sm); - -int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf); -int eap_is_wps_pin_enrollee(struct eap_peer_config *conf); - -struct ext_password_data; -void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext); -void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len); -int eap_peer_was_failure_expected(struct eap_sm *sm); - -#endif /* IEEE8021X_EAPOL */ - -#endif /* EAP_H */ diff --git a/contrib/hostapd/src/eap_peer/eap_aka.c b/contrib/hostapd/src/eap_peer/eap_aka.c deleted file mode 100644 index d3cbaca6d5..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_aka.c +++ /dev/null @@ -1,1537 +0,0 @@ -/* - * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448) - * Copyright (c) 2004-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "pcsc_funcs.h" -#include "crypto/crypto.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "crypto/milenage.h" -#include "eap_common/eap_sim_common.h" -#include "eap_config.h" -#include "eap_i.h" - - -struct eap_aka_data { - u8 ik[EAP_AKA_IK_LEN], ck[EAP_AKA_CK_LEN], res[EAP_AKA_RES_MAX_LEN]; - size_t res_len; - u8 nonce_s[EAP_SIM_NONCE_S_LEN]; - u8 mk[EAP_SIM_MK_LEN]; - u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN]; - u8 k_encr[EAP_SIM_K_ENCR_LEN]; - u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */ - u8 msk[EAP_SIM_KEYING_DATA_LEN]; - u8 emsk[EAP_EMSK_LEN]; - u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN]; - u8 auts[EAP_AKA_AUTS_LEN]; - - int num_id_req, num_notification; - u8 *pseudonym; - size_t pseudonym_len; - u8 *reauth_id; - size_t reauth_id_len; - int reauth; - unsigned int counter, counter_too_small; - u8 *last_eap_identity; - size_t last_eap_identity_len; - enum { - CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE - } state; - - struct wpabuf *id_msgs; - int prev_id; - int result_ind, use_result_ind; - u8 eap_method; - u8 *network_name; - size_t network_name_len; - u16 kdf; - int kdf_negotiation; -}; - - -#ifndef CONFIG_NO_STDOUT_DEBUG -static const char * eap_aka_state_txt(int state) -{ - switch (state) { - case CONTINUE: - return "CONTINUE"; - case RESULT_SUCCESS: - return "RESULT_SUCCESS"; - case RESULT_FAILURE: - return "RESULT_FAILURE"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "?"; - } -} -#endif /* CONFIG_NO_STDOUT_DEBUG */ - - -static void eap_aka_state(struct eap_aka_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s", - eap_aka_state_txt(data->state), - eap_aka_state_txt(state)); - data->state = state; -} - - -static void * eap_aka_init(struct eap_sm *sm) -{ - struct eap_aka_data *data; - const char *phase1 = eap_get_config_phase1(sm); - struct eap_peer_config *config = eap_get_config(sm); - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - - data->eap_method = EAP_TYPE_AKA; - - eap_aka_state(data, CONTINUE); - data->prev_id = -1; - - data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL; - - if (config && config->anonymous_identity) { - data->pseudonym = os_malloc(config->anonymous_identity_len); - if (data->pseudonym) { - os_memcpy(data->pseudonym, config->anonymous_identity, - config->anonymous_identity_len); - data->pseudonym_len = config->anonymous_identity_len; - } - } - - return data; -} - - -#ifdef EAP_AKA_PRIME -static void * eap_aka_prime_init(struct eap_sm *sm) -{ - struct eap_aka_data *data = eap_aka_init(sm); - if (data == NULL) - return NULL; - data->eap_method = EAP_TYPE_AKA_PRIME; - return data; -} -#endif /* EAP_AKA_PRIME */ - - -static void eap_aka_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_aka_data *data = priv; - if (data) { - os_free(data->pseudonym); - os_free(data->reauth_id); - os_free(data->last_eap_identity); - wpabuf_free(data->id_msgs); - os_free(data->network_name); - os_free(data); - } -} - - -static int eap_aka_ext_sim_req(struct eap_sm *sm, struct eap_aka_data *data) -{ - char req[200], *pos, *end; - - wpa_printf(MSG_DEBUG, "EAP-AKA: Use external USIM processing"); - pos = req; - end = pos + sizeof(req); - pos += os_snprintf(pos, end - pos, "UMTS-AUTH"); - pos += os_snprintf(pos, end - pos, ":"); - pos += wpa_snprintf_hex(pos, end - pos, data->rand, EAP_AKA_RAND_LEN); - pos += os_snprintf(pos, end - pos, ":"); - pos += wpa_snprintf_hex(pos, end - pos, data->autn, EAP_AKA_AUTN_LEN); - - eap_sm_request_sim(sm, req); - return 1; -} - - -static int eap_aka_ext_sim_result(struct eap_sm *sm, struct eap_aka_data *data, - struct eap_peer_config *conf) -{ - char *resp, *pos; - - wpa_printf(MSG_DEBUG, - "EAP-AKA: Use result from external USIM processing"); - - resp = conf->external_sim_resp; - conf->external_sim_resp = NULL; - - if (os_strncmp(resp, "UMTS-AUTS:", 10) == 0) { - pos = resp + 10; - if (hexstr2bin(pos, data->auts, EAP_AKA_AUTS_LEN) < 0) - goto invalid; - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: AUTS", data->auts, - EAP_AKA_AUTS_LEN); - os_free(resp); - return -2; - } - - if (os_strncmp(resp, "UMTS-AUTH:", 10) != 0) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized external USIM processing response"); - os_free(resp); - return -1; - } - - pos = resp + 10; - wpa_hexdump(MSG_DEBUG, "EAP-AKA: RAND", data->rand, EAP_AKA_RAND_LEN); - - if (hexstr2bin(pos, data->ik, EAP_AKA_IK_LEN) < 0) - goto invalid; - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", data->ik, EAP_AKA_IK_LEN); - pos += EAP_AKA_IK_LEN * 2; - if (*pos != ':') - goto invalid; - pos++; - - if (hexstr2bin(pos, data->ck, EAP_AKA_CK_LEN) < 0) - goto invalid; - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", data->ck, EAP_AKA_CK_LEN); - pos += EAP_AKA_CK_LEN * 2; - if (*pos != ':') - goto invalid; - pos++; - - data->res_len = os_strlen(pos) / 2; - if (data->res_len > EAP_AKA_RES_MAX_LEN) { - data->res_len = 0; - goto invalid; - } - if (hexstr2bin(pos, data->res, data->res_len) < 0) - goto invalid; - wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: RES", data->res, data->res_len); - - os_free(resp); - return 0; - -invalid: - wpa_printf(MSG_DEBUG, "EAP-AKA: Invalid external USIM processing UMTS-AUTH response"); - os_free(resp); - return -1; -} - - -static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data) -{ - struct eap_peer_config *conf; - - wpa_printf(MSG_DEBUG, "EAP-AKA: UMTS authentication algorithm"); - - conf = eap_get_config(sm); - if (conf == NULL) - return -1; - - if (sm->external_sim) { - if (conf->external_sim_resp) - return eap_aka_ext_sim_result(sm, data, conf); - else - return eap_aka_ext_sim_req(sm, data); - } - - if (conf->pcsc) { - return scard_umts_auth(sm->scard_ctx, data->rand, - data->autn, data->res, &data->res_len, - data->ik, data->ck, data->auts); - } - -#ifdef CONFIG_USIM_SIMULATOR - if (conf->password) { - u8 opc[16], k[16], sqn[6]; - const char *pos; - wpa_printf(MSG_DEBUG, "EAP-AKA: Use internal Milenage " - "implementation for UMTS authentication"); - if (conf->password_len < 78) { - wpa_printf(MSG_DEBUG, "EAP-AKA: invalid Milenage " - "password"); - return -1; - } - pos = (const char *) conf->password; - if (hexstr2bin(pos, k, 16)) - return -1; - pos += 32; - if (*pos != ':') - return -1; - pos++; - - if (hexstr2bin(pos, opc, 16)) - return -1; - pos += 32; - if (*pos != ':') - return -1; - pos++; - - if (hexstr2bin(pos, sqn, 6)) - return -1; - - return milenage_check(opc, k, sqn, data->rand, data->autn, - data->ik, data->ck, - data->res, &data->res_len, data->auts); - } -#endif /* CONFIG_USIM_SIMULATOR */ - -#ifdef CONFIG_USIM_HARDCODED - wpa_printf(MSG_DEBUG, "EAP-AKA: Use hardcoded Kc and SRES values for " - "testing"); - - /* These hardcoded Kc and SRES values are used for testing. - * Could consider making them configurable. */ - os_memset(data->res, '2', EAP_AKA_RES_MAX_LEN); - data->res_len = EAP_AKA_RES_MAX_LEN; - os_memset(data->ik, '3', EAP_AKA_IK_LEN); - os_memset(data->ck, '4', EAP_AKA_CK_LEN); - { - u8 autn[EAP_AKA_AUTN_LEN]; - os_memset(autn, '1', EAP_AKA_AUTN_LEN); - if (os_memcmp(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) { - wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match " - "with expected value"); - return -1; - } - } -#if 0 - { - static int test_resync = 1; - if (test_resync) { - /* Test Resynchronization */ - test_resync = 0; - return -2; - } - } -#endif - return 0; - -#else /* CONFIG_USIM_HARDCODED */ - - wpa_printf(MSG_DEBUG, "EAP-AKA: No UMTS authentication algorith " - "enabled"); - return -1; - -#endif /* CONFIG_USIM_HARDCODED */ -} - - -#define CLEAR_PSEUDONYM 0x01 -#define CLEAR_REAUTH_ID 0x02 -#define CLEAR_EAP_ID 0x04 - -static void eap_aka_clear_identities(struct eap_sm *sm, - struct eap_aka_data *data, int id) -{ - if ((id & CLEAR_PSEUDONYM) && data->pseudonym) { - wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym"); - os_free(data->pseudonym); - data->pseudonym = NULL; - data->pseudonym_len = 0; - eap_set_anon_id(sm, NULL, 0); - } - if ((id & CLEAR_REAUTH_ID) && data->reauth_id) { - wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id"); - os_free(data->reauth_id); - data->reauth_id = NULL; - data->reauth_id_len = 0; - } - if ((id & CLEAR_EAP_ID) && data->last_eap_identity) { - wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id"); - os_free(data->last_eap_identity); - data->last_eap_identity = NULL; - data->last_eap_identity_len = 0; - } -} - - -static int eap_aka_learn_ids(struct eap_sm *sm, struct eap_aka_data *data, - struct eap_sim_attrs *attr) -{ - if (attr->next_pseudonym) { - const u8 *identity = NULL; - size_t identity_len = 0; - const u8 *realm = NULL; - size_t realm_len = 0; - - wpa_hexdump_ascii(MSG_DEBUG, - "EAP-AKA: (encr) AT_NEXT_PSEUDONYM", - attr->next_pseudonym, - attr->next_pseudonym_len); - os_free(data->pseudonym); - /* Look for the realm of the permanent identity */ - identity = eap_get_config_identity(sm, &identity_len); - if (identity) { - for (realm = identity, realm_len = identity_len; - realm_len > 0; realm_len--, realm++) { - if (*realm == '@') - break; - } - } - data->pseudonym = os_malloc(attr->next_pseudonym_len + - realm_len); - if (data->pseudonym == NULL) { - wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for " - "next pseudonym"); - data->pseudonym_len = 0; - return -1; - } - os_memcpy(data->pseudonym, attr->next_pseudonym, - attr->next_pseudonym_len); - if (realm_len) { - os_memcpy(data->pseudonym + attr->next_pseudonym_len, - realm, realm_len); - } - data->pseudonym_len = attr->next_pseudonym_len + realm_len; - eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len); - } - - if (attr->next_reauth_id) { - os_free(data->reauth_id); - data->reauth_id = os_malloc(attr->next_reauth_id_len); - if (data->reauth_id == NULL) { - wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for " - "next reauth_id"); - data->reauth_id_len = 0; - return -1; - } - os_memcpy(data->reauth_id, attr->next_reauth_id, - attr->next_reauth_id_len); - data->reauth_id_len = attr->next_reauth_id_len; - wpa_hexdump_ascii(MSG_DEBUG, - "EAP-AKA: (encr) AT_NEXT_REAUTH_ID", - data->reauth_id, - data->reauth_id_len); - } - - return 0; -} - - -static int eap_aka_add_id_msg(struct eap_aka_data *data, - const struct wpabuf *msg) -{ - if (msg == NULL) - return -1; - - if (data->id_msgs == NULL) { - data->id_msgs = wpabuf_dup(msg); - return data->id_msgs == NULL ? -1 : 0; - } - - if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0) - return -1; - wpabuf_put_buf(data->id_msgs, msg); - - return 0; -} - - -static void eap_aka_add_checkcode(struct eap_aka_data *data, - struct eap_sim_msg *msg) -{ - const u8 *addr; - size_t len; - u8 hash[SHA256_MAC_LEN]; - - wpa_printf(MSG_DEBUG, " AT_CHECKCODE"); - - if (data->id_msgs == NULL) { - /* - * No EAP-AKA/Identity packets were exchanged - send empty - * checkcode. - */ - eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0); - return; - } - - /* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */ - addr = wpabuf_head(data->id_msgs); - len = wpabuf_len(data->id_msgs); - wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len); -#ifdef EAP_AKA_PRIME - if (data->eap_method == EAP_TYPE_AKA_PRIME) - sha256_vector(1, &addr, &len, hash); - else -#endif /* EAP_AKA_PRIME */ - sha1_vector(1, &addr, &len, hash); - - eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash, - data->eap_method == EAP_TYPE_AKA_PRIME ? - EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN); -} - - -static int eap_aka_verify_checkcode(struct eap_aka_data *data, - const u8 *checkcode, size_t checkcode_len) -{ - const u8 *addr; - size_t len; - u8 hash[SHA256_MAC_LEN]; - size_t hash_len; - - if (checkcode == NULL) - return -1; - - if (data->id_msgs == NULL) { - if (checkcode_len != 0) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server " - "indicates that AKA/Identity messages were " - "used, but they were not"); - return -1; - } - return 0; - } - - hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ? - EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN; - - if (checkcode_len != hash_len) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server " - "indicates that AKA/Identity message were not " - "used, but they were"); - return -1; - } - - /* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */ - addr = wpabuf_head(data->id_msgs); - len = wpabuf_len(data->id_msgs); -#ifdef EAP_AKA_PRIME - if (data->eap_method == EAP_TYPE_AKA_PRIME) - sha256_vector(1, &addr, &len, hash); - else -#endif /* EAP_AKA_PRIME */ - sha1_vector(1, &addr, &len, hash); - - if (os_memcmp(hash, checkcode, hash_len) != 0) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE"); - return -1; - } - - return 0; -} - - -static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id, - int err) -{ - struct eap_sim_msg *msg; - - eap_aka_state(data, FAILURE); - data->num_id_req = 0; - data->num_notification = 0; - - wpa_printf(MSG_DEBUG, "EAP-AKA: Send Client-Error (error code %d)", - err); - msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, - EAP_AKA_SUBTYPE_CLIENT_ERROR); - eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0); - return eap_sim_msg_finish(msg, NULL, NULL, 0); -} - - -static struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data, - u8 id) -{ - struct eap_sim_msg *msg; - - eap_aka_state(data, FAILURE); - data->num_id_req = 0; - data->num_notification = 0; - - wpa_printf(MSG_DEBUG, "Generating EAP-AKA Authentication-Reject " - "(id=%d)", id); - msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, - EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT); - return eap_sim_msg_finish(msg, NULL, NULL, 0); -} - - -static struct wpabuf * eap_aka_synchronization_failure( - struct eap_aka_data *data, u8 id) -{ - struct eap_sim_msg *msg; - - data->num_id_req = 0; - data->num_notification = 0; - - wpa_printf(MSG_DEBUG, "Generating EAP-AKA Synchronization-Failure " - "(id=%d)", id); - msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, - EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE); - wpa_printf(MSG_DEBUG, " AT_AUTS"); - eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts, - EAP_AKA_AUTS_LEN); - return eap_sim_msg_finish(msg, NULL, NULL, 0); -} - - -static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, - struct eap_aka_data *data, - u8 id, - enum eap_sim_id_req id_req) -{ - const u8 *identity = NULL; - size_t identity_len = 0; - struct eap_sim_msg *msg; - - data->reauth = 0; - if (id_req == ANY_ID && data->reauth_id) { - identity = data->reauth_id; - identity_len = data->reauth_id_len; - data->reauth = 1; - } else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) && - data->pseudonym) { - identity = data->pseudonym; - identity_len = data->pseudonym_len; - eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID); - } else if (id_req != NO_ID_REQ) { - identity = eap_get_config_identity(sm, &identity_len); - if (identity) { - eap_aka_clear_identities(sm, data, CLEAR_PSEUDONYM | - CLEAR_REAUTH_ID); - } - } - if (id_req != NO_ID_REQ) - eap_aka_clear_identities(sm, data, CLEAR_EAP_ID); - - wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id); - msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, - EAP_AKA_SUBTYPE_IDENTITY); - - if (identity) { - wpa_hexdump_ascii(MSG_DEBUG, " AT_IDENTITY", - identity, identity_len); - eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len, - identity, identity_len); - } - - return eap_sim_msg_finish(msg, NULL, NULL, 0); -} - - -static struct wpabuf * eap_aka_response_challenge(struct eap_aka_data *data, - u8 id) -{ - struct eap_sim_msg *msg; - - wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)", id); - msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, - EAP_AKA_SUBTYPE_CHALLENGE); - wpa_printf(MSG_DEBUG, " AT_RES"); - eap_sim_msg_add(msg, EAP_SIM_AT_RES, data->res_len * 8, - data->res, data->res_len); - eap_aka_add_checkcode(data, msg); - if (data->use_result_ind) { - wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); - eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); - } - wpa_printf(MSG_DEBUG, " AT_MAC"); - eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, (u8 *) "", 0); -} - - -static struct wpabuf * eap_aka_response_reauth(struct eap_aka_data *data, - u8 id, int counter_too_small, - const u8 *nonce_s) -{ - struct eap_sim_msg *msg; - unsigned int counter; - - wpa_printf(MSG_DEBUG, "Generating EAP-AKA Reauthentication (id=%d)", - id); - msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, - EAP_AKA_SUBTYPE_REAUTHENTICATION); - wpa_printf(MSG_DEBUG, " AT_IV"); - wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); - eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); - - if (counter_too_small) { - wpa_printf(MSG_DEBUG, " *AT_COUNTER_TOO_SMALL"); - eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0); - counter = data->counter_too_small; - } else - counter = data->counter; - - wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", counter); - eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); - - if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt " - "AT_ENCR_DATA"); - eap_sim_msg_free(msg); - return NULL; - } - eap_aka_add_checkcode(data, msg); - if (data->use_result_ind) { - wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); - eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); - } - wpa_printf(MSG_DEBUG, " AT_MAC"); - eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, nonce_s, - EAP_SIM_NONCE_S_LEN); -} - - -static struct wpabuf * eap_aka_response_notification(struct eap_aka_data *data, - u8 id, u16 notification) -{ - struct eap_sim_msg *msg; - u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL; - - wpa_printf(MSG_DEBUG, "Generating EAP-AKA Notification (id=%d)", id); - msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, - EAP_AKA_SUBTYPE_NOTIFICATION); - if (k_aut && data->reauth) { - wpa_printf(MSG_DEBUG, " AT_IV"); - wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); - eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, - EAP_SIM_AT_ENCR_DATA); - wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", data->counter); - eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, - NULL, 0); - if (eap_sim_msg_add_encr_end(msg, data->k_encr, - EAP_SIM_AT_PADDING)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt " - "AT_ENCR_DATA"); - eap_sim_msg_free(msg); - return NULL; - } - } - if (k_aut) { - wpa_printf(MSG_DEBUG, " AT_MAC"); - eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - } - return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0); -} - - -static struct wpabuf * eap_aka_process_identity(struct eap_sm *sm, - struct eap_aka_data *data, - u8 id, - const struct wpabuf *reqData, - struct eap_sim_attrs *attr) -{ - int id_error; - struct wpabuf *buf; - - wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Identity"); - - id_error = 0; - switch (attr->id_req) { - case NO_ID_REQ: - break; - case ANY_ID: - if (data->num_id_req > 0) - id_error++; - data->num_id_req++; - break; - case FULLAUTH_ID: - if (data->num_id_req > 1) - id_error++; - data->num_id_req++; - break; - case PERMANENT_ID: - if (data->num_id_req > 2) - id_error++; - data->num_id_req++; - break; - } - if (id_error) { - wpa_printf(MSG_INFO, "EAP-AKA: Too many ID requests " - "used within one authentication"); - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - - buf = eap_aka_response_identity(sm, data, id, attr->id_req); - - if (data->prev_id != id) { - eap_aka_add_id_msg(data, reqData); - eap_aka_add_id_msg(data, buf); - data->prev_id = id; - } - - return buf; -} - - -static int eap_aka_verify_mac(struct eap_aka_data *data, - const struct wpabuf *req, - const u8 *mac, const u8 *extra, - size_t extra_len) -{ - if (data->eap_method == EAP_TYPE_AKA_PRIME) - return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra, - extra_len); - return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len); -} - - -#ifdef EAP_AKA_PRIME -static struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data, - u8 id, u16 kdf) -{ - struct eap_sim_msg *msg; - - data->kdf_negotiation = 1; - data->kdf = kdf; - wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d) (KDF " - "select)", id); - msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, - EAP_AKA_SUBTYPE_CHALLENGE); - wpa_printf(MSG_DEBUG, " AT_KDF"); - eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0); - return eap_sim_msg_finish(msg, NULL, NULL, 0); -} - - -static struct wpabuf * eap_aka_prime_kdf_neg(struct eap_aka_data *data, - u8 id, struct eap_sim_attrs *attr) -{ - size_t i; - - for (i = 0; i < attr->kdf_count; i++) { - if (attr->kdf[i] == EAP_AKA_PRIME_KDF) - return eap_aka_prime_kdf_select(data, id, - EAP_AKA_PRIME_KDF); - } - - /* No matching KDF found - fail authentication as if AUTN had been - * incorrect */ - return eap_aka_authentication_reject(data, id); -} - - -static int eap_aka_prime_kdf_valid(struct eap_aka_data *data, - struct eap_sim_attrs *attr) -{ - size_t i, j; - - if (attr->kdf_count == 0) - return 0; - - /* The only allowed (and required) duplication of a KDF is the addition - * of the selected KDF into the beginning of the list. */ - - if (data->kdf_negotiation) { - if (attr->kdf[0] != data->kdf) { - wpa_printf(MSG_WARNING, "EAP-AKA': The server did not " - "accept the selected KDF"); - return 0; - } - - for (i = 1; i < attr->kdf_count; i++) { - if (attr->kdf[i] == data->kdf) - break; - } - if (i == attr->kdf_count && - attr->kdf_count < EAP_AKA_PRIME_KDF_MAX) { - wpa_printf(MSG_WARNING, "EAP-AKA': The server did not " - "duplicate the selected KDF"); - return 0; - } - - /* TODO: should check that the list is identical to the one - * used in the previous Challenge message apart from the added - * entry in the beginning. */ - } - - for (i = data->kdf ? 1 : 0; i < attr->kdf_count; i++) { - for (j = i + 1; j < attr->kdf_count; j++) { - if (attr->kdf[i] == attr->kdf[j]) { - wpa_printf(MSG_WARNING, "EAP-AKA': The server " - "included a duplicated KDF"); - return 0; - } - } - } - - return 1; -} -#endif /* EAP_AKA_PRIME */ - - -static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm, - struct eap_aka_data *data, - u8 id, - const struct wpabuf *reqData, - struct eap_sim_attrs *attr) -{ - const u8 *identity; - size_t identity_len; - int res; - struct eap_sim_attrs eattr; - - wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Challenge"); - - if (attr->checkcode && - eap_aka_verify_checkcode(data, attr->checkcode, - attr->checkcode_len)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the " - "message"); - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - -#ifdef EAP_AKA_PRIME - if (data->eap_method == EAP_TYPE_AKA_PRIME) { - if (!attr->kdf_input || attr->kdf_input_len == 0) { - wpa_printf(MSG_WARNING, "EAP-AKA': Challenge message " - "did not include non-empty AT_KDF_INPUT"); - /* Fail authentication as if AUTN had been incorrect */ - return eap_aka_authentication_reject(data, id); - } - os_free(data->network_name); - data->network_name = os_malloc(attr->kdf_input_len); - if (data->network_name == NULL) { - wpa_printf(MSG_WARNING, "EAP-AKA': No memory for " - "storing Network Name"); - return eap_aka_authentication_reject(data, id); - } - os_memcpy(data->network_name, attr->kdf_input, - attr->kdf_input_len); - data->network_name_len = attr->kdf_input_len; - wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': Network Name " - "(AT_KDF_INPUT)", - data->network_name, data->network_name_len); - /* TODO: check Network Name per 3GPP.33.402 */ - - if (!eap_aka_prime_kdf_valid(data, attr)) - return eap_aka_authentication_reject(data, id); - - if (attr->kdf[0] != EAP_AKA_PRIME_KDF) - return eap_aka_prime_kdf_neg(data, id, attr); - - data->kdf = EAP_AKA_PRIME_KDF; - wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf); - } - - if (data->eap_method == EAP_TYPE_AKA && attr->bidding) { - u16 flags = WPA_GET_BE16(attr->bidding); - if ((flags & EAP_AKA_BIDDING_FLAG_D) && - eap_allowed_method(sm, EAP_VENDOR_IETF, - EAP_TYPE_AKA_PRIME)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Bidding down from " - "AKA' to AKA detected"); - /* Fail authentication as if AUTN had been incorrect */ - return eap_aka_authentication_reject(data, id); - } - } -#endif /* EAP_AKA_PRIME */ - - data->reauth = 0; - if (!attr->mac || !attr->rand || !attr->autn) { - wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message " - "did not include%s%s%s", - !attr->mac ? " AT_MAC" : "", - !attr->rand ? " AT_RAND" : "", - !attr->autn ? " AT_AUTN" : ""); - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - os_memcpy(data->rand, attr->rand, EAP_AKA_RAND_LEN); - os_memcpy(data->autn, attr->autn, EAP_AKA_AUTN_LEN); - - res = eap_aka_umts_auth(sm, data); - if (res == -1) { - wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication " - "failed (AUTN)"); - return eap_aka_authentication_reject(data, id); - } else if (res == -2) { - wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication " - "failed (AUTN seq# -> AUTS)"); - return eap_aka_synchronization_failure(data, id); - } else if (res > 0) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Wait for external USIM processing"); - return NULL; - } else if (res) { - wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed"); - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } -#ifdef EAP_AKA_PRIME - if (data->eap_method == EAP_TYPE_AKA_PRIME) { - /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the - * needed 6-octet SQN ^ AK for CK',IK' derivation */ - u16 amf = WPA_GET_BE16(data->autn + 6); - if (!(amf & 0x8000)) { - wpa_printf(MSG_WARNING, "EAP-AKA': AMF separation bit " - "not set (AMF=0x%4x)", amf); - return eap_aka_authentication_reject(data, id); - } - eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik, - data->autn, - data->network_name, - data->network_name_len); - } -#endif /* EAP_AKA_PRIME */ - if (data->last_eap_identity) { - identity = data->last_eap_identity; - identity_len = data->last_eap_identity_len; - } else if (data->pseudonym) { - identity = data->pseudonym; - identity_len = data->pseudonym_len; - } else - identity = eap_get_config_identity(sm, &identity_len); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK " - "derivation", identity, identity_len); - if (data->eap_method == EAP_TYPE_AKA_PRIME) { - eap_aka_prime_derive_keys(identity, identity_len, data->ik, - data->ck, data->k_encr, data->k_aut, - data->k_re, data->msk, data->emsk); - } else { - eap_aka_derive_mk(identity, identity_len, data->ik, data->ck, - data->mk); - eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, - data->msk, data->emsk); - } - if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message " - "used invalid AT_MAC"); - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - - /* 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(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); - - if (attr->encr_data) { - u8 *decrypted; - decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, - attr->encr_data_len, attr->iv, - &eattr, 0); - if (decrypted == NULL) { - return eap_aka_client_error( - data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - eap_aka_learn_ids(sm, data, &eattr); - os_free(decrypted); - } - - if (data->result_ind && attr->result_ind) - data->use_result_ind = 1; - - if (data->state != FAILURE && data->state != RESULT_FAILURE) { - eap_aka_state(data, data->use_result_ind ? - RESULT_SUCCESS : SUCCESS); - } - - data->num_id_req = 0; - data->num_notification = 0; - /* RFC 4187 specifies that counter is initialized to one after - * fullauth, but initializing it to zero makes it easier to implement - * reauth verification. */ - data->counter = 0; - return eap_aka_response_challenge(data, id); -} - - -static int eap_aka_process_notification_reauth(struct eap_aka_data *data, - struct eap_sim_attrs *attr) -{ - struct eap_sim_attrs eattr; - u8 *decrypted; - - if (attr->encr_data == NULL || attr->iv == NULL) { - wpa_printf(MSG_WARNING, "EAP-AKA: Notification message after " - "reauth did not include encrypted data"); - return -1; - } - - decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, - attr->encr_data_len, attr->iv, &eattr, - 0); - if (decrypted == NULL) { - wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted " - "data from notification message"); - return -1; - } - - if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) { - wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification " - "message does not match with counter in reauth " - "message"); - os_free(decrypted); - return -1; - } - - os_free(decrypted); - return 0; -} - - -static int eap_aka_process_notification_auth(struct eap_aka_data *data, - const struct wpabuf *reqData, - struct eap_sim_attrs *attr) -{ - if (attr->mac == NULL) { - wpa_printf(MSG_INFO, "EAP-AKA: no AT_MAC in after_auth " - "Notification message"); - return -1; - } - - if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Notification message " - "used invalid AT_MAC"); - return -1; - } - - if (data->reauth && - eap_aka_process_notification_reauth(data, attr)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Invalid notification " - "message after reauth"); - return -1; - } - - return 0; -} - - -static struct wpabuf * eap_aka_process_notification( - struct eap_sm *sm, struct eap_aka_data *data, u8 id, - const struct wpabuf *reqData, struct eap_sim_attrs *attr) -{ - wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Notification"); - if (data->num_notification > 0) { - wpa_printf(MSG_INFO, "EAP-AKA: too many notification " - "rounds (only one allowed)"); - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - data->num_notification++; - if (attr->notification == -1) { - wpa_printf(MSG_INFO, "EAP-AKA: no AT_NOTIFICATION in " - "Notification message"); - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - - if ((attr->notification & 0x4000) == 0 && - eap_aka_process_notification_auth(data, reqData, attr)) { - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - - eap_sim_report_notification(sm->msg_ctx, attr->notification, 1); - if (attr->notification >= 0 && attr->notification < 32768) { - eap_aka_state(data, FAILURE); - } else if (attr->notification == EAP_SIM_SUCCESS && - data->state == RESULT_SUCCESS) - eap_aka_state(data, SUCCESS); - return eap_aka_response_notification(data, id, attr->notification); -} - - -static struct wpabuf * eap_aka_process_reauthentication( - struct eap_sm *sm, struct eap_aka_data *data, u8 id, - const struct wpabuf *reqData, struct eap_sim_attrs *attr) -{ - struct eap_sim_attrs eattr; - u8 *decrypted; - - wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Reauthentication"); - - if (attr->checkcode && - eap_aka_verify_checkcode(data, attr->checkcode, - attr->checkcode_len)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the " - "message"); - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - - if (data->reauth_id == NULL) { - wpa_printf(MSG_WARNING, "EAP-AKA: Server is trying " - "reauthentication, but no reauth_id available"); - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - - data->reauth = 1; - if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication " - "did not have valid AT_MAC"); - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - - if (attr->encr_data == NULL || attr->iv == NULL) { - wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication " - "message did not include encrypted data"); - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - - decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, - attr->encr_data_len, attr->iv, &eattr, - 0); - if (decrypted == NULL) { - wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted " - "data from reauthentication message"); - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - - if (eattr.nonce_s == NULL || eattr.counter < 0) { - wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet", - !eattr.nonce_s ? " AT_NONCE_S" : "", - eattr.counter < 0 ? " AT_COUNTER" : ""); - os_free(decrypted); - return eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - } - - if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) { - struct wpabuf *res; - wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter " - "(%d <= %d)", eattr.counter, data->counter); - data->counter_too_small = eattr.counter; - - /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current - * reauth_id must not be used to start a new reauthentication. - * However, since it was used in the last EAP-Response-Identity - * packet, it has to saved for the following fullauth to be - * used in MK derivation. */ - os_free(data->last_eap_identity); - data->last_eap_identity = data->reauth_id; - data->last_eap_identity_len = data->reauth_id_len; - data->reauth_id = NULL; - data->reauth_id_len = 0; - - res = eap_aka_response_reauth(data, id, 1, eattr.nonce_s); - os_free(decrypted); - - return res; - } - data->counter = eattr.counter; - - os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S", - data->nonce_s, EAP_SIM_NONCE_S_LEN); - - if (data->eap_method == EAP_TYPE_AKA_PRIME) { - eap_aka_prime_derive_keys_reauth(data->k_re, data->counter, - data->reauth_id, - data->reauth_id_len, - data->nonce_s, - data->msk, data->emsk); - } else { - eap_sim_derive_keys_reauth(data->counter, data->reauth_id, - data->reauth_id_len, - data->nonce_s, data->mk, - data->msk, data->emsk); - } - eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); - eap_aka_learn_ids(sm, data, &eattr); - - if (data->result_ind && attr->result_ind) - data->use_result_ind = 1; - - if (data->state != FAILURE && data->state != RESULT_FAILURE) { - eap_aka_state(data, data->use_result_ind ? - RESULT_SUCCESS : SUCCESS); - } - - data->num_id_req = 0; - data->num_notification = 0; - if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of " - "fast reauths performed - force fullauth"); - eap_aka_clear_identities(sm, data, - CLEAR_REAUTH_ID | CLEAR_EAP_ID); - } - os_free(decrypted); - return eap_aka_response_reauth(data, id, 0, data->nonce_s); -} - - -static struct wpabuf * eap_aka_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_aka_data *data = priv; - const struct eap_hdr *req; - u8 subtype, id; - struct wpabuf *res; - const u8 *pos; - struct eap_sim_attrs attr; - size_t len; - - wpa_hexdump_buf(MSG_DEBUG, "EAP-AKA: EAP data", reqData); - if (eap_get_config_identity(sm, &len) == NULL) { - wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured"); - eap_sm_request_identity(sm); - ret->ignore = TRUE; - return NULL; - } - - pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData, - &len); - if (pos == NULL || len < 1) { - ret->ignore = TRUE; - return NULL; - } - req = wpabuf_head(reqData); - id = req->identifier; - len = be_to_host16(req->length); - - ret->ignore = FALSE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - ret->allowNotifications = TRUE; - - subtype = *pos++; - wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype); - pos += 2; /* Reserved */ - - if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, - data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1, - 0)) { - res = eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - goto done; - } - - switch (subtype) { - case EAP_AKA_SUBTYPE_IDENTITY: - res = eap_aka_process_identity(sm, data, id, reqData, &attr); - break; - case EAP_AKA_SUBTYPE_CHALLENGE: - res = eap_aka_process_challenge(sm, data, id, reqData, &attr); - break; - case EAP_AKA_SUBTYPE_NOTIFICATION: - res = eap_aka_process_notification(sm, data, id, reqData, - &attr); - break; - case EAP_AKA_SUBTYPE_REAUTHENTICATION: - res = eap_aka_process_reauthentication(sm, data, id, reqData, - &attr); - break; - case EAP_AKA_SUBTYPE_CLIENT_ERROR: - wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error"); - res = eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype); - res = eap_aka_client_error(data, id, - EAP_AKA_UNABLE_TO_PROCESS_PACKET); - break; - } - -done: - if (data->state == FAILURE) { - ret->decision = DECISION_FAIL; - ret->methodState = METHOD_DONE; - } else if (data->state == SUCCESS) { - ret->decision = data->use_result_ind ? - DECISION_UNCOND_SUCC : DECISION_COND_SUCC; - /* - * It is possible for the server to reply with AKA - * Notification, so we must allow the method to continue and - * not only accept EAP-Success at this point. - */ - ret->methodState = data->use_result_ind ? - METHOD_DONE : METHOD_MAY_CONT; - } else if (data->state == RESULT_FAILURE) - ret->methodState = METHOD_CONT; - else if (data->state == RESULT_SUCCESS) - ret->methodState = METHOD_CONT; - - if (ret->methodState == METHOD_DONE) { - ret->allowNotifications = FALSE; - } - - return res; -} - - -static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv) -{ - struct eap_aka_data *data = priv; - return data->pseudonym || data->reauth_id; -} - - -static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_aka_data *data = priv; - eap_aka_clear_identities(sm, data, CLEAR_EAP_ID); - data->prev_id = -1; - wpabuf_free(data->id_msgs); - data->id_msgs = NULL; - data->use_result_ind = 0; - data->kdf_negotiation = 0; -} - - -static void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_aka_data *data = priv; - data->num_id_req = 0; - data->num_notification = 0; - eap_aka_state(data, CONTINUE); - return priv; -} - - -static const u8 * eap_aka_get_identity(struct eap_sm *sm, void *priv, - size_t *len) -{ - struct eap_aka_data *data = priv; - - if (data->reauth_id) { - *len = data->reauth_id_len; - return data->reauth_id; - } - - if (data->pseudonym) { - *len = data->pseudonym_len; - return data->pseudonym; - } - - return NULL; -} - - -static Boolean eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_aka_data *data = priv; - return data->state == SUCCESS; -} - - -static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_aka_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_SIM_KEYING_DATA_LEN); - if (key == NULL) - return NULL; - - *len = EAP_SIM_KEYING_DATA_LEN; - os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); - - return key; -} - - -static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_aka_data *data = priv; - u8 *id; - - if (data->state != SUCCESS) - return NULL; - - *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN; - id = os_malloc(*len); - if (id == NULL) - return NULL; - - id[0] = data->eap_method; - os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN); - os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn, EAP_AKA_AUTN_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len); - - return id; -} - - -static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_aka_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - - *len = EAP_EMSK_LEN; - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - - return key; -} - - -int eap_peer_aka_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA"); - if (eap == NULL) - return -1; - - eap->init = eap_aka_init; - eap->deinit = eap_aka_deinit; - eap->process = eap_aka_process; - eap->isKeyAvailable = eap_aka_isKeyAvailable; - eap->getKey = eap_aka_getKey; - eap->getSessionId = eap_aka_get_session_id; - eap->has_reauth_data = eap_aka_has_reauth_data; - eap->deinit_for_reauth = eap_aka_deinit_for_reauth; - eap->init_for_reauth = eap_aka_init_for_reauth; - eap->get_identity = eap_aka_get_identity; - eap->get_emsk = eap_aka_get_emsk; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} - - -#ifdef EAP_AKA_PRIME -int eap_peer_aka_prime_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME, - "AKA'"); - if (eap == NULL) - return -1; - - eap->init = eap_aka_prime_init; - eap->deinit = eap_aka_deinit; - eap->process = eap_aka_process; - eap->isKeyAvailable = eap_aka_isKeyAvailable; - eap->getKey = eap_aka_getKey; - eap->getSessionId = eap_aka_get_session_id; - eap->has_reauth_data = eap_aka_has_reauth_data; - eap->deinit_for_reauth = eap_aka_deinit_for_reauth; - eap->init_for_reauth = eap_aka_init_for_reauth; - eap->get_identity = eap_aka_get_identity; - eap->get_emsk = eap_aka_get_emsk; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - - return ret; -} -#endif /* EAP_AKA_PRIME */ diff --git a/contrib/hostapd/src/eap_peer/eap_config.h b/contrib/hostapd/src/eap_peer/eap_config.h deleted file mode 100644 index 98ec1f7631..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_config.h +++ /dev/null @@ -1,713 +0,0 @@ -/* - * EAP peer configuration data - * Copyright (c) 2003-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_CONFIG_H -#define EAP_CONFIG_H - -/** - * struct eap_peer_config - EAP peer configuration/credentials - */ -struct eap_peer_config { - /** - * identity - EAP Identity - * - * This field is used to set the real user identity or NAI (for - * EAP-PSK/PAX/SAKE/GPSK). - */ - u8 *identity; - - /** - * identity_len - EAP Identity length - */ - size_t identity_len; - - /** - * anonymous_identity - Anonymous EAP Identity - * - * This field is used for unencrypted use with EAP types that support - * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the - * real identity (identity field) only to the authentication server. - * - * If not set, the identity field will be used for both unencrypted and - * protected fields. - * - * This field can also be used with EAP-SIM/AKA/AKA' to store the - * pseudonym identity. - */ - u8 *anonymous_identity; - - /** - * anonymous_identity_len - Length of anonymous_identity - */ - size_t anonymous_identity_len; - - /** - * password - Password string for EAP - * - * This field can include either the plaintext password (default - * option) or a NtPasswordHash (16-byte MD4 hash of the unicode - * presentation of the password) if flags field has - * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can - * only be used with authentication mechanism that use this hash as the - * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2, - * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP). - * - * In addition, this field is used to configure a pre-shared key for - * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK - * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length - * PSK. - */ - u8 *password; - - /** - * password_len - Length of password field - */ - size_t password_len; - - /** - * ca_cert - File path to CA certificate file (PEM/DER) - * - * This file can have one or more trusted CA certificates. If ca_cert - * and ca_path are not included, server certificate will not be - * verified. This is insecure and a trusted CA certificate should - * always be configured when using EAP-TLS/TTLS/PEAP. Full path to the - * file should be used since working directory may change when - * wpa_supplicant is run in the background. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - * - * Alternatively, this can be used to only perform matching of the - * server certificate (SHA-256 hash of the DER encoded X.509 - * certificate). In this case, the possible CA certificates in the - * server certificate chain are ignored and only the server certificate - * is verified. This is configured with the following format: - * hash:://server/sha256/cert_hash_in_hex - * For example: "hash://server/sha256/ - * 5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a" - * - * On Windows, trusted CA certificates can be loaded from the system - * certificate store by setting this to cert_store://name, e.g., - * ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT". - * Note that when running wpa_supplicant as an application, the user - * certificate store (My user account) is used, whereas computer store - * (Computer account) is used when running wpasvc as a service. - */ - u8 *ca_cert; - - /** - * ca_path - Directory path for CA certificate files (PEM) - * - * This path may contain multiple CA certificates in OpenSSL format. - * Common use for this is to point to system trusted CA list which is - * often installed into directory like /etc/ssl/certs. If configured, - * these certificates are added to the list of trusted CAs. ca_cert - * may also be included in that case, but it is not required. - */ - u8 *ca_path; - - /** - * client_cert - File path to client certificate file (PEM/DER) - * - * This field is used with EAP method that use TLS authentication. - * Usually, this is only configured for EAP-TLS, even though this could - * in theory be used with EAP-TTLS and EAP-PEAP, too. Full path to the - * file should be used since working directory may change when - * wpa_supplicant is run in the background. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *client_cert; - - /** - * private_key - File path to client private key file (PEM/DER/PFX) - * - * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be - * commented out. Both the private key and certificate will be read - * from the PKCS#12 file in this case. Full path to the file should be - * used since working directory may change when wpa_supplicant is run - * in the background. - * - * Windows certificate store can be used by leaving client_cert out and - * configuring private_key in one of the following formats: - * - * cert://substring_to_match - * - * hash://certificate_thumbprint_in_hex - * - * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4" - * - * Note that when running wpa_supplicant as an application, the user - * certificate store (My user account) is used, whereas computer store - * (Computer account) is used when running wpasvc as a service. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *private_key; - - /** - * private_key_passwd - Password for private key file - * - * If left out, this will be asked through control interface. - */ - u8 *private_key_passwd; - - /** - * dh_file - File path to DH/DSA parameters file (in PEM format) - * - * This is an optional configuration file for setting parameters for an - * ephemeral DH key exchange. In most cases, the default RSA - * authentication does not use this configuration. However, it is - * possible setup RSA to use ephemeral DH key exchange. In addition, - * ciphers with DSA keys always use ephemeral DH keys. This can be used - * to achieve forward secrecy. If the file is in DSA parameters format, - * it will be automatically converted into DH params. Full path to the - * file should be used since working directory may change when - * wpa_supplicant is run in the background. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *dh_file; - - /** - * subject_match - Constraint for server certificate subject - * - * This substring is matched against the subject of the authentication - * server certificate. If this string is set, the server sertificate is - * only accepted if it contains this string in the subject. The subject - * string is in following format: - * - * /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com - */ - u8 *subject_match; - - /** - * altsubject_match - Constraint for server certificate alt. subject - * - * Semicolon separated string of entries to be matched against the - * alternative subject name of the authentication server certificate. - * If this string is set, the server sertificate is only accepted if it - * contains one of the entries in an alternative subject name - * extension. - * - * altSubjectName string is in following format: TYPE:VALUE - * - * Example: EMAIL:server@example.com - * Example: DNS:server.example.com;DNS:server2.example.com - * - * Following types are supported: EMAIL, DNS, URI - */ - u8 *altsubject_match; - - /** - * domain_suffix_match - Constraint for server domain name - * - * If set, this FQDN is used as a suffix match requirement for the - * server certificate in SubjectAltName dNSName element(s). If a - * matching dNSName is found, this constraint is met. If no dNSName - * values are present, this constraint is matched against SubjetName CN - * using same suffix match comparison. Suffix match here means that the - * host/domain name is compared one label at a time starting from the - * top-level domain and all the labels in domain_suffix_match shall be - * included in the certificate. The certificate may include additional - * sub-level labels in addition to the required labels. - * - * For example, domain_suffix_match=example.com would match - * test.example.com but would not match test-example.com. - */ - char *domain_suffix_match; - - /** - * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2) - * - * This file can have one or more trusted CA certificates. If ca_cert2 - * and ca_path2 are not included, server certificate will not be - * verified. This is insecure and a trusted CA certificate should - * always be configured. Full path to the file should be used since - * working directory may change when wpa_supplicant is run in the - * background. - * - * This field is like ca_cert, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *ca_cert2; - - /** - * ca_path2 - Directory path for CA certificate files (PEM) (Phase 2) - * - * This path may contain multiple CA certificates in OpenSSL format. - * Common use for this is to point to system trusted CA list which is - * often installed into directory like /etc/ssl/certs. If configured, - * these certificates are added to the list of trusted CAs. ca_cert - * may also be included in that case, but it is not required. - * - * This field is like ca_path, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - u8 *ca_path2; - - /** - * client_cert2 - File path to client certificate file - * - * This field is like client_cert, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the - * file should be used since working directory may change when - * wpa_supplicant is run in the background. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *client_cert2; - - /** - * private_key2 - File path to client private key file - * - * This field is like private_key, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the - * file should be used since working directory may change when - * wpa_supplicant is run in the background. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *private_key2; - - /** - * private_key2_passwd - Password for private key file - * - * This field is like private_key_passwd, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - u8 *private_key2_passwd; - - /** - * dh_file2 - File path to DH/DSA parameters file (in PEM format) - * - * This field is like dh_file, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the - * file should be used since working directory may change when - * wpa_supplicant is run in the background. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *dh_file2; - - /** - * subject_match2 - Constraint for server certificate subject - * - * This field is like subject_match, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - u8 *subject_match2; - - /** - * altsubject_match2 - Constraint for server certificate alt. subject - * - * This field is like altsubject_match, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - u8 *altsubject_match2; - - /** - * domain_suffix_match2 - Constraint for server domain name - * - * This field is like domain_suffix_match, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - char *domain_suffix_match2; - - /** - * eap_methods - Allowed EAP methods - * - * (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of - * allowed EAP methods or %NULL if all methods are accepted. - */ - struct eap_method_type *eap_methods; - - /** - * phase1 - Phase 1 (outer authentication) parameters - * - * String with field-value pairs, e.g., "peapver=0" or - * "peapver=1 peaplabel=1". - * - * 'peapver' can be used to force which PEAP version (0 or 1) is used. - * - * 'peaplabel=1' can be used to force new label, "client PEAP - * encryption", to be used during key derivation when PEAPv1 or newer. - * - * Most existing PEAPv1 implementation seem to be using the old label, - * "client EAP encryption", and wpa_supplicant is now using that as the - * default value. - * - * Some servers, e.g., Radiator, may require peaplabel=1 configuration - * to interoperate with PEAPv1; see eap_testing.txt for more details. - * - * 'peap_outer_success=0' can be used to terminate PEAP authentication - * on tunneled EAP-Success. This is required with some RADIUS servers - * that implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g., - * Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode). - * - * include_tls_length=1 can be used to force wpa_supplicant to include - * TLS Message Length field in all TLS messages even if they are not - * fragmented. - * - * sim_min_num_chal=3 can be used to configure EAP-SIM to require three - * challenges (by default, it accepts 2 or 3). - * - * result_ind=1 can be used to enable EAP-SIM and EAP-AKA to use - * protected result indication. - * - * fast_provisioning option can be used to enable in-line provisioning - * of EAP-FAST credentials (PAC): - * 0 = disabled, - * 1 = allow unauthenticated provisioning, - * 2 = allow authenticated provisioning, - * 3 = allow both unauthenticated and authenticated provisioning - * - * fast_max_pac_list_len=num option can be used to set the maximum - * number of PAC entries to store in a PAC list (default: 10). - * - * fast_pac_format=binary option can be used to select binary format - * for storing PAC entries in order to save some space (the default - * text format uses about 2.5 times the size of minimal binary format). - * - * crypto_binding option can be used to control PEAPv0 cryptobinding - * behavior: - * 0 = do not use cryptobinding (default) - * 1 = use cryptobinding if server supports it - * 2 = require cryptobinding - * - * EAP-WSC (WPS) uses following options: pin=Device_Password and - * uuid=Device_UUID - */ - char *phase1; - - /** - * phase2 - Phase2 (inner authentication with TLS tunnel) parameters - * - * String with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or - * "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS. - */ - char *phase2; - - /** - * pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM - * - * This field is used to configure PC/SC smartcard interface. - * Currently, the only configuration is whether this field is %NULL (do - * not use PC/SC) or non-NULL (e.g., "") to enable PC/SC. - * - * This field is used for EAP-SIM and EAP-AKA. - */ - char *pcsc; - - /** - * pin - PIN for USIM, GSM SIM, and smartcards - * - * This field is used to configure PIN for SIM and smartcards for - * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a - * smartcard is used for private key operations. - * - * If left out, this will be asked through control interface. - */ - char *pin; - - /** - * engine - Enable OpenSSL engine (e.g., for smartcard access) - * - * This is used if private key operations for EAP-TLS are performed - * using a smartcard. - */ - int engine; - - /** - * engine_id - Engine ID for OpenSSL engine - * - * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11 - * engine. - * - * This is used if private key operations for EAP-TLS are performed - * using a smartcard. - */ - char *engine_id; - - /** - * engine2 - Enable OpenSSL engine (e.g., for smartcard) (Phase 2) - * - * This is used if private key operations for EAP-TLS are performed - * using a smartcard. - * - * This field is like engine, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - int engine2; - - - /** - * pin2 - PIN for USIM, GSM SIM, and smartcards (Phase 2) - * - * This field is used to configure PIN for SIM and smartcards for - * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a - * smartcard is used for private key operations. - * - * This field is like pin2, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - * - * If left out, this will be asked through control interface. - */ - char *pin2; - - /** - * engine2_id - Engine ID for OpenSSL engine (Phase 2) - * - * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11 - * engine. - * - * This is used if private key operations for EAP-TLS are performed - * using a smartcard. - * - * This field is like engine_id, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - char *engine2_id; - - - /** - * key_id - Key ID for OpenSSL engine - * - * This is used if private key operations for EAP-TLS are performed - * using a smartcard. - */ - char *key_id; - - /** - * cert_id - Cert ID for OpenSSL engine - * - * This is used if the certificate operations for EAP-TLS are performed - * using a smartcard. - */ - char *cert_id; - - /** - * ca_cert_id - CA Cert ID for OpenSSL engine - * - * This is used if the CA certificate for EAP-TLS is on a smartcard. - */ - char *ca_cert_id; - - /** - * key2_id - Key ID for OpenSSL engine (phase2) - * - * This is used if private key operations for EAP-TLS are performed - * using a smartcard. - */ - char *key2_id; - - /** - * cert2_id - Cert ID for OpenSSL engine (phase2) - * - * This is used if the certificate operations for EAP-TLS are performed - * using a smartcard. - */ - char *cert2_id; - - /** - * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2) - * - * This is used if the CA certificate for EAP-TLS is on a smartcard. - */ - char *ca_cert2_id; - - /** - * otp - One-time-password - * - * This field should not be set in configuration step. It is only used - * internally when OTP is entered through the control interface. - */ - u8 *otp; - - /** - * otp_len - Length of the otp field - */ - size_t otp_len; - - /** - * pending_req_identity - Whether there is a pending identity request - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request needed - * information. - */ - int pending_req_identity; - - /** - * pending_req_password - Whether there is a pending password request - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request needed - * information. - */ - int pending_req_password; - - /** - * pending_req_pin - Whether there is a pending PIN request - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request needed - * information. - */ - int pending_req_pin; - - /** - * pending_req_new_password - Pending password update request - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request needed - * information. - */ - int pending_req_new_password; - - /** - * pending_req_passphrase - Pending passphrase request - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request needed - * information. - */ - int pending_req_passphrase; - - /** - * pending_req_otp - Whether there is a pending OTP request - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request needed - * information. - */ - char *pending_req_otp; - - /** - * pending_req_otp_len - Length of the pending OTP request - */ - size_t pending_req_otp_len; - - /** - * pac_file - File path or blob name for the PAC entries (EAP-FAST) - * - * wpa_supplicant will need to be able to create this file and write - * updates to it when PAC is being provisioned or refreshed. Full path - * to the file should be used since working directory may change when - * wpa_supplicant is run in the background. - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - char *pac_file; - - /** - * mschapv2_retry - MSCHAPv2 retry in progress - * - * This field is used internally by EAP-MSCHAPv2 and should not be set - * as part of configuration. - */ - int mschapv2_retry; - - /** - * new_password - New password for password update - * - * This field is used during MSCHAPv2 password update. This is normally - * requested from the user through the control interface and not set - * from configuration. - */ - u8 *new_password; - - /** - * new_password_len - Length of new_password field - */ - size_t new_password_len; - - /** - * fragment_size - Maximum EAP fragment size in bytes (default 1398) - * - * This value limits the fragment size for EAP methods that support - * fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set - * small enough to make the EAP messages fit in MTU of the network - * interface used for EAPOL. The default value is suitable for most - * cases. - */ - int fragment_size; - -#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0) -#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1) - /** - * flags - Network configuration flags (bitfield) - * - * This variable is used for internal flags to describe further details - * for the network parameters. - * bit 0 = password is represented as a 16-byte NtPasswordHash value - * instead of plaintext password - * bit 1 = password is stored in external storage; the value in the - * password field is the name of that external entry - */ - u32 flags; - - /** - * ocsp - Whether to use/require OCSP to check server certificate - * - * 0 = do not use OCSP stapling (TLS certificate status extension) - * 1 = try to use OCSP stapling, but not require response - * 2 = require valid OCSP stapling response - */ - int ocsp; - - /** - * external_sim_resp - Response from external SIM processing - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request external - * SIM/USIM processing. - */ - char *external_sim_resp; -}; - - -/** - * struct wpa_config_blob - Named configuration blob - * - * This data structure is used to provide storage for binary objects to store - * abstract information like certificates and private keys inlined with the - * configuration data. - */ -struct wpa_config_blob { - /** - * name - Blob name - */ - char *name; - - /** - * data - Pointer to binary data - */ - u8 *data; - - /** - * len - Length of binary data - */ - size_t len; - - /** - * next - Pointer to next blob in the configuration - */ - struct wpa_config_blob *next; -}; - -#endif /* EAP_CONFIG_H */ diff --git a/contrib/hostapd/src/eap_peer/eap_eke.c b/contrib/hostapd/src/eap_peer/eap_eke.c deleted file mode 100644 index 864ea1d970..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_eke.c +++ /dev/null @@ -1,765 +0,0 @@ -/* - * EAP peer method: EAP-EKE (RFC 6124) - * Copyright (c) 2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/random.h" -#include "eap_peer/eap_i.h" -#include "eap_common/eap_eke_common.h" - -struct eap_eke_data { - enum { - IDENTITY, COMMIT, CONFIRM, SUCCESS, FAILURE - } state; - u8 msk[EAP_MSK_LEN]; - u8 emsk[EAP_EMSK_LEN]; - u8 *peerid; - size_t peerid_len; - u8 *serverid; - size_t serverid_len; - u8 dh_priv[EAP_EKE_MAX_DH_LEN]; - struct eap_eke_session sess; - u8 nonce_p[EAP_EKE_MAX_NONCE_LEN]; - u8 nonce_s[EAP_EKE_MAX_NONCE_LEN]; - struct wpabuf *msgs; - u8 dhgroup; /* forced DH group or 0 to allow all supported */ - u8 encr; /* forced encryption algorithm or 0 to allow all supported */ - u8 prf; /* forced PRF or 0 to allow all supported */ - u8 mac; /* forced MAC or 0 to allow all supported */ -}; - - -static const char * eap_eke_state_txt(int state) -{ - switch (state) { - case IDENTITY: - return "IDENTITY"; - case COMMIT: - return "COMMIT"; - case CONFIRM: - return "CONFIRM"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "?"; - } -} - - -static void eap_eke_state(struct eap_eke_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s", - eap_eke_state_txt(data->state), eap_eke_state_txt(state)); - data->state = state; -} - - -static void eap_eke_deinit(struct eap_sm *sm, void *priv); - - -static void * eap_eke_init(struct eap_sm *sm) -{ - struct eap_eke_data *data; - const u8 *identity, *password; - size_t identity_len, password_len; - const char *phase1; - - password = eap_get_config_password(sm, &password_len); - if (!password) { - wpa_printf(MSG_INFO, "EAP-EKE: No password configured"); - return NULL; - } - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - eap_eke_state(data, IDENTITY); - - identity = eap_get_config_identity(sm, &identity_len); - if (identity) { - data->peerid = os_malloc(identity_len); - if (data->peerid == NULL) { - eap_eke_deinit(sm, data); - return NULL; - } - os_memcpy(data->peerid, identity, identity_len); - data->peerid_len = identity_len; - } - - phase1 = eap_get_config_phase1(sm); - if (phase1) { - const char *pos; - - pos = os_strstr(phase1, "dhgroup="); - if (pos) { - data->dhgroup = atoi(pos + 8); - wpa_printf(MSG_DEBUG, "EAP-EKE: Forced dhgroup %u", - data->dhgroup); - } - - pos = os_strstr(phase1, "encr="); - if (pos) { - data->encr = atoi(pos + 5); - wpa_printf(MSG_DEBUG, "EAP-EKE: Forced encr %u", - data->encr); - } - - pos = os_strstr(phase1, "prf="); - if (pos) { - data->prf = atoi(pos + 4); - wpa_printf(MSG_DEBUG, "EAP-EKE: Forced prf %u", - data->prf); - } - - pos = os_strstr(phase1, "mac="); - if (pos) { - data->mac = atoi(pos + 4); - wpa_printf(MSG_DEBUG, "EAP-EKE: Forced mac %u", - data->mac); - } - } - - return data; -} - - -static void eap_eke_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_eke_data *data = priv; - eap_eke_session_clean(&data->sess); - os_free(data->serverid); - os_free(data->peerid); - wpabuf_free(data->msgs); - os_free(data); -} - - -static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id, - size_t length, u8 eke_exch) -{ - struct wpabuf *msg; - size_t plen; - - plen = 1 + length; - - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen, - EAP_CODE_RESPONSE, id); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory"); - return NULL; - } - - wpabuf_put_u8(msg, eke_exch); - - return msg; -} - - -static int eap_eke_supp_dhgroup(u8 dhgroup) -{ - return dhgroup == EAP_EKE_DHGROUP_EKE_2 || - dhgroup == EAP_EKE_DHGROUP_EKE_5 || - dhgroup == EAP_EKE_DHGROUP_EKE_14 || - dhgroup == EAP_EKE_DHGROUP_EKE_15 || - dhgroup == EAP_EKE_DHGROUP_EKE_16; -} - - -static int eap_eke_supp_encr(u8 encr) -{ - return encr == EAP_EKE_ENCR_AES128_CBC; -} - - -static int eap_eke_supp_prf(u8 prf) -{ - return prf == EAP_EKE_PRF_HMAC_SHA1 || - prf == EAP_EKE_PRF_HMAC_SHA2_256; -} - - -static int eap_eke_supp_mac(u8 mac) -{ - return mac == EAP_EKE_MAC_HMAC_SHA1 || - mac == EAP_EKE_MAC_HMAC_SHA2_256; -} - - -static struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - u32 failure_code) -{ - struct wpabuf *resp; - - wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x", - failure_code); - - resp = eap_eke_build_msg(data, eap_get_id(reqData), 4, EAP_EKE_FAILURE); - if (resp) - wpabuf_put_be32(resp, failure_code); - - os_memset(data->dh_priv, 0, sizeof(data->dh_priv)); - eap_eke_session_clean(&data->sess); - - eap_eke_state(data, FAILURE); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - ret->allowNotifications = FALSE; - - return resp; -} - - -static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - const u8 *payload, - size_t payload_len) -{ - struct wpabuf *resp; - unsigned num_prop, i; - const u8 *pos, *end; - const u8 *prop = NULL; - u8 idtype; - - if (data->state != IDENTITY) { - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PROTO_ERROR); - } - - wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request"); - - if (payload_len < 2 + 4) { - wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data"); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PROTO_ERROR); - } - - pos = payload; - end = payload + payload_len; - - num_prop = *pos++; - pos++; /* Ignore Reserved field */ - - if (pos + num_prop * 4 > end) { - wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)", - num_prop); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PROTO_ERROR); - } - - for (i = 0; i < num_prop; i++) { - const u8 *tmp = pos; - - wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u", - i, pos[0], pos[1], pos[2], pos[3]); - pos += 4; - - if ((data->dhgroup && data->dhgroup != *tmp) || - !eap_eke_supp_dhgroup(*tmp)) - continue; - tmp++; - if ((data->encr && data->encr != *tmp) || - !eap_eke_supp_encr(*tmp)) - continue; - tmp++; - if ((data->prf && data->prf != *tmp) || - !eap_eke_supp_prf(*tmp)) - continue; - tmp++; - if ((data->mac && data->mac != *tmp) || - !eap_eke_supp_mac(*tmp)) - continue; - - prop = tmp - 3; - if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2], - prop[3]) < 0) { - prop = NULL; - continue; - } - - wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal"); - break; - } - - if (prop == NULL) { - wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found"); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN); - } - - pos += (num_prop - i - 1) * 4; - - if (pos == end) { - wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity"); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PROTO_ERROR); - } - - idtype = *pos++; - wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity", - pos, end - pos); - os_free(data->serverid); - data->serverid = os_malloc(end - pos); - if (data->serverid == NULL) { - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - os_memcpy(data->serverid, pos, end - pos); - data->serverid_len = end - pos; - - wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response"); - - resp = eap_eke_build_msg(data, eap_get_id(reqData), - 2 + 4 + 1 + data->peerid_len, - EAP_EKE_ID); - if (resp == NULL) { - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - - wpabuf_put_u8(resp, 1); /* NumProposals */ - wpabuf_put_u8(resp, 0); /* Reserved */ - wpabuf_put_data(resp, prop, 4); /* Selected Proposal */ - wpabuf_put_u8(resp, EAP_EKE_ID_NAI); - if (data->peerid) - wpabuf_put_data(resp, data->peerid, data->peerid_len); - - wpabuf_free(data->msgs); - data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp)); - if (data->msgs == NULL) { - wpabuf_free(resp); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - wpabuf_put_buf(data->msgs, reqData); - wpabuf_put_buf(data->msgs, resp); - - eap_eke_state(data, COMMIT); - - return resp; -} - - -static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm, - struct eap_eke_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - const u8 *payload, - size_t payload_len) -{ - struct wpabuf *resp; - const u8 *pos, *end, *dhcomp; - size_t prot_len; - u8 *rpos; - u8 key[EAP_EKE_MAX_KEY_LEN]; - u8 pub[EAP_EKE_MAX_DH_LEN]; - const u8 *password; - size_t password_len; - - if (data->state != COMMIT) { - wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PROTO_ERROR); - } - - wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request"); - - password = eap_get_config_password(sm, &password_len); - if (password == NULL) { - wpa_printf(MSG_INFO, "EAP-EKE: No password configured!"); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PASSWD_NOT_FOUND); - } - - pos = payload; - end = payload + payload_len; - - if (pos + data->sess.dhcomp_len > end) { - wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit"); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PROTO_ERROR); - } - - wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S", - pos, data->sess.dhcomp_len); - dhcomp = pos; - pos += data->sess.dhcomp_len; - wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos); - - /* - * temp = prf(0+, password) - * key = prf+(temp, ID_S | ID_P) - */ - if (eap_eke_derive_key(&data->sess, password, password_len, - data->serverid, data->serverid_len, - data->peerid, data->peerid_len, key) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key"); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - - /* - * y_p = g ^ x_p (mod p) - * x_p = random number 2 .. p-1 - */ - if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH"); - os_memset(key, 0, sizeof(key)); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - - if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0) - { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret"); - os_memset(key, 0, sizeof(key)); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - - if (eap_eke_derive_ke_ki(&data->sess, - data->serverid, data->serverid_len, - data->peerid, data->peerid_len) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki"); - os_memset(key, 0, sizeof(key)); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - - wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response"); - - resp = eap_eke_build_msg(data, eap_get_id(reqData), - data->sess.dhcomp_len + data->sess.pnonce_len, - EAP_EKE_COMMIT); - if (resp == NULL) { - os_memset(key, 0, sizeof(key)); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - - /* DHComponent_P = Encr(key, y_p) */ - rpos = wpabuf_put(resp, data->sess.dhcomp_len); - if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S"); - os_memset(key, 0, sizeof(key)); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - os_memset(key, 0, sizeof(key)); - - wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P", - rpos, data->sess.dhcomp_len); - - if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) { - wpabuf_free(resp); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P", - data->nonce_p, data->sess.nonce_len); - prot_len = wpabuf_tailroom(resp); - if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len, - wpabuf_put(resp, 0), &prot_len) < 0) { - wpabuf_free(resp); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", - wpabuf_put(resp, 0), prot_len); - wpabuf_put(resp, prot_len); - - /* TODO: CBValue */ - - if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp)) - < 0) { - wpabuf_free(resp); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - wpabuf_put_buf(data->msgs, reqData); - wpabuf_put_buf(data->msgs, resp); - - eap_eke_state(data, CONFIRM); - - return resp; -} - - -static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - const u8 *payload, - size_t payload_len) -{ - struct wpabuf *resp; - const u8 *pos, *end; - size_t prot_len; - u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN]; - u8 auth_s[EAP_EKE_MAX_HASH_LEN]; - size_t decrypt_len; - u8 *auth; - - if (data->state != CONFIRM) { - wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)", - data->state); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PROTO_ERROR); - } - - wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request"); - - pos = payload; - end = payload + payload_len; - - if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) { - wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit"); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PROTO_ERROR); - } - - decrypt_len = sizeof(nonces); - if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len, - nonces, &decrypt_len) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS"); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_AUTHENTICATION_FAIL); - } - if (decrypt_len != (size_t) 2 * data->sess.nonce_len) { - wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S"); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_AUTHENTICATION_FAIL); - } - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S", - nonces, 2 * data->sess.nonce_len); - if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match trnsmitted Nonce_P"); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_AUTHENTICATION_FAIL); - } - - os_memcpy(data->nonce_s, nonces + data->sess.nonce_len, - data->sess.nonce_len); - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S", - data->nonce_s, data->sess.nonce_len); - - if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len, - data->peerid, data->peerid_len, - data->nonce_p, data->nonce_s) < 0) { - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - - if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0) - { - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len); - if (os_memcmp(auth_s, pos + data->sess.pnonce_ps_len, - data->sess.prf_len) != 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match"); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_AUTHENTICATION_FAIL); - } - - wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response"); - - resp = eap_eke_build_msg(data, eap_get_id(reqData), - data->sess.pnonce_len + data->sess.prf_len, - EAP_EKE_CONFIRM); - if (resp == NULL) { - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - - prot_len = wpabuf_tailroom(resp); - if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len, - wpabuf_put(resp, 0), &prot_len) < 0) { - wpabuf_free(resp); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - wpabuf_put(resp, prot_len); - - auth = wpabuf_put(resp, data->sess.prf_len); - if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) { - wpabuf_free(resp); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len); - - if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len, - data->peerid, data->peerid_len, - data->nonce_s, data->nonce_p, - data->msk, data->emsk) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK"); - wpabuf_free(resp); - return eap_eke_build_fail(data, ret, reqData, - EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - } - - os_memset(data->dh_priv, 0, sizeof(data->dh_priv)); - eap_eke_session_clean(&data->sess); - - eap_eke_state(data, SUCCESS); - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_COND_SUCC; - ret->allowNotifications = FALSE; - - return resp; -} - - -static struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - const u8 *payload, - size_t payload_len) -{ - wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request"); - - if (payload_len < 4) { - wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure"); - } else { - u32 code; - code = WPA_GET_BE32(payload); - wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code); - } - - return eap_eke_build_fail(data, ret, reqData, EAP_EKE_FAIL_NO_ERROR); -} - - -static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_eke_data *data = priv; - struct wpabuf *resp; - const u8 *pos, *end; - size_t len; - u8 eke_exch; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len); - if (pos == NULL || len < 1) { - ret->ignore = TRUE; - return NULL; - } - - end = pos + len; - eke_exch = *pos++; - - wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch); - wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos); - - ret->ignore = FALSE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - ret->allowNotifications = TRUE; - - switch (eke_exch) { - case EAP_EKE_ID: - resp = eap_eke_process_id(data, ret, reqData, pos, end - pos); - break; - case EAP_EKE_COMMIT: - resp = eap_eke_process_commit(sm, data, ret, reqData, - pos, end - pos); - break; - case EAP_EKE_CONFIRM: - resp = eap_eke_process_confirm(data, ret, reqData, - pos, end - pos); - break; - case EAP_EKE_FAILURE: - resp = eap_eke_process_failure(data, ret, reqData, - pos, end - pos); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch); - ret->ignore = TRUE; - return NULL; - } - - if (ret->methodState == METHOD_DONE) - ret->allowNotifications = FALSE; - - return resp; -} - - -static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_eke_data *data = priv; - return data->state == SUCCESS; -} - - -static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_eke_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->msk, EAP_MSK_LEN); - *len = EAP_MSK_LEN; - - return key; -} - - -static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_eke_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - *len = EAP_EMSK_LEN; - - return key; -} - - -int eap_peer_eke_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE"); - if (eap == NULL) - return -1; - - eap->init = eap_eke_init; - eap->deinit = eap_eke_deinit; - eap->process = eap_eke_process; - eap->isKeyAvailable = eap_eke_isKeyAvailable; - eap->getKey = eap_eke_getKey; - eap->get_emsk = eap_eke_get_emsk; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_fast.c b/contrib/hostapd/src/eap_peer/eap_fast.c deleted file mode 100644 index 1b0c562a60..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_fast.c +++ /dev/null @@ -1,1761 +0,0 @@ -/* - * EAP peer method: EAP-FAST (RFC 4851) - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/tls.h" -#include "crypto/sha1.h" -#include "eap_common/eap_tlv_common.h" -#include "eap_i.h" -#include "eap_tls_common.h" -#include "eap_config.h" -#include "eap_fast_pac.h" - -#ifdef EAP_FAST_DYNAMIC -#include "eap_fast_pac.c" -#endif /* EAP_FAST_DYNAMIC */ - -/* TODO: - * - test session resumption and enable it if it interoperates - * - password change (pending mschapv2 packet; replay decrypted packet) - */ - - -static void eap_fast_deinit(struct eap_sm *sm, void *priv); - - -struct eap_fast_data { - struct eap_ssl_data ssl; - - int fast_version; - - const struct eap_method *phase2_method; - void *phase2_priv; - int phase2_success; - - struct eap_method_type phase2_type; - struct eap_method_type *phase2_types; - size_t num_phase2_types; - int resuming; /* starting a resumed session */ - struct eap_fast_key_block_provisioning *key_block_p; -#define EAP_FAST_PROV_UNAUTH 1 -#define EAP_FAST_PROV_AUTH 2 - int provisioning_allowed; /* Allowed PAC provisioning modes */ - int provisioning; /* doing PAC provisioning (not the normal auth) */ - int anon_provisioning; /* doing anonymous (unauthenticated) - * provisioning */ - int session_ticket_used; - - u8 key_data[EAP_FAST_KEY_LEN]; - u8 *session_id; - size_t id_len; - u8 emsk[EAP_EMSK_LEN]; - int success; - - struct eap_fast_pac *pac; - struct eap_fast_pac *current_pac; - size_t max_pac_list_len; - int use_pac_binary_format; - - u8 simck[EAP_FAST_SIMCK_LEN]; - int simck_idx; - - struct wpabuf *pending_phase2_req; -}; - - -static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len, - const u8 *client_random, - const u8 *server_random, - u8 *master_secret) -{ - struct eap_fast_data *data = ctx; - - wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback"); - - if (client_random == NULL || server_random == NULL || - master_secret == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket failed - fall " - "back to full TLS handshake"); - data->session_ticket_used = 0; - if (data->provisioning_allowed) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Try to provision a " - "new PAC-Key"); - data->provisioning = 1; - data->current_pac = NULL; - } - return 0; - } - - wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket", ticket, len); - - if (data->current_pac == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key available for " - "using SessionTicket"); - data->session_ticket_used = 0; - return 0; - } - - eap_fast_derive_master_secret(data->current_pac->pac_key, - server_random, client_random, - master_secret); - - data->session_ticket_used = 1; - - return 1; -} - - -static int eap_fast_parse_phase1(struct eap_fast_data *data, - const char *phase1) -{ - const char *pos; - - pos = os_strstr(phase1, "fast_provisioning="); - if (pos) { - data->provisioning_allowed = atoi(pos + 18); - wpa_printf(MSG_DEBUG, "EAP-FAST: Automatic PAC provisioning " - "mode: %d", data->provisioning_allowed); - } - - pos = os_strstr(phase1, "fast_max_pac_list_len="); - if (pos) { - data->max_pac_list_len = atoi(pos + 22); - if (data->max_pac_list_len == 0) - data->max_pac_list_len = 1; - wpa_printf(MSG_DEBUG, "EAP-FAST: Maximum PAC list length: %lu", - (unsigned long) data->max_pac_list_len); - } - - pos = os_strstr(phase1, "fast_pac_format=binary"); - if (pos) { - data->use_pac_binary_format = 1; - wpa_printf(MSG_DEBUG, "EAP-FAST: Using binary format for PAC " - "list"); - } - - return 0; -} - - -static void * eap_fast_init(struct eap_sm *sm) -{ - struct eap_fast_data *data; - struct eap_peer_config *config = eap_get_config(sm); - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->fast_version = EAP_FAST_VERSION; - data->max_pac_list_len = 10; - - if (config && config->phase1 && - eap_fast_parse_phase1(data, config->phase1) < 0) { - eap_fast_deinit(sm, data); - return NULL; - } - - if (eap_peer_select_phase2_methods(config, "auth=", - &data->phase2_types, - &data->num_phase2_types) < 0) { - eap_fast_deinit(sm, data); - return NULL; - } - - data->phase2_type.vendor = EAP_VENDOR_IETF; - data->phase2_type.method = EAP_TYPE_NONE; - - if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_FAST)) { - wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL."); - eap_fast_deinit(sm, data); - return NULL; - } - - if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn, - eap_fast_session_ticket_cb, - data) < 0) { - wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket " - "callback"); - eap_fast_deinit(sm, data); - return NULL; - } - - /* - * The local RADIUS server in a Cisco AP does not seem to like empty - * fragments before data, so disable that workaround for CBC. - * TODO: consider making this configurable - */ - if (tls_connection_enable_workaround(sm->ssl_ctx, data->ssl.conn)) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to enable TLS " - "workarounds"); - } - - if (!config->pac_file) { - wpa_printf(MSG_INFO, "EAP-FAST: No PAC file configured"); - eap_fast_deinit(sm, data); - return NULL; - } - - if (data->use_pac_binary_format && - eap_fast_load_pac_bin(sm, &data->pac, config->pac_file) < 0) { - wpa_printf(MSG_INFO, "EAP-FAST: Failed to load PAC file"); - eap_fast_deinit(sm, data); - return NULL; - } - - if (!data->use_pac_binary_format && - eap_fast_load_pac(sm, &data->pac, config->pac_file) < 0) { - wpa_printf(MSG_INFO, "EAP-FAST: Failed to load PAC file"); - eap_fast_deinit(sm, data); - return NULL; - } - eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len); - - if (data->pac == NULL && !data->provisioning_allowed) { - wpa_printf(MSG_INFO, "EAP-FAST: No PAC configured and " - "provisioning disabled"); - eap_fast_deinit(sm, data); - return NULL; - } - - return data; -} - - -static void eap_fast_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_fast_data *data = priv; - struct eap_fast_pac *pac, *prev; - - if (data == NULL) - return; - if (data->phase2_priv && data->phase2_method) - data->phase2_method->deinit(sm, data->phase2_priv); - os_free(data->phase2_types); - os_free(data->key_block_p); - eap_peer_tls_ssl_deinit(sm, &data->ssl); - - pac = data->pac; - prev = NULL; - while (pac) { - prev = pac; - pac = pac->next; - eap_fast_free_pac(prev); - } - os_free(data->session_id); - wpabuf_free(data->pending_phase2_req); - os_free(data); -} - - -static int eap_fast_derive_msk(struct eap_fast_data *data) -{ - eap_fast_derive_eap_msk(data->simck, data->key_data); - eap_fast_derive_eap_emsk(data->simck, data->emsk); - data->success = 1; - return 0; -} - - -static void eap_fast_derive_key_auth(struct eap_sm *sm, - struct eap_fast_data *data) -{ - u8 *sks; - - /* RFC 4851, Section 5.1: - * Extra key material after TLS key_block: session_key_seed[40] - */ - - sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion", - EAP_FAST_SKS_LEN); - if (sks == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive " - "session_key_seed"); - return; - } - - /* - * RFC 4851, Section 5.2: - * S-IMCK[0] = session_key_seed - */ - wpa_hexdump_key(MSG_DEBUG, - "EAP-FAST: session_key_seed (SKS = S-IMCK[0])", - sks, EAP_FAST_SKS_LEN); - data->simck_idx = 0; - os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN); - os_free(sks); -} - - -static void eap_fast_derive_key_provisioning(struct eap_sm *sm, - struct eap_fast_data *data) -{ - os_free(data->key_block_p); - data->key_block_p = (struct eap_fast_key_block_provisioning *) - eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, - "key expansion", - sizeof(*data->key_block_p)); - if (data->key_block_p == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block"); - return; - } - /* - * RFC 4851, Section 5.2: - * S-IMCK[0] = session_key_seed - */ - wpa_hexdump_key(MSG_DEBUG, - "EAP-FAST: session_key_seed (SKS = S-IMCK[0])", - data->key_block_p->session_key_seed, - sizeof(data->key_block_p->session_key_seed)); - data->simck_idx = 0; - os_memcpy(data->simck, data->key_block_p->session_key_seed, - EAP_FAST_SIMCK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge", - data->key_block_p->server_challenge, - sizeof(data->key_block_p->server_challenge)); - wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge", - data->key_block_p->client_challenge, - sizeof(data->key_block_p->client_challenge)); -} - - -static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data) -{ - if (data->anon_provisioning) - eap_fast_derive_key_provisioning(sm, data); - else - eap_fast_derive_key_auth(sm, data); -} - - -static int eap_fast_init_phase2_method(struct eap_sm *sm, - struct eap_fast_data *data) -{ - data->phase2_method = - eap_peer_get_eap_method(data->phase2_type.vendor, - data->phase2_type.method); - if (data->phase2_method == NULL) - return -1; - - if (data->key_block_p) { - sm->auth_challenge = data->key_block_p->server_challenge; - sm->peer_challenge = data->key_block_p->client_challenge; - } - sm->init_phase2 = 1; - data->phase2_priv = data->phase2_method->init(sm); - sm->init_phase2 = 0; - sm->auth_challenge = NULL; - sm->peer_challenge = NULL; - - return data->phase2_priv == NULL ? -1 : 0; -} - - -static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type) -{ - size_t i; - - /* TODO: TNC with anonymous provisioning; need to require both - * completed MSCHAPv2 and TNC */ - - if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) { - wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed " - "during unauthenticated provisioning; reject phase2" - " type %d", type); - return -1; - } - -#ifdef EAP_TNC - if (type == EAP_TYPE_TNC) { - data->phase2_type.vendor = EAP_VENDOR_IETF; - data->phase2_type.method = EAP_TYPE_TNC; - wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP " - "vendor %d method %d for TNC", - data->phase2_type.vendor, - data->phase2_type.method); - return 0; - } -#endif /* EAP_TNC */ - - for (i = 0; i < data->num_phase2_types; i++) { - if (data->phase2_types[i].vendor != EAP_VENDOR_IETF || - data->phase2_types[i].method != type) - continue; - - data->phase2_type.vendor = data->phase2_types[i].vendor; - data->phase2_type.method = data->phase2_types[i].method; - wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP " - "vendor %d method %d", - data->phase2_type.vendor, - data->phase2_type.method); - break; - } - - if (type != data->phase2_type.method || type == EAP_TYPE_NONE) - return -1; - - return 0; -} - - -static int eap_fast_phase2_request(struct eap_sm *sm, - struct eap_fast_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, - struct wpabuf **resp) -{ - size_t len = be_to_host16(hdr->length); - u8 *pos; - struct eap_method_ret iret; - struct eap_peer_config *config = eap_get_config(sm); - struct wpabuf msg; - - if (len <= sizeof(struct eap_hdr)) { - wpa_printf(MSG_INFO, "EAP-FAST: too short " - "Phase 2 request (len=%lu)", (unsigned long) len); - return -1; - } - pos = (u8 *) (hdr + 1); - wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos); - if (*pos == EAP_TYPE_IDENTITY) { - *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); - return 0; - } - - if (data->phase2_priv && data->phase2_method && - *pos != data->phase2_type.method) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - " - "deinitialize previous method"); - data->phase2_method->deinit(sm, data->phase2_priv); - data->phase2_method = NULL; - data->phase2_priv = NULL; - data->phase2_type.vendor = EAP_VENDOR_IETF; - data->phase2_type.method = EAP_TYPE_NONE; - } - - if (data->phase2_type.vendor == EAP_VENDOR_IETF && - data->phase2_type.method == EAP_TYPE_NONE && - eap_fast_select_phase2_method(data, *pos) < 0) { - if (eap_peer_tls_phase2_nak(data->phase2_types, - data->num_phase2_types, - hdr, resp)) - return -1; - return 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; - ret->decision = DECISION_FAIL; - return -1; - } - - os_memset(&iret, 0, sizeof(iret)); - wpabuf_set(&msg, hdr, len); - *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, - &msg); - if (*resp == NULL || - (iret.methodState == METHOD_DONE && - iret.decision == DECISION_FAIL)) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - } else if ((iret.methodState == METHOD_DONE || - iret.methodState == METHOD_MAY_CONT) && - (iret.decision == DECISION_UNCOND_SUCC || - iret.decision == DECISION_COND_SUCC)) { - data->phase2_success = 1; - } - - if (*resp == NULL && config && - (config->pending_req_identity || config->pending_req_password || - config->pending_req_otp || config->pending_req_new_password)) { - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = wpabuf_alloc_copy(hdr, len); - } else if (*resp == NULL) - return -1; - - return 0; -} - - -static struct wpabuf * eap_fast_tlv_nak(int vendor_id, int tlv_type) -{ - struct wpabuf *buf; - struct eap_tlv_nak_tlv *nak; - buf = wpabuf_alloc(sizeof(*nak)); - if (buf == NULL) - return NULL; - nak = wpabuf_put(buf, sizeof(*nak)); - nak->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_NAK_TLV); - nak->length = host_to_be16(6); - nak->vendor_id = host_to_be32(vendor_id); - nak->nak_type = host_to_be16(tlv_type); - return buf; -} - - -static struct wpabuf * eap_fast_tlv_result(int status, int intermediate) -{ - struct wpabuf *buf; - struct eap_tlv_intermediate_result_tlv *result; - buf = wpabuf_alloc(sizeof(*result)); - if (buf == NULL) - return NULL; - wpa_printf(MSG_DEBUG, "EAP-FAST: Add %sResult TLV(status=%d)", - intermediate ? "Intermediate " : "", status); - result = wpabuf_put(buf, sizeof(*result)); - result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | - (intermediate ? - EAP_TLV_INTERMEDIATE_RESULT_TLV : - EAP_TLV_RESULT_TLV)); - result->length = host_to_be16(2); - result->status = host_to_be16(status); - return buf; -} - - -static struct wpabuf * eap_fast_tlv_pac_ack(void) -{ - struct wpabuf *buf; - struct eap_tlv_result_tlv *res; - struct eap_tlv_pac_ack_tlv *ack; - - buf = wpabuf_alloc(sizeof(*res) + sizeof(*ack)); - if (buf == NULL) - return NULL; - - wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV (ack)"); - ack = wpabuf_put(buf, sizeof(*ack)); - ack->tlv_type = host_to_be16(EAP_TLV_PAC_TLV | - EAP_TLV_TYPE_MANDATORY); - ack->length = host_to_be16(sizeof(*ack) - sizeof(struct eap_tlv_hdr)); - ack->pac_type = host_to_be16(PAC_TYPE_PAC_ACKNOWLEDGEMENT); - ack->pac_len = host_to_be16(2); - ack->result = host_to_be16(EAP_TLV_RESULT_SUCCESS); - - return buf; -} - - -static struct wpabuf * eap_fast_process_eap_payload_tlv( - struct eap_sm *sm, struct eap_fast_data *data, - struct eap_method_ret *ret, - u8 *eap_payload_tlv, size_t eap_payload_tlv_len) -{ - struct eap_hdr *hdr; - struct wpabuf *resp = NULL; - - if (eap_payload_tlv_len < sizeof(*hdr)) { - wpa_printf(MSG_DEBUG, "EAP-FAST: too short EAP " - "Payload TLV (len=%lu)", - (unsigned long) eap_payload_tlv_len); - return NULL; - } - - hdr = (struct eap_hdr *) eap_payload_tlv; - if (be_to_host16(hdr->length) > eap_payload_tlv_len) { - wpa_printf(MSG_DEBUG, "EAP-FAST: EAP packet overflow in " - "EAP Payload TLV"); - return NULL; - } - - if (hdr->code != EAP_CODE_REQUEST) { - wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in " - "Phase 2 EAP header", hdr->code); - return NULL; - } - - if (eap_fast_phase2_request(sm, data, ret, hdr, &resp)) { - wpa_printf(MSG_INFO, "EAP-FAST: Phase2 Request processing " - "failed"); - return NULL; - } - - return eap_fast_tlv_eap_payload(resp); -} - - -static int eap_fast_validate_crypto_binding( - struct eap_tlv_crypto_binding_tlv *_bind) -{ - wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV: Version %d " - "Received Version %d SubType %d", - _bind->version, _bind->received_version, _bind->subtype); - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", - _bind->nonce, sizeof(_bind->nonce)); - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", - _bind->compound_mac, sizeof(_bind->compound_mac)); - - if (_bind->version != EAP_FAST_VERSION || - _bind->received_version != EAP_FAST_VERSION || - _bind->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST) { - wpa_printf(MSG_INFO, "EAP-FAST: Invalid version/subtype in " - "Crypto-Binding TLV: Version %d " - "Received Version %d SubType %d", - _bind->version, _bind->received_version, - _bind->subtype); - return -1; - } - - return 0; -} - - -static void eap_fast_write_crypto_binding( - struct eap_tlv_crypto_binding_tlv *rbind, - struct eap_tlv_crypto_binding_tlv *_bind, const u8 *cmk) -{ - rbind->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | - EAP_TLV_CRYPTO_BINDING_TLV); - rbind->length = host_to_be16(sizeof(*rbind) - - sizeof(struct eap_tlv_hdr)); - rbind->version = EAP_FAST_VERSION; - rbind->received_version = _bind->version; - rbind->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE; - os_memcpy(rbind->nonce, _bind->nonce, sizeof(_bind->nonce)); - inc_byte_array(rbind->nonce, sizeof(rbind->nonce)); - hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) rbind, sizeof(*rbind), - rbind->compound_mac); - - wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: Version %d " - "Received Version %d SubType %d", - rbind->version, rbind->received_version, rbind->subtype); - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", - rbind->nonce, sizeof(rbind->nonce)); - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", - rbind->compound_mac, sizeof(rbind->compound_mac)); -} - - -static int eap_fast_get_phase2_key(struct eap_sm *sm, - struct eap_fast_data *data, - u8 *isk, size_t isk_len) -{ - u8 *key; - size_t key_len; - - os_memset(isk, 0, isk_len); - - if (data->phase2_method == NULL || data->phase2_priv == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not " - "available"); - return -1; - } - - if (data->phase2_method->isKeyAvailable == NULL || - data->phase2_method->getKey == NULL) - return 0; - - if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) || - (key = data->phase2_method->getKey(sm, data->phase2_priv, - &key_len)) == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material " - "from Phase 2"); - return -1; - } - - if (key_len > isk_len) - key_len = isk_len; - if (key_len == 32 && - data->phase2_method->vendor == EAP_VENDOR_IETF && - data->phase2_method->method == EAP_TYPE_MSCHAPV2) { - /* - * EAP-FAST uses reverse order for MS-MPPE keys when deriving - * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct - * ISK for EAP-FAST cryptobinding. - */ - os_memcpy(isk, key + 16, 16); - os_memcpy(isk + 16, key, 16); - } else - os_memcpy(isk, key, key_len); - os_free(key); - - return 0; -} - - -static int eap_fast_get_cmk(struct eap_sm *sm, struct eap_fast_data *data, - u8 *cmk) -{ - u8 isk[32], imck[60]; - - wpa_printf(MSG_DEBUG, "EAP-FAST: Determining CMK[%d] for Compound MIC " - "calculation", data->simck_idx + 1); - - /* - * RFC 4851, Section 5.2: - * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys", - * MSK[j], 60) - * S-IMCK[j] = first 40 octets of IMCK[j] - * CMK[j] = last 20 octets of IMCK[j] - */ - - if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0) - return -1; - wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk)); - sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN, - "Inner Methods Compound Keys", - isk, sizeof(isk), imck, sizeof(imck)); - data->simck_idx++; - os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN); - wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]", - data->simck, EAP_FAST_SIMCK_LEN); - os_memcpy(cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN); - wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", - cmk, EAP_FAST_CMK_LEN); - - return 0; -} - - -static u8 * eap_fast_write_pac_request(u8 *pos, u16 pac_type) -{ - struct eap_tlv_hdr *pac; - struct eap_tlv_request_action_tlv *act; - struct eap_tlv_pac_type_tlv *type; - - act = (struct eap_tlv_request_action_tlv *) pos; - act->tlv_type = host_to_be16(EAP_TLV_REQUEST_ACTION_TLV); - act->length = host_to_be16(2); - act->action = host_to_be16(EAP_TLV_ACTION_PROCESS_TLV); - - pac = (struct eap_tlv_hdr *) (act + 1); - pac->tlv_type = host_to_be16(EAP_TLV_PAC_TLV); - pac->length = host_to_be16(sizeof(*type)); - - type = (struct eap_tlv_pac_type_tlv *) (pac + 1); - type->tlv_type = host_to_be16(PAC_TYPE_PAC_TYPE); - type->length = host_to_be16(2); - type->pac_type = host_to_be16(pac_type); - - return (u8 *) (type + 1); -} - - -static struct wpabuf * eap_fast_process_crypto_binding( - struct eap_sm *sm, struct eap_fast_data *data, - struct eap_method_ret *ret, - struct eap_tlv_crypto_binding_tlv *_bind, size_t bind_len) -{ - struct wpabuf *resp; - u8 *pos; - u8 cmk[EAP_FAST_CMK_LEN], cmac[SHA1_MAC_LEN]; - int res; - size_t len; - - if (eap_fast_validate_crypto_binding(_bind) < 0) - return NULL; - - if (eap_fast_get_cmk(sm, data, cmk) < 0) - return NULL; - - /* Validate received Compound MAC */ - os_memcpy(cmac, _bind->compound_mac, sizeof(cmac)); - os_memset(_bind->compound_mac, 0, sizeof(cmac)); - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for Compound " - "MAC calculation", (u8 *) _bind, bind_len); - hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) _bind, bind_len, - _bind->compound_mac); - res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac)); - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC", - cmac, sizeof(cmac)); - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC", - _bind->compound_mac, sizeof(cmac)); - if (res != 0) { - wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match"); - os_memcpy(_bind->compound_mac, cmac, sizeof(cmac)); - return NULL; - } - - /* - * Compound MAC was valid, so authentication succeeded. Reply with - * crypto binding to allow server to complete authentication. - */ - - len = sizeof(struct eap_tlv_crypto_binding_tlv); - resp = wpabuf_alloc(len); - if (resp == NULL) - return NULL; - - if (!data->anon_provisioning && data->phase2_success && - eap_fast_derive_msk(data) < 0) { - wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - data->phase2_success = 0; - wpabuf_free(resp); - return NULL; - } - - if (!data->anon_provisioning && data->phase2_success) { - os_free(data->session_id); - data->session_id = eap_peer_tls_derive_session_id( - sm, &data->ssl, EAP_TYPE_FAST, &data->id_len); - if (data->session_id) { - wpa_hexdump(MSG_DEBUG, "EAP-FAST: Derived Session-Id", - data->session_id, data->id_len); - } else { - wpa_printf(MSG_ERROR, "EAP-FAST: Failed to derive " - "Session-Id"); - wpabuf_free(resp); - return NULL; - } - } - - pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv)); - eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *) - pos, _bind, cmk); - - return resp; -} - - -static void eap_fast_parse_pac_tlv(struct eap_fast_pac *entry, int type, - u8 *pos, size_t len, int *pac_key_found) -{ - switch (type & 0x7fff) { - case PAC_TYPE_PAC_KEY: - wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key", pos, len); - if (len != EAP_FAST_PAC_KEY_LEN) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid PAC-Key " - "length %lu", (unsigned long) len); - break; - } - *pac_key_found = 1; - os_memcpy(entry->pac_key, pos, len); - break; - case PAC_TYPE_PAC_OPAQUE: - wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque", pos, len); - entry->pac_opaque = pos; - entry->pac_opaque_len = len; - break; - case PAC_TYPE_PAC_INFO: - wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info", pos, len); - entry->pac_info = pos; - entry->pac_info_len = len; - break; - default: - wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC type %d", - type); - break; - } -} - - -static int eap_fast_process_pac_tlv(struct eap_fast_pac *entry, - u8 *pac, size_t pac_len) -{ - struct pac_tlv_hdr *hdr; - u8 *pos; - size_t left, len; - int type, pac_key_found = 0; - - pos = pac; - left = pac_len; - - while (left > sizeof(*hdr)) { - hdr = (struct pac_tlv_hdr *) pos; - type = be_to_host16(hdr->type); - len = be_to_host16(hdr->len); - pos += sizeof(*hdr); - left -= sizeof(*hdr); - if (len > left) { - wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV overrun " - "(type=%d len=%lu left=%lu)", - type, (unsigned long) len, - (unsigned long) left); - return -1; - } - - eap_fast_parse_pac_tlv(entry, type, pos, len, &pac_key_found); - - pos += len; - left -= len; - } - - if (!pac_key_found || !entry->pac_opaque || !entry->pac_info) { - wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV does not include " - "all the required fields"); - return -1; - } - - return 0; -} - - -static int eap_fast_parse_pac_info(struct eap_fast_pac *entry, int type, - u8 *pos, size_t len) -{ - u16 pac_type; - u32 lifetime; - struct os_time now; - - switch (type & 0x7fff) { - case PAC_TYPE_CRED_LIFETIME: - if (len != 4) { - wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info - " - "Invalid CRED_LIFETIME length - ignored", - pos, len); - return 0; - } - - /* - * This is not currently saved separately in PAC files since - * the server can automatically initiate PAC update when - * needed. Anyway, the information is available from PAC-Info - * dump if it is needed for something in the future. - */ - lifetime = WPA_GET_BE32(pos); - os_get_time(&now); - wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info - CRED_LIFETIME %d " - "(%d days)", - lifetime, (lifetime - (u32) now.sec) / 86400); - break; - case PAC_TYPE_A_ID: - wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - A-ID", - pos, len); - entry->a_id = pos; - entry->a_id_len = len; - break; - case PAC_TYPE_I_ID: - wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - I-ID", - pos, len); - entry->i_id = pos; - entry->i_id_len = len; - break; - case PAC_TYPE_A_ID_INFO: - wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - A-ID-Info", - pos, len); - entry->a_id_info = pos; - entry->a_id_info_len = len; - break; - case PAC_TYPE_PAC_TYPE: - /* RFC 5422, Section 4.2.6 - PAC-Type TLV */ - if (len != 2) { - wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC-Type " - "length %lu (expected 2)", - (unsigned long) len); - wpa_hexdump_ascii(MSG_DEBUG, - "EAP-FAST: PAC-Info - PAC-Type", - pos, len); - return -1; - } - pac_type = WPA_GET_BE16(pos); - if (pac_type != PAC_TYPE_TUNNEL_PAC && - pac_type != PAC_TYPE_USER_AUTHORIZATION && - pac_type != PAC_TYPE_MACHINE_AUTHENTICATION) { - wpa_printf(MSG_INFO, "EAP-FAST: Unsupported PAC Type " - "%d", pac_type); - return -1; - } - - wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info - PAC-Type %d", - pac_type); - entry->pac_type = pac_type; - break; - default: - wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC-Info " - "type %d", type); - break; - } - - return 0; -} - - -static int eap_fast_process_pac_info(struct eap_fast_pac *entry) -{ - struct pac_tlv_hdr *hdr; - u8 *pos; - size_t left, len; - int type; - - /* RFC 5422, Section 4.2.4 */ - - /* PAC-Type defaults to Tunnel PAC (Type 1) */ - entry->pac_type = PAC_TYPE_TUNNEL_PAC; - - pos = entry->pac_info; - left = entry->pac_info_len; - while (left > sizeof(*hdr)) { - hdr = (struct pac_tlv_hdr *) pos; - type = be_to_host16(hdr->type); - len = be_to_host16(hdr->len); - pos += sizeof(*hdr); - left -= sizeof(*hdr); - if (len > left) { - wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info overrun " - "(type=%d len=%lu left=%lu)", - type, (unsigned long) len, - (unsigned long) left); - return -1; - } - - if (eap_fast_parse_pac_info(entry, type, pos, len) < 0) - return -1; - - pos += len; - left -= len; - } - - if (entry->a_id == NULL || entry->a_id_info == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info does not include " - "all the required fields"); - return -1; - } - - return 0; -} - - -static struct wpabuf * eap_fast_process_pac(struct eap_sm *sm, - struct eap_fast_data *data, - struct eap_method_ret *ret, - u8 *pac, size_t pac_len) -{ - struct eap_peer_config *config = eap_get_config(sm); - struct eap_fast_pac entry; - - os_memset(&entry, 0, sizeof(entry)); - if (eap_fast_process_pac_tlv(&entry, pac, pac_len) || - eap_fast_process_pac_info(&entry)) - return NULL; - - eap_fast_add_pac(&data->pac, &data->current_pac, &entry); - eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len); - if (data->use_pac_binary_format) - eap_fast_save_pac_bin(sm, data->pac, config->pac_file); - else - eap_fast_save_pac(sm, data->pac, config->pac_file); - - if (data->provisioning) { - if (data->anon_provisioning) { - /* - * Unauthenticated provisioning does not provide keying - * material and must end with an EAP-Failure. - * Authentication will be done separately after this. - */ - data->success = 0; - ret->decision = DECISION_FAIL; - } else { - /* - * Server may or may not allow authenticated - * provisioning also for key generation. - */ - ret->decision = DECISION_COND_SUCC; - } - wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV " - "- Provisioning completed successfully"); - sm->expected_failure = 1; - } else { - /* - * This is PAC refreshing, i.e., normal authentication that is - * 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_COND_SUCC; - } - ret->methodState = METHOD_DONE; - return eap_fast_tlv_pac_ack(); -} - - -static int eap_fast_parse_decrypted(struct wpabuf *decrypted, - struct eap_fast_tlv_parse *tlv, - struct wpabuf **resp) -{ - int mandatory, tlv_type, len, res; - u8 *pos, *end; - - os_memset(tlv, 0, sizeof(*tlv)); - - /* Parse TLVs from the decrypted Phase 2 data */ - pos = wpabuf_mhead(decrypted); - end = pos + wpabuf_len(decrypted); - while (pos + 4 < end) { - mandatory = pos[0] & 0x80; - tlv_type = WPA_GET_BE16(pos) & 0x3fff; - pos += 2; - len = WPA_GET_BE16(pos); - pos += 2; - if (pos + len > end) { - wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow"); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: " - "TLV type %d length %d%s", - tlv_type, len, mandatory ? " (mandatory)" : ""); - - res = eap_fast_parse_tlv(tlv, tlv_type, pos, len); - if (res == -2) - break; - if (res < 0) { - if (mandatory) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown " - "mandatory TLV type %d", tlv_type); - *resp = eap_fast_tlv_nak(0, tlv_type); - break; - } else { - wpa_printf(MSG_DEBUG, "EAP-FAST: ignored " - "unknown optional TLV type %d", - tlv_type); - } - } - - pos += len; - } - - return 0; -} - - -static int eap_fast_encrypt_response(struct eap_sm *sm, - struct eap_fast_data *data, - struct wpabuf *resp, - u8 identifier, struct wpabuf **out_data) -{ - if (resp == NULL) - return 0; - - wpa_hexdump_buf(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 data", - resp); - if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_FAST, - data->fast_version, identifier, - resp, out_data)) { - wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 " - "frame"); - } - wpabuf_free(resp); - - return 0; -} - - -static struct wpabuf * eap_fast_pac_request(void) -{ - struct wpabuf *tmp; - u8 *pos, *pos2; - - tmp = wpabuf_alloc(sizeof(struct eap_tlv_hdr) + - sizeof(struct eap_tlv_request_action_tlv) + - sizeof(struct eap_tlv_pac_type_tlv)); - if (tmp == NULL) - return NULL; - - pos = wpabuf_put(tmp, 0); - pos2 = eap_fast_write_pac_request(pos, PAC_TYPE_TUNNEL_PAC); - wpabuf_put(tmp, pos2 - pos); - return tmp; -} - - -static int eap_fast_process_decrypted(struct eap_sm *sm, - struct eap_fast_data *data, - struct eap_method_ret *ret, - const struct eap_hdr *req, - struct wpabuf *decrypted, - struct wpabuf **out_data) -{ - struct wpabuf *resp = NULL, *tmp; - struct eap_fast_tlv_parse tlv; - int failed = 0; - - if (eap_fast_parse_decrypted(decrypted, &tlv, &resp) < 0) - return 0; - if (resp) - return eap_fast_encrypt_response(sm, data, resp, - req->identifier, out_data); - - if (tlv.result == EAP_TLV_RESULT_FAILURE) { - resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0); - return eap_fast_encrypt_response(sm, data, resp, - req->identifier, out_data); - } - - if (tlv.iresult == EAP_TLV_RESULT_FAILURE) { - resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1); - return eap_fast_encrypt_response(sm, data, resp, - req->identifier, out_data); - } - - if (tlv.crypto_binding) { - tmp = eap_fast_process_crypto_binding(sm, data, ret, - tlv.crypto_binding, - tlv.crypto_binding_len); - if (tmp == NULL) - failed = 1; - else - resp = wpabuf_concat(resp, tmp); - } - - if (tlv.iresult == EAP_TLV_RESULT_SUCCESS) { - tmp = eap_fast_tlv_result(failed ? EAP_TLV_RESULT_FAILURE : - EAP_TLV_RESULT_SUCCESS, 1); - resp = wpabuf_concat(resp, tmp); - } - - if (tlv.eap_payload_tlv) { - tmp = eap_fast_process_eap_payload_tlv( - sm, data, ret, tlv.eap_payload_tlv, - tlv.eap_payload_tlv_len); - resp = wpabuf_concat(resp, tmp); - } - - if (tlv.pac && tlv.result != EAP_TLV_RESULT_SUCCESS) { - wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV " - "acknowledging success"); - failed = 1; - } else if (tlv.pac && tlv.result == EAP_TLV_RESULT_SUCCESS) { - tmp = eap_fast_process_pac(sm, data, ret, tlv.pac, - tlv.pac_len); - resp = wpabuf_concat(resp, tmp); - } - - if (data->current_pac == NULL && data->provisioning && - !data->anon_provisioning && !tlv.pac && - (tlv.iresult == EAP_TLV_RESULT_SUCCESS || - tlv.result == EAP_TLV_RESULT_SUCCESS)) { - /* - * Need to request Tunnel PAC when using authenticated - * provisioning. - */ - wpa_printf(MSG_DEBUG, "EAP-FAST: Request Tunnel PAC"); - tmp = eap_fast_pac_request(); - resp = wpabuf_concat(resp, tmp); - } - - if (tlv.result == EAP_TLV_RESULT_SUCCESS && !failed) { - tmp = eap_fast_tlv_result(EAP_TLV_RESULT_SUCCESS, 0); - resp = wpabuf_concat(tmp, resp); - } else if (failed) { - tmp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0); - resp = wpabuf_concat(tmp, resp); - } - - if (resp && tlv.result == EAP_TLV_RESULT_SUCCESS && !failed && - tlv.crypto_binding && data->phase2_success) { - if (data->anon_provisioning) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Unauthenticated " - "provisioning completed successfully."); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - sm->expected_failure = 1; - } else { - wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication " - "completed successfully."); - if (data->provisioning) - ret->methodState = METHOD_MAY_CONT; - else - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - } - } - - if (resp == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send " - "empty response packet"); - resp = wpabuf_alloc(1); - } - - return eap_fast_encrypt_response(sm, data, resp, req->identifier, - out_data); -} - - -static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data, - struct eap_method_ret *ret, - const struct eap_hdr *req, - const struct wpabuf *in_data, - struct wpabuf **out_data) -{ - struct wpabuf *in_decrypted; - int res; - - wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for" - " Phase 2", (unsigned long) wpabuf_len(in_data)); - - if (data->pending_phase2_req) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Pending Phase 2 request - " - "skip decryption and use old data"); - /* Clear TLS reassembly state. */ - eap_peer_tls_reset_input(&data->ssl); - - in_decrypted = data->pending_phase2_req; - data->pending_phase2_req = NULL; - goto continue_req; - } - - if (wpabuf_len(in_data) == 0) { - /* Received TLS ACK - requesting more fragments */ - return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_FAST, - data->fast_version, - req->identifier, NULL, out_data); - } - - res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); - if (res) - return res; - -continue_req: - wpa_hexdump_buf(MSG_MSGDUMP, "EAP-FAST: Decrypted Phase 2 TLV(s)", - in_decrypted); - - if (wpabuf_len(in_decrypted) < 4) { - wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 " - "TLV frame (len=%lu)", - (unsigned long) wpabuf_len(in_decrypted)); - wpabuf_free(in_decrypted); - return -1; - } - - res = eap_fast_process_decrypted(sm, data, ret, req, - in_decrypted, out_data); - - wpabuf_free(in_decrypted); - - return res; -} - - -static const u8 * eap_fast_get_a_id(const u8 *buf, size_t len, size_t *id_len) -{ - const u8 *a_id; - struct pac_tlv_hdr *hdr; - - /* - * Parse authority identity (A-ID) from the EAP-FAST/Start. This - * supports both raw A-ID and one inside an A-ID TLV. - */ - a_id = buf; - *id_len = len; - if (len > sizeof(*hdr)) { - int tlen; - hdr = (struct pac_tlv_hdr *) buf; - tlen = be_to_host16(hdr->len); - if (be_to_host16(hdr->type) == PAC_TYPE_A_ID && - sizeof(*hdr) + tlen <= len) { - wpa_printf(MSG_DEBUG, "EAP-FAST: A-ID was in TLV " - "(Start)"); - a_id = (u8 *) (hdr + 1); - *id_len = tlen; - } - } - wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: A-ID", a_id, *id_len); - - return a_id; -} - - -static void eap_fast_select_pac(struct eap_fast_data *data, - const u8 *a_id, size_t a_id_len) -{ - data->current_pac = eap_fast_get_pac(data->pac, a_id, a_id_len, - PAC_TYPE_TUNNEL_PAC); - if (data->current_pac == NULL) { - /* - * Tunnel PAC was not available for this A-ID. Try to use - * Machine Authentication PAC, if one is available. - */ - data->current_pac = eap_fast_get_pac( - data->pac, a_id, a_id_len, - PAC_TYPE_MACHINE_AUTHENTICATION); - } - - if (data->current_pac) { - wpa_printf(MSG_DEBUG, "EAP-FAST: PAC found for this A-ID " - "(PAC-Type %d)", data->current_pac->pac_type); - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-FAST: A-ID-Info", - data->current_pac->a_id_info, - data->current_pac->a_id_info_len); - } -} - - -static int eap_fast_use_pac_opaque(struct eap_sm *sm, - struct eap_fast_data *data, - struct eap_fast_pac *pac) -{ - u8 *tlv; - size_t tlv_len, olen; - struct eap_tlv_hdr *ehdr; - - olen = pac->pac_opaque_len; - tlv_len = sizeof(*ehdr) + olen; - tlv = os_malloc(tlv_len); - if (tlv) { - ehdr = (struct eap_tlv_hdr *) tlv; - ehdr->tlv_type = host_to_be16(PAC_TYPE_PAC_OPAQUE); - ehdr->length = host_to_be16(olen); - os_memcpy(ehdr + 1, pac->pac_opaque, olen); - } - if (tlv == NULL || - tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn, - TLS_EXT_PAC_OPAQUE, - tlv, tlv_len) < 0) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to add PAC-Opaque TLS " - "extension"); - os_free(tlv); - return -1; - } - os_free(tlv); - - return 0; -} - - -static int eap_fast_clear_pac_opaque_ext(struct eap_sm *sm, - struct eap_fast_data *data) -{ - if (tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn, - TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to remove PAC-Opaque " - "TLS extension"); - return -1; - } - return 0; -} - - -static int eap_fast_set_provisioning_ciphers(struct eap_sm *sm, - struct eap_fast_data *data) -{ - u8 ciphers[5]; - int count = 0; - - if (data->provisioning_allowed & EAP_FAST_PROV_UNAUTH) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Enabling unauthenticated " - "provisioning TLS cipher suites"); - ciphers[count++] = TLS_CIPHER_ANON_DH_AES128_SHA; - } - - if (data->provisioning_allowed & EAP_FAST_PROV_AUTH) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Enabling authenticated " - "provisioning TLS cipher suites"); - ciphers[count++] = TLS_CIPHER_RSA_DHE_AES128_SHA; - ciphers[count++] = TLS_CIPHER_AES128_SHA; - ciphers[count++] = TLS_CIPHER_RC4_SHA; - } - - ciphers[count++] = TLS_CIPHER_NONE; - - if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn, - ciphers)) { - wpa_printf(MSG_INFO, "EAP-FAST: Could not configure TLS " - "cipher suites for provisioning"); - return -1; - } - - return 0; -} - - -static int eap_fast_process_start(struct eap_sm *sm, - struct eap_fast_data *data, u8 flags, - const u8 *pos, size_t left) -{ - const u8 *a_id; - size_t a_id_len; - - /* EAP-FAST Version negotiation (section 3.1) */ - wpa_printf(MSG_DEBUG, "EAP-FAST: Start (server ver=%d, own ver=%d)", - flags & EAP_TLS_VERSION_MASK, data->fast_version); - if ((flags & EAP_TLS_VERSION_MASK) < data->fast_version) - data->fast_version = flags & EAP_TLS_VERSION_MASK; - wpa_printf(MSG_DEBUG, "EAP-FAST: Using FAST version %d", - data->fast_version); - - a_id = eap_fast_get_a_id(pos, left, &a_id_len); - eap_fast_select_pac(data, a_id, a_id_len); - - if (data->resuming && data->current_pac) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Trying to resume session - " - "do not add PAC-Opaque to TLS ClientHello"); - if (eap_fast_clear_pac_opaque_ext(sm, data) < 0) - return -1; - } else if (data->current_pac) { - /* - * PAC found for the A-ID and we are not resuming an old - * session, so add PAC-Opaque extension to ClientHello. - */ - if (eap_fast_use_pac_opaque(sm, data, data->current_pac) < 0) - return -1; - } else { - /* No PAC found, so we must provision one. */ - if (!data->provisioning_allowed) { - wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found and " - "provisioning disabled"); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found - " - "starting provisioning"); - if (eap_fast_set_provisioning_ciphers(sm, data) < 0 || - eap_fast_clear_pac_opaque_ext(sm, data) < 0) - return -1; - data->provisioning = 1; - } - - return 0; -} - - -static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - const struct eap_hdr *req; - size_t left; - int res; - u8 flags, id; - struct wpabuf *resp; - const u8 *pos; - struct eap_fast_data *data = priv; - - pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_FAST, ret, - reqData, &left, &flags); - if (pos == NULL) - return NULL; - - req = wpabuf_head(reqData); - id = req->identifier; - - if (flags & EAP_TLS_FLAGS_START) { - if (eap_fast_process_start(sm, data, flags, pos, left) < 0) - return NULL; - - left = 0; /* A-ID is not used in further packet processing */ - } - - resp = NULL; - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && - !data->resuming) { - /* Process tunneled (encrypted) phase 2 data. */ - struct wpabuf msg; - wpabuf_set(&msg, pos, left); - res = eap_fast_decrypt(sm, data, ret, req, &msg, &resp); - if (res < 0) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - /* - * Ack possible Alert that may have caused failure in - * decryption. - */ - res = 1; - } - } else { - /* Continue processing TLS handshake (phase 1). */ - res = eap_peer_tls_process_helper(sm, &data->ssl, - EAP_TYPE_FAST, - data->fast_version, id, pos, - left, &resp); - - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { - char cipher[80]; - wpa_printf(MSG_DEBUG, - "EAP-FAST: TLS done, proceed to Phase 2"); - if (data->provisioning && - (!(data->provisioning_allowed & - EAP_FAST_PROV_AUTH) || - tls_get_cipher(sm->ssl_ctx, data->ssl.conn, - cipher, sizeof(cipher)) < 0 || - os_strstr(cipher, "ADH-") || - os_strstr(cipher, "anon"))) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Using " - "anonymous (unauthenticated) " - "provisioning"); - data->anon_provisioning = 1; - } else - data->anon_provisioning = 0; - data->resuming = 0; - eap_fast_derive_keys(sm, data); - } - - if (res == 2) { - struct wpabuf msg; - /* - * Application data included in the handshake message. - */ - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = resp; - resp = NULL; - wpabuf_set(&msg, pos, left); - res = eap_fast_decrypt(sm, data, ret, req, &msg, - &resp); - } - } - - if (res == 1) { - wpabuf_free(resp); - return eap_peer_tls_build_ack(id, EAP_TYPE_FAST, - data->fast_version); - } - - return resp; -} - - -#if 0 /* FIX */ -static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv) -{ - struct eap_fast_data *data = priv; - return tls_connection_established(sm->ssl_ctx, data->ssl.conn); -} - - -static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_fast_data *data = priv; - os_free(data->key_block_p); - data->key_block_p = NULL; - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = NULL; -} - - -static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_fast_data *data = priv; - if (eap_peer_tls_reauth_init(sm, &data->ssl)) { - os_free(data); - return NULL; - } - os_free(data->session_id); - data->session_id = NULL; - if (data->phase2_priv && data->phase2_method && - data->phase2_method->init_for_reauth) - data->phase2_method->init_for_reauth(sm, data->phase2_priv); - data->phase2_success = 0; - data->resuming = 1; - data->provisioning = 0; - data->anon_provisioning = 0; - data->simck_idx = 0; - return priv; -} -#endif - - -static int eap_fast_get_status(struct eap_sm *sm, void *priv, char *buf, - size_t buflen, int verbose) -{ - struct eap_fast_data *data = priv; - int len, ret; - - len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); - if (data->phase2_method) { - ret = os_snprintf(buf + len, buflen - len, - "EAP-FAST Phase2 method=%s\n", - data->phase2_method->name); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - } - return len; -} - - -static Boolean eap_fast_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_fast_data *data = priv; - return data->success; -} - - -static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_fast_data *data = priv; - u8 *key; - - if (!data->success) - return NULL; - - key = os_malloc(EAP_FAST_KEY_LEN); - if (key == NULL) - return NULL; - - *len = EAP_FAST_KEY_LEN; - os_memcpy(key, data->key_data, EAP_FAST_KEY_LEN); - - return key; -} - - -static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_fast_data *data = priv; - u8 *id; - - if (!data->success) - return NULL; - - id = os_malloc(data->id_len); - if (id == NULL) - return NULL; - - *len = data->id_len; - os_memcpy(id, data->session_id, data->id_len); - - return id; -} - - -static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_fast_data *data = priv; - u8 *key; - - if (!data->success) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - - *len = EAP_EMSK_LEN; - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - - return key; -} - - -int eap_peer_fast_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST"); - if (eap == NULL) - return -1; - - eap->init = eap_fast_init; - eap->deinit = eap_fast_deinit; - eap->process = eap_fast_process; - eap->isKeyAvailable = eap_fast_isKeyAvailable; - eap->getKey = eap_fast_getKey; - eap->getSessionId = eap_fast_get_session_id; - eap->get_status = eap_fast_get_status; -#if 0 - eap->has_reauth_data = eap_fast_has_reauth_data; - eap->deinit_for_reauth = eap_fast_deinit_for_reauth; - eap->init_for_reauth = eap_fast_init_for_reauth; -#endif - eap->get_emsk = eap_fast_get_emsk; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_fast_pac.c b/contrib/hostapd/src/eap_peer/eap_fast_pac.c deleted file mode 100644 index 8c480b9679..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_fast_pac.c +++ /dev/null @@ -1,921 +0,0 @@ -/* - * EAP peer method: EAP-FAST PAC file processing - * Copyright (c) 2004-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_config.h" -#include "eap_i.h" -#include "eap_fast_pac.h" - -/* TODO: encrypt PAC-Key in the PAC file */ - - -/* Text data format */ -static const char *pac_file_hdr = - "wpa_supplicant EAP-FAST PAC file - version 1"; - -/* - * Binary data format - * 4-octet magic value: 6A E4 92 0C - * 2-octet version (big endian) - * - * - * version=0: - * Sequence of PAC entries: - * 2-octet PAC-Type (big endian) - * 32-octet PAC-Key - * 2-octet PAC-Opaque length (big endian) - * PAC-Opaque data (length bytes) - * 2-octet PAC-Info length (big endian) - * PAC-Info data (length bytes) - */ - -#define EAP_FAST_PAC_BINARY_MAGIC 0x6ae4920c -#define EAP_FAST_PAC_BINARY_FORMAT_VERSION 0 - - -/** - * eap_fast_free_pac - Free PAC data - * @pac: Pointer to the PAC entry - * - * Note that the PAC entry must not be in a list since this function does not - * remove the list links. - */ -void eap_fast_free_pac(struct eap_fast_pac *pac) -{ - os_free(pac->pac_opaque); - os_free(pac->pac_info); - os_free(pac->a_id); - os_free(pac->i_id); - os_free(pac->a_id_info); - os_free(pac); -} - - -/** - * eap_fast_get_pac - Get a PAC entry based on A-ID - * @pac_root: Pointer to root of the PAC list - * @a_id: A-ID to search for - * @a_id_len: Length of A-ID - * @pac_type: PAC-Type to search for - * Returns: Pointer to the PAC entry, or %NULL if A-ID not found - */ -struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_pac *pac_root, - const u8 *a_id, size_t a_id_len, - u16 pac_type) -{ - struct eap_fast_pac *pac = pac_root; - - while (pac) { - if (pac->pac_type == pac_type && pac->a_id_len == a_id_len && - os_memcmp(pac->a_id, a_id, a_id_len) == 0) { - return pac; - } - pac = pac->next; - } - return NULL; -} - - -static void eap_fast_remove_pac(struct eap_fast_pac **pac_root, - struct eap_fast_pac **pac_current, - const u8 *a_id, size_t a_id_len, u16 pac_type) -{ - struct eap_fast_pac *pac, *prev; - - pac = *pac_root; - prev = NULL; - - while (pac) { - if (pac->pac_type == pac_type && pac->a_id_len == a_id_len && - os_memcmp(pac->a_id, a_id, a_id_len) == 0) { - if (prev == NULL) - *pac_root = pac->next; - else - prev->next = pac->next; - if (*pac_current == pac) - *pac_current = NULL; - eap_fast_free_pac(pac); - break; - } - prev = pac; - pac = pac->next; - } -} - - -static int eap_fast_copy_buf(u8 **dst, size_t *dst_len, - const u8 *src, size_t src_len) -{ - if (src) { - *dst = os_malloc(src_len); - if (*dst == NULL) - return -1; - os_memcpy(*dst, src, src_len); - *dst_len = src_len; - } - return 0; -} - - -/** - * eap_fast_add_pac - Add a copy of a PAC entry to a list - * @pac_root: Pointer to PAC list root pointer - * @pac_current: Pointer to the current PAC pointer - * @entry: New entry to clone and add to the list - * Returns: 0 on success, -1 on failure - * - * This function makes a clone of the given PAC entry and adds this copied - * entry to the list (pac_root). If an old entry for the same A-ID is found, - * it will be removed from the PAC list and in this case, pac_current entry - * is set to %NULL if it was the removed entry. - */ -int eap_fast_add_pac(struct eap_fast_pac **pac_root, - struct eap_fast_pac **pac_current, - struct eap_fast_pac *entry) -{ - struct eap_fast_pac *pac; - - if (entry == NULL || entry->a_id == NULL) - return -1; - - /* Remove a possible old entry for the matching A-ID. */ - eap_fast_remove_pac(pac_root, pac_current, - entry->a_id, entry->a_id_len, entry->pac_type); - - /* Allocate a new entry and add it to the list of PACs. */ - pac = os_zalloc(sizeof(*pac)); - if (pac == NULL) - return -1; - - pac->pac_type = entry->pac_type; - os_memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN); - if (eap_fast_copy_buf(&pac->pac_opaque, &pac->pac_opaque_len, - entry->pac_opaque, entry->pac_opaque_len) < 0 || - eap_fast_copy_buf(&pac->pac_info, &pac->pac_info_len, - entry->pac_info, entry->pac_info_len) < 0 || - eap_fast_copy_buf(&pac->a_id, &pac->a_id_len, - entry->a_id, entry->a_id_len) < 0 || - eap_fast_copy_buf(&pac->i_id, &pac->i_id_len, - entry->i_id, entry->i_id_len) < 0 || - eap_fast_copy_buf(&pac->a_id_info, &pac->a_id_info_len, - entry->a_id_info, entry->a_id_info_len) < 0) { - eap_fast_free_pac(pac); - return -1; - } - - pac->next = *pac_root; - *pac_root = pac; - - return 0; -} - - -struct eap_fast_read_ctx { - FILE *f; - const char *pos; - const char *end; - int line; - char *buf; - size_t buf_len; -}; - -static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char **value) -{ - char *pos; - - rc->line++; - if (rc->f) { - if (fgets(rc->buf, rc->buf_len, rc->f) == NULL) - return -1; - } else { - const char *l_end; - size_t len; - if (rc->pos >= rc->end) - return -1; - l_end = rc->pos; - while (l_end < rc->end && *l_end != '\n') - l_end++; - len = l_end - rc->pos; - if (len >= rc->buf_len) - len = rc->buf_len - 1; - os_memcpy(rc->buf, rc->pos, len); - rc->buf[len] = '\0'; - rc->pos = l_end + 1; - } - - rc->buf[rc->buf_len - 1] = '\0'; - pos = rc->buf; - while (*pos != '\0') { - if (*pos == '\n' || *pos == '\r') { - *pos = '\0'; - break; - } - pos++; - } - - pos = os_strchr(rc->buf, '='); - if (pos) - *pos++ = '\0'; - *value = pos; - - return 0; -} - - -static u8 * eap_fast_parse_hex(const char *value, size_t *len) -{ - int hlen; - u8 *buf; - - if (value == NULL) - return NULL; - hlen = os_strlen(value); - if (hlen & 1) - return NULL; - *len = hlen / 2; - buf = os_malloc(*len); - if (buf == NULL) - return NULL; - if (hexstr2bin(value, buf, *len)) { - os_free(buf); - return NULL; - } - return buf; -} - - -static int eap_fast_init_pac_data(struct eap_sm *sm, const char *pac_file, - struct eap_fast_read_ctx *rc) -{ - os_memset(rc, 0, sizeof(*rc)); - - rc->buf_len = 2048; - rc->buf = os_malloc(rc->buf_len); - if (rc->buf == NULL) - return -1; - - if (os_strncmp(pac_file, "blob://", 7) == 0) { - const struct wpa_config_blob *blob; - blob = eap_get_config_blob(sm, pac_file + 7); - if (blob == NULL) { - wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - " - "assume no PAC entries have been " - "provisioned", pac_file + 7); - os_free(rc->buf); - return -1; - } - rc->pos = (char *) blob->data; - rc->end = (char *) blob->data + blob->len; - } else { - rc->f = fopen(pac_file, "rb"); - if (rc->f == NULL) { - wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - " - "assume no PAC entries have been " - "provisioned", pac_file); - os_free(rc->buf); - return -1; - } - } - - return 0; -} - - -static void eap_fast_deinit_pac_data(struct eap_fast_read_ctx *rc) -{ - os_free(rc->buf); - if (rc->f) - fclose(rc->f); -} - - -static const char * eap_fast_parse_start(struct eap_fast_pac **pac) -{ - if (*pac) - return "START line without END"; - - *pac = os_zalloc(sizeof(struct eap_fast_pac)); - if (*pac == NULL) - return "No memory for PAC entry"; - (*pac)->pac_type = PAC_TYPE_TUNNEL_PAC; - return NULL; -} - - -static const char * eap_fast_parse_end(struct eap_fast_pac **pac_root, - struct eap_fast_pac **pac) -{ - if (*pac == NULL) - return "END line without START"; - if (*pac_root) { - struct eap_fast_pac *end = *pac_root; - while (end->next) - end = end->next; - end->next = *pac; - } else - *pac_root = *pac; - - *pac = NULL; - return NULL; -} - - -static const char * eap_fast_parse_pac_type(struct eap_fast_pac *pac, - char *pos) -{ - pac->pac_type = atoi(pos); - if (pac->pac_type != PAC_TYPE_TUNNEL_PAC && - pac->pac_type != PAC_TYPE_USER_AUTHORIZATION && - pac->pac_type != PAC_TYPE_MACHINE_AUTHENTICATION) - return "Unrecognized PAC-Type"; - - return NULL; -} - - -static const char * eap_fast_parse_pac_key(struct eap_fast_pac *pac, char *pos) -{ - u8 *key; - size_t key_len; - - key = eap_fast_parse_hex(pos, &key_len); - if (key == NULL || key_len != EAP_FAST_PAC_KEY_LEN) { - os_free(key); - return "Invalid PAC-Key"; - } - - os_memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN); - os_free(key); - - return NULL; -} - - -static const char * eap_fast_parse_pac_opaque(struct eap_fast_pac *pac, - char *pos) -{ - os_free(pac->pac_opaque); - pac->pac_opaque = eap_fast_parse_hex(pos, &pac->pac_opaque_len); - if (pac->pac_opaque == NULL) - return "Invalid PAC-Opaque"; - return NULL; -} - - -static const char * eap_fast_parse_a_id(struct eap_fast_pac *pac, char *pos) -{ - os_free(pac->a_id); - pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len); - if (pac->a_id == NULL) - return "Invalid A-ID"; - return NULL; -} - - -static const char * eap_fast_parse_i_id(struct eap_fast_pac *pac, char *pos) -{ - os_free(pac->i_id); - pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len); - if (pac->i_id == NULL) - return "Invalid I-ID"; - return NULL; -} - - -static const char * eap_fast_parse_a_id_info(struct eap_fast_pac *pac, - char *pos) -{ - os_free(pac->a_id_info); - pac->a_id_info = eap_fast_parse_hex(pos, &pac->a_id_info_len); - if (pac->a_id_info == NULL) - return "Invalid A-ID-Info"; - return NULL; -} - - -/** - * eap_fast_load_pac - Load PAC entries (text format) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @pac_root: Pointer to root of the PAC list (to be filled) - * @pac_file: Name of the PAC file/blob to load - * Returns: 0 on success, -1 on failure - */ -int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root, - const char *pac_file) -{ - struct eap_fast_read_ctx rc; - struct eap_fast_pac *pac = NULL; - int count = 0; - char *pos; - const char *err = NULL; - - if (pac_file == NULL) - return -1; - - if (eap_fast_init_pac_data(sm, pac_file, &rc) < 0) - return 0; - - if (eap_fast_read_line(&rc, &pos) < 0) { - /* empty file - assume it is fine to overwrite */ - eap_fast_deinit_pac_data(&rc); - return 0; - } - if (os_strcmp(pac_file_hdr, rc.buf) != 0) - err = "Unrecognized header line"; - - while (!err && eap_fast_read_line(&rc, &pos) == 0) { - if (os_strcmp(rc.buf, "START") == 0) - err = eap_fast_parse_start(&pac); - else if (os_strcmp(rc.buf, "END") == 0) { - err = eap_fast_parse_end(pac_root, &pac); - count++; - } else if (!pac) - err = "Unexpected line outside START/END block"; - else if (os_strcmp(rc.buf, "PAC-Type") == 0) - err = eap_fast_parse_pac_type(pac, pos); - else if (os_strcmp(rc.buf, "PAC-Key") == 0) - err = eap_fast_parse_pac_key(pac, pos); - else if (os_strcmp(rc.buf, "PAC-Opaque") == 0) - err = eap_fast_parse_pac_opaque(pac, pos); - else if (os_strcmp(rc.buf, "A-ID") == 0) - err = eap_fast_parse_a_id(pac, pos); - else if (os_strcmp(rc.buf, "I-ID") == 0) - err = eap_fast_parse_i_id(pac, pos); - else if (os_strcmp(rc.buf, "A-ID-Info") == 0) - err = eap_fast_parse_a_id_info(pac, pos); - } - - if (pac) { - err = "PAC block not terminated with END"; - eap_fast_free_pac(pac); - } - - eap_fast_deinit_pac_data(&rc); - - if (err) { - wpa_printf(MSG_INFO, "EAP-FAST: %s in '%s:%d'", - err, pac_file, rc.line); - return -1; - } - - wpa_printf(MSG_DEBUG, "EAP-FAST: Read %d PAC entries from '%s'", - count, pac_file); - - return 0; -} - - -static void eap_fast_write(char **buf, char **pos, size_t *buf_len, - const char *field, const u8 *data, - size_t len, int txt) -{ - size_t i, need; - int ret; - char *end; - - if (data == NULL || buf == NULL || *buf == NULL || - pos == NULL || *pos == NULL || *pos < *buf) - return; - - need = os_strlen(field) + len * 2 + 30; - if (txt) - need += os_strlen(field) + len + 20; - - if (*pos - *buf + need > *buf_len) { - char *nbuf = os_realloc(*buf, *buf_len + need); - if (nbuf == NULL) { - os_free(*buf); - *buf = NULL; - return; - } - *pos = nbuf + (*pos - *buf); - *buf = nbuf; - *buf_len += need; - } - end = *buf + *buf_len; - - ret = os_snprintf(*pos, end - *pos, "%s=", field); - if (ret < 0 || ret >= end - *pos) - return; - *pos += ret; - *pos += wpa_snprintf_hex(*pos, end - *pos, data, len); - ret = os_snprintf(*pos, end - *pos, "\n"); - if (ret < 0 || ret >= end - *pos) - return; - *pos += ret; - - if (txt) { - ret = os_snprintf(*pos, end - *pos, "%s-txt=", field); - if (ret < 0 || ret >= end - *pos) - return; - *pos += ret; - for (i = 0; i < len; i++) { - ret = os_snprintf(*pos, end - *pos, "%c", data[i]); - if (ret < 0 || ret >= end - *pos) - return; - *pos += ret; - } - ret = os_snprintf(*pos, end - *pos, "\n"); - if (ret < 0 || ret >= end - *pos) - return; - *pos += ret; - } -} - - -static int eap_fast_write_pac(struct eap_sm *sm, const char *pac_file, - char *buf, size_t len) -{ - if (os_strncmp(pac_file, "blob://", 7) == 0) { - struct wpa_config_blob *blob; - blob = os_zalloc(sizeof(*blob)); - if (blob == NULL) - return -1; - blob->data = (u8 *) buf; - blob->len = len; - buf = NULL; - blob->name = os_strdup(pac_file + 7); - if (blob->name == NULL) { - os_free(blob); - return -1; - } - eap_set_config_blob(sm, blob); - } else { - FILE *f; - f = fopen(pac_file, "wb"); - if (f == NULL) { - wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC " - "file '%s' for writing", pac_file); - return -1; - } - if (fwrite(buf, 1, len, f) != len) { - wpa_printf(MSG_INFO, "EAP-FAST: Failed to write all " - "PACs into '%s'", pac_file); - fclose(f); - return -1; - } - os_free(buf); - fclose(f); - } - - return 0; -} - - -static int eap_fast_add_pac_data(struct eap_fast_pac *pac, char **buf, - char **pos, size_t *buf_len) -{ - int ret; - - ret = os_snprintf(*pos, *buf + *buf_len - *pos, - "START\nPAC-Type=%d\n", pac->pac_type); - if (ret < 0 || ret >= *buf + *buf_len - *pos) - return -1; - - *pos += ret; - eap_fast_write(buf, pos, buf_len, "PAC-Key", - pac->pac_key, EAP_FAST_PAC_KEY_LEN, 0); - eap_fast_write(buf, pos, buf_len, "PAC-Opaque", - pac->pac_opaque, pac->pac_opaque_len, 0); - eap_fast_write(buf, pos, buf_len, "PAC-Info", - pac->pac_info, pac->pac_info_len, 0); - eap_fast_write(buf, pos, buf_len, "A-ID", - pac->a_id, pac->a_id_len, 0); - eap_fast_write(buf, pos, buf_len, "I-ID", - pac->i_id, pac->i_id_len, 1); - eap_fast_write(buf, pos, buf_len, "A-ID-Info", - pac->a_id_info, pac->a_id_info_len, 1); - if (*buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC " - "data"); - return -1; - } - ret = os_snprintf(*pos, *buf + *buf_len - *pos, "END\n"); - if (ret < 0 || ret >= *buf + *buf_len - *pos) - return -1; - *pos += ret; - - return 0; -} - - -/** - * eap_fast_save_pac - Save PAC entries (text format) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @pac_root: Root of the PAC list - * @pac_file: Name of the PAC file/blob - * Returns: 0 on success, -1 on failure - */ -int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root, - const char *pac_file) -{ - struct eap_fast_pac *pac; - int ret, count = 0; - char *buf, *pos; - size_t buf_len; - - if (pac_file == NULL) - return -1; - - buf_len = 1024; - pos = buf = os_malloc(buf_len); - if (buf == NULL) - return -1; - - ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr); - if (ret < 0 || ret >= buf + buf_len - pos) { - os_free(buf); - return -1; - } - pos += ret; - - pac = pac_root; - while (pac) { - if (eap_fast_add_pac_data(pac, &buf, &pos, &buf_len)) { - os_free(buf); - return -1; - } - count++; - pac = pac->next; - } - - if (eap_fast_write_pac(sm, pac_file, buf, pos - buf)) { - os_free(buf); - return -1; - } - - wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %d PAC entries into '%s'", - count, pac_file); - - return 0; -} - - -/** - * eap_fast_pac_list_truncate - Truncate a PAC list to the given length - * @pac_root: Root of the PAC list - * @max_len: Maximum length of the list (>= 1) - * Returns: Number of PAC entries removed - */ -size_t eap_fast_pac_list_truncate(struct eap_fast_pac *pac_root, - size_t max_len) -{ - struct eap_fast_pac *pac, *prev; - size_t count; - - pac = pac_root; - prev = NULL; - count = 0; - - while (pac) { - count++; - if (count > max_len) - break; - prev = pac; - pac = pac->next; - } - - if (count <= max_len || prev == NULL) - return 0; - - count = 0; - prev->next = NULL; - - while (pac) { - prev = pac; - pac = pac->next; - eap_fast_free_pac(prev); - count++; - } - - return count; -} - - -static void eap_fast_pac_get_a_id(struct eap_fast_pac *pac) -{ - u8 *pos, *end; - u16 type, len; - - pos = pac->pac_info; - end = pos + pac->pac_info_len; - - while (pos + 4 < end) { - type = WPA_GET_BE16(pos); - pos += 2; - len = WPA_GET_BE16(pos); - pos += 2; - if (pos + len > end) - break; - - if (type == PAC_TYPE_A_ID) { - os_free(pac->a_id); - pac->a_id = os_malloc(len); - if (pac->a_id == NULL) - break; - os_memcpy(pac->a_id, pos, len); - pac->a_id_len = len; - } - - if (type == PAC_TYPE_A_ID_INFO) { - os_free(pac->a_id_info); - pac->a_id_info = os_malloc(len); - if (pac->a_id_info == NULL) - break; - os_memcpy(pac->a_id_info, pos, len); - pac->a_id_info_len = len; - } - - pos += len; - } -} - - -/** - * eap_fast_load_pac_bin - Load PAC entries (binary format) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @pac_root: Pointer to root of the PAC list (to be filled) - * @pac_file: Name of the PAC file/blob to load - * Returns: 0 on success, -1 on failure - */ -int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root, - const char *pac_file) -{ - const struct wpa_config_blob *blob = NULL; - u8 *buf, *end, *pos; - size_t len, count = 0; - struct eap_fast_pac *pac, *prev; - - *pac_root = NULL; - - if (pac_file == NULL) - return -1; - - if (os_strncmp(pac_file, "blob://", 7) == 0) { - blob = eap_get_config_blob(sm, pac_file + 7); - if (blob == NULL) { - wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - " - "assume no PAC entries have been " - "provisioned", pac_file + 7); - return 0; - } - buf = blob->data; - len = blob->len; - } else { - buf = (u8 *) os_readfile(pac_file, &len); - if (buf == NULL) { - wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - " - "assume no PAC entries have been " - "provisioned", pac_file); - return 0; - } - } - - if (len == 0) { - if (blob == NULL) - os_free(buf); - return 0; - } - - if (len < 6 || WPA_GET_BE32(buf) != EAP_FAST_PAC_BINARY_MAGIC || - WPA_GET_BE16(buf + 4) != EAP_FAST_PAC_BINARY_FORMAT_VERSION) { - wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC file '%s' (bin)", - pac_file); - if (blob == NULL) - os_free(buf); - return -1; - } - - pac = prev = NULL; - pos = buf + 6; - end = buf + len; - while (pos < end) { - if (end - pos < 2 + 32 + 2 + 2) - goto parse_fail; - - pac = os_zalloc(sizeof(*pac)); - if (pac == NULL) - goto parse_fail; - - pac->pac_type = WPA_GET_BE16(pos); - pos += 2; - os_memcpy(pac->pac_key, pos, EAP_FAST_PAC_KEY_LEN); - pos += EAP_FAST_PAC_KEY_LEN; - pac->pac_opaque_len = WPA_GET_BE16(pos); - pos += 2; - if (pos + pac->pac_opaque_len + 2 > end) - goto parse_fail; - pac->pac_opaque = os_malloc(pac->pac_opaque_len); - if (pac->pac_opaque == NULL) - goto parse_fail; - os_memcpy(pac->pac_opaque, pos, pac->pac_opaque_len); - pos += pac->pac_opaque_len; - pac->pac_info_len = WPA_GET_BE16(pos); - pos += 2; - if (pos + pac->pac_info_len > end) - goto parse_fail; - pac->pac_info = os_malloc(pac->pac_info_len); - if (pac->pac_info == NULL) - goto parse_fail; - os_memcpy(pac->pac_info, pos, pac->pac_info_len); - pos += pac->pac_info_len; - eap_fast_pac_get_a_id(pac); - - count++; - if (prev) - prev->next = pac; - else - *pac_root = pac; - prev = pac; - } - - if (blob == NULL) - os_free(buf); - - wpa_printf(MSG_DEBUG, "EAP-FAST: Read %lu PAC entries from '%s' (bin)", - (unsigned long) count, pac_file); - - return 0; - -parse_fail: - wpa_printf(MSG_INFO, "EAP-FAST: Failed to parse PAC file '%s' (bin)", - pac_file); - if (blob == NULL) - os_free(buf); - if (pac) - eap_fast_free_pac(pac); - return -1; -} - - -/** - * eap_fast_save_pac_bin - Save PAC entries (binary format) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @pac_root: Root of the PAC list - * @pac_file: Name of the PAC file/blob - * Returns: 0 on success, -1 on failure - */ -int eap_fast_save_pac_bin(struct eap_sm *sm, struct eap_fast_pac *pac_root, - const char *pac_file) -{ - size_t len, count = 0; - struct eap_fast_pac *pac; - u8 *buf, *pos; - - len = 6; - pac = pac_root; - while (pac) { - if (pac->pac_opaque_len > 65535 || - pac->pac_info_len > 65535) - return -1; - len += 2 + EAP_FAST_PAC_KEY_LEN + 2 + pac->pac_opaque_len + - 2 + pac->pac_info_len; - pac = pac->next; - } - - buf = os_malloc(len); - if (buf == NULL) - return -1; - - pos = buf; - WPA_PUT_BE32(pos, EAP_FAST_PAC_BINARY_MAGIC); - pos += 4; - WPA_PUT_BE16(pos, EAP_FAST_PAC_BINARY_FORMAT_VERSION); - pos += 2; - - pac = pac_root; - while (pac) { - WPA_PUT_BE16(pos, pac->pac_type); - pos += 2; - os_memcpy(pos, pac->pac_key, EAP_FAST_PAC_KEY_LEN); - pos += EAP_FAST_PAC_KEY_LEN; - WPA_PUT_BE16(pos, pac->pac_opaque_len); - pos += 2; - os_memcpy(pos, pac->pac_opaque, pac->pac_opaque_len); - pos += pac->pac_opaque_len; - WPA_PUT_BE16(pos, pac->pac_info_len); - pos += 2; - os_memcpy(pos, pac->pac_info, pac->pac_info_len); - pos += pac->pac_info_len; - - pac = pac->next; - count++; - } - - if (eap_fast_write_pac(sm, pac_file, (char *) buf, len)) { - os_free(buf); - return -1; - } - - wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %lu PAC entries into '%s' " - "(bin)", (unsigned long) count, pac_file); - - return 0; -} diff --git a/contrib/hostapd/src/eap_peer/eap_fast_pac.h b/contrib/hostapd/src/eap_peer/eap_fast_pac.h deleted file mode 100644 index 8815d9168d..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_fast_pac.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * EAP peer method: EAP-FAST PAC file processing - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_FAST_PAC_H -#define EAP_FAST_PAC_H - -#include "eap_common/eap_fast_common.h" - -struct eap_fast_pac { - struct eap_fast_pac *next; - - u8 pac_key[EAP_FAST_PAC_KEY_LEN]; - u8 *pac_opaque; - size_t pac_opaque_len; - u8 *pac_info; - size_t pac_info_len; - u8 *a_id; - size_t a_id_len; - u8 *i_id; - size_t i_id_len; - u8 *a_id_info; - size_t a_id_info_len; - u16 pac_type; -}; - - -void eap_fast_free_pac(struct eap_fast_pac *pac); -struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_pac *pac_root, - const u8 *a_id, size_t a_id_len, - u16 pac_type); -int eap_fast_add_pac(struct eap_fast_pac **pac_root, - struct eap_fast_pac **pac_current, - struct eap_fast_pac *entry); -int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root, - const char *pac_file); -int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root, - const char *pac_file); -size_t eap_fast_pac_list_truncate(struct eap_fast_pac *pac_root, - size_t max_len); -int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root, - const char *pac_file); -int eap_fast_save_pac_bin(struct eap_sm *sm, struct eap_fast_pac *pac_root, - const char *pac_file); - -#endif /* EAP_FAST_PAC_H */ diff --git a/contrib/hostapd/src/eap_peer/eap_gpsk.c b/contrib/hostapd/src/eap_peer/eap_gpsk.c deleted file mode 100644 index 5b023c7933..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_gpsk.c +++ /dev/null @@ -1,783 +0,0 @@ -/* - * EAP peer method: EAP-GPSK (RFC 5433) - * Copyright (c) 2006-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/random.h" -#include "eap_peer/eap_i.h" -#include "eap_common/eap_gpsk_common.h" - -struct eap_gpsk_data { - enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state; - u8 rand_server[EAP_GPSK_RAND_LEN]; - u8 rand_peer[EAP_GPSK_RAND_LEN]; - u8 msk[EAP_MSK_LEN]; - u8 emsk[EAP_EMSK_LEN]; - u8 sk[EAP_GPSK_MAX_SK_LEN]; - size_t sk_len; - u8 pk[EAP_GPSK_MAX_PK_LEN]; - size_t pk_len; - u8 session_id[128]; - size_t id_len; - u8 *id_peer; - size_t id_peer_len; - u8 *id_server; - size_t id_server_len; - int vendor; /* CSuite/Specifier */ - int specifier; /* CSuite/Specifier */ - u8 *psk; - size_t psk_len; - u16 forced_cipher; /* force cipher or 0 to allow all supported */ -}; - - -static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data, - u8 identifier, - const u8 *csuite_list, - size_t csuite_list_len); -static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data, - u8 identifier); - - -#ifndef CONFIG_NO_STDOUT_DEBUG -static const char * eap_gpsk_state_txt(int state) -{ - switch (state) { - case GPSK_1: - return "GPSK-1"; - case GPSK_3: - return "GPSK-3"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "?"; - } -} -#endif /* CONFIG_NO_STDOUT_DEBUG */ - - -static void eap_gpsk_state(struct eap_gpsk_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s", - eap_gpsk_state_txt(data->state), - eap_gpsk_state_txt(state)); - data->state = state; -} - - -static void eap_gpsk_deinit(struct eap_sm *sm, void *priv); - - -static void * eap_gpsk_init(struct eap_sm *sm) -{ - struct eap_gpsk_data *data; - const u8 *identity, *password; - size_t identity_len, password_len; - const char *phase1; - - password = eap_get_config_password(sm, &password_len); - if (password == NULL) { - wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured"); - return NULL; - } - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = GPSK_1; - - identity = eap_get_config_identity(sm, &identity_len); - if (identity) { - data->id_peer = os_malloc(identity_len); - if (data->id_peer == NULL) { - eap_gpsk_deinit(sm, data); - return NULL; - } - os_memcpy(data->id_peer, identity, identity_len); - data->id_peer_len = identity_len; - } - - phase1 = eap_get_config_phase1(sm); - if (phase1) { - const char *pos; - - pos = os_strstr(phase1, "cipher="); - if (pos) { - data->forced_cipher = atoi(pos + 7); - wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u", - data->forced_cipher); - } - } - - data->psk = os_malloc(password_len); - if (data->psk == NULL) { - eap_gpsk_deinit(sm, data); - return NULL; - } - os_memcpy(data->psk, password, password_len); - data->psk_len = password_len; - - return data; -} - - -static void eap_gpsk_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_gpsk_data *data = priv; - os_free(data->id_server); - os_free(data->id_peer); - os_free(data->psk); - os_free(data); -} - - -static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data, - const u8 *pos, const u8 *end) -{ - u16 alen; - - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet"); - return NULL; - } - alen = WPA_GET_BE16(pos); - pos += 2; - if (end - pos < alen) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow"); - return NULL; - } - os_free(data->id_server); - data->id_server = os_malloc(alen); - if (data->id_server == NULL) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server"); - return NULL; - } - os_memcpy(data->id_server, pos, alen); - data->id_server_len = alen; - wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server", - data->id_server, data->id_server_len); - pos += alen; - - return pos; -} - - -static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data, - const u8 *pos, const u8 *end) -{ - if (pos == NULL) - return NULL; - - if (end - pos < EAP_GPSK_RAND_LEN) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow"); - return NULL; - } - os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server", - data->rand_server, EAP_GPSK_RAND_LEN); - pos += EAP_GPSK_RAND_LEN; - - return pos; -} - - -static int eap_gpsk_select_csuite(struct eap_sm *sm, - struct eap_gpsk_data *data, - const u8 *csuite_list, - size_t csuite_list_len) -{ - struct eap_gpsk_csuite *csuite; - int i, count; - - count = csuite_list_len / sizeof(struct eap_gpsk_csuite); - data->vendor = EAP_GPSK_VENDOR_IETF; - data->specifier = EAP_GPSK_CIPHER_RESERVED; - csuite = (struct eap_gpsk_csuite *) csuite_list; - for (i = 0; i < count; i++) { - int vendor, specifier; - vendor = WPA_GET_BE32(csuite->vendor); - specifier = WPA_GET_BE16(csuite->specifier); - wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d", - i, vendor, specifier); - if (data->vendor == EAP_GPSK_VENDOR_IETF && - data->specifier == EAP_GPSK_CIPHER_RESERVED && - eap_gpsk_supported_ciphersuite(vendor, specifier) && - (!data->forced_cipher || data->forced_cipher == specifier)) - { - data->vendor = vendor; - data->specifier = specifier; - } - csuite++; - } - if (data->vendor == EAP_GPSK_VENDOR_IETF && - data->specifier == EAP_GPSK_CIPHER_RESERVED) { - wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported " - "ciphersuite found"); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d", - data->vendor, data->specifier); - - return 0; -} - - -static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm, - struct eap_gpsk_data *data, - const u8 **list, - size_t *list_len, - const u8 *pos, const u8 *end) -{ - if (pos == NULL) - return NULL; - - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet"); - return NULL; - } - *list_len = WPA_GET_BE16(pos); - pos += 2; - if (end - pos < (int) *list_len) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow"); - return NULL; - } - if (*list_len == 0 || (*list_len % sizeof(struct eap_gpsk_csuite))) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu", - (unsigned long) *list_len); - return NULL; - } - *list = pos; - pos += *list_len; - - if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0) - return NULL; - - return pos; -} - - -static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm, - struct eap_gpsk_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - const u8 *payload, - size_t payload_len) -{ - size_t csuite_list_len; - const u8 *csuite_list, *pos, *end; - struct wpabuf *resp; - - if (data->state != GPSK_1) { - ret->ignore = TRUE; - return NULL; - } - - wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1"); - - end = payload + payload_len; - - pos = eap_gpsk_process_id_server(data, payload, end); - pos = eap_gpsk_process_rand_server(data, pos, end); - pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list, - &csuite_list_len, pos, end); - if (pos == NULL) { - ret->methodState = METHOD_DONE; - eap_gpsk_state(data, FAILURE); - return NULL; - } - - resp = eap_gpsk_send_gpsk_2(data, eap_get_id(reqData), - csuite_list, csuite_list_len); - if (resp == NULL) - return NULL; - - eap_gpsk_state(data, GPSK_3); - - return resp; -} - - -static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data, - u8 identifier, - const u8 *csuite_list, - size_t csuite_list_len) -{ - struct wpabuf *resp; - size_t len, miclen; - u8 *rpos, *start; - struct eap_gpsk_csuite *csuite; - - wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2"); - - miclen = eap_gpsk_mic_len(data->vendor, data->specifier); - len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len + - 2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len + - sizeof(struct eap_gpsk_csuite) + 2 + miclen; - - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, - EAP_CODE_RESPONSE, identifier); - if (resp == NULL) - return NULL; - - wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2); - start = wpabuf_put(resp, 0); - - wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer", - data->id_peer, data->id_peer_len); - wpabuf_put_be16(resp, data->id_peer_len); - wpabuf_put_data(resp, data->id_peer, data->id_peer_len); - - wpabuf_put_be16(resp, data->id_server_len); - wpabuf_put_data(resp, data->id_server, data->id_server_len); - - if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data " - "for RAND_Peer"); - eap_gpsk_state(data, FAILURE); - wpabuf_free(resp); - return NULL; - } - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer", - data->rand_peer, EAP_GPSK_RAND_LEN); - wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN); - wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN); - - wpabuf_put_be16(resp, csuite_list_len); - wpabuf_put_data(resp, csuite_list, csuite_list_len); - - csuite = wpabuf_put(resp, sizeof(*csuite)); - WPA_PUT_BE32(csuite->vendor, data->vendor); - WPA_PUT_BE16(csuite->specifier, data->specifier); - - if (eap_gpsk_derive_keys(data->psk, data->psk_len, - data->vendor, data->specifier, - data->rand_peer, data->rand_server, - data->id_peer, data->id_peer_len, - data->id_server, data->id_server_len, - data->msk, data->emsk, - data->sk, &data->sk_len, - data->pk, &data->pk_len) < 0) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys"); - eap_gpsk_state(data, FAILURE); - wpabuf_free(resp); - return NULL; - } - - if (eap_gpsk_derive_session_id(data->psk, data->psk_len, - data->vendor, data->specifier, - data->rand_peer, data->rand_server, - data->id_peer, data->id_peer_len, - data->id_server, data->id_server_len, - EAP_TYPE_GPSK, - data->session_id, &data->id_len) < 0) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id"); - eap_gpsk_state(data, FAILURE); - wpabuf_free(resp); - return NULL; - } - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id", - data->session_id, data->id_len); - - /* No PD_Payload_1 */ - wpabuf_put_be16(resp, 0); - - rpos = wpabuf_put(resp, miclen); - if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, - data->specifier, start, rpos - start, rpos) < - 0) { - eap_gpsk_state(data, FAILURE); - wpabuf_free(resp); - return NULL; - } - - return resp; -} - - -static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data, - const u8 *pos, const u8 *end) -{ - if (end - pos < EAP_GPSK_RAND_LEN) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " - "RAND_Peer"); - return NULL; - } - if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and " - "GPSK-3 did not match"); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2", - data->rand_peer, EAP_GPSK_RAND_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3", - pos, EAP_GPSK_RAND_LEN); - return NULL; - } - pos += EAP_GPSK_RAND_LEN; - - if (end - pos < EAP_GPSK_RAND_LEN) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " - "RAND_Server"); - return NULL; - } - if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and " - "GPSK-3 did not match"); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1", - data->rand_server, EAP_GPSK_RAND_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3", - pos, EAP_GPSK_RAND_LEN); - return NULL; - } - pos += EAP_GPSK_RAND_LEN; - - return pos; -} - - -static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data, - const u8 *pos, const u8 *end) -{ - size_t len; - - if (pos == NULL) - return NULL; - - if (end - pos < (int) 2) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " - "length(ID_Server)"); - return NULL; - } - - len = WPA_GET_BE16(pos); - pos += 2; - - if (end - pos < (int) len) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " - "ID_Server"); - return NULL; - } - - if (len != data->id_server_len || - os_memcmp(pos, data->id_server, len) != 0) { - wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with " - "the one used in GPSK-1"); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1", - data->id_server, data->id_server_len); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3", - pos, len); - return NULL; - } - - pos += len; - - return pos; -} - - -static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data, - const u8 *pos, const u8 *end) -{ - int vendor, specifier; - const struct eap_gpsk_csuite *csuite; - - if (pos == NULL) - return NULL; - - if (end - pos < (int) sizeof(*csuite)) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " - "CSuite_Sel"); - return NULL; - } - csuite = (const struct eap_gpsk_csuite *) pos; - vendor = WPA_GET_BE32(csuite->vendor); - specifier = WPA_GET_BE16(csuite->specifier); - pos += sizeof(*csuite); - if (vendor != data->vendor || specifier != data->specifier) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not " - "match with the one sent in GPSK-2 (%d:%d)", - vendor, specifier, data->vendor, data->specifier); - return NULL; - } - - return pos; -} - - -static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data, - const u8 *pos, const u8 *end) -{ - u16 alen; - - if (pos == NULL) - return NULL; - - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " - "PD_Payload_2 length"); - return NULL; - } - alen = WPA_GET_BE16(pos); - pos += 2; - if (end - pos < alen) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " - "%d-octet PD_Payload_2", alen); - return NULL; - } - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen); - pos += alen; - - return pos; -} - - -static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data, - const u8 *payload, - const u8 *pos, const u8 *end) -{ - size_t miclen; - u8 mic[EAP_GPSK_MAX_MIC_LEN]; - - if (pos == NULL) - return NULL; - - miclen = eap_gpsk_mic_len(data->vendor, data->specifier); - if (end - pos < (int) miclen) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " - "(left=%lu miclen=%lu)", - (unsigned long) (end - pos), - (unsigned long) miclen); - return NULL; - } - if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, - data->specifier, payload, pos - payload, mic) - < 0) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); - return NULL; - } - if (os_memcmp(mic, pos, miclen) != 0) { - wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3"); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); - return NULL; - } - pos += miclen; - - return pos; -} - - -static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm, - struct eap_gpsk_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - const u8 *payload, - size_t payload_len) -{ - struct wpabuf *resp; - const u8 *pos, *end; - - if (data->state != GPSK_3) { - ret->ignore = TRUE; - return NULL; - } - - wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3"); - - end = payload + payload_len; - - pos = eap_gpsk_validate_rand(data, payload, end); - pos = eap_gpsk_validate_id_server(data, pos, end); - pos = eap_gpsk_validate_csuite(data, pos, end); - pos = eap_gpsk_validate_pd_payload_2(data, pos, end); - pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end); - - if (pos == NULL) { - eap_gpsk_state(data, FAILURE); - return NULL; - } - if (pos != end) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " - "data in the end of GPSK-2", - (unsigned long) (end - pos)); - } - - resp = eap_gpsk_send_gpsk_4(data, eap_get_id(reqData)); - if (resp == NULL) - return NULL; - - eap_gpsk_state(data, SUCCESS); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - - return resp; -} - - -static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data, - u8 identifier) -{ - struct wpabuf *resp; - u8 *rpos, *start; - size_t mlen; - - wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4"); - - mlen = eap_gpsk_mic_len(data->vendor, data->specifier); - - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen, - EAP_CODE_RESPONSE, identifier); - if (resp == NULL) - return NULL; - - wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4); - start = wpabuf_put(resp, 0); - - /* No PD_Payload_3 */ - wpabuf_put_be16(resp, 0); - - rpos = wpabuf_put(resp, mlen); - if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, - data->specifier, start, rpos - start, rpos) < - 0) { - eap_gpsk_state(data, FAILURE); - wpabuf_free(resp); - return NULL; - } - - return resp; -} - - -static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_gpsk_data *data = priv; - struct wpabuf *resp; - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len); - if (pos == NULL || len < 1) { - ret->ignore = TRUE; - return NULL; - } - - wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos); - - ret->ignore = FALSE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - ret->allowNotifications = FALSE; - - switch (*pos) { - case EAP_GPSK_OPCODE_GPSK_1: - resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData, - pos + 1, len - 1); - break; - case EAP_GPSK_OPCODE_GPSK_3: - resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData, - pos + 1, len - 1); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with " - "unknown opcode %d", *pos); - ret->ignore = TRUE; - return NULL; - } - - return resp; -} - - -static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_gpsk_data *data = priv; - return data->state == SUCCESS; -} - - -static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_gpsk_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->msk, EAP_MSK_LEN); - *len = EAP_MSK_LEN; - - return key; -} - - -static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_gpsk_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - *len = EAP_EMSK_LEN; - - return key; -} - - -static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_gpsk_data *data = priv; - u8 *sid; - - if (data->state != SUCCESS) - return NULL; - - sid = os_malloc(data->id_len); - if (sid == NULL) - return NULL; - os_memcpy(sid, data->session_id, data->id_len); - *len = data->id_len; - - return sid; -} - - -int eap_peer_gpsk_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK"); - if (eap == NULL) - return -1; - - eap->init = eap_gpsk_init; - eap->deinit = eap_gpsk_deinit; - eap->process = eap_gpsk_process; - eap->isKeyAvailable = eap_gpsk_isKeyAvailable; - eap->getKey = eap_gpsk_getKey; - eap->get_emsk = eap_gpsk_get_emsk; - eap->getSessionId = eap_gpsk_get_session_id; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_gtc.c b/contrib/hostapd/src/eap_peer/eap_gtc.c deleted file mode 100644 index 9f3cfbdaca..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_gtc.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * EAP peer method: EAP-GTC (RFC 3748) - * Copyright (c) 2004-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" - - -struct eap_gtc_data { - int prefix; -}; - - -static void * eap_gtc_init(struct eap_sm *sm) -{ - struct eap_gtc_data *data; - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - - if (sm->m && sm->m->vendor == EAP_VENDOR_IETF && - sm->m->method == EAP_TYPE_FAST) { - wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix " - "with challenge/response"); - data->prefix = 1; - } - return data; -} - - -static void eap_gtc_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_gtc_data *data = priv; - os_free(data); -} - - -static struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_gtc_data *data = priv; - struct wpabuf *resp; - const u8 *pos, *password, *identity; - size_t password_len, identity_len, len, plen; - int otp; - u8 id; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqData, &len); - if (pos == NULL) { - ret->ignore = TRUE; - return NULL; - } - id = eap_get_id(reqData); - - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message", pos, len); - if (data->prefix && - (len < 10 || os_memcmp(pos, "CHALLENGE=", 10) != 0)) { - wpa_printf(MSG_DEBUG, "EAP-GTC: Challenge did not start with " - "expected prefix"); - - /* Send an empty response in order to allow tunneled - * acknowledgement of the failure. This will also cover the - * error case which seems to use EAP-MSCHAPv2 like error - * reporting with EAP-GTC inside EAP-FAST tunnel. */ - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, - 0, EAP_CODE_RESPONSE, id); - return resp; - } - - password = eap_get_config_otp(sm, &password_len); - if (password) - otp = 1; - else { - password = eap_get_config_password(sm, &password_len); - otp = 0; - } - - if (password == NULL) { - wpa_printf(MSG_INFO, "EAP-GTC: Password not configured"); - eap_sm_request_otp(sm, (const char *) pos, len); - ret->ignore = TRUE; - return NULL; - } - - ret->ignore = FALSE; - - ret->methodState = data->prefix ? METHOD_MAY_CONT : METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - ret->allowNotifications = FALSE; - - plen = password_len; - identity = eap_get_config_identity(sm, &identity_len); - if (identity == NULL) - return NULL; - if (data->prefix) - plen += 9 + identity_len + 1; - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, plen, - EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - if (data->prefix) { - wpabuf_put_data(resp, "RESPONSE=", 9); - wpabuf_put_data(resp, identity, identity_len); - wpabuf_put_u8(resp, '\0'); - } - wpabuf_put_data(resp, password, password_len); - wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", - wpabuf_head_u8(resp) + sizeof(struct eap_hdr) + - 1, plen); - - if (otp) { - wpa_printf(MSG_DEBUG, "EAP-GTC: Forgetting used password"); - eap_clear_config_otp(sm); - } - - return resp; -} - - -int eap_peer_gtc_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC"); - if (eap == NULL) - return -1; - - eap->init = eap_gtc_init; - eap->deinit = eap_gtc_deinit; - eap->process = eap_gtc_process; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_i.h b/contrib/hostapd/src/eap_peer/eap_i.h deleted file mode 100644 index 8288ba5b51..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_i.h +++ /dev/null @@ -1,373 +0,0 @@ -/* - * EAP peer state machines internal structures (RFC 4137) - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_I_H -#define EAP_I_H - -#include "wpabuf.h" -#include "eap_peer/eap.h" -#include "eap_common/eap_common.h" - -/* RFC 4137 - EAP Peer state machine */ - -typedef enum { - DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC -} EapDecision; - -typedef enum { - METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE -} EapMethodState; - -/** - * struct eap_method_ret - EAP return values from struct eap_method::process() - * - * These structure contains OUT variables for the interface between peer state - * machine and methods (RFC 4137, Sect. 4.2). eapRespData will be returned as - * the return value of struct eap_method::process() so it is not included in - * this structure. - */ -struct eap_method_ret { - /** - * ignore - Whether method decided to drop the current packed (OUT) - */ - Boolean ignore; - - /** - * methodState - Method-specific state (IN/OUT) - */ - EapMethodState methodState; - - /** - * decision - Authentication decision (OUT) - */ - EapDecision decision; - - /** - * allowNotifications - Whether method allows notifications (OUT) - */ - Boolean allowNotifications; -}; - - -/** - * struct eap_method - EAP method interface - * This structure defines the EAP method interface. Each method will need to - * register its own EAP type, EAP name, and set of function pointers for method - * specific operations. This interface is based on section 4.4 of RFC 4137. - */ -struct eap_method { - /** - * vendor - EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF) - */ - int vendor; - - /** - * method - EAP type number (EAP_TYPE_*) - */ - EapType method; - - /** - * name - Name of the method (e.g., "TLS") - */ - const char *name; - - /** - * init - Initialize an EAP method - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * Returns: Pointer to allocated private data, or %NULL on failure - * - * This function is used to initialize the EAP method explicitly - * instead of using METHOD_INIT state as specific in RFC 4137. The - * method is expected to initialize it method-specific state and return - * a pointer that will be used as the priv argument to other calls. - */ - void * (*init)(struct eap_sm *sm); - - /** - * deinit - Deinitialize an EAP method - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * - * Deinitialize the EAP method and free any allocated private data. - */ - void (*deinit)(struct eap_sm *sm, void *priv); - - /** - * process - Process an EAP request - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * @ret: Return values from EAP request validation and processing - * @reqData: EAP request to be processed (eapReqData) - * Returns: Pointer to allocated EAP response packet (eapRespData) - * - * This function is a combination of m.check(), m.process(), and - * m.buildResp() procedures defined in section 4.4 of RFC 4137 In other - * words, this function validates the incoming request, processes it, - * and build a response packet. m.check() and m.process() return values - * are returned through struct eap_method_ret *ret variable. Caller is - * responsible for freeing the returned EAP response packet. - */ - struct wpabuf * (*process)(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData); - - /** - * isKeyAvailable - Find out whether EAP method has keying material - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * Returns: %TRUE if key material (eapKeyData) is available - */ - Boolean (*isKeyAvailable)(struct eap_sm *sm, void *priv); - - /** - * getKey - Get EAP method specific keying material (eapKeyData) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * @len: Pointer to variable to store key length (eapKeyDataLen) - * Returns: Keying material (eapKeyData) or %NULL if not available - * - * This function can be used to get the keying material from the EAP - * method. The key may already be stored in the method-specific private - * data or this function may derive the key. - */ - u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len); - - /** - * get_status - Get EAP method status - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * @buf: Buffer for status information - * @buflen: Maximum buffer length - * @verbose: Whether to include verbose status information - * Returns: Number of bytes written to buf - * - * Query EAP method for status information. This function fills in a - * text area with current status information from the EAP method. If - * the buffer (buf) is not large enough, status information will be - * truncated to fit the buffer. - */ - int (*get_status)(struct eap_sm *sm, void *priv, char *buf, - size_t buflen, int verbose); - - /** - * has_reauth_data - Whether method is ready for fast reauthentication - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * Returns: %TRUE or %FALSE based on whether fast reauthentication is - * possible - * - * This function is an optional handler that only EAP methods - * supporting fast re-authentication need to implement. - */ - Boolean (*has_reauth_data)(struct eap_sm *sm, void *priv); - - /** - * deinit_for_reauth - Release data that is not needed for fast re-auth - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * - * This function is an optional handler that only EAP methods - * supporting fast re-authentication need to implement. This is called - * when authentication has been completed and EAP state machine is - * requesting that enough state information is maintained for fast - * re-authentication - */ - void (*deinit_for_reauth)(struct eap_sm *sm, void *priv); - - /** - * init_for_reauth - Prepare for start of fast re-authentication - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * - * This function is an optional handler that only EAP methods - * supporting fast re-authentication need to implement. This is called - * when EAP authentication is started and EAP state machine is - * requesting fast re-authentication to be used. - */ - void * (*init_for_reauth)(struct eap_sm *sm, void *priv); - - /** - * get_identity - Get method specific identity for re-authentication - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * @len: Length of the returned identity - * Returns: Pointer to the method specific identity or %NULL if default - * identity is to be used - * - * This function is an optional handler that only EAP methods - * that use method specific identity need to implement. - */ - const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len); - - /** - * free - Free EAP method data - * @method: Pointer to the method data registered with - * eap_peer_method_register(). - * - * This function will be called when the EAP method is being - * unregistered. If the EAP method allocated resources during - * registration (e.g., allocated struct eap_method), they should be - * freed in this function. No other method functions will be called - * after this call. If this function is not defined (i.e., function - * pointer is %NULL), a default handler is used to release the method - * data with free(method). This is suitable for most cases. - */ - void (*free)(struct eap_method *method); - -#define EAP_PEER_METHOD_INTERFACE_VERSION 1 - /** - * version - Version of the EAP peer method interface - * - * The EAP peer method implementation should set this variable to - * EAP_PEER_METHOD_INTERFACE_VERSION. This is used to verify that the - * EAP method is using supported API version when using dynamically - * loadable EAP methods. - */ - int version; - - /** - * next - Pointer to the next EAP method - * - * This variable is used internally in the EAP method registration code - * to create a linked list of registered EAP methods. - */ - struct eap_method *next; - -#ifdef CONFIG_DYNAMIC_EAP_METHODS - /** - * dl_handle - Handle for the dynamic library - * - * This variable is used internally in the EAP method registration code - * to store a handle for the dynamic library. If the method is linked - * in statically, this is %NULL. - */ - void *dl_handle; -#endif /* CONFIG_DYNAMIC_EAP_METHODS */ - - /** - * get_emsk - Get EAP method specific keying extended material (EMSK) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * @len: Pointer to a variable to store EMSK length - * Returns: EMSK or %NULL if not available - * - * This function can be used to get the extended keying material from - * the EAP method. The key may already be stored in the method-specific - * private data or this function may derive the key. - */ - u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len); - - /** - * getSessionId - Get EAP method specific Session-Id - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * @len: Pointer to a variable to store Session-Id length - * Returns: Session-Id or %NULL if not available - * - * This function can be used to get the Session-Id from the EAP method. - * The Session-Id may already be stored in the method-specific private - * data or this function may derive the Session-Id. - */ - u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len); -}; - - -/** - * struct eap_sm - EAP state machine data - */ -struct eap_sm { - enum { - EAP_INITIALIZE, EAP_DISABLED, EAP_IDLE, EAP_RECEIVED, - EAP_GET_METHOD, EAP_METHOD, EAP_SEND_RESPONSE, EAP_DISCARD, - EAP_IDENTITY, EAP_NOTIFICATION, EAP_RETRANSMIT, EAP_SUCCESS, - EAP_FAILURE - } EAP_state; - /* Long-term local variables */ - EapType selectedMethod; - EapMethodState methodState; - int lastId; - struct wpabuf *lastRespData; - EapDecision decision; - /* Short-term local variables */ - Boolean rxReq; - Boolean rxSuccess; - Boolean rxFailure; - int reqId; - EapType reqMethod; - int reqVendor; - u32 reqVendorMethod; - Boolean ignore; - /* Constants */ - int ClientTimeout; - - /* Miscellaneous variables */ - Boolean allowNotifications; /* peer state machine <-> methods */ - struct wpabuf *eapRespData; /* peer to lower layer */ - Boolean eapKeyAvailable; /* peer to lower layer */ - u8 *eapKeyData; /* peer to lower layer */ - size_t eapKeyDataLen; /* peer to lower layer */ - u8 *eapSessionId; /* peer to lower layer */ - size_t eapSessionIdLen; /* peer to lower layer */ - const struct eap_method *m; /* selected EAP method */ - /* not defined in RFC 4137 */ - Boolean changed; - void *eapol_ctx; - struct eapol_callbacks *eapol_cb; - void *eap_method_priv; - int init_phase2; - int fast_reauth; - - Boolean rxResp /* LEAP only */; - Boolean leap_done; - Boolean peap_done; - u8 req_md5[16]; /* MD5() of the current EAP packet */ - u8 last_md5[16]; /* MD5() of the previously received EAP packet; used - * in duplicate request detection. */ - - void *msg_ctx; - void *scard_ctx; - void *ssl_ctx; - void *ssl_ctx2; - - unsigned int workaround; - - /* Optional challenges generated in Phase 1 (EAP-FAST) */ - u8 *peer_challenge, *auth_challenge; - - int num_rounds; - int force_disabled; - - struct wps_context *wps; - - int prev_failure; - - struct ext_password_data *ext_pw; - struct wpabuf *ext_pw_buf; - - int external_sim; - - unsigned int expected_failure:1; -}; - -const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len); -const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len); -const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash); -const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len); -const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len); -void eap_clear_config_otp(struct eap_sm *sm); -const char * eap_get_config_phase1(struct eap_sm *sm); -const char * eap_get_config_phase2(struct eap_sm *sm); -int eap_get_config_fragment_size(struct eap_sm *sm); -struct eap_peer_config * eap_get_config(struct eap_sm *sm); -void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob); -const struct wpa_config_blob * -eap_get_config_blob(struct eap_sm *sm, const char *name); -void eap_notify_pending(struct eap_sm *sm); -int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method); - -#endif /* EAP_I_H */ diff --git a/contrib/hostapd/src/eap_peer/eap_ikev2.c b/contrib/hostapd/src/eap_peer/eap_ikev2.c deleted file mode 100644 index 2d7841dd01..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_ikev2.c +++ /dev/null @@ -1,536 +0,0 @@ -/* - * EAP-IKEv2 peer (RFC 5106) - * Copyright (c) 2007-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" -#include "eap_common/eap_ikev2_common.h" -#include "ikev2.h" - - -struct eap_ikev2_data { - struct ikev2_responder_data ikev2; - enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state; - struct wpabuf *in_buf; - struct wpabuf *out_buf; - size_t out_used; - size_t fragment_size; - int keys_ready; - u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN]; - int keymat_ok; -}; - - -static const char * eap_ikev2_state_txt(int state) -{ - switch (state) { - case WAIT_START: - return "WAIT_START"; - case PROC_MSG: - return "PROC_MSG"; - case WAIT_FRAG_ACK: - return "WAIT_FRAG_ACK"; - case DONE: - return "DONE"; - case FAIL: - return "FAIL"; - default: - return "?"; - } -} - - -static void eap_ikev2_state(struct eap_ikev2_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s", - eap_ikev2_state_txt(data->state), - eap_ikev2_state_txt(state)); - data->state = state; -} - - -static void * eap_ikev2_init(struct eap_sm *sm) -{ - struct eap_ikev2_data *data; - const u8 *identity, *password; - size_t identity_len, password_len; - int fragment_size; - - identity = eap_get_config_identity(sm, &identity_len); - if (identity == NULL) { - wpa_printf(MSG_INFO, "EAP-IKEV2: No identity available"); - return NULL; - } - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = WAIT_START; - fragment_size = eap_get_config_fragment_size(sm); - if (fragment_size <= 0) - data->fragment_size = IKEV2_FRAGMENT_SIZE; - else - data->fragment_size = fragment_size; - data->ikev2.state = SA_INIT; - data->ikev2.peer_auth = PEER_AUTH_SECRET; - data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); - if (data->ikev2.key_pad == NULL) - goto failed; - data->ikev2.key_pad_len = 21; - data->ikev2.IDr = os_malloc(identity_len); - if (data->ikev2.IDr == NULL) - goto failed; - os_memcpy(data->ikev2.IDr, identity, identity_len); - data->ikev2.IDr_len = identity_len; - - password = eap_get_config_password(sm, &password_len); - if (password) { - data->ikev2.shared_secret = os_malloc(password_len); - if (data->ikev2.shared_secret == NULL) - goto failed; - os_memcpy(data->ikev2.shared_secret, password, password_len); - data->ikev2.shared_secret_len = password_len; - } - - return data; - -failed: - ikev2_responder_deinit(&data->ikev2); - os_free(data); - return NULL; -} - - -static void eap_ikev2_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_ikev2_data *data = priv; - wpabuf_free(data->in_buf); - wpabuf_free(data->out_buf); - ikev2_responder_deinit(&data->ikev2); - os_free(data); -} - - -static int eap_ikev2_peer_keymat(struct eap_ikev2_data *data) -{ - if (eap_ikev2_derive_keymat( - data->ikev2.proposal.prf, &data->ikev2.keys, - data->ikev2.i_nonce, data->ikev2.i_nonce_len, - data->ikev2.r_nonce, data->ikev2.r_nonce_len, - data->keymat) < 0) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to " - "derive key material"); - return -1; - } - data->keymat_ok = 1; - return 0; -} - - -static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, - struct eap_method_ret *ret, u8 id) -{ - struct wpabuf *resp; - u8 flags; - size_t send_len, plen, icv_len = 0; - - ret->ignore = FALSE; - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Response"); - ret->allowNotifications = TRUE; - - flags = 0; - send_len = wpabuf_len(data->out_buf) - data->out_used; - if (1 + send_len > data->fragment_size) { - send_len = data->fragment_size - 1; - flags |= IKEV2_FLAGS_MORE_FRAGMENTS; - if (data->out_used == 0) { - flags |= IKEV2_FLAGS_LENGTH_INCLUDED; - send_len -= 4; - } - } -#ifdef CCNS_PL - /* Some issues figuring out the length of the message if Message Length - * field not included?! */ - if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) - flags |= IKEV2_FLAGS_LENGTH_INCLUDED; -#endif /* CCNS_PL */ - - plen = 1 + send_len; - if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) - plen += 4; - if (data->keys_ready) { - const struct ikev2_integ_alg *integ; - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum " - "Data"); - flags |= IKEV2_FLAGS_ICV_INCLUDED; - integ = ikev2_get_integ(data->ikev2.proposal.integ); - if (integ == NULL) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " - "transform / cannot generate ICV"); - return NULL; - } - icv_len = integ->hash_len; - - plen += icv_len; - } - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen, - EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - - wpabuf_put_u8(resp, flags); /* Flags */ - if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) - wpabuf_put_be32(resp, wpabuf_len(data->out_buf)); - - wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, - send_len); - data->out_used += send_len; - - if (flags & IKEV2_FLAGS_ICV_INCLUDED) { - const u8 *msg = wpabuf_head(resp); - size_t len = wpabuf_len(resp); - ikev2_integ_hash(data->ikev2.proposal.integ, - data->ikev2.keys.SK_ar, - data->ikev2.keys.SK_integ_len, - msg, len, wpabuf_put(resp, icv_len)); - } - - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - - if (data->out_used == wpabuf_len(data->out_buf)) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " - "(message sent completely)", - (unsigned long) send_len); - wpabuf_free(data->out_buf); - data->out_buf = NULL; - data->out_used = 0; - switch (data->ikev2.state) { - case SA_AUTH: - /* SA_INIT was sent out, so message have to be - * integrity protected from now on. */ - data->keys_ready = 1; - break; - case IKEV2_DONE: - ret->methodState = METHOD_DONE; - if (data->state == FAIL) - break; - ret->decision = DECISION_COND_SUCC; - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication " - "completed successfully"); - if (eap_ikev2_peer_keymat(data)) - break; - eap_ikev2_state(data, DONE); - break; - case IKEV2_FAILED: - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication " - "failed"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - break; - default: - break; - } - } else { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " - "(%lu more to send)", (unsigned long) send_len, - (unsigned long) wpabuf_len(data->out_buf) - - data->out_used); - eap_ikev2_state(data, WAIT_FRAG_ACK); - } - - return resp; -} - - -static int eap_ikev2_process_icv(struct eap_ikev2_data *data, - const struct wpabuf *reqData, - u8 flags, const u8 *pos, const u8 **end) -{ - if (flags & IKEV2_FLAGS_ICV_INCLUDED) { - int icv_len = eap_ikev2_validate_icv( - data->ikev2.proposal.integ, &data->ikev2.keys, 1, - reqData, pos, *end); - if (icv_len < 0) - return -1; - /* Hide Integrity Checksum Data from further processing */ - *end -= icv_len; - } else if (data->keys_ready) { - wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have " - "included integrity checksum"); - return -1; - } - - return 0; -} - - -static int eap_ikev2_process_cont(struct eap_ikev2_data *data, - const u8 *buf, size_t len) -{ - /* Process continuation of a pending message */ - if (len > wpabuf_tailroom(data->in_buf)) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow"); - eap_ikev2_state(data, FAIL); - return -1; - } - - wpabuf_put_data(data->in_buf, buf, len); - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting " - "for %lu bytes more", (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); - - return 0; -} - - -static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data, - struct eap_method_ret *ret, - u8 id, u8 flags, - u32 message_length, - const u8 *buf, size_t len) -{ - /* Process a fragment that is not the last one of the message */ - if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in " - "a fragmented packet"); - ret->ignore = TRUE; - return NULL; - } - - if (data->in_buf == NULL) { - /* First fragment of the message */ - data->in_buf = wpabuf_alloc(message_length); - if (data->in_buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for " - "message"); - ret->ignore = TRUE; - return NULL; - } - wpabuf_put_data(data->in_buf, buf, len); - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first " - "fragment, waiting for %lu bytes more", - (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); - } - - return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE); -} - - -static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_ikev2_data *data = priv; - const u8 *start, *pos, *end; - size_t len; - u8 flags, id; - u32 message_length = 0; - struct wpabuf tmpbuf; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len); - if (pos == NULL) { - ret->ignore = TRUE; - return NULL; - } - - id = eap_get_id(reqData); - - start = pos; - end = start + len; - - if (len == 0) - flags = 0; /* fragment ack */ - else - flags = *pos++; - - if (eap_ikev2_process_icv(data, reqData, flags, pos, &end) < 0) { - ret->ignore = TRUE; - return NULL; - } - - if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { - if (end - pos < 4) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); - ret->ignore = TRUE; - return NULL; - } - message_length = WPA_GET_BE32(pos); - pos += 4; - - if (message_length < (u32) (end - pos)) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " - "Length (%d; %ld remaining in this msg)", - message_length, (long) (end - pos)); - ret->ignore = TRUE; - return NULL; - } - } - - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " - "Message Length %u", flags, message_length); - - if (data->state == WAIT_FRAG_ACK) { -#ifdef CCNS_PL - if (len > 1) /* Empty Flags field included in ACK */ -#else /* CCNS_PL */ - if (len != 0) -#endif /* CCNS_PL */ - { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " - "in WAIT_FRAG_ACK state"); - ret->ignore = TRUE; - return NULL; - } - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); - eap_ikev2_state(data, PROC_MSG); - return eap_ikev2_build_msg(data, ret, id); - } - - if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { - ret->ignore = TRUE; - return NULL; - } - - if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { - return eap_ikev2_process_fragment(data, ret, id, flags, - message_length, pos, - end - pos); - } - - if (data->in_buf == NULL) { - /* Wrap unfragmented messages as wpabuf without extra copy */ - wpabuf_set(&tmpbuf, pos, end - pos); - data->in_buf = &tmpbuf; - } - - if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) { - if (data->in_buf == &tmpbuf) - data->in_buf = NULL; - eap_ikev2_state(data, FAIL); - return NULL; - } - - if (data->in_buf != &tmpbuf) - wpabuf_free(data->in_buf); - data->in_buf = NULL; - - if (data->out_buf == NULL) { - data->out_buf = ikev2_responder_build(&data->ikev2); - if (data->out_buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate " - "IKEv2 message"); - return NULL; - } - data->out_used = 0; - } - - eap_ikev2_state(data, PROC_MSG); - return eap_ikev2_build_msg(data, ret, id); -} - - -static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_ikev2_data *data = priv; - return data->state == DONE && data->keymat_ok; -} - - -static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_ikev2_data *data = priv; - u8 *key; - - if (data->state != DONE || !data->keymat_ok) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key) { - os_memcpy(key, data->keymat, EAP_MSK_LEN); - *len = EAP_MSK_LEN; - } - - return key; -} - - -static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_ikev2_data *data = priv; - u8 *key; - - if (data->state != DONE || !data->keymat_ok) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key) { - os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN); - *len = EAP_EMSK_LEN; - } - - return key; -} - - -static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_ikev2_data *data = priv; - u8 *sid; - size_t sid_len; - size_t offset; - - if (data->state != DONE || !data->keymat_ok) - return NULL; - - sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len; - sid = os_malloc(sid_len); - if (sid) { - offset = 0; - sid[offset] = EAP_TYPE_IKEV2; - offset++; - os_memcpy(sid + offset, data->ikev2.i_nonce, - data->ikev2.i_nonce_len); - offset += data->ikev2.i_nonce_len; - os_memcpy(sid + offset, data->ikev2.r_nonce, - data->ikev2.r_nonce_len); - *len = sid_len; - wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id", - sid, sid_len); - } - - return sid; -} - - -int eap_peer_ikev2_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_IKEV2, - "IKEV2"); - if (eap == NULL) - return -1; - - eap->init = eap_ikev2_init; - eap->deinit = eap_ikev2_deinit; - eap->process = eap_ikev2_process; - eap->isKeyAvailable = eap_ikev2_isKeyAvailable; - eap->getKey = eap_ikev2_getKey; - eap->get_emsk = eap_ikev2_get_emsk; - eap->getSessionId = eap_ikev2_get_session_id; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_leap.c b/contrib/hostapd/src/eap_peer/eap_leap.c deleted file mode 100644 index df3401384c..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_leap.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * EAP peer method: LEAP - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/ms_funcs.h" -#include "crypto/crypto.h" -#include "crypto/random.h" -#include "eap_i.h" - -#define LEAP_VERSION 1 -#define LEAP_CHALLENGE_LEN 8 -#define LEAP_RESPONSE_LEN 24 -#define LEAP_KEY_LEN 16 - - -struct eap_leap_data { - enum { - LEAP_WAIT_CHALLENGE, - LEAP_WAIT_SUCCESS, - LEAP_WAIT_RESPONSE, - LEAP_DONE - } state; - - u8 peer_challenge[LEAP_CHALLENGE_LEN]; - u8 peer_response[LEAP_RESPONSE_LEN]; - - u8 ap_challenge[LEAP_CHALLENGE_LEN]; - u8 ap_response[LEAP_RESPONSE_LEN]; -}; - - -static void * eap_leap_init(struct eap_sm *sm) -{ - struct eap_leap_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = LEAP_WAIT_CHALLENGE; - - sm->leap_done = FALSE; - return data; -} - - -static void eap_leap_deinit(struct eap_sm *sm, void *priv) -{ - os_free(priv); -} - - -static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_leap_data *data = priv; - struct wpabuf *resp; - const u8 *pos, *challenge, *identity, *password; - u8 challenge_len, *rpos; - size_t identity_len, password_len, len; - int pwhash; - - wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password2(sm, &password_len, &pwhash); - if (identity == NULL || password == NULL) - return NULL; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len); - if (pos == NULL || len < 3) { - wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame"); - ret->ignore = TRUE; - return NULL; - } - - if (*pos != LEAP_VERSION) { - wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " - "%d", *pos); - ret->ignore = TRUE; - return NULL; - } - pos++; - - pos++; /* skip unused byte */ - - challenge_len = *pos++; - if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > len - 3) { - wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge " - "(challenge_len=%d reqDataLen=%lu)", - challenge_len, (unsigned long) wpabuf_len(reqData)); - ret->ignore = TRUE; - return NULL; - } - challenge = pos; - os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP", - challenge, LEAP_CHALLENGE_LEN); - - wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response"); - - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, - 3 + LEAP_RESPONSE_LEN + identity_len, - EAP_CODE_RESPONSE, eap_get_id(reqData)); - if (resp == NULL) - return NULL; - wpabuf_put_u8(resp, LEAP_VERSION); - wpabuf_put_u8(resp, 0); /* unused */ - wpabuf_put_u8(resp, LEAP_RESPONSE_LEN); - rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN); - if (pwhash) - challenge_response(challenge, password, rpos); - else - nt_challenge_response(challenge, password, password_len, rpos); - os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response", - rpos, LEAP_RESPONSE_LEN); - wpabuf_put_data(resp, identity, identity_len); - - data->state = LEAP_WAIT_SUCCESS; - - return resp; -} - - -static struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_leap_data *data = priv; - struct wpabuf *resp; - u8 *pos; - const u8 *identity; - size_t identity_len; - - wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success"); - - identity = eap_get_config_identity(sm, &identity_len); - if (identity == NULL) - return NULL; - - if (data->state != LEAP_WAIT_SUCCESS) { - wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in " - "unexpected state (%d) - ignored", data->state); - ret->ignore = TRUE; - return NULL; - } - - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, - 3 + LEAP_CHALLENGE_LEN + identity_len, - EAP_CODE_REQUEST, eap_get_id(reqData)); - if (resp == NULL) - return NULL; - wpabuf_put_u8(resp, LEAP_VERSION); - wpabuf_put_u8(resp, 0); /* unused */ - wpabuf_put_u8(resp, LEAP_CHALLENGE_LEN); - pos = wpabuf_put(resp, LEAP_CHALLENGE_LEN); - if (random_get_bytes(pos, LEAP_CHALLENGE_LEN)) { - wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data " - "for challenge"); - wpabuf_free(resp); - ret->ignore = TRUE; - return NULL; - } - os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos, - LEAP_CHALLENGE_LEN); - wpabuf_put_data(resp, identity, identity_len); - - data->state = LEAP_WAIT_RESPONSE; - - return resp; -} - - -static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_leap_data *data = priv; - const u8 *pos, *password; - u8 response_len, pw_hash[16], pw_hash_hash[16], - expected[LEAP_RESPONSE_LEN]; - size_t password_len, len; - int pwhash; - - wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response"); - - password = eap_get_config_password2(sm, &password_len, &pwhash); - if (password == NULL) - return NULL; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len); - if (pos == NULL || len < 3) { - wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame"); - ret->ignore = TRUE; - return NULL; - } - - if (*pos != LEAP_VERSION) { - wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " - "%d", *pos); - ret->ignore = TRUE; - return NULL; - } - pos++; - - pos++; /* skip unused byte */ - - response_len = *pos++; - if (response_len != LEAP_RESPONSE_LEN || response_len > len - 3) { - wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response " - "(response_len=%d reqDataLen=%lu)", - response_len, (unsigned long) wpabuf_len(reqData)); - ret->ignore = TRUE; - return NULL; - } - - wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP", - pos, LEAP_RESPONSE_LEN); - os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN); - - if (pwhash) { - if (hash_nt_password_hash(password, pw_hash_hash)) { - ret->ignore = TRUE; - return NULL; - } - } else { - if (nt_password_hash(password, password_len, pw_hash) || - hash_nt_password_hash(pw_hash, pw_hash_hash)) { - ret->ignore = TRUE; - return NULL; - } - } - challenge_response(data->ap_challenge, pw_hash_hash, expected); - - ret->methodState = METHOD_DONE; - ret->allowNotifications = FALSE; - - if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) { - wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid " - "response - authentication failed"); - wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP", - expected, LEAP_RESPONSE_LEN); - ret->decision = DECISION_FAIL; - return NULL; - } - - ret->decision = DECISION_UNCOND_SUCC; - - /* LEAP is somewhat odd method since it sends EAP-Success in the middle - * of the authentication. Use special variable to transit EAP state - * machine to SUCCESS state. */ - sm->leap_done = TRUE; - data->state = LEAP_DONE; - - /* No more authentication messages expected; AP will send EAPOL-Key - * frames if encryption is enabled. */ - return NULL; -} - - -static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - const struct eap_hdr *eap; - size_t password_len; - const u8 *password; - - password = eap_get_config_password(sm, &password_len); - if (password == NULL) { - wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured"); - eap_sm_request_password(sm); - ret->ignore = TRUE; - return NULL; - } - - /* - * LEAP needs to be able to handle EAP-Success frame which does not - * include Type field. Consequently, eap_hdr_validate() cannot be used - * here. This validation will be done separately for EAP-Request and - * EAP-Response frames. - */ - eap = wpabuf_head(reqData); - if (wpabuf_len(reqData) < sizeof(*eap) || - be_to_host16(eap->length) > wpabuf_len(reqData)) { - wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame"); - ret->ignore = TRUE; - return NULL; - } - - ret->ignore = FALSE; - ret->allowNotifications = TRUE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - - sm->leap_done = FALSE; - - switch (eap->code) { - case EAP_CODE_REQUEST: - return eap_leap_process_request(sm, priv, ret, reqData); - case EAP_CODE_SUCCESS: - return eap_leap_process_success(sm, priv, ret, reqData); - case EAP_CODE_RESPONSE: - return eap_leap_process_response(sm, priv, ret, reqData); - default: - wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - " - "ignored", eap->code); - ret->ignore = TRUE; - return NULL; - } -} - - -static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_leap_data *data = priv; - return data->state == LEAP_DONE; -} - - -static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_leap_data *data = priv; - u8 *key, pw_hash_hash[16], pw_hash[16]; - const u8 *addr[5], *password; - size_t elen[5], password_len; - int pwhash; - - if (data->state != LEAP_DONE) - return NULL; - - password = eap_get_config_password2(sm, &password_len, &pwhash); - if (password == NULL) - return NULL; - - key = os_malloc(LEAP_KEY_LEN); - if (key == NULL) - return NULL; - - if (pwhash) { - if (hash_nt_password_hash(password, pw_hash_hash)) { - os_free(key); - return NULL; - } - } else { - if (nt_password_hash(password, password_len, pw_hash) || - hash_nt_password_hash(pw_hash, pw_hash_hash)) { - os_free(key); - return NULL; - } - } - wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash", - pw_hash_hash, 16); - wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge", - data->peer_challenge, LEAP_CHALLENGE_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response", - data->peer_response, LEAP_RESPONSE_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge", - data->ap_challenge, LEAP_CHALLENGE_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response", - data->ap_response, LEAP_RESPONSE_LEN); - - addr[0] = pw_hash_hash; - elen[0] = 16; - addr[1] = data->ap_challenge; - elen[1] = LEAP_CHALLENGE_LEN; - addr[2] = data->ap_response; - elen[2] = LEAP_RESPONSE_LEN; - addr[3] = data->peer_challenge; - elen[3] = LEAP_CHALLENGE_LEN; - addr[4] = data->peer_response; - elen[4] = LEAP_RESPONSE_LEN; - md5_vector(5, addr, elen, key); - wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN); - *len = LEAP_KEY_LEN; - - return key; -} - - -int eap_peer_leap_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP"); - if (eap == NULL) - return -1; - - eap->init = eap_leap_init; - eap->deinit = eap_leap_deinit; - eap->process = eap_leap_process; - eap->isKeyAvailable = eap_leap_isKeyAvailable; - eap->getKey = eap_leap_getKey; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_md5.c b/contrib/hostapd/src/eap_peer/eap_md5.c deleted file mode 100644 index d06befaeb1..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_md5.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994) - * Copyright (c) 2004-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" -#include "eap_common/chap.h" - - -static void * eap_md5_init(struct eap_sm *sm) -{ - /* No need for private data. However, must return non-NULL to indicate - * success. */ - return (void *) 1; -} - - -static void eap_md5_deinit(struct eap_sm *sm, void *priv) -{ -} - - -static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct wpabuf *resp; - const u8 *pos, *challenge, *password; - u8 *rpos, id; - size_t len, challenge_len, password_len; - - password = eap_get_config_password(sm, &password_len); - if (password == NULL) { - wpa_printf(MSG_INFO, "EAP-MD5: Password not configured"); - eap_sm_request_password(sm); - ret->ignore = TRUE; - return NULL; - } - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, reqData, &len); - if (pos == NULL || len == 0) { - wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)", - pos, (unsigned long) len); - ret->ignore = TRUE; - return NULL; - } - - /* - * CHAP Challenge: - * Value-Size (1 octet) | Value(Challenge) | Name(optional) - */ - challenge_len = *pos++; - if (challenge_len == 0 || challenge_len > len - 1) { - wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge " - "(challenge_len=%lu len=%lu)", - (unsigned long) challenge_len, (unsigned long) len); - ret->ignore = TRUE; - return NULL; - } - ret->ignore = FALSE; - challenge = pos; - wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", - challenge, challenge_len); - - wpa_printf(MSG_DEBUG, "EAP-MD5: Generating Challenge Response"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - ret->allowNotifications = TRUE; - - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHAP_MD5_LEN, - EAP_CODE_RESPONSE, eap_get_id(reqData)); - if (resp == NULL) - return NULL; - - /* - * CHAP Response: - * Value-Size (1 octet) | Value(Response) | Name(optional) - */ - wpabuf_put_u8(resp, CHAP_MD5_LEN); - - id = eap_get_id(resp); - rpos = wpabuf_put(resp, CHAP_MD5_LEN); - if (chap_md5(id, password, password_len, challenge, challenge_len, - rpos)) { - wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed"); - ret->ignore = TRUE; - wpabuf_free(resp); - return NULL; - } - wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, CHAP_MD5_LEN); - - return resp; -} - - -int eap_peer_md5_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5"); - if (eap == NULL) - return -1; - - eap->init = eap_md5_init; - eap->deinit = eap_md5_deinit; - eap->process = eap_md5_process; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_methods.c b/contrib/hostapd/src/eap_peer/eap_methods.c deleted file mode 100644 index 83a1457964..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_methods.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * EAP peer: Method registration - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#ifdef CONFIG_DYNAMIC_EAP_METHODS -#include -#endif /* CONFIG_DYNAMIC_EAP_METHODS */ - -#include "common.h" -#include "eap_i.h" -#include "eap_methods.h" - - -static struct eap_method *eap_methods = NULL; - - -/** - * eap_peer_get_eap_method - Get EAP method based on type number - * @vendor: EAP Vendor-Id (0 = IETF) - * @method: EAP type number - * Returns: Pointer to EAP method or %NULL if not found - */ -const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method) -{ - struct eap_method *m; - for (m = eap_methods; m; m = m->next) { - if (m->vendor == vendor && m->method == method) - return m; - } - return NULL; -} - - -/** - * eap_peer_get_type - Get EAP type for the given EAP method name - * @name: EAP method name, e.g., TLS - * @vendor: Buffer for returning EAP Vendor-Id - * Returns: EAP method type or %EAP_TYPE_NONE if not found - * - * This function maps EAP type names into EAP type numbers based on the list of - * EAP methods included in the build. - */ -EapType eap_peer_get_type(const char *name, int *vendor) -{ - struct eap_method *m; - for (m = eap_methods; m; m = m->next) { - if (os_strcmp(m->name, name) == 0) { - *vendor = m->vendor; - return m->method; - } - } - *vendor = EAP_VENDOR_IETF; - return EAP_TYPE_NONE; -} - - -/** - * eap_get_name - Get EAP method name for the given EAP type - * @vendor: EAP Vendor-Id (0 = IETF) - * @type: EAP method type - * Returns: EAP method name, e.g., TLS, or %NULL if not found - * - * This function maps EAP type numbers into EAP type names based on the list of - * EAP methods included in the build. - */ -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; - } - return NULL; -} - - -/** - * eap_get_names - Get space separated list of names for supported EAP methods - * @buf: Buffer for names - * @buflen: Buffer length - * Returns: Number of characters written into buf (not including nul - * termination) - */ -size_t eap_get_names(char *buf, size_t buflen) -{ - char *pos, *end; - struct eap_method *m; - int ret; - - if (buflen == 0) - return 0; - - pos = buf; - end = pos + buflen; - - for (m = eap_methods; m; m = m->next) { - ret = os_snprintf(pos, end - pos, "%s%s", - m == eap_methods ? "" : " ", m->name); - if (ret < 0 || ret >= end - pos) - break; - pos += ret; - } - buf[buflen - 1] = '\0'; - - return pos - buf; -} - - -/** - * eap_get_names_as_string_array - Get supported EAP methods as string array - * @num: Buffer for returning the number of items in array, not including %NULL - * terminator. This parameter can be %NULL if the length is not needed. - * Returns: A %NULL-terminated array of strings, or %NULL on error. - * - * This function returns the list of names for all supported EAP methods as an - * array of strings. The caller must free the returned array items and the - * array. - */ -char ** eap_get_names_as_string_array(size_t *num) -{ - struct eap_method *m; - size_t array_len = 0; - char **array; - int i = 0, j; - - for (m = eap_methods; m; m = m->next) - array_len++; - - array = os_zalloc(sizeof(char *) * (array_len + 1)); - if (array == NULL) - return NULL; - - for (m = eap_methods; m; m = m->next) { - array[i++] = os_strdup(m->name); - if (array[i - 1] == NULL) { - for (j = 0; j < i; j++) - os_free(array[j]); - os_free(array); - return NULL; - } - } - array[i] = NULL; - - if (num) - *num = array_len; - - return array; -} - - -/** - * eap_peer_get_methods - Get a list of enabled EAP peer methods - * @count: Set to number of available methods - * Returns: List of enabled EAP peer methods - */ -const struct eap_method * eap_peer_get_methods(size_t *count) -{ - int c = 0; - struct eap_method *m; - - for (m = eap_methods; m; m = m->next) - c++; - - *count = c; - return eap_methods; -} - - -#ifdef CONFIG_DYNAMIC_EAP_METHODS -/** - * eap_peer_method_load - Load a dynamic EAP method library (shared object) - * @so: File path for the shared object file to load - * Returns: 0 on success, -1 on failure - */ -int eap_peer_method_load(const char *so) -{ - void *handle; - int (*dyn_init)(void); - int ret; - - handle = dlopen(so, RTLD_LAZY); - if (handle == NULL) { - wpa_printf(MSG_ERROR, "EAP: Failed to open dynamic EAP method " - "'%s': %s", so, dlerror()); - return -1; - } - - dyn_init = dlsym(handle, "eap_peer_method_dynamic_init"); - if (dyn_init == NULL) { - dlclose(handle); - wpa_printf(MSG_ERROR, "EAP: Invalid EAP method '%s' - no " - "eap_peer_method_dynamic_init()", so); - return -1; - } - - ret = dyn_init(); - if (ret) { - dlclose(handle); - wpa_printf(MSG_ERROR, "EAP: Failed to add EAP method '%s' - " - "ret %d", so, ret); - return ret; - } - - /* Store the handle for this shared object. It will be freed with - * dlclose() when the EAP method is unregistered. */ - eap_methods->dl_handle = handle; - - wpa_printf(MSG_DEBUG, "EAP: Loaded dynamic EAP method: '%s'", so); - - return 0; -} - - -/** - * eap_peer_method_unload - Unload a dynamic EAP method library (shared object) - * @method: Pointer to the dynamically loaded EAP method - * Returns: 0 on success, -1 on failure - * - * This function can be used to unload EAP methods that have been previously - * loaded with eap_peer_method_load(). Before unloading the method, all - * references to the method must be removed to make sure that no dereferences - * of freed memory will occur after unloading. - */ -int eap_peer_method_unload(struct eap_method *method) -{ - struct eap_method *m, *prev; - void *handle; - - m = eap_methods; - prev = NULL; - while (m) { - if (m == method) - break; - prev = m; - m = m->next; - } - - if (m == NULL || m->dl_handle == NULL) - return -1; - - if (prev) - prev->next = m->next; - else - eap_methods = m->next; - - handle = m->dl_handle; - - if (m->free) - m->free(m); - else - eap_peer_method_free(m); - - dlclose(handle); - - return 0; -} -#endif /* CONFIG_DYNAMIC_EAP_METHODS */ - - -/** - * eap_peer_method_alloc - Allocate EAP peer method structure - * @version: Version of the EAP peer method interface (set to - * EAP_PEER_METHOD_INTERFACE_VERSION) - * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF) - * @method: EAP type number (EAP_TYPE_*) - * @name: Name of the method (e.g., "TLS") - * Returns: Allocated EAP method structure or %NULL on failure - * - * The returned structure should be freed with eap_peer_method_free() when it - * is not needed anymore. - */ -struct eap_method * eap_peer_method_alloc(int version, int vendor, - EapType method, const char *name) -{ - struct eap_method *eap; - eap = os_zalloc(sizeof(*eap)); - if (eap == NULL) - return NULL; - eap->version = version; - eap->vendor = vendor; - eap->method = method; - eap->name = name; - return eap; -} - - -/** - * eap_peer_method_free - Free EAP peer method structure - * @method: Method structure allocated with eap_peer_method_alloc() - */ -void eap_peer_method_free(struct eap_method *method) -{ - os_free(method); -} - - -/** - * eap_peer_method_register - Register an EAP peer method - * @method: EAP method to register - * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method - * has already been registered - * - * Each EAP peer method needs to call this function to register itself as a - * supported EAP method. - */ -int eap_peer_method_register(struct eap_method *method) -{ - struct eap_method *m, *last = NULL; - - if (method == NULL || method->name == NULL || - method->version != EAP_PEER_METHOD_INTERFACE_VERSION) - return -1; - - for (m = eap_methods; m; m = m->next) { - if ((m->vendor == method->vendor && - m->method == method->method) || - os_strcmp(m->name, method->name) == 0) - return -2; - last = m; - } - - if (last) - last->next = method; - else - eap_methods = method; - - return 0; -} - - -/** - * eap_peer_unregister_methods - Unregister EAP peer methods - * - * This function is called at program termination to unregister all EAP peer - * methods. - */ -void eap_peer_unregister_methods(void) -{ - struct eap_method *m; -#ifdef CONFIG_DYNAMIC_EAP_METHODS - void *handle; -#endif /* CONFIG_DYNAMIC_EAP_METHODS */ - - while (eap_methods) { - m = eap_methods; - eap_methods = eap_methods->next; - -#ifdef CONFIG_DYNAMIC_EAP_METHODS - handle = m->dl_handle; -#endif /* CONFIG_DYNAMIC_EAP_METHODS */ - - if (m->free) - m->free(m); - else - eap_peer_method_free(m); - -#ifdef CONFIG_DYNAMIC_EAP_METHODS - if (handle) - dlclose(handle); -#endif /* CONFIG_DYNAMIC_EAP_METHODS */ - } -} diff --git a/contrib/hostapd/src/eap_peer/eap_methods.h b/contrib/hostapd/src/eap_peer/eap_methods.h deleted file mode 100644 index a465fd2354..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_methods.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * EAP peer: Method registration - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_METHODS_H -#define EAP_METHODS_H - -#include "eap_common/eap_defs.h" - -const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method); -const struct eap_method * eap_peer_get_methods(size_t *count); - -struct eap_method * eap_peer_method_alloc(int version, int vendor, - EapType method, const char *name); -void eap_peer_method_free(struct eap_method *method); -int eap_peer_method_register(struct eap_method *method); - - -#ifdef IEEE8021X_EAPOL - -EapType eap_peer_get_type(const char *name, int *vendor); -const char * eap_get_name(int vendor, EapType type); -size_t eap_get_names(char *buf, size_t buflen); -char ** eap_get_names_as_string_array(size_t *num); -void eap_peer_unregister_methods(void); - -#else /* IEEE8021X_EAPOL */ - -static inline EapType eap_peer_get_type(const char *name, int *vendor) -{ - *vendor = EAP_VENDOR_IETF; - return EAP_TYPE_NONE; -} - -static inline const char * eap_get_name(int vendor, EapType type) -{ - return NULL; -} - -static inline size_t eap_get_names(char *buf, size_t buflen) -{ - return 0; -} - -static inline int eap_peer_register_methods(void) -{ - return 0; -} - -static inline void eap_peer_unregister_methods(void) -{ -} - -static inline char ** eap_get_names_as_string_array(size_t *num) -{ - return NULL; -} - -#endif /* IEEE8021X_EAPOL */ - - -#ifdef CONFIG_DYNAMIC_EAP_METHODS - -int eap_peer_method_load(const char *so); -int eap_peer_method_unload(struct eap_method *method); - -#else /* CONFIG_DYNAMIC_EAP_METHODS */ - -static inline int eap_peer_method_load(const char *so) -{ - return 0; -} - -static inline int eap_peer_method_unload(struct eap_method *method) -{ - return 0; -} - -#endif /* CONFIG_DYNAMIC_EAP_METHODS */ - -/* EAP peer method registration calls for statically linked in methods */ -int eap_peer_md5_register(void); -int eap_peer_tls_register(void); -int eap_peer_unauth_tls_register(void); -int eap_peer_mschapv2_register(void); -int eap_peer_peap_register(void); -int eap_peer_ttls_register(void); -int eap_peer_gtc_register(void); -int eap_peer_otp_register(void); -int eap_peer_sim_register(void); -int eap_peer_leap_register(void); -int eap_peer_psk_register(void); -int eap_peer_aka_register(void); -int eap_peer_aka_prime_register(void); -int eap_peer_fast_register(void); -int eap_peer_pax_register(void); -int eap_peer_sake_register(void); -int eap_peer_gpsk_register(void); -int eap_peer_wsc_register(void); -int eap_peer_ikev2_register(void); -int eap_peer_vendor_test_register(void); -int eap_peer_tnc_register(void); -int eap_peer_pwd_register(void); -int eap_peer_eke_register(void); - -#endif /* EAP_METHODS_H */ diff --git a/contrib/hostapd/src/eap_peer/eap_mschapv2.c b/contrib/hostapd/src/eap_peer/eap_mschapv2.c deleted file mode 100644 index f9aa74257d..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_mschapv2.c +++ /dev/null @@ -1,877 +0,0 @@ -/* - * EAP peer method: EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt) - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file implements EAP peer part of EAP-MSCHAPV2 method (EAP type 26). - * draft-kamath-pppext-eap-mschapv2-00.txt defines the Microsoft EAP CHAP - * Extensions Protocol, Version 2, for mutual authentication and key - * derivation. This encapsulates MS-CHAP-v2 protocol which is defined in - * RFC 2759. Use of EAP-MSCHAPV2 derived keys with MPPE cipher is described in - * RFC 3079. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/ms_funcs.h" -#include "crypto/random.h" -#include "common/wpa_ctrl.h" -#include "mschapv2.h" -#include "eap_i.h" -#include "eap_config.h" - - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct eap_mschapv2_hdr { - u8 op_code; /* MSCHAPV2_OP_* */ - u8 mschapv2_id; /* usually same as EAP identifier; must be changed - * for challenges, but not for success/failure */ - u8 ms_length[2]; /* Note: misaligned; length - 5 */ - /* followed by data */ -} STRUCT_PACKED; - -/* Response Data field */ -struct ms_response { - u8 peer_challenge[MSCHAPV2_CHAL_LEN]; - u8 reserved[8]; - u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN]; - u8 flags; -} STRUCT_PACKED; - -/* Change-Password Data field */ -struct ms_change_password { - u8 encr_password[516]; - u8 encr_hash[16]; - u8 peer_challenge[MSCHAPV2_CHAL_LEN]; - u8 reserved[8]; - u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN]; - u8 flags[2]; -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - -#define MSCHAPV2_OP_CHALLENGE 1 -#define MSCHAPV2_OP_RESPONSE 2 -#define MSCHAPV2_OP_SUCCESS 3 -#define MSCHAPV2_OP_FAILURE 4 -#define MSCHAPV2_OP_CHANGE_PASSWORD 7 - -#define ERROR_RESTRICTED_LOGON_HOURS 646 -#define ERROR_ACCT_DISABLED 647 -#define ERROR_PASSWD_EXPIRED 648 -#define ERROR_NO_DIALIN_PERMISSION 649 -#define ERROR_AUTHENTICATION_FAILURE 691 -#define ERROR_CHANGING_PASSWORD 709 - -#define PASSWD_CHANGE_CHAL_LEN 16 -#define MSCHAPV2_KEY_LEN 16 - - -struct eap_mschapv2_data { - u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN]; - int auth_response_valid; - - int prev_error; - u8 passwd_change_challenge[PASSWD_CHANGE_CHAL_LEN]; - int passwd_change_challenge_valid; - int passwd_change_version; - - /* Optional challenge values generated in EAP-FAST Phase 1 negotiation - */ - u8 *peer_challenge; - u8 *auth_challenge; - - int phase2; - u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; - int master_key_valid; - int success; - - struct wpabuf *prev_challenge; -}; - - -static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv); - - -static void * eap_mschapv2_init(struct eap_sm *sm) -{ - struct eap_mschapv2_data *data; - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - - if (sm->peer_challenge) { - data->peer_challenge = os_malloc(MSCHAPV2_CHAL_LEN); - if (data->peer_challenge == NULL) { - eap_mschapv2_deinit(sm, data); - return NULL; - } - os_memcpy(data->peer_challenge, sm->peer_challenge, - MSCHAPV2_CHAL_LEN); - } - - if (sm->auth_challenge) { - data->auth_challenge = os_malloc(MSCHAPV2_CHAL_LEN); - if (data->auth_challenge == NULL) { - eap_mschapv2_deinit(sm, data); - return NULL; - } - os_memcpy(data->auth_challenge, sm->auth_challenge, - MSCHAPV2_CHAL_LEN); - } - - data->phase2 = sm->init_phase2; - - return data; -} - - -static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_mschapv2_data *data = priv; - os_free(data->peer_challenge); - os_free(data->auth_challenge); - wpabuf_free(data->prev_challenge); - os_free(data); -} - - -static struct wpabuf * eap_mschapv2_challenge_reply( - struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id, - u8 mschapv2_id, const u8 *auth_challenge) -{ - struct wpabuf *resp; - struct eap_mschapv2_hdr *ms; - u8 *peer_challenge; - int ms_len; - struct ms_response *r; - size_t identity_len, password_len; - const u8 *identity, *password; - int pwhash; - - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password2(sm, &password_len, &pwhash); - if (identity == NULL || password == NULL) - return NULL; - - ms_len = sizeof(*ms) + 1 + sizeof(*r) + identity_len; - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, - EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - - ms = wpabuf_put(resp, sizeof(*ms)); - ms->op_code = MSCHAPV2_OP_RESPONSE; - ms->mschapv2_id = mschapv2_id; - if (data->prev_error) { - /* - * TODO: this does not seem to be enough when processing two - * or more failure messages. IAS did not increment mschapv2_id - * in its own packets, but it seemed to expect the peer to - * increment this for all packets(?). - */ - ms->mschapv2_id++; - } - WPA_PUT_BE16(ms->ms_length, ms_len); - - wpabuf_put_u8(resp, sizeof(*r)); /* Value-Size */ - - /* Response */ - r = wpabuf_put(resp, sizeof(*r)); - peer_challenge = r->peer_challenge; - if (data->peer_challenge) { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated " - "in Phase 1"); - peer_challenge = data->peer_challenge; - os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN); - } else if (random_get_bytes(peer_challenge, MSCHAPV2_CHAL_LEN)) { - wpabuf_free(resp); - return NULL; - } - os_memset(r->reserved, 0, 8); - if (data->auth_challenge) { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated " - "in Phase 1"); - auth_challenge = data->auth_challenge; - } - if (mschapv2_derive_response(identity, identity_len, password, - password_len, pwhash, auth_challenge, - peer_challenge, r->nt_response, - data->auth_response, data->master_key)) { - wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to derive " - "response"); - wpabuf_free(resp); - return NULL; - } - data->auth_response_valid = 1; - data->master_key_valid = 1; - - r->flags = 0; /* reserved, must be zero */ - - wpabuf_put_data(resp, identity, identity_len); - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d " - "(response)", id, ms->mschapv2_id); - return resp; -} - - -/** - * eap_mschapv2_process - Process an EAP-MSCHAPv2 challenge message - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Pointer to private EAP method data from eap_mschapv2_init() - * @ret: Return values from EAP request validation and processing - * @req: Pointer to EAP-MSCHAPv2 header from the request - * @req_len: Length of the EAP-MSCHAPv2 data - * @id: EAP identifier used in the request - * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if - * no reply available - */ -static struct wpabuf * eap_mschapv2_challenge( - struct eap_sm *sm, struct eap_mschapv2_data *data, - struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, - size_t req_len, u8 id) -{ - size_t len, challenge_len; - const u8 *pos, *challenge; - - if (eap_get_config_identity(sm, &len) == NULL || - eap_get_config_password(sm, &len) == NULL) - return NULL; - - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge"); - if (req_len < sizeof(*req) + 1) { - wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge data " - "(len %lu)", (unsigned long) req_len); - ret->ignore = TRUE; - return NULL; - } - pos = (const u8 *) (req + 1); - challenge_len = *pos++; - len = req_len - sizeof(*req) - 1; - if (challenge_len != MSCHAPV2_CHAL_LEN) { - wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length " - "%lu", (unsigned long) challenge_len); - ret->ignore = TRUE; - return NULL; - } - - if (len < challenge_len) { - wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge" - " packet: len=%lu challenge_len=%lu", - (unsigned long) len, (unsigned long) challenge_len); - ret->ignore = TRUE; - return NULL; - } - - if (data->passwd_change_challenge_valid) { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the " - "failure message"); - challenge = data->passwd_change_challenge; - } else - challenge = pos; - pos += challenge_len; - len -= challenge_len; - wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername", - pos, len); - - ret->ignore = FALSE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - ret->allowNotifications = TRUE; - - return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id, - challenge); -} - - -static void eap_mschapv2_password_changed(struct eap_sm *sm, - struct eap_mschapv2_data *data) -{ - struct eap_peer_config *config = eap_get_config(sm); - if (config && config->new_password) { - wpa_msg(sm->msg_ctx, MSG_INFO, - WPA_EVENT_PASSWORD_CHANGED - "EAP-MSCHAPV2: Password changed successfully"); - data->prev_error = 0; - os_free(config->password); - if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { - /* TODO: update external storage */ - } else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) { - config->password = os_malloc(16); - config->password_len = 16; - if (config->password) { - nt_password_hash(config->new_password, - config->new_password_len, - config->password); - } - os_free(config->new_password); - } else { - config->password = config->new_password; - config->password_len = config->new_password_len; - } - config->new_password = NULL; - config->new_password_len = 0; - } -} - - -/** - * eap_mschapv2_process - Process an EAP-MSCHAPv2 success message - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Pointer to private EAP method data from eap_mschapv2_init() - * @ret: Return values from EAP request validation and processing - * @req: Pointer to EAP-MSCHAPv2 header from the request - * @req_len: Length of the EAP-MSCHAPv2 data - * @id: EAP identifier used in th erequest - * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if - * no reply available - */ -static struct wpabuf * eap_mschapv2_success(struct eap_sm *sm, - struct eap_mschapv2_data *data, - struct eap_method_ret *ret, - const struct eap_mschapv2_hdr *req, - size_t req_len, u8 id) -{ - struct wpabuf *resp; - const u8 *pos; - size_t len; - - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success"); - len = req_len - sizeof(*req); - pos = (const u8 *) (req + 1); - if (!data->auth_response_valid || - mschapv2_verify_auth_response(data->auth_response, pos, len)) { - wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: Invalid authenticator " - "response in success request"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return NULL; - } - pos += 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN; - len -= 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN; - while (len > 0 && *pos == ' ') { - pos++; - len--; - } - wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Success message", - pos, len); - wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Authentication succeeded"); - - /* Note: Only op_code of the EAP-MSCHAPV2 header is included in success - * message. */ - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1, - EAP_CODE_RESPONSE, id); - if (resp == NULL) { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate " - "buffer for success response"); - ret->ignore = TRUE; - return NULL; - } - - wpabuf_put_u8(resp, MSCHAPV2_OP_SUCCESS); /* op_code */ - - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - ret->allowNotifications = FALSE; - data->success = 1; - - if (data->prev_error == ERROR_PASSWD_EXPIRED) - eap_mschapv2_password_changed(sm, data); - - return resp; -} - - -static int eap_mschapv2_failure_txt(struct eap_sm *sm, - struct eap_mschapv2_data *data, char *txt) -{ - char *pos, *msg = ""; - int retry = 1; - struct eap_peer_config *config = eap_get_config(sm); - - /* For example: - * E=691 R=1 C=<32 octets hex challenge> V=3 M=Authentication Failure - */ - - pos = txt; - - if (pos && os_strncmp(pos, "E=", 2) == 0) { - pos += 2; - data->prev_error = atoi(pos); - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: error %d", - data->prev_error); - pos = os_strchr(pos, ' '); - if (pos) - pos++; - } - - if (pos && os_strncmp(pos, "R=", 2) == 0) { - pos += 2; - retry = atoi(pos); - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: retry is %sallowed", - retry == 1 ? "" : "not "); - pos = os_strchr(pos, ' '); - if (pos) - pos++; - } - - if (pos && os_strncmp(pos, "C=", 2) == 0) { - int hex_len; - pos += 2; - hex_len = os_strchr(pos, ' ') - (char *) pos; - if (hex_len == PASSWD_CHANGE_CHAL_LEN * 2) { - if (hexstr2bin(pos, data->passwd_change_challenge, - PASSWD_CHANGE_CHAL_LEN)) { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid " - "failure challenge"); - } else { - wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: failure " - "challenge", - data->passwd_change_challenge, - PASSWD_CHANGE_CHAL_LEN); - data->passwd_change_challenge_valid = 1; - } - } else { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid failure " - "challenge len %d", hex_len); - } - pos = os_strchr(pos, ' '); - if (pos) - pos++; - } else { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: required challenge field " - "was not present in failure message"); - } - - if (pos && os_strncmp(pos, "V=", 2) == 0) { - pos += 2; - data->passwd_change_version = atoi(pos); - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: password changing " - "protocol version %d", data->passwd_change_version); - pos = os_strchr(pos, ' '); - if (pos) - pos++; - } - - if (pos && os_strncmp(pos, "M=", 2) == 0) { - pos += 2; - msg = pos; - } - wpa_msg(sm->msg_ctx, MSG_WARNING, - "EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error " - "%d)", - msg, retry == 1 ? "" : "not ", data->prev_error); - if (data->prev_error == ERROR_PASSWD_EXPIRED && - data->passwd_change_version == 3 && config) { - if (config->new_password == NULL) { - wpa_msg(sm->msg_ctx, MSG_INFO, - "EAP-MSCHAPV2: Password expired - password " - "change required"); - eap_sm_request_new_password(sm); - } - } else if (retry == 1 && config) { - /* TODO: could prevent the current password from being used - * again at least for some period of time */ - if (!config->mschapv2_retry) - eap_sm_request_identity(sm); - eap_sm_request_password(sm); - config->mschapv2_retry = 1; - } else if (config) { - /* TODO: prevent retries using same username/password */ - config->mschapv2_retry = 0; - } - - return retry == 1; -} - - -static struct wpabuf * eap_mschapv2_change_password( - struct eap_sm *sm, struct eap_mschapv2_data *data, - struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, u8 id) -{ - struct wpabuf *resp; - int ms_len; - const u8 *username, *password, *new_password; - size_t username_len, password_len, new_password_len; - struct eap_mschapv2_hdr *ms; - struct ms_change_password *cp; - u8 password_hash[16], password_hash_hash[16]; - int pwhash; - - username = eap_get_config_identity(sm, &username_len); - password = eap_get_config_password2(sm, &password_len, &pwhash); - new_password = eap_get_config_new_password(sm, &new_password_len); - if (username == NULL || password == NULL || new_password == NULL) - return NULL; - - username = mschapv2_remove_domain(username, &username_len); - - ret->ignore = FALSE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_COND_SUCC; - ret->allowNotifications = TRUE; - - ms_len = sizeof(*ms) + sizeof(*cp); - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, - EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - - ms = wpabuf_put(resp, sizeof(*ms)); - ms->op_code = MSCHAPV2_OP_CHANGE_PASSWORD; - ms->mschapv2_id = req->mschapv2_id + 1; - WPA_PUT_BE16(ms->ms_length, ms_len); - cp = wpabuf_put(resp, sizeof(*cp)); - - /* Encrypted-Password */ - if (pwhash) { - if (encrypt_pw_block_with_password_hash( - new_password, new_password_len, - password, cp->encr_password)) - goto fail; - } else { - if (new_password_encrypted_with_old_nt_password_hash( - new_password, new_password_len, - password, password_len, cp->encr_password)) - goto fail; - } - - /* Encrypted-Hash */ - if (pwhash) { - u8 new_password_hash[16]; - nt_password_hash(new_password, new_password_len, - new_password_hash); - nt_password_hash_encrypted_with_block(password, - new_password_hash, - cp->encr_hash); - } else { - old_nt_password_hash_encrypted_with_new_nt_password_hash( - new_password, new_password_len, - password, password_len, cp->encr_hash); - } - - /* Peer-Challenge */ - if (random_get_bytes(cp->peer_challenge, MSCHAPV2_CHAL_LEN)) - goto fail; - - /* Reserved, must be zero */ - os_memset(cp->reserved, 0, 8); - - /* NT-Response */ - wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge", - data->passwd_change_challenge, PASSWD_CHANGE_CHAL_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge", - cp->peer_challenge, MSCHAPV2_CHAL_LEN); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username", - username, username_len); - wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: new password", - new_password, new_password_len); - generate_nt_response(data->passwd_change_challenge, cp->peer_challenge, - username, username_len, - new_password, new_password_len, - cp->nt_response); - wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: NT-Response", - cp->nt_response, MSCHAPV2_NT_RESPONSE_LEN); - - /* Authenticator response is not really needed yet, but calculate it - * here so that challenges need not be saved. */ - generate_authenticator_response(new_password, new_password_len, - cp->peer_challenge, - data->passwd_change_challenge, - username, username_len, - cp->nt_response, data->auth_response); - data->auth_response_valid = 1; - - /* Likewise, generate master_key here since we have the needed data - * available. */ - nt_password_hash(new_password, new_password_len, password_hash); - hash_nt_password_hash(password_hash, password_hash_hash); - get_master_key(password_hash_hash, cp->nt_response, data->master_key); - data->master_key_valid = 1; - - /* Flags */ - os_memset(cp->flags, 0, 2); - - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d " - "(change pw)", id, ms->mschapv2_id); - - return resp; - -fail: - wpabuf_free(resp); - return NULL; -} - - -/** - * eap_mschapv2_process - Process an EAP-MSCHAPv2 failure message - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Pointer to private EAP method data from eap_mschapv2_init() - * @ret: Return values from EAP request validation and processing - * @req: Pointer to EAP-MSCHAPv2 header from the request - * @req_len: Length of the EAP-MSCHAPv2 data - * @id: EAP identifier used in th erequest - * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if - * no reply available - */ -static struct wpabuf * eap_mschapv2_failure(struct eap_sm *sm, - struct eap_mschapv2_data *data, - struct eap_method_ret *ret, - const struct eap_mschapv2_hdr *req, - size_t req_len, u8 id) -{ - struct wpabuf *resp; - const u8 *msdata = (const u8 *) (req + 1); - char *buf; - size_t len = req_len - sizeof(*req); - int retry = 0; - - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received failure"); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Failure data", - msdata, len); - /* - * eap_mschapv2_failure_txt() expects a nul terminated string, so we - * must allocate a large enough temporary buffer to create that since - * the received message does not include nul termination. - */ - buf = dup_binstr(msdata, len); - if (buf) { - retry = eap_mschapv2_failure_txt(sm, data, buf); - os_free(buf); - } - - ret->ignore = FALSE; - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - ret->allowNotifications = FALSE; - - if (data->prev_error == ERROR_PASSWD_EXPIRED && - data->passwd_change_version == 3) { - struct eap_peer_config *config = eap_get_config(sm); - if (config && config->new_password) - return eap_mschapv2_change_password(sm, data, ret, req, - id); - if (config && config->pending_req_new_password) - return NULL; - } else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) { - /* TODO: could try to retry authentication, e.g, after having - * changed the username/password. In this case, EAP MS-CHAP-v2 - * Failure Response would not be sent here. */ - return NULL; - } - - /* Note: Only op_code of the EAP-MSCHAPV2 header is included in failure - * message. */ - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1, - EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - - wpabuf_put_u8(resp, MSCHAPV2_OP_FAILURE); /* op_code */ - - return resp; -} - - -static int eap_mschapv2_check_config(struct eap_sm *sm) -{ - size_t len; - - if (eap_get_config_identity(sm, &len) == NULL) { - wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured"); - eap_sm_request_identity(sm); - return -1; - } - - if (eap_get_config_password(sm, &len) == NULL) { - wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured"); - eap_sm_request_password(sm); - return -1; - } - - return 0; -} - - -static int eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len, - const struct eap_mschapv2_hdr *ms) -{ - size_t ms_len = WPA_GET_BE16(ms->ms_length); - - if (ms_len == len) - return 0; - - wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%lu " - "ms_len=%lu", (unsigned long) len, (unsigned long) ms_len); - if (sm->workaround) { - /* Some authentication servers use invalid ms_len, - * ignore it for interoperability. */ - wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore" - " invalid ms_len %lu (len %lu)", - (unsigned long) ms_len, - (unsigned long) len); - return 0; - } - - return -1; -} - - -static void eap_mschapv2_copy_challenge(struct eap_mschapv2_data *data, - const struct wpabuf *reqData) -{ - /* - * Store a copy of the challenge message, so that it can be processed - * again in case retry is allowed after a possible failure. - */ - wpabuf_free(data->prev_challenge); - data->prev_challenge = wpabuf_dup(reqData); -} - - -/** - * eap_mschapv2_process - Process an EAP-MSCHAPv2 request - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_mschapv2_init() - * @ret: Return values from EAP request validation and processing - * @reqData: EAP request to be processed (eapReqData) - * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if - * no reply available - */ -static struct wpabuf * eap_mschapv2_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_mschapv2_data *data = priv; - struct eap_peer_config *config = eap_get_config(sm); - const struct eap_mschapv2_hdr *ms; - int using_prev_challenge = 0; - const u8 *pos; - size_t len; - u8 id; - - if (eap_mschapv2_check_config(sm)) { - ret->ignore = TRUE; - return NULL; - } - - if (config->mschapv2_retry && data->prev_challenge && - data->prev_error == ERROR_AUTHENTICATION_FAILURE) { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Replacing pending packet " - "with the previous challenge"); - - reqData = data->prev_challenge; - using_prev_challenge = 1; - config->mschapv2_retry = 0; - } - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqData, - &len); - if (pos == NULL || len < sizeof(*ms) + 1) { - ret->ignore = TRUE; - return NULL; - } - - ms = (const struct eap_mschapv2_hdr *) pos; - if (eap_mschapv2_check_mslen(sm, len, ms)) { - ret->ignore = TRUE; - return NULL; - } - - id = eap_get_id(reqData); - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d", - id, ms->mschapv2_id); - - switch (ms->op_code) { - case MSCHAPV2_OP_CHALLENGE: - if (!using_prev_challenge) - eap_mschapv2_copy_challenge(data, reqData); - return eap_mschapv2_challenge(sm, data, ret, ms, len, id); - case MSCHAPV2_OP_SUCCESS: - return eap_mschapv2_success(sm, data, ret, ms, len, id); - case MSCHAPV2_OP_FAILURE: - return eap_mschapv2_failure(sm, data, ret, ms, len, id); - default: - wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored", - ms->op_code); - ret->ignore = TRUE; - return NULL; - } -} - - -static Boolean eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_mschapv2_data *data = priv; - return data->success && data->master_key_valid; -} - - -static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_mschapv2_data *data = priv; - u8 *key; - int key_len; - - if (!data->master_key_valid || !data->success) - return NULL; - - key_len = 2 * MSCHAPV2_KEY_LEN; - - key = os_malloc(key_len); - if (key == NULL) - return NULL; - - /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e., - * peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */ - get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0); - get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN, - MSCHAPV2_KEY_LEN, 0, 0); - - wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", - key, key_len); - - *len = key_len; - return key; -} - - -/** - * eap_peer_mschapv2_register - Register EAP-MSCHAPv2 peer method - * Returns: 0 on success, -1 on failure - * - * This function is used to register EAP-MSCHAPv2 peer method into the EAP - * method list. - */ -int eap_peer_mschapv2_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, - "MSCHAPV2"); - if (eap == NULL) - return -1; - - eap->init = eap_mschapv2_init; - eap->deinit = eap_mschapv2_deinit; - eap->process = eap_mschapv2_process; - eap->isKeyAvailable = eap_mschapv2_isKeyAvailable; - eap->getKey = eap_mschapv2_getKey; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_otp.c b/contrib/hostapd/src/eap_peer/eap_otp.c deleted file mode 100644 index 9ac744a7dd..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_otp.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * EAP peer method: EAP-OTP (RFC 3748) - * Copyright (c) 2004-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" - - -static void * eap_otp_init(struct eap_sm *sm) -{ - /* No need for private data. However, must return non-NULL to indicate - * success. */ - return (void *) 1; -} - - -static void eap_otp_deinit(struct eap_sm *sm, void *priv) -{ -} - - -static struct wpabuf * eap_otp_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct wpabuf *resp; - const u8 *pos, *password; - size_t password_len, len; - int otp; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_OTP, reqData, &len); - if (pos == NULL) { - ret->ignore = TRUE; - return NULL; - } - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-OTP: Request message", - pos, len); - - password = eap_get_config_otp(sm, &password_len); - if (password) - otp = 1; - else { - password = eap_get_config_password(sm, &password_len); - otp = 0; - } - - if (password == NULL) { - wpa_printf(MSG_INFO, "EAP-OTP: Password not configured"); - eap_sm_request_otp(sm, (const char *) pos, len); - ret->ignore = TRUE; - return NULL; - } - - ret->ignore = FALSE; - - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - ret->allowNotifications = FALSE; - - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_OTP, password_len, - EAP_CODE_RESPONSE, eap_get_id(reqData)); - if (resp == NULL) - return NULL; - wpabuf_put_data(resp, password, password_len); - wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-OTP: Response", - password, password_len); - - if (otp) { - wpa_printf(MSG_DEBUG, "EAP-OTP: Forgetting used password"); - eap_clear_config_otp(sm); - } - - return resp; -} - - -int eap_peer_otp_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_OTP, "OTP"); - if (eap == NULL) - return -1; - - eap->init = eap_otp_init; - eap->deinit = eap_otp_deinit; - eap->process = eap_otp_process; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_pax.c b/contrib/hostapd/src/eap_peer/eap_pax.c deleted file mode 100644 index 7f87052071..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_pax.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - * EAP peer method: EAP-PAX (RFC 4746) - * Copyright (c) 2005-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/random.h" -#include "eap_common/eap_pax_common.h" -#include "eap_i.h" - -/* - * Note: only PAX_STD subprotocol is currently supported - * - * TODO: Add support with PAX_SEC with the mandatory to implement ciphersuite - * (HMAC_SHA1_128, IANA DH Group 14 (2048 bits), RSA-PKCS1-V1_5) and - * recommended ciphersuite (HMAC_SHA256_128, IANA DH Group 15 (3072 bits), - * RSAES-OAEP). - */ - -struct eap_pax_data { - enum { PAX_INIT, PAX_STD_2_SENT, PAX_DONE } state; - u8 mac_id, dh_group_id, public_key_id; - union { - u8 e[2 * EAP_PAX_RAND_LEN]; - struct { - u8 x[EAP_PAX_RAND_LEN]; /* server rand */ - u8 y[EAP_PAX_RAND_LEN]; /* client rand */ - } r; - } rand; - char *cid; - size_t cid_len; - u8 ak[EAP_PAX_AK_LEN]; - u8 mk[EAP_PAX_MK_LEN]; - u8 ck[EAP_PAX_CK_LEN]; - u8 ick[EAP_PAX_ICK_LEN]; -}; - - -static void eap_pax_deinit(struct eap_sm *sm, void *priv); - - -static void * eap_pax_init(struct eap_sm *sm) -{ - struct eap_pax_data *data; - const u8 *identity, *password; - size_t identity_len, password_len; - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password(sm, &password_len); - if (!identity || !password) { - wpa_printf(MSG_INFO, "EAP-PAX: CID (nai) or key (password) " - "not configured"); - return NULL; - } - - if (password_len != EAP_PAX_AK_LEN) { - wpa_printf(MSG_INFO, "EAP-PAX: Invalid PSK length"); - return NULL; - } - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = PAX_INIT; - - data->cid = os_malloc(identity_len); - if (data->cid == NULL) { - eap_pax_deinit(sm, data); - return NULL; - } - os_memcpy(data->cid, identity, identity_len); - data->cid_len = identity_len; - - os_memcpy(data->ak, password, EAP_PAX_AK_LEN); - - return data; -} - - -static void eap_pax_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_pax_data *data = priv; - os_free(data->cid); - os_free(data); -} - - -static struct wpabuf * eap_pax_alloc_resp(const struct eap_pax_hdr *req, - u8 id, u8 op_code, size_t plen) -{ - struct wpabuf *resp; - struct eap_pax_hdr *pax; - - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX, - sizeof(*pax) + plen, EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - - pax = wpabuf_put(resp, sizeof(*pax)); - pax->op_code = op_code; - pax->flags = 0; - pax->mac_id = req->mac_id; - pax->dh_group_id = req->dh_group_id; - pax->public_key_id = req->public_key_id; - - return resp; -} - - -static struct wpabuf * eap_pax_process_std_1(struct eap_pax_data *data, - struct eap_method_ret *ret, u8 id, - const struct eap_pax_hdr *req, - size_t req_plen) -{ - struct wpabuf *resp; - const u8 *pos; - u8 *rpos; - size_t left, plen; - - wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (received)"); - - if (data->state != PAX_INIT) { - wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 received in " - "unexpected state (%d) - ignored", data->state); - ret->ignore = TRUE; - return NULL; - } - - if (req->flags & EAP_PAX_FLAGS_CE) { - wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with CE flag set - " - "ignored"); - ret->ignore = TRUE; - return NULL; - } - - left = req_plen - sizeof(*req); - - if (left < 2 + EAP_PAX_RAND_LEN) { - wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with too short " - "payload"); - ret->ignore = TRUE; - return NULL; - } - - pos = (const u8 *) (req + 1); - if (WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) { - wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with incorrect A " - "length %d (expected %d)", - WPA_GET_BE16(pos), EAP_PAX_RAND_LEN); - ret->ignore = TRUE; - return NULL; - } - - pos += 2; - left -= 2; - os_memcpy(data->rand.r.x, pos, EAP_PAX_RAND_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: X (server rand)", - data->rand.r.x, EAP_PAX_RAND_LEN); - pos += EAP_PAX_RAND_LEN; - left -= EAP_PAX_RAND_LEN; - - if (left > 0) { - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload", - pos, left); - } - - if (random_get_bytes(data->rand.r.y, EAP_PAX_RAND_LEN)) { - wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data"); - ret->ignore = TRUE; - return NULL; - } - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)", - data->rand.r.y, EAP_PAX_RAND_LEN); - - if (eap_pax_initial_key_derivation(req->mac_id, data->ak, data->rand.e, - data->mk, data->ck, data->ick) < 0) - { - ret->ignore = TRUE; - return NULL; - } - - wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-2 (sending)"); - - plen = 2 + EAP_PAX_RAND_LEN + 2 + data->cid_len + 2 + EAP_PAX_MAC_LEN + - EAP_PAX_ICV_LEN; - resp = eap_pax_alloc_resp(req, id, EAP_PAX_OP_STD_2, plen); - if (resp == NULL) - return NULL; - - wpabuf_put_be16(resp, EAP_PAX_RAND_LEN); - wpabuf_put_data(resp, data->rand.r.y, EAP_PAX_RAND_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: B = Y (client rand)", - data->rand.r.y, EAP_PAX_RAND_LEN); - - wpabuf_put_be16(resp, data->cid_len); - wpabuf_put_data(resp, data->cid, data->cid_len); - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID", - (u8 *) data->cid, data->cid_len); - - wpabuf_put_be16(resp, EAP_PAX_MAC_LEN); - rpos = wpabuf_put(resp, EAP_PAX_MAC_LEN); - eap_pax_mac(req->mac_id, data->ck, EAP_PAX_CK_LEN, - data->rand.r.x, EAP_PAX_RAND_LEN, - data->rand.r.y, EAP_PAX_RAND_LEN, - (u8 *) data->cid, data->cid_len, rpos); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)", - rpos, EAP_PAX_MAC_LEN); - - /* Optional ADE could be added here, if needed */ - - rpos = wpabuf_put(resp, EAP_PAX_ICV_LEN); - eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN, - wpabuf_head(resp), wpabuf_len(resp) - EAP_PAX_ICV_LEN, - NULL, 0, NULL, 0, rpos); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN); - - data->state = PAX_STD_2_SENT; - data->mac_id = req->mac_id; - data->dh_group_id = req->dh_group_id; - data->public_key_id = req->public_key_id; - - return resp; -} - - -static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data, - struct eap_method_ret *ret, u8 id, - const struct eap_pax_hdr *req, - size_t req_plen) -{ - struct wpabuf *resp; - u8 *rpos, mac[EAP_PAX_MAC_LEN]; - const u8 *pos; - size_t left; - - wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (received)"); - - if (data->state != PAX_STD_2_SENT) { - wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 received in " - "unexpected state (%d) - ignored", data->state); - ret->ignore = TRUE; - return NULL; - } - - if (req->flags & EAP_PAX_FLAGS_CE) { - wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with CE flag set - " - "ignored"); - ret->ignore = TRUE; - return NULL; - } - - left = req_plen - sizeof(*req); - - if (left < 2 + EAP_PAX_MAC_LEN) { - wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with too short " - "payload"); - ret->ignore = TRUE; - return NULL; - } - - pos = (const u8 *) (req + 1); - if (WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) { - wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with incorrect " - "MAC_CK length %d (expected %d)", - WPA_GET_BE16(pos), EAP_PAX_MAC_LEN); - ret->ignore = TRUE; - return NULL; - } - pos += 2; - left -= 2; - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)", - pos, EAP_PAX_MAC_LEN); - eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN, - data->rand.r.y, EAP_PAX_RAND_LEN, - (u8 *) data->cid, data->cid_len, NULL, 0, mac); - if (os_memcmp(pos, mac, EAP_PAX_MAC_LEN) != 0) { - wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) " - "received"); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected MAC_CK(B, CID)", - mac, EAP_PAX_MAC_LEN); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return NULL; - } - - pos += EAP_PAX_MAC_LEN; - left -= EAP_PAX_MAC_LEN; - - if (left > 0) { - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload", - pos, left); - } - - wpa_printf(MSG_DEBUG, "EAP-PAX: PAX-ACK (sending)"); - - resp = eap_pax_alloc_resp(req, id, EAP_PAX_OP_ACK, EAP_PAX_ICV_LEN); - if (resp == NULL) - return NULL; - - /* Optional ADE could be added here, if needed */ - - rpos = wpabuf_put(resp, EAP_PAX_ICV_LEN); - eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN, - wpabuf_head(resp), wpabuf_len(resp) - EAP_PAX_ICV_LEN, - NULL, 0, NULL, 0, rpos); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN); - - data->state = PAX_DONE; - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - ret->allowNotifications = FALSE; - - return resp; -} - - -static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_pax_data *data = priv; - const struct eap_pax_hdr *req; - struct wpabuf *resp; - u8 icvbuf[EAP_PAX_ICV_LEN], id; - const u8 *icv, *pos; - size_t len; - u16 flen, mlen; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, reqData, &len); - if (pos == NULL || len < EAP_PAX_ICV_LEN) { - ret->ignore = TRUE; - return NULL; - } - id = eap_get_id(reqData); - req = (const struct eap_pax_hdr *) pos; - flen = len - EAP_PAX_ICV_LEN; - mlen = wpabuf_len(reqData) - EAP_PAX_ICV_LEN; - - wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x " - "flags 0x%x mac_id 0x%x dh_group_id 0x%x " - "public_key_id 0x%x", - req->op_code, req->flags, req->mac_id, req->dh_group_id, - req->public_key_id); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload", - pos, len - EAP_PAX_ICV_LEN); - - if (data->state != PAX_INIT && data->mac_id != req->mac_id) { - wpa_printf(MSG_INFO, "EAP-PAX: MAC ID changed during " - "authentication (was 0x%d, is 0x%d)", - data->mac_id, req->mac_id); - ret->ignore = TRUE; - return NULL; - } - - if (data->state != PAX_INIT && data->dh_group_id != req->dh_group_id) { - wpa_printf(MSG_INFO, "EAP-PAX: DH Group ID changed during " - "authentication (was 0x%d, is 0x%d)", - data->dh_group_id, req->dh_group_id); - ret->ignore = TRUE; - return NULL; - } - - if (data->state != PAX_INIT && - data->public_key_id != req->public_key_id) { - wpa_printf(MSG_INFO, "EAP-PAX: Public Key ID changed during " - "authentication (was 0x%d, is 0x%d)", - data->public_key_id, req->public_key_id); - ret->ignore = TRUE; - return NULL; - } - - /* TODO: add support EAP_PAX_HMAC_SHA256_128 */ - if (req->mac_id != EAP_PAX_MAC_HMAC_SHA1_128) { - wpa_printf(MSG_INFO, "EAP-PAX: Unsupported MAC ID 0x%x", - req->mac_id); - ret->ignore = TRUE; - return NULL; - } - - if (req->dh_group_id != EAP_PAX_DH_GROUP_NONE) { - wpa_printf(MSG_INFO, "EAP-PAX: Unsupported DH Group ID 0x%x", - req->dh_group_id); - ret->ignore = TRUE; - return NULL; - } - - if (req->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) { - wpa_printf(MSG_INFO, "EAP-PAX: Unsupported Public Key ID 0x%x", - req->public_key_id); - ret->ignore = TRUE; - return NULL; - } - - if (req->flags & EAP_PAX_FLAGS_MF) { - /* TODO: add support for reassembling fragments */ - wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported - " - "ignored packet"); - ret->ignore = TRUE; - return NULL; - } - - icv = pos + len - EAP_PAX_ICV_LEN; - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN); - if (req->op_code == EAP_PAX_OP_STD_1) { - eap_pax_mac(req->mac_id, (u8 *) "", 0, - wpabuf_head(reqData), mlen, NULL, 0, NULL, 0, - icvbuf); - } else { - eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN, - wpabuf_head(reqData), mlen, NULL, 0, NULL, 0, - icvbuf); - } - if (os_memcmp(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) { - wpa_printf(MSG_DEBUG, "EAP-PAX: invalid ICV - ignoring the " - "message"); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected ICV", - icvbuf, EAP_PAX_ICV_LEN); - ret->ignore = TRUE; - return NULL; - } - - ret->ignore = FALSE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - ret->allowNotifications = TRUE; - - switch (req->op_code) { - case EAP_PAX_OP_STD_1: - resp = eap_pax_process_std_1(data, ret, id, req, flen); - break; - case EAP_PAX_OP_STD_3: - resp = eap_pax_process_std_3(data, ret, id, req, flen); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-PAX: ignoring message with unknown " - "op_code %d", req->op_code); - ret->ignore = TRUE; - return NULL; - } - - if (ret->methodState == METHOD_DONE) { - ret->allowNotifications = FALSE; - } - - return resp; -} - - -static Boolean eap_pax_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_pax_data *data = priv; - return data->state == PAX_DONE; -} - - -static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_pax_data *data = priv; - u8 *key; - - if (data->state != PAX_DONE) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key == NULL) - return NULL; - - *len = EAP_MSK_LEN; - eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN, - "Master Session Key", data->rand.e, 2 * EAP_PAX_RAND_LEN, - EAP_MSK_LEN, key); - - return key; -} - - -static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_pax_data *data = priv; - u8 *key; - - if (data->state != PAX_DONE) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - - *len = EAP_EMSK_LEN; - eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN, - "Extended Master Session Key", - data->rand.e, 2 * EAP_PAX_RAND_LEN, - EAP_EMSK_LEN, key); - - return key; -} - - -int eap_peer_pax_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX"); - if (eap == NULL) - return -1; - - eap->init = eap_pax_init; - eap->deinit = eap_pax_deinit; - eap->process = eap_pax_process; - eap->isKeyAvailable = eap_pax_isKeyAvailable; - eap->getKey = eap_pax_getKey; - eap->get_emsk = eap_pax_get_emsk; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_peap.c b/contrib/hostapd/src/eap_peer/eap_peap.c deleted file mode 100644 index 8634f754c9..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_peap.c +++ /dev/null @@ -1,1248 +0,0 @@ -/* - * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt) - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha1.h" -#include "crypto/tls.h" -#include "eap_common/eap_tlv_common.h" -#include "eap_common/eap_peap_common.h" -#include "eap_i.h" -#include "eap_tls_common.h" -#include "eap_config.h" -#include "tncc.h" - - -/* Maximum supported PEAP version - * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt - * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt - */ -#define EAP_PEAP_VERSION 1 - - -static void eap_peap_deinit(struct eap_sm *sm, void *priv); - - -struct eap_peap_data { - struct eap_ssl_data ssl; - - int peap_version, force_peap_version, force_new_label; - - const struct eap_method *phase2_method; - void *phase2_priv; - int phase2_success; - int phase2_eap_success; - int phase2_eap_started; - - struct eap_method_type phase2_type; - struct eap_method_type *phase2_types; - size_t num_phase2_types; - - int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner - * EAP-Success - * 1 = reply with tunneled EAP-Success to inner - * EAP-Success and expect AS to send outer - * (unencrypted) EAP-Success after this - * 2 = reply with PEAP/TLS ACK to inner - * EAP-Success and expect AS to send outer - * (unencrypted) EAP-Success after this */ - int resuming; /* starting a resumed session */ - int reauth; /* reauthentication */ - u8 *key_data; - u8 *session_id; - size_t id_len; - - struct wpabuf *pending_phase2_req; - enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding; - int crypto_binding_used; - u8 binding_nonce[32]; - u8 ipmk[40]; - u8 cmk[20]; - int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP) - * is enabled. */ -}; - - -static int eap_peap_parse_phase1(struct eap_peap_data *data, - const char *phase1) -{ - const char *pos; - - pos = os_strstr(phase1, "peapver="); - if (pos) { - data->force_peap_version = atoi(pos + 8); - data->peap_version = data->force_peap_version; - wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d", - data->force_peap_version); - } - - if (os_strstr(phase1, "peaplabel=1")) { - data->force_new_label = 1; - wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key " - "derivation"); - } - - if (os_strstr(phase1, "peap_outer_success=0")) { - data->peap_outer_success = 0; - wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on " - "tunneled EAP-Success"); - } else if (os_strstr(phase1, "peap_outer_success=1")) { - data->peap_outer_success = 1; - wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success " - "after receiving tunneled EAP-Success"); - } else if (os_strstr(phase1, "peap_outer_success=2")) { - data->peap_outer_success = 2; - wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after " - "receiving tunneled EAP-Success"); - } - - if (os_strstr(phase1, "crypto_binding=0")) { - data->crypto_binding = NO_BINDING; - wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding"); - } else if (os_strstr(phase1, "crypto_binding=1")) { - data->crypto_binding = OPTIONAL_BINDING; - wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding"); - } else if (os_strstr(phase1, "crypto_binding=2")) { - data->crypto_binding = REQUIRE_BINDING; - wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding"); - } - -#ifdef EAP_TNC - if (os_strstr(phase1, "tnc=soh2")) { - data->soh = 2; - wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); - } else if (os_strstr(phase1, "tnc=soh1")) { - data->soh = 1; - wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled"); - } else if (os_strstr(phase1, "tnc=soh")) { - data->soh = 2; - wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); - } -#endif /* EAP_TNC */ - - return 0; -} - - -static void * eap_peap_init(struct eap_sm *sm) -{ - struct eap_peap_data *data; - struct eap_peer_config *config = eap_get_config(sm); - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - sm->peap_done = FALSE; - data->peap_version = EAP_PEAP_VERSION; - data->force_peap_version = -1; - data->peap_outer_success = 2; - data->crypto_binding = OPTIONAL_BINDING; - - if (config && config->phase1 && - eap_peap_parse_phase1(data, config->phase1) < 0) { - eap_peap_deinit(sm, data); - return NULL; - } - - if (eap_peer_select_phase2_methods(config, "auth=", - &data->phase2_types, - &data->num_phase2_types) < 0) { - eap_peap_deinit(sm, data); - return NULL; - } - - data->phase2_type.vendor = EAP_VENDOR_IETF; - data->phase2_type.method = EAP_TYPE_NONE; - - if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_PEAP)) { - wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL."); - eap_peap_deinit(sm, data); - return NULL; - } - - return data; -} - - -static void eap_peap_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_peap_data *data = priv; - if (data == NULL) - return; - if (data->phase2_priv && data->phase2_method) - data->phase2_method->deinit(sm, data->phase2_priv); - os_free(data->phase2_types); - eap_peer_tls_ssl_deinit(sm, &data->ssl); - os_free(data->key_data); - os_free(data->session_id); - wpabuf_free(data->pending_phase2_req); - os_free(data); -} - - -/** - * eap_tlv_build_nak - Build EAP-TLV NAK message - * @id: EAP identifier for the header - * @nak_type: TLV type (EAP_TLV_*) - * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure - * - * 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) -{ - struct wpabuf *msg; - - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10, - EAP_CODE_RESPONSE, id); - if (msg == NULL) - return NULL; - - wpabuf_put_u8(msg, 0x80); /* Mandatory */ - wpabuf_put_u8(msg, EAP_TLV_NAK_TLV); - wpabuf_put_be16(msg, 6); /* Length */ - wpabuf_put_be32(msg, 0); /* Vendor-Id */ - wpabuf_put_be16(msg, nak_type); /* NAK-Type */ - - return msg; -} - - -static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data, - u8 *isk, size_t isk_len) -{ - u8 *key; - size_t key_len; - - os_memset(isk, 0, isk_len); - if (data->phase2_method == NULL || data->phase2_priv == NULL || - data->phase2_method->isKeyAvailable == NULL || - data->phase2_method->getKey == NULL) - return 0; - - if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) || - (key = data->phase2_method->getKey(sm, data->phase2_priv, - &key_len)) == NULL) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material " - "from Phase 2"); - return -1; - } - - if (key_len > isk_len) - key_len = isk_len; - os_memcpy(isk, key, key_len); - os_free(key); - - return 0; -} - - -static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) -{ - u8 *tk; - u8 isk[32], imck[60]; - - /* - * Tunnel key (TK) is the first 60 octets of the key generated by - * phase 1 of PEAP (based on TLS). - */ - tk = data->key_data; - if (tk == NULL) - return -1; - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60); - - if (data->reauth && - tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { - /* Fast-connect: IPMK|CMK = TK */ - os_memcpy(data->ipmk, tk, 40); - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK", - data->ipmk, 40); - os_memcpy(data->cmk, tk + 40, 20); - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK", - data->cmk, 20); - return 0; - } - - if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0) - return -1; - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk)); - - /* - * IPMK Seed = "Inner Methods Compound Keys" | ISK - * TempKey = First 40 octets of TK - * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60) - * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space - * in the end of the label just before ISK; is that just a typo?) - */ - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40); - 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)); - - os_memcpy(data->ipmk, imck, 40); - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40); - os_memcpy(data->cmk, imck + 40, 20); - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20); - - return 0; -} - - -static int eap_tlv_add_cryptobinding(struct eap_sm *sm, - struct eap_peap_data *data, - struct wpabuf *buf) -{ - u8 *mac; - u8 eap_type = EAP_TYPE_PEAP; - const u8 *addr[2]; - size_t len[2]; - u16 tlv_type; - - /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ - addr[0] = wpabuf_put(buf, 0); - len[0] = 60; - addr[1] = &eap_type; - len[1] = 1; - - tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; - wpabuf_put_be16(buf, tlv_type); - wpabuf_put_be16(buf, 56); - - wpabuf_put_u8(buf, 0); /* Reserved */ - wpabuf_put_u8(buf, data->peap_version); /* Version */ - wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */ - wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */ - wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */ - mac = wpabuf_put(buf, 20); /* Compound_MAC */ - wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20); - wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1", - addr[0], len[0]); - wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", - addr[1], len[1]); - hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac); - wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN); - data->crypto_binding_used = 1; - - return 0; -} - - -/** - * eap_tlv_build_result - Build EAP-TLV Result message - * @id: EAP identifier for the header - * @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 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, - int crypto_tlv_used, - int id, u16 status) -{ - struct wpabuf *msg; - size_t len; - - if (data->crypto_binding == NO_BINDING) - crypto_tlv_used = 0; - - len = 6; - if (crypto_tlv_used) - len += 60; /* Cryptobinding TLV */ - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len, - EAP_CODE_RESPONSE, id); - if (msg == NULL) - return NULL; - - wpabuf_put_u8(msg, 0x80); /* Mandatory */ - wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV); - wpabuf_put_be16(msg, 2); /* Length */ - wpabuf_put_be16(msg, status); /* Status */ - - if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) { - wpabuf_free(msg); - return NULL; - } - - return msg; -} - - -static int eap_tlv_validate_cryptobinding(struct eap_sm *sm, - struct eap_peap_data *data, - const u8 *crypto_tlv, - size_t crypto_tlv_len) -{ - u8 buf[61], mac[SHA1_MAC_LEN]; - const u8 *pos; - - if (eap_peap_derive_cmk(sm, data) < 0) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK"); - return -1; - } - - if (crypto_tlv_len != 4 + 56) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV " - "length %d", (int) crypto_tlv_len); - return -1; - } - - pos = crypto_tlv; - pos += 4; /* TLV header */ - if (pos[1] != data->peap_version) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version " - "mismatch (was %d; expected %d)", - pos[1], data->peap_version); - return -1; - } - - if (pos[3] != 0) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV " - "SubType %d", pos[3]); - return -1; - } - pos += 4; - os_memcpy(data->binding_nonce, pos, 32); - pos += 32; /* Nonce */ - - /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ - os_memcpy(buf, crypto_tlv, 60); - os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */ - buf[60] = EAP_TYPE_PEAP; - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data", - buf, sizeof(buf)); - hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac); - - if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in " - "cryptobinding TLV"); - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC", - pos, SHA1_MAC_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC", - mac, SHA1_MAC_LEN); - return -1; - } - - wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received"); - - return 0; -} - - -/** - * eap_tlv_process - Process a received EAP-TLV message and generate a response - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @ret: Return values from EAP request validation and processing - * @req: EAP-TLV request to be processed. The caller must have validated that - * the buffer is large enough to contain full request (hdr->length bytes) and - * that the EAP type is EAP_TYPE_TLV. - * @resp: Buffer to return a pointer to the allocated response message. This - * field should be initialized to %NULL before the call. The value will be - * updated if a response message is generated. The caller is responsible for - * freeing the allocated message. - * @force_failure: Force negotiation to fail - * Returns: 0 on success, -1 on failure - */ -static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data, - struct eap_method_ret *ret, - const struct wpabuf *req, struct wpabuf **resp, - int force_failure) -{ - size_t left, tlv_len; - const u8 *pos; - const u8 *result_tlv = NULL, *crypto_tlv = NULL; - size_t result_tlv_len = 0, crypto_tlv_len = 0; - int tlv_type, mandatory; - - /* Parse TLVs */ - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left); - if (pos == NULL) - return -1; - wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left); - while (left >= 4) { - mandatory = !!(pos[0] & 0x80); - tlv_type = WPA_GET_BE16(pos) & 0x3fff; - pos += 2; - tlv_len = WPA_GET_BE16(pos); - pos += 2; - left -= 4; - if (tlv_len > left) { - wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun " - "(tlv_len=%lu left=%lu)", - (unsigned long) tlv_len, - (unsigned long) left); - return -1; - } - switch (tlv_type) { - case EAP_TLV_RESULT_TLV: - result_tlv = pos; - result_tlv_len = tlv_len; - break; - case EAP_TLV_CRYPTO_BINDING_TLV: - crypto_tlv = pos; - crypto_tlv_len = tlv_len; - break; - default: - wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type " - "%d%s", tlv_type, - mandatory ? " (mandatory)" : ""); - if (mandatory) { - /* NAK TLV and ignore all TLVs in this packet. - */ - *resp = eap_tlv_build_nak(eap_get_id(req), - tlv_type); - return *resp == NULL ? -1 : 0; - } - /* Ignore this TLV, but process other TLVs */ - break; - } - - pos += tlv_len; - left -= tlv_len; - } - if (left) { - wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in " - "Request (left=%lu)", (unsigned long) left); - return -1; - } - - /* Process supported TLVs */ - if (crypto_tlv && data->crypto_binding != NO_BINDING) { - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV", - crypto_tlv, crypto_tlv_len); - if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4, - crypto_tlv_len + 4) < 0) { - if (result_tlv == NULL) - return -1; - force_failure = 1; - crypto_tlv = NULL; /* do not include Cryptobinding TLV - * in response, if the received - * cryptobinding was invalid. */ - } - } else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV"); - return -1; - } - - if (result_tlv) { - int status, resp_status; - wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV", - result_tlv, result_tlv_len); - if (result_tlv_len < 2) { - wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV " - "(len=%lu)", - (unsigned long) result_tlv_len); - return -1; - } - status = WPA_GET_BE16(result_tlv); - if (status == EAP_TLV_RESULT_SUCCESS) { - wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success " - "- EAP-TLV/Phase2 Completed"); - if (force_failure) { - wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure" - " - force failed Phase 2"); - resp_status = EAP_TLV_RESULT_FAILURE; - ret->decision = DECISION_FAIL; - } else { - resp_status = EAP_TLV_RESULT_SUCCESS; - ret->decision = DECISION_UNCOND_SUCC; - } - } else if (status == EAP_TLV_RESULT_FAILURE) { - wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure"); - resp_status = EAP_TLV_RESULT_FAILURE; - ret->decision = DECISION_FAIL; - } else { - wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result " - "Status %d", status); - resp_status = EAP_TLV_RESULT_FAILURE; - ret->decision = DECISION_FAIL; - } - ret->methodState = METHOD_DONE; - - *resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL, - eap_get_id(req), resp_status); - } - - return 0; -} - - -static int eap_peap_phase2_request(struct eap_sm *sm, - struct eap_peap_data *data, - struct eap_method_ret *ret, - struct wpabuf *req, - struct wpabuf **resp) -{ - struct eap_hdr *hdr = wpabuf_mhead(req); - size_t len = be_to_host16(hdr->length); - u8 *pos; - struct eap_method_ret iret; - struct eap_peer_config *config = eap_get_config(sm); - - if (len <= sizeof(struct eap_hdr)) { - wpa_printf(MSG_INFO, "EAP-PEAP: too short " - "Phase 2 request (len=%lu)", (unsigned long) len); - return -1; - } - pos = (u8 *) (hdr + 1); - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos); - switch (*pos) { - case EAP_TYPE_IDENTITY: - *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); - break; - case EAP_TYPE_TLV: - os_memset(&iret, 0, sizeof(iret)); - if (eap_tlv_process(sm, data, &iret, req, resp, - data->phase2_eap_started && - !data->phase2_eap_success)) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return -1; - } - if (iret.methodState == METHOD_DONE || - iret.methodState == METHOD_MAY_CONT) { - ret->methodState = iret.methodState; - ret->decision = iret.decision; - data->phase2_success = 1; - } - break; - case EAP_TYPE_EXPANDED: -#ifdef EAP_TNC - if (data->soh) { - const u8 *epos; - size_t eleft; - - epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, - req, &eleft); - if (epos) { - struct wpabuf *buf; - wpa_printf(MSG_DEBUG, - "EAP-PEAP: SoH EAP Extensions"); - buf = tncc_process_soh_request(data->soh, - epos, eleft); - if (buf) { - *resp = eap_msg_alloc( - EAP_VENDOR_MICROSOFT, 0x21, - wpabuf_len(buf), - EAP_CODE_RESPONSE, - hdr->identifier); - if (*resp == NULL) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return -1; - } - wpabuf_put_buf(*resp, buf); - wpabuf_free(buf); - break; - } - } - } -#endif /* EAP_TNC */ - /* fall through */ - default: - if (data->phase2_type.vendor == EAP_VENDOR_IETF && - data->phase2_type.method == EAP_TYPE_NONE) { - size_t i; - for (i = 0; i < data->num_phase2_types; i++) { - if (data->phase2_types[i].vendor != - EAP_VENDOR_IETF || - data->phase2_types[i].method != *pos) - continue; - - data->phase2_type.vendor = - data->phase2_types[i].vendor; - data->phase2_type.method = - data->phase2_types[i].method; - wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected " - "Phase 2 EAP vendor %d method %d", - data->phase2_type.vendor, - data->phase2_type.method); - break; - } - } - if (*pos != data->phase2_type.method || - *pos == EAP_TYPE_NONE) { - if (eap_peer_tls_phase2_nak(data->phase2_types, - data->num_phase2_types, - hdr, resp)) - return -1; - return 0; - } - - if (data->phase2_priv == NULL) { - data->phase2_method = eap_peer_get_eap_method( - data->phase2_type.vendor, - data->phase2_type.method); - if (data->phase2_method) { - sm->init_phase2 = 1; - data->phase2_priv = - data->phase2_method->init(sm); - sm->init_phase2 = 0; - } - } - if (data->phase2_priv == NULL || data->phase2_method == NULL) { - wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize " - "Phase 2 EAP method %d", *pos); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return -1; - } - data->phase2_eap_started = 1; - os_memset(&iret, 0, sizeof(iret)); - *resp = data->phase2_method->process(sm, data->phase2_priv, - &iret, req); - if ((iret.methodState == METHOD_DONE || - iret.methodState == METHOD_MAY_CONT) && - (iret.decision == DECISION_UNCOND_SUCC || - iret.decision == DECISION_COND_SUCC)) { - data->phase2_eap_success = 1; - data->phase2_success = 1; - } - break; - } - - if (*resp == NULL && - (config->pending_req_identity || config->pending_req_password || - config->pending_req_otp || config->pending_req_new_password)) { - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = wpabuf_alloc_copy(hdr, len); - } - - return 0; -} - - -static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data, - struct eap_method_ret *ret, - const struct eap_hdr *req, - const struct wpabuf *in_data, - struct wpabuf **out_data) -{ - struct wpabuf *in_decrypted = NULL; - int res, skip_change = 0; - struct eap_hdr *hdr, *rhdr; - struct wpabuf *resp = NULL; - size_t len; - - wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" - " Phase 2", (unsigned long) wpabuf_len(in_data)); - - if (data->pending_phase2_req) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - " - "skip decryption and use old data"); - /* Clear TLS reassembly state. */ - eap_peer_tls_reset_input(&data->ssl); - in_decrypted = data->pending_phase2_req; - data->pending_phase2_req = NULL; - skip_change = 1; - goto continue_req; - } - - if (wpabuf_len(in_data) == 0 && sm->workaround && - data->phase2_success) { - /* - * Cisco ACS seems to be using TLS ACK to terminate - * EAP-PEAPv0/GTC. Try to reply with TLS ACK. - */ - wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but " - "expected data - acknowledge with TLS ACK since " - "Phase 2 has been completed"); - ret->decision = DECISION_COND_SUCC; - ret->methodState = METHOD_DONE; - return 1; - } else if (wpabuf_len(in_data) == 0) { - /* Received TLS ACK - requesting more fragments */ - return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, - data->peap_version, - req->identifier, NULL, out_data); - } - - res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); - if (res) - return res; - -continue_req: - wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", - in_decrypted); - - hdr = wpabuf_mhead(in_decrypted); - if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST && - be_to_host16(hdr->length) == 5 && - eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) { - /* At least FreeRADIUS seems to send full EAP header with - * EAP Request Identity */ - skip_change = 1; - } - if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST && - eap_get_type(in_decrypted) == EAP_TYPE_TLV) { - skip_change = 1; - } - - if (data->peap_version == 0 && !skip_change) { - struct eap_hdr *nhdr; - struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) + - wpabuf_len(in_decrypted)); - if (nmsg == NULL) { - wpabuf_free(in_decrypted); - return 0; - } - nhdr = wpabuf_put(nmsg, sizeof(*nhdr)); - wpabuf_put_buf(nmsg, in_decrypted); - nhdr->code = req->code; - nhdr->identifier = req->identifier; - nhdr->length = host_to_be16(sizeof(struct eap_hdr) + - wpabuf_len(in_decrypted)); - - wpabuf_free(in_decrypted); - in_decrypted = nmsg; - } - - hdr = wpabuf_mhead(in_decrypted); - if (wpabuf_len(in_decrypted) < sizeof(*hdr)) { - wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " - "EAP frame (len=%lu)", - (unsigned long) wpabuf_len(in_decrypted)); - wpabuf_free(in_decrypted); - return 0; - } - len = be_to_host16(hdr->length); - if (len > wpabuf_len(in_decrypted)) { - wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in " - "Phase 2 EAP frame (len=%lu hdr->length=%lu)", - (unsigned long) wpabuf_len(in_decrypted), - (unsigned long) len); - wpabuf_free(in_decrypted); - return 0; - } - if (len < wpabuf_len(in_decrypted)) { - wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has " - "shorter length than full decrypted data " - "(%lu < %lu)", - (unsigned long) len, - (unsigned long) wpabuf_len(in_decrypted)); - } - wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d " - "identifier=%d length=%lu", hdr->code, hdr->identifier, - (unsigned long) len); - switch (hdr->code) { - case EAP_CODE_REQUEST: - if (eap_peap_phase2_request(sm, data, ret, in_decrypted, - &resp)) { - wpabuf_free(in_decrypted); - wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request " - "processing failed"); - return 0; - } - break; - case EAP_CODE_SUCCESS: - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success"); - if (data->peap_version == 1) { - /* EAP-Success within TLS tunnel is used to indicate - * shutdown of the TLS channel. The authentication has - * been completed. */ - if (data->phase2_eap_started && - !data->phase2_eap_success) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 " - "Success used to indicate success, " - "but Phase 2 EAP was not yet " - "completed successfully"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - wpabuf_free(in_decrypted); - return 0; - } - wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - " - "EAP-Success within TLS tunnel - " - "authentication completed"); - ret->decision = DECISION_UNCOND_SUCC; - ret->methodState = METHOD_DONE; - data->phase2_success = 1; - if (data->peap_outer_success == 2) { - wpabuf_free(in_decrypted); - wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK " - "to finish authentication"); - return 1; - } else if (data->peap_outer_success == 1) { - /* Reply with EAP-Success within the TLS - * channel to complete the authentication. */ - resp = wpabuf_alloc(sizeof(struct eap_hdr)); - if (resp) { - rhdr = wpabuf_put(resp, sizeof(*rhdr)); - rhdr->code = EAP_CODE_SUCCESS; - rhdr->identifier = hdr->identifier; - rhdr->length = - host_to_be16(sizeof(*rhdr)); - } - } else { - /* No EAP-Success expected for Phase 1 (outer, - * unencrypted auth), so force EAP state - * machine to SUCCESS state. */ - sm->peap_done = TRUE; - } - } else { - /* FIX: ? */ - } - break; - case EAP_CODE_FAILURE: - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure"); - ret->decision = DECISION_FAIL; - ret->methodState = METHOD_MAY_CONT; - ret->allowNotifications = FALSE; - /* Reply with EAP-Failure within the TLS channel to complete - * failure reporting. */ - resp = wpabuf_alloc(sizeof(struct eap_hdr)); - if (resp) { - rhdr = wpabuf_put(resp, sizeof(*rhdr)); - rhdr->code = EAP_CODE_FAILURE; - rhdr->identifier = hdr->identifier; - rhdr->length = host_to_be16(sizeof(*rhdr)); - } - break; - default: - wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in " - "Phase 2 EAP header", hdr->code); - break; - } - - wpabuf_free(in_decrypted); - - if (resp) { - int skip_change2 = 0; - struct wpabuf *rmsg, buf; - - wpa_hexdump_buf_key(MSG_DEBUG, - "EAP-PEAP: Encrypting Phase 2 data", resp); - /* PEAP version changes */ - if (wpabuf_len(resp) >= 5 && - wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE && - eap_get_type(resp) == EAP_TYPE_TLV) - skip_change2 = 1; - rmsg = resp; - if (data->peap_version == 0 && !skip_change2) { - wpabuf_set(&buf, wpabuf_head_u8(resp) + - sizeof(struct eap_hdr), - wpabuf_len(resp) - sizeof(struct eap_hdr)); - rmsg = &buf; - } - - if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, - data->peap_version, req->identifier, - rmsg, out_data)) { - wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt " - "a Phase 2 frame"); - } - wpabuf_free(resp); - } - - return 0; -} - - -static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - const struct eap_hdr *req; - size_t left; - int res; - u8 flags, id; - struct wpabuf *resp; - const u8 *pos; - struct eap_peap_data *data = priv; - - pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret, - reqData, &left, &flags); - if (pos == NULL) - return NULL; - req = wpabuf_head(reqData); - id = req->identifier; - - if (flags & EAP_TLS_FLAGS_START) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own " - "ver=%d)", flags & EAP_TLS_VERSION_MASK, - data->peap_version); - if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version) - data->peap_version = flags & EAP_TLS_VERSION_MASK; - if (data->force_peap_version >= 0 && - data->force_peap_version != data->peap_version) { - wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select " - "forced PEAP version %d", - data->force_peap_version); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - ret->allowNotifications = FALSE; - return NULL; - } - wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d", - data->peap_version); - left = 0; /* make sure that this frame is empty, even though it - * should always be, anyway */ - } - - resp = NULL; - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && - !data->resuming) { - struct wpabuf msg; - wpabuf_set(&msg, pos, left); - res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp); - } else { - res = eap_peer_tls_process_helper(sm, &data->ssl, - EAP_TYPE_PEAP, - data->peap_version, id, pos, - left, &resp); - - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { - char *label; - wpa_printf(MSG_DEBUG, - "EAP-PEAP: TLS done, proceed to Phase 2"); - os_free(data->key_data); - /* draft-josefsson-ppext-eap-tls-eap-05.txt - * specifies that PEAPv1 would use "client PEAP - * encryption" as the label. However, most existing - * PEAPv1 implementations seem to be using the old - * label, "client EAP encryption", instead. Use the old - * label by default, but allow it to be configured with - * phase1 parameter peaplabel=1. */ - if (data->force_new_label) - label = "client PEAP encryption"; - else - label = "client EAP encryption"; - wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in " - "key derivation", label); - data->key_data = - eap_peer_tls_derive_key(sm, &data->ssl, label, - EAP_TLS_KEY_LEN); - if (data->key_data) { - wpa_hexdump_key(MSG_DEBUG, - "EAP-PEAP: Derived key", - data->key_data, - EAP_TLS_KEY_LEN); - } else { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to " - "derive key"); - } - - os_free(data->session_id); - data->session_id = - eap_peer_tls_derive_session_id(sm, &data->ssl, - EAP_TYPE_PEAP, - &data->id_len); - if (data->session_id) { - wpa_hexdump(MSG_DEBUG, - "EAP-PEAP: Derived Session-Id", - data->session_id, data->id_len); - } else { - wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to " - "derive Session-Id"); - } - - if (sm->workaround && data->resuming) { - /* - * At least few RADIUS servers (Aegis v1.1.6; - * but not v1.1.4; and Cisco ACS) seem to be - * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco - * ACS) session resumption with outer - * EAP-Success. This does not seem to follow - * draft-josefsson-pppext-eap-tls-eap-05.txt - * section 4.2, so only allow this if EAP - * workarounds are enabled. - */ - wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - " - "allow outer EAP-Success to " - "terminate PEAP resumption"); - ret->decision = DECISION_COND_SUCC; - data->phase2_success = 1; - } - - data->resuming = 0; - } - - if (res == 2) { - struct wpabuf msg; - /* - * Application data included in the handshake message. - */ - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = resp; - resp = NULL; - wpabuf_set(&msg, pos, left); - res = eap_peap_decrypt(sm, data, ret, req, &msg, - &resp); - } - } - - if (ret->methodState == METHOD_DONE) { - ret->allowNotifications = FALSE; - } - - if (res == 1) { - wpabuf_free(resp); - return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP, - data->peap_version); - } - - return resp; -} - - -static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv) -{ - struct eap_peap_data *data = priv; - return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && - data->phase2_success; -} - - -static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_peap_data *data = priv; - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = NULL; - data->crypto_binding_used = 0; -} - - -static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_peap_data *data = priv; - os_free(data->key_data); - data->key_data = NULL; - os_free(data->session_id); - data->session_id = NULL; - if (eap_peer_tls_reauth_init(sm, &data->ssl)) { - os_free(data); - return NULL; - } - if (data->phase2_priv && data->phase2_method && - data->phase2_method->init_for_reauth) - data->phase2_method->init_for_reauth(sm, data->phase2_priv); - data->phase2_success = 0; - data->phase2_eap_success = 0; - data->phase2_eap_started = 0; - data->resuming = 1; - data->reauth = 1; - sm->peap_done = FALSE; - return priv; -} - - -static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf, - size_t buflen, int verbose) -{ - struct eap_peap_data *data = priv; - int len, ret; - - len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); - if (data->phase2_method) { - ret = os_snprintf(buf + len, buflen - len, - "EAP-PEAPv%d Phase2 method=%s\n", - data->peap_version, - data->phase2_method->name); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - } - return len; -} - - -static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_peap_data *data = priv; - return data->key_data != NULL && data->phase2_success; -} - - -static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_peap_data *data = priv; - u8 *key; - - if (data->key_data == NULL || !data->phase2_success) - return NULL; - - key = os_malloc(EAP_TLS_KEY_LEN); - if (key == NULL) - return NULL; - - *len = EAP_TLS_KEY_LEN; - - if (data->crypto_binding_used) { - u8 csk[128]; - /* - * Note: It looks like Microsoft implementation requires null - * termination for this label while the one used for deriving - * IPMK|CMK did not use null termination. - */ - 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", - key, EAP_TLS_KEY_LEN); - } else - os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); - - return key; -} - - -static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_peap_data *data = priv; - u8 *id; - - if (data->session_id == NULL || !data->phase2_success) - return NULL; - - id = os_malloc(data->id_len); - if (id == NULL) - return NULL; - - *len = data->id_len; - os_memcpy(id, data->session_id, data->id_len); - - return id; -} - - -int eap_peer_peap_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP"); - if (eap == NULL) - return -1; - - eap->init = eap_peap_init; - eap->deinit = eap_peap_deinit; - eap->process = eap_peap_process; - eap->isKeyAvailable = eap_peap_isKeyAvailable; - eap->getKey = eap_peap_getKey; - eap->get_status = eap_peap_get_status; - eap->has_reauth_data = eap_peap_has_reauth_data; - eap->deinit_for_reauth = eap_peap_deinit_for_reauth; - eap->init_for_reauth = eap_peap_init_for_reauth; - eap->getSessionId = eap_peap_get_session_id; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_proxy.h b/contrib/hostapd/src/eap_peer/eap_proxy.h deleted file mode 100644 index 23cdbe698b..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_proxy.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * EAP proxy definitions - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_PROXY_H -#define EAP_PROXY_H - -struct eap_proxy_sm; -struct eapol_callbacks; -struct eap_sm; -struct eap_peer_config; - -enum eap_proxy_status { - EAP_PROXY_FAILURE = 0x00, - EAP_PROXY_SUCCESS -}; - -struct eap_proxy_sm * -eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb, - void *msg_ctx); - -void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy); - -int eap_proxy_key_available(struct eap_proxy_sm *sm); - -const u8 * eap_proxy_get_eapKeyData(struct eap_proxy_sm *sm, size_t *len); - -struct wpabuf * eap_proxy_get_eapRespData(struct eap_proxy_sm *sm); - -int eap_proxy_sm_step(struct eap_proxy_sm *sm, struct eap_sm *eap_sm); - -enum eap_proxy_status -eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData, - int eapReqDataLen); - -int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen, - int verbose); - -int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf, - size_t *imsi_len); - -int eap_proxy_notify_config(struct eap_proxy_sm *sm, - struct eap_peer_config *config); - -#endif /* EAP_PROXY_H */ diff --git a/contrib/hostapd/src/eap_peer/eap_proxy_dummy.c b/contrib/hostapd/src/eap_peer/eap_proxy_dummy.c deleted file mode 100644 index d84f01234e..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_proxy_dummy.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * EAP proxy - dummy implementation for build testing - * Copyright (c) 2013 Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_proxy.h" - -struct eap_proxy_sm * -eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb, - void *msg_ctx) -{ - return NULL; -} - - -void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy) -{ -} - - -int eap_proxy_key_available(struct eap_proxy_sm *sm) -{ - return 0; -} - - -const u8 * eap_proxy_get_eapKeyData(struct eap_proxy_sm *sm, size_t *len) -{ - return NULL; -} - - -struct wpabuf * eap_proxy_get_eapRespData(struct eap_proxy_sm *sm) -{ - return NULL; -} - - -int eap_proxy_sm_step(struct eap_proxy_sm *sm, struct eap_sm *eap_sm) -{ - return 0; -} - - -enum eap_proxy_status -eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData, - int eapReqDataLen) -{ - return EAP_PROXY_FAILURE; -} - - -int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen, - int verbose) -{ - return 0; -} - - -int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf, - size_t *imsi_len) -{ - return -1; -} - - -int eap_proxy_notify_config(struct eap_proxy_sm *sm, - struct eap_peer_config *config) -{ - return -1; -} diff --git a/contrib/hostapd/src/eap_peer/eap_psk.c b/contrib/hostapd/src/eap_peer/eap_psk.c deleted file mode 100644 index cd0e3f9666..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_psk.c +++ /dev/null @@ -1,502 +0,0 @@ -/* - * EAP peer method: EAP-PSK (RFC 4764) - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * Note: EAP-PSK is an EAP authentication method and as such, completely - * different from WPA-PSK. This file is not needed for WPA-PSK functionality. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/aes_wrap.h" -#include "crypto/random.h" -#include "eap_common/eap_psk_common.h" -#include "eap_i.h" - - -struct eap_psk_data { - enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state; - u8 rand_p[EAP_PSK_RAND_LEN]; - u8 rand_s[EAP_PSK_RAND_LEN]; - u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN]; - u8 *id_s, *id_p; - size_t id_s_len, id_p_len; - u8 msk[EAP_MSK_LEN]; - u8 emsk[EAP_EMSK_LEN]; -}; - - -static void * eap_psk_init(struct eap_sm *sm) -{ - struct eap_psk_data *data; - const u8 *identity, *password; - size_t identity_len, password_len; - - password = eap_get_config_password(sm, &password_len); - if (!password || password_len != 16) { - wpa_printf(MSG_INFO, "EAP-PSK: 16-octet pre-shared key not " - "configured"); - return NULL; - } - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - if (eap_psk_key_setup(password, data->ak, data->kdk)) { - os_free(data); - return NULL; - } - wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN); - data->state = PSK_INIT; - - identity = eap_get_config_identity(sm, &identity_len); - if (identity) { - data->id_p = os_malloc(identity_len); - if (data->id_p) - os_memcpy(data->id_p, identity, identity_len); - data->id_p_len = identity_len; - } - if (data->id_p == NULL) { - wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity"); - os_free(data); - return NULL; - } - - return data; -} - - -static void eap_psk_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_psk_data *data = priv; - os_free(data->id_s); - os_free(data->id_p); - os_free(data); -} - - -static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - const struct eap_psk_hdr_1 *hdr1; - struct eap_psk_hdr_2 *hdr2; - struct wpabuf *resp; - u8 *buf, *pos; - size_t buflen, len; - const u8 *cpos; - - wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state"); - - cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); - hdr1 = (const struct eap_psk_hdr_1 *) cpos; - if (cpos == NULL || len < sizeof(*hdr1)) { - wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message " - "length (%lu; expected %lu or more)", - (unsigned long) len, - (unsigned long) sizeof(*hdr1)); - ret->ignore = TRUE; - return NULL; - } - wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags); - if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) { - wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)", - EAP_PSK_FLAGS_GET_T(hdr1->flags)); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return NULL; - } - wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s, - EAP_PSK_RAND_LEN); - os_memcpy(data->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN); - os_free(data->id_s); - data->id_s_len = len - sizeof(*hdr1); - data->id_s = os_malloc(data->id_s_len); - if (data->id_s == NULL) { - wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for " - "ID_S (len=%lu)", (unsigned long) data->id_s_len); - ret->ignore = TRUE; - return NULL; - } - os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S", - data->id_s, data->id_s_len); - - if (random_get_bytes(data->rand_p, EAP_PSK_RAND_LEN)) { - wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data"); - ret->ignore = TRUE; - return NULL; - } - - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, - sizeof(*hdr2) + data->id_p_len, EAP_CODE_RESPONSE, - eap_get_id(reqData)); - if (resp == NULL) - return NULL; - hdr2 = wpabuf_put(resp, sizeof(*hdr2)); - hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */ - os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN); - os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN); - wpabuf_put_data(resp, data->id_p, data->id_p_len); - /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */ - buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN; - buf = os_malloc(buflen); - if (buf == NULL) { - wpabuf_free(resp); - return NULL; - } - os_memcpy(buf, data->id_p, data->id_p_len); - pos = buf + data->id_p_len; - os_memcpy(pos, data->id_s, data->id_s_len); - pos += data->id_s_len; - os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN); - pos += EAP_PSK_RAND_LEN; - os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN); - if (omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p)) { - os_free(buf); - wpabuf_free(resp); - return NULL; - } - os_free(buf); - wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p, - EAP_PSK_RAND_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P", - data->id_p, data->id_p_len); - - data->state = PSK_MAC_SENT; - - return resp; -} - - -static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - const struct eap_psk_hdr_3 *hdr3; - struct eap_psk_hdr_4 *hdr4; - struct wpabuf *resp; - u8 *buf, *rpchannel, nonce[16], *decrypted; - const u8 *pchannel, *tag, *msg; - u8 mac[EAP_PSK_MAC_LEN]; - size_t buflen, left, data_len, len, plen; - int failed = 0; - const u8 *pos; - - wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state"); - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, - reqData, &len); - hdr3 = (const struct eap_psk_hdr_3 *) pos; - if (pos == NULL || len < sizeof(*hdr3)) { - wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message " - "length (%lu; expected %lu or more)", - (unsigned long) len, - (unsigned long) sizeof(*hdr3)); - ret->ignore = TRUE; - return NULL; - } - left = len - sizeof(*hdr3); - pchannel = (const u8 *) (hdr3 + 1); - wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags); - if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) { - wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)", - EAP_PSK_FLAGS_GET_T(hdr3->flags)); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return NULL; - } - wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s, - EAP_PSK_RAND_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left); - - if (left < 4 + 16 + 1) { - wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in " - "third message (len=%lu, expected 21)", - (unsigned long) left); - ret->ignore = TRUE; - return NULL; - } - - /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */ - buflen = data->id_s_len + EAP_PSK_RAND_LEN; - buf = os_malloc(buflen); - if (buf == NULL) - return NULL; - 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, mac)) { - os_free(buf); - return NULL; - } - os_free(buf); - if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) { - wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third " - "message"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return NULL; - } - wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully"); - - if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, - data->msk, data->emsk)) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return NULL; - } - wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN); - - os_memset(nonce, 0, 12); - os_memcpy(nonce + 12, pchannel, 4); - pchannel += 4; - left -= 4; - - tag = pchannel; - pchannel += 16; - left -= 16; - - msg = pchannel; - - wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce", - nonce, sizeof(nonce)); - wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", - wpabuf_head(reqData), 5); - wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left); - - decrypted = os_malloc(left); - if (decrypted == NULL) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return NULL; - } - os_memcpy(decrypted, msg, left); - - if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce), - wpabuf_head(reqData), - sizeof(struct eap_hdr) + 1 + - sizeof(*hdr3) - EAP_PSK_MAC_LEN, decrypted, - left, tag)) { - wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed"); - os_free(decrypted); - return NULL; - } - wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message", - decrypted, left); - - /* Verify R flag */ - switch (decrypted[0] >> 6) { - case EAP_PSK_R_FLAG_CONT: - wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported"); - failed = 1; - break; - case EAP_PSK_R_FLAG_DONE_SUCCESS: - wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS"); - break; - case EAP_PSK_R_FLAG_DONE_FAILURE: - wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE"); - wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected " - "authentication"); - failed = 1; - break; - } - - data_len = 1; - if ((decrypted[0] & EAP_PSK_E_FLAG) && left > 1) - data_len++; - plen = sizeof(*hdr4) + 4 + 16 + data_len; - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, plen, - EAP_CODE_RESPONSE, eap_get_id(reqData)); - if (resp == NULL) { - os_free(decrypted); - return NULL; - } - hdr4 = wpabuf_put(resp, sizeof(*hdr4)); - hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */ - os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN); - rpchannel = wpabuf_put(resp, 4 + 16 + data_len); - - /* nonce++ */ - inc_byte_array(nonce, sizeof(nonce)); - os_memcpy(rpchannel, nonce + 12, 4); - - if (decrypted[0] & EAP_PSK_E_FLAG) { - wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag"); - failed = 1; - rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) | - EAP_PSK_E_FLAG; - if (left > 1) { - /* Add empty EXT_Payload with same EXT_Type */ - rpchannel[4 + 16 + 1] = decrypted[1]; - } - } else if (failed) - rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6; - else - rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; - - wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)", - rpchannel + 4 + 16, data_len); - if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), - wpabuf_head(resp), - sizeof(struct eap_hdr) + 1 + sizeof(*hdr4), - rpchannel + 4 + 16, data_len, rpchannel + 4)) { - os_free(decrypted); - wpabuf_free(resp); - return NULL; - } - wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)", - rpchannel, 4 + 16 + data_len); - - wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully", - failed ? "un" : ""); - data->state = PSK_DONE; - ret->methodState = METHOD_DONE; - ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC; - - os_free(decrypted); - - return resp; -} - - -static struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_psk_data *data = priv; - const u8 *pos; - struct wpabuf *resp = NULL; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); - if (pos == NULL) { - ret->ignore = TRUE; - return NULL; - } - - ret->ignore = FALSE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - ret->allowNotifications = TRUE; - - switch (data->state) { - case PSK_INIT: - resp = eap_psk_process_1(data, ret, reqData); - break; - case PSK_MAC_SENT: - resp = eap_psk_process_3(data, ret, reqData); - break; - case PSK_DONE: - wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore " - "unexpected message"); - ret->ignore = TRUE; - return NULL; - } - - if (ret->methodState == METHOD_DONE) { - ret->allowNotifications = FALSE; - } - - return resp; -} - - -static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_psk_data *data = priv; - return data->state == PSK_DONE; -} - - -static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_psk_data *data = priv; - u8 *key; - - if (data->state != PSK_DONE) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key == NULL) - return NULL; - - *len = EAP_MSK_LEN; - os_memcpy(key, data->msk, EAP_MSK_LEN); - - return key; -} - - -static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_psk_data *data = priv; - u8 *id; - - if (data->state != PSK_DONE) - return NULL; - - *len = 1 + 2 * EAP_PSK_RAND_LEN; - id = os_malloc(*len); - if (id == NULL) - return NULL; - - id[0] = EAP_TYPE_PSK; - os_memcpy(id + 1, data->rand_p, EAP_PSK_RAND_LEN); - os_memcpy(id + 1 + EAP_PSK_RAND_LEN, data->rand_s, EAP_PSK_RAND_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-PSK: Derived Session-Id", id, *len); - - return id; -} - - -static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_psk_data *data = priv; - u8 *key; - - if (data->state != PSK_DONE) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - - *len = EAP_EMSK_LEN; - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - - return key; -} - - -int eap_peer_psk_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK"); - if (eap == NULL) - return -1; - - eap->init = eap_psk_init; - eap->deinit = eap_psk_deinit; - eap->process = eap_psk_process; - eap->isKeyAvailable = eap_psk_isKeyAvailable; - eap->getKey = eap_psk_getKey; - eap->getSessionId = eap_psk_get_session_id; - eap->get_emsk = eap_psk_get_emsk; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_pwd.c b/contrib/hostapd/src/eap_peer/eap_pwd.c deleted file mode 100644 index fef478370c..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_pwd.c +++ /dev/null @@ -1,927 +0,0 @@ -/* - * EAP peer method: EAP-pwd (RFC 5931) - * Copyright (c) 2010, Dan Harkins - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha256.h" -#include "eap_peer/eap_i.h" -#include "eap_common/eap_pwd_common.h" - - -struct eap_pwd_data { - enum { - PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE - } state; - u8 *id_peer; - size_t id_peer_len; - u8 *id_server; - size_t id_server_len; - u8 *password; - size_t password_len; - u16 group_num; - EAP_PWD_group *grp; - - struct wpabuf *inbuf; - size_t in_frag_pos; - struct wpabuf *outbuf; - size_t out_frag_pos; - size_t mtu; - - BIGNUM *k; - BIGNUM *private_value; - BIGNUM *server_scalar; - BIGNUM *my_scalar; - EC_POINT *my_element; - EC_POINT *server_element; - - u8 msk[EAP_MSK_LEN]; - u8 emsk[EAP_EMSK_LEN]; - - BN_CTX *bnctx; -}; - - -#ifndef CONFIG_NO_STDOUT_DEBUG -static const char * eap_pwd_state_txt(int state) -{ - switch (state) { - case PWD_ID_Req: - return "PWD-ID-Req"; - case PWD_Commit_Req: - return "PWD-Commit-Req"; - case PWD_Confirm_Req: - return "PWD-Confirm-Req"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "PWD-UNK"; - } -} -#endif /* CONFIG_NO_STDOUT_DEBUG */ - - -static void eap_pwd_state(struct eap_pwd_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-PWD: %s -> %s", - eap_pwd_state_txt(data->state), eap_pwd_state_txt(state)); - data->state = state; -} - - -static void * eap_pwd_init(struct eap_sm *sm) -{ - struct eap_pwd_data *data; - const u8 *identity, *password; - size_t identity_len, password_len; - int fragment_size; - - password = eap_get_config_password(sm, &password_len); - if (password == NULL) { - wpa_printf(MSG_INFO, "EAP-PWD: No password configured!"); - return NULL; - } - - identity = eap_get_config_identity(sm, &identity_len); - if (identity == NULL) { - wpa_printf(MSG_INFO, "EAP-PWD: No identity configured!"); - return NULL; - } - - if ((data = os_zalloc(sizeof(*data))) == NULL) { - wpa_printf(MSG_INFO, "EAP-PWD: memory allocation data fail"); - return NULL; - } - - if ((data->bnctx = BN_CTX_new()) == NULL) { - wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail"); - os_free(data); - return NULL; - } - - if ((data->id_peer = os_malloc(identity_len)) == NULL) { - wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); - BN_CTX_free(data->bnctx); - os_free(data); - return NULL; - } - - os_memcpy(data->id_peer, identity, identity_len); - data->id_peer_len = identity_len; - - if ((data->password = os_malloc(password_len)) == NULL) { - wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail"); - BN_CTX_free(data->bnctx); - os_free(data->id_peer); - os_free(data); - return NULL; - } - os_memcpy(data->password, password, password_len); - data->password_len = password_len; - - data->out_frag_pos = data->in_frag_pos = 0; - data->inbuf = data->outbuf = NULL; - fragment_size = eap_get_config_fragment_size(sm); - if (fragment_size <= 0) - data->mtu = 1020; /* default from RFC 5931 */ - else - data->mtu = fragment_size; - - data->state = PWD_ID_Req; - - return data; -} - - -static void eap_pwd_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_pwd_data *data = priv; - - BN_free(data->private_value); - BN_free(data->server_scalar); - BN_free(data->my_scalar); - BN_free(data->k); - BN_CTX_free(data->bnctx); - EC_POINT_free(data->my_element); - EC_POINT_free(data->server_element); - os_free(data->id_peer); - os_free(data->id_server); - os_free(data->password); - if (data->grp) { - EC_GROUP_free(data->grp->group); - EC_POINT_free(data->grp->pwe); - BN_free(data->grp->order); - BN_free(data->grp->prime); - os_free(data->grp); - } - os_free(data); -} - - -static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_pwd_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key == NULL) - return NULL; - - os_memcpy(key, data->msk, EAP_MSK_LEN); - *len = EAP_MSK_LEN; - - return key; -} - - -static void -eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - const u8 *payload, size_t payload_len) -{ - struct eap_pwd_id *id; - - if (data->state != PWD_ID_Req) { - ret->ignore = TRUE; - eap_pwd_state(data, FAILURE); - return; - } - - if (payload_len < sizeof(struct eap_pwd_id)) { - ret->ignore = TRUE; - eap_pwd_state(data, FAILURE); - return; - } - - id = (struct eap_pwd_id *) payload; - data->group_num = be_to_host16(id->group_num); - if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) || - (id->prf != EAP_PWD_DEFAULT_PRF)) { - ret->ignore = TRUE; - eap_pwd_state(data, FAILURE); - return; - } - - wpa_printf(MSG_DEBUG, "EAP-PWD (peer): using group %d", - data->group_num); - - data->id_server = os_malloc(payload_len - sizeof(struct eap_pwd_id)); - if (data->id_server == NULL) { - wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); - eap_pwd_state(data, FAILURE); - return; - } - data->id_server_len = payload_len - sizeof(struct eap_pwd_id); - os_memcpy(data->id_server, id->identity, data->id_server_len); - wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of", - data->id_server, data->id_server_len); - - if ((data->grp = (EAP_PWD_group *) os_malloc(sizeof(EAP_PWD_group))) == - NULL) { - wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for " - "group"); - eap_pwd_state(data, FAILURE); - return; - } - - /* compute PWE */ - if (compute_password_element(data->grp, data->group_num, - data->password, data->password_len, - data->id_server, data->id_server_len, - data->id_peer, data->id_peer_len, - id->token)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE"); - eap_pwd_state(data, FAILURE); - return; - } - - wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...", - BN_num_bits(data->grp->prime)); - - data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) + - data->id_peer_len); - if (data->outbuf == NULL) { - eap_pwd_state(data, FAILURE); - return; - } - wpabuf_put_be16(data->outbuf, data->group_num); - wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC); - wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF); - wpabuf_put_data(data->outbuf, id->token, sizeof(id->token)); - wpabuf_put_u8(data->outbuf, EAP_PWD_PREP_NONE); - wpabuf_put_data(data->outbuf, data->id_peer, data->id_peer_len); - - eap_pwd_state(data, PWD_Commit_Req); -} - - -static void -eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - const u8 *payload, size_t payload_len) -{ - EC_POINT *K = NULL, *point = NULL; - BIGNUM *mask = NULL, *x = NULL, *y = NULL, *cofactor = NULL; - u16 offset; - u8 *ptr, *scalar = NULL, *element = NULL; - - if (((data->private_value = BN_new()) == NULL) || - ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) || - ((cofactor = BN_new()) == NULL) || - ((data->my_scalar = BN_new()) == NULL) || - ((mask = BN_new()) == NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail"); - goto fin; - } - - if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) { - wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor " - "for curve"); - goto fin; - } - - BN_rand_range(data->private_value, data->grp->order); - BN_rand_range(mask, data->grp->order); - BN_add(data->my_scalar, data->private_value, mask); - BN_mod(data->my_scalar, data->my_scalar, data->grp->order, - data->bnctx); - - if (!EC_POINT_mul(data->grp->group, data->my_element, NULL, - data->grp->pwe, mask, data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation " - "fail"); - eap_pwd_state(data, FAILURE); - goto fin; - } - - if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx)) - { - wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail"); - goto fin; - } - BN_free(mask); - - if (((x = BN_new()) == NULL) || - ((y = BN_new()) == NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): point allocation fail"); - goto fin; - } - - /* process the request */ - if (((data->server_scalar = BN_new()) == NULL) || - ((data->k = BN_new()) == NULL) || - ((K = EC_POINT_new(data->grp->group)) == NULL) || - ((point = EC_POINT_new(data->grp->group)) == NULL) || - ((data->server_element = EC_POINT_new(data->grp->group)) == NULL)) - { - wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation " - "fail"); - goto fin; - } - - /* element, x then y, followed by scalar */ - ptr = (u8 *) payload; - BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x); - ptr += BN_num_bytes(data->grp->prime); - BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y); - ptr += BN_num_bytes(data->grp->prime); - BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->server_scalar); - if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group, - data->server_element, x, y, - data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element " - "fail"); - goto fin; - } - - /* check to ensure server's element is not in a small sub-group */ - if (BN_cmp(cofactor, BN_value_one())) { - if (!EC_POINT_mul(data->grp->group, point, NULL, - data->server_element, cofactor, NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply " - "server element by order!\n"); - goto fin; - } - if (EC_POINT_is_at_infinity(data->grp->group, point)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): server element " - "is at infinity!\n"); - goto fin; - } - } - - /* compute the shared key, k */ - if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe, - data->server_scalar, data->bnctx)) || - (!EC_POINT_add(data->grp->group, K, K, data->server_element, - data->bnctx)) || - (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value, - data->bnctx))) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key " - "fail"); - goto fin; - } - - /* ensure that the shared key isn't in a small sub-group */ - if (BN_cmp(cofactor, BN_value_one())) { - if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor, - NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply " - "shared key point by order"); - goto fin; - } - } - - /* - * This check is strictly speaking just for the case above where - * co-factor > 1 but it was suggested that even though this is probably - * never going to happen it is a simple and safe check "just to be - * sure" so let's be safe. - */ - if (EC_POINT_is_at_infinity(data->grp->group, K)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at " - "infinity!\n"); - goto fin; - } - - if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k, - NULL, data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract " - "shared secret from point"); - goto fin; - } - - /* now do the response */ - if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, - data->my_element, x, y, - data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail"); - goto fin; - } - - if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) || - ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) == - NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): data allocation fail"); - goto fin; - } - - /* - * bignums occupy as little memory as possible so one that is - * sufficiently smaller than the prime or order might need pre-pending - * with zeros. - */ - os_memset(scalar, 0, BN_num_bytes(data->grp->order)); - os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2); - offset = BN_num_bytes(data->grp->order) - - BN_num_bytes(data->my_scalar); - BN_bn2bin(data->my_scalar, scalar + offset); - - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); - BN_bn2bin(x, element + offset); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); - BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset); - - data->outbuf = wpabuf_alloc(BN_num_bytes(data->grp->order) + - 2 * BN_num_bytes(data->grp->prime)); - if (data->outbuf == NULL) - goto fin; - - /* we send the element as (x,y) follwed by the scalar */ - wpabuf_put_data(data->outbuf, element, - 2 * BN_num_bytes(data->grp->prime)); - wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order)); - -fin: - os_free(scalar); - os_free(element); - BN_free(x); - BN_free(y); - BN_free(cofactor); - EC_POINT_free(K); - EC_POINT_free(point); - if (data->outbuf == NULL) - eap_pwd_state(data, FAILURE); - else - eap_pwd_state(data, PWD_Confirm_Req); -} - - -static void -eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - const u8 *payload, size_t payload_len) -{ - BIGNUM *x = NULL, *y = NULL; - struct crypto_hash *hash; - u32 cs; - u16 grp; - u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr; - int offset; - - /* - * first build up the ciphersuite which is group | random_function | - * prf - */ - grp = htons(data->group_num); - ptr = (u8 *) &cs; - os_memcpy(ptr, &grp, sizeof(u16)); - ptr += sizeof(u16); - *ptr = EAP_PWD_DEFAULT_RAND_FUNC; - ptr += sizeof(u8); - *ptr = EAP_PWD_DEFAULT_PRF; - - /* each component of the cruft will be at most as big as the prime */ - if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) || - ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation " - "fail"); - goto fin; - } - - /* - * server's commit is H(k | server_element | server_scalar | - * peer_element | peer_scalar | ciphersuite) - */ - hash = eap_pwd_h_init(); - if (hash == NULL) - goto fin; - - /* - * zero the memory each time because this is mod prime math and some - * value may start with a few zeros and the previous one did not. - */ - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); - BN_bn2bin(data->k, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - - /* server element: x, y */ - if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, - data->server_element, x, y, - data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " - "assignment fail"); - goto fin; - } - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); - BN_bn2bin(x, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); - BN_bn2bin(y, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - - /* server scalar */ - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->order) - - BN_num_bytes(data->server_scalar); - BN_bn2bin(data->server_scalar, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); - - /* my element: x, y */ - if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, - data->my_element, x, y, - data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " - "assignment fail"); - goto fin; - } - - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); - BN_bn2bin(x, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); - BN_bn2bin(y, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - - /* my scalar */ - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->order) - - BN_num_bytes(data->my_scalar); - BN_bn2bin(data->my_scalar, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); - - /* the ciphersuite */ - eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32)); - - /* random function fin */ - eap_pwd_h_final(hash, conf); - - ptr = (u8 *) payload; - if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify"); - goto fin; - } - - wpa_printf(MSG_DEBUG, "EAP-pwd (peer): confirm verified"); - - /* - * compute confirm: - * H(k | peer_element | peer_scalar | server_element | server_scalar | - * ciphersuite) - */ - hash = eap_pwd_h_init(); - if (hash == NULL) - goto fin; - - /* k */ - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); - BN_bn2bin(data->k, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - - /* my element */ - if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, - data->my_element, x, y, - data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point " - "assignment fail"); - goto fin; - } - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); - BN_bn2bin(x, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); - BN_bn2bin(y, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - - /* my scalar */ - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->order) - - BN_num_bytes(data->my_scalar); - BN_bn2bin(data->my_scalar, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); - - /* server element: x, y */ - if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, - data->server_element, x, y, - data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point " - "assignment fail"); - goto fin; - } - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); - BN_bn2bin(x, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); - BN_bn2bin(y, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - - /* server scalar */ - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->order) - - BN_num_bytes(data->server_scalar); - BN_bn2bin(data->server_scalar, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); - - /* the ciphersuite */ - eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32)); - - /* all done */ - eap_pwd_h_final(hash, conf); - - if (compute_keys(data->grp, data->bnctx, data->k, - data->my_scalar, data->server_scalar, conf, ptr, - &cs, data->msk, data->emsk) < 0) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | " - "EMSK"); - goto fin; - } - - data->outbuf = wpabuf_alloc(SHA256_MAC_LEN); - if (data->outbuf == NULL) - goto fin; - - wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN); - -fin: - os_free(cruft); - BN_free(x); - BN_free(y); - ret->methodState = METHOD_DONE; - if (data->outbuf == NULL) { - ret->decision = DECISION_FAIL; - eap_pwd_state(data, FAILURE); - } else { - ret->decision = DECISION_UNCOND_SUCC; - eap_pwd_state(data, SUCCESS); - } -} - - -static struct wpabuf * -eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_pwd_data *data = priv; - struct wpabuf *resp = NULL; - const u8 *pos, *buf; - size_t len; - u16 tot_len = 0; - u8 lm_exch; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, reqData, &len); - if ((pos == NULL) || (len < 1)) { - wpa_printf(MSG_DEBUG, "EAP-pwd: Got a frame but pos is %s and " - "len is %d", - pos == NULL ? "NULL" : "not NULL", (int) len); - ret->ignore = TRUE; - return NULL; - } - - ret->ignore = FALSE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - ret->allowNotifications = FALSE; - - lm_exch = *pos; - pos++; /* skip over the bits and the exch */ - len--; - - /* - * we're fragmenting so send out the next fragment - */ - if (data->out_frag_pos) { - /* - * this should be an ACK - */ - if (len) - wpa_printf(MSG_INFO, "Bad Response! Fragmenting but " - "not an ACK"); - - wpa_printf(MSG_DEBUG, "EAP-pwd: Got an ACK for a fragment"); - /* - * check if there are going to be more fragments - */ - len = wpabuf_len(data->outbuf) - data->out_frag_pos; - if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { - len = data->mtu - EAP_PWD_HDR_SIZE; - EAP_PWD_SET_MORE_BIT(lm_exch); - } - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, - EAP_PWD_HDR_SIZE + len, - EAP_CODE_RESPONSE, eap_get_id(reqData)); - if (resp == NULL) { - wpa_printf(MSG_INFO, "Unable to allocate memory for " - "next fragment!"); - return NULL; - } - wpabuf_put_u8(resp, lm_exch); - buf = wpabuf_head_u8(data->outbuf); - wpabuf_put_data(resp, buf + data->out_frag_pos, len); - data->out_frag_pos += len; - /* - * this is the last fragment so get rid of the out buffer - */ - if (data->out_frag_pos >= wpabuf_len(data->outbuf)) { - wpabuf_free(data->outbuf); - data->outbuf = NULL; - data->out_frag_pos = 0; - } - wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes", - data->out_frag_pos == 0 ? "last" : "next", - (int) len); - return resp; - } - - /* - * see if this is a fragment that needs buffering - * - * if it's the first fragment there'll be a length field - */ - if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { - tot_len = WPA_GET_BE16(pos); - wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments whose " - "total length = %d", tot_len); - data->inbuf = wpabuf_alloc(tot_len); - if (data->inbuf == NULL) { - wpa_printf(MSG_INFO, "Out of memory to buffer " - "fragments!"); - return NULL; - } - pos += sizeof(u16); - len -= sizeof(u16); - } - /* - * buffer and ACK the fragment - */ - if (EAP_PWD_GET_MORE_BIT(lm_exch)) { - data->in_frag_pos += len; - if (data->in_frag_pos > wpabuf_size(data->inbuf)) { - wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack " - "detected (%d vs. %d)!", - (int) data->in_frag_pos, - (int) wpabuf_len(data->inbuf)); - wpabuf_free(data->inbuf); - data->in_frag_pos = 0; - return NULL; - } - wpabuf_put_data(data->inbuf, pos, len); - - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, - EAP_PWD_HDR_SIZE, - EAP_CODE_RESPONSE, eap_get_id(reqData)); - if (resp != NULL) - wpabuf_put_u8(resp, (EAP_PWD_GET_EXCHANGE(lm_exch))); - wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a %d byte fragment", - (int) len); - return resp; - } - /* - * we're buffering and this is the last fragment - */ - if (data->in_frag_pos) { - wpabuf_put_data(data->inbuf, pos, len); - wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes", - (int) len); - data->in_frag_pos += len; - pos = wpabuf_head_u8(data->inbuf); - len = data->in_frag_pos; - } - wpa_printf(MSG_DEBUG, "EAP-pwd: processing frame: exch %d, len %d", - EAP_PWD_GET_EXCHANGE(lm_exch), (int) len); - - switch (EAP_PWD_GET_EXCHANGE(lm_exch)) { - case EAP_PWD_OPCODE_ID_EXCH: - eap_pwd_perform_id_exchange(sm, data, ret, reqData, - pos, len); - break; - case EAP_PWD_OPCODE_COMMIT_EXCH: - eap_pwd_perform_commit_exchange(sm, data, ret, reqData, - pos, len); - break; - case EAP_PWD_OPCODE_CONFIRM_EXCH: - eap_pwd_perform_confirm_exchange(sm, data, ret, reqData, - pos, len); - break; - default: - wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown " - "opcode %d", lm_exch); - break; - } - /* - * if we buffered the just processed input now's the time to free it - */ - if (data->in_frag_pos) { - wpabuf_free(data->inbuf); - data->in_frag_pos = 0; - } - - if (data->outbuf == NULL) - return NULL; /* generic failure */ - - /* - * we have output! Do we need to fragment it? - */ - len = wpabuf_len(data->outbuf); - if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, data->mtu, - EAP_CODE_RESPONSE, eap_get_id(reqData)); - /* - * if so it's the first so include a length field - */ - EAP_PWD_SET_LENGTH_BIT(lm_exch); - EAP_PWD_SET_MORE_BIT(lm_exch); - tot_len = len; - /* - * keep the packet at the MTU - */ - len = data->mtu - EAP_PWD_HDR_SIZE - sizeof(u16); - wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, total " - "length = %d", tot_len); - } else { - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, - EAP_PWD_HDR_SIZE + len, - EAP_CODE_RESPONSE, eap_get_id(reqData)); - } - if (resp == NULL) - return NULL; - - wpabuf_put_u8(resp, lm_exch); - if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { - wpabuf_put_be16(resp, tot_len); - data->out_frag_pos += len; - } - buf = wpabuf_head_u8(data->outbuf); - wpabuf_put_data(resp, buf, len); - /* - * if we're not fragmenting then there's no need to carry this around - */ - if (data->out_frag_pos == 0) { - wpabuf_free(data->outbuf); - data->outbuf = NULL; - data->out_frag_pos = 0; - } - - return resp; -} - - -static Boolean eap_pwd_key_available(struct eap_sm *sm, void *priv) -{ - struct eap_pwd_data *data = priv; - return data->state == SUCCESS; -} - - -static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_pwd_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - if ((key = os_malloc(EAP_EMSK_LEN)) == NULL) - return NULL; - - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - *len = EAP_EMSK_LEN; - - return key; -} - - -int eap_peer_pwd_register(void) -{ - struct eap_method *eap; - int ret; - - EVP_add_digest(EVP_sha256()); - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD"); - if (eap == NULL) - return -1; - - eap->init = eap_pwd_init; - eap->deinit = eap_pwd_deinit; - eap->process = eap_pwd_process; - eap->isKeyAvailable = eap_pwd_key_available; - eap->getKey = eap_pwd_getkey; - eap->get_emsk = eap_pwd_get_emsk; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_sake.c b/contrib/hostapd/src/eap_peer/eap_sake.c deleted file mode 100644 index 431519cae6..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_sake.c +++ /dev/null @@ -1,517 +0,0 @@ -/* - * EAP peer method: EAP-SAKE (RFC 4763) - * Copyright (c) 2006-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/random.h" -#include "eap_peer/eap_i.h" -#include "eap_common/eap_sake_common.h" - -struct eap_sake_data { - enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state; - u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN]; - u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN]; - u8 rand_s[EAP_SAKE_RAND_LEN]; - u8 rand_p[EAP_SAKE_RAND_LEN]; - struct { - u8 auth[EAP_SAKE_TEK_AUTH_LEN]; - u8 cipher[EAP_SAKE_TEK_CIPHER_LEN]; - } tek; - u8 msk[EAP_MSK_LEN]; - u8 emsk[EAP_EMSK_LEN]; - u8 session_id; - int session_id_set; - u8 *peerid; - size_t peerid_len; - u8 *serverid; - size_t serverid_len; -}; - - -static const char * eap_sake_state_txt(int state) -{ - switch (state) { - case IDENTITY: - return "IDENTITY"; - case CHALLENGE: - return "CHALLENGE"; - case CONFIRM: - return "CONFIRM"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "?"; - } -} - - -static void eap_sake_state(struct eap_sake_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s", - eap_sake_state_txt(data->state), - eap_sake_state_txt(state)); - data->state = state; -} - - -static void eap_sake_deinit(struct eap_sm *sm, void *priv); - - -static void * eap_sake_init(struct eap_sm *sm) -{ - struct eap_sake_data *data; - const u8 *identity, *password; - size_t identity_len, password_len; - - password = eap_get_config_password(sm, &password_len); - if (!password || password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) { - wpa_printf(MSG_INFO, "EAP-SAKE: No key of correct length " - "configured"); - return NULL; - } - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = IDENTITY; - - identity = eap_get_config_identity(sm, &identity_len); - if (identity) { - data->peerid = os_malloc(identity_len); - if (data->peerid == NULL) { - eap_sake_deinit(sm, data); - return NULL; - } - os_memcpy(data->peerid, identity, identity_len); - data->peerid_len = identity_len; - } - - os_memcpy(data->root_secret_a, password, EAP_SAKE_ROOT_SECRET_LEN); - os_memcpy(data->root_secret_b, - password + EAP_SAKE_ROOT_SECRET_LEN, - EAP_SAKE_ROOT_SECRET_LEN); - - return data; -} - - -static void eap_sake_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_sake_data *data = priv; - os_free(data->serverid); - os_free(data->peerid); - os_free(data); -} - - -static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data, - int id, size_t length, u8 subtype) -{ - struct eap_sake_hdr *sake; - struct wpabuf *msg; - size_t plen; - - plen = length + sizeof(struct eap_sake_hdr); - - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen, - EAP_CODE_RESPONSE, id); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory " - "request"); - return NULL; - } - - sake = wpabuf_put(msg, sizeof(*sake)); - sake->version = EAP_SAKE_VERSION; - sake->session_id = data->session_id; - sake->subtype = subtype; - - return msg; -} - - -static struct wpabuf * eap_sake_process_identity(struct eap_sm *sm, - struct eap_sake_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - const u8 *payload, - size_t payload_len) -{ - struct eap_sake_parse_attr attr; - struct wpabuf *resp; - - if (data->state != IDENTITY) { - ret->ignore = TRUE; - return NULL; - } - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity"); - - if (eap_sake_parse_attributes(payload, payload_len, &attr)) - return NULL; - - if (!attr.perm_id_req && !attr.any_id_req) { - wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or " - "AT_ANY_ID_REQ in Request/Identity"); - return NULL; - } - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity"); - - resp = eap_sake_build_msg(data, eap_get_id(reqData), - 2 + data->peerid_len, - EAP_SAKE_SUBTYPE_IDENTITY); - if (resp == NULL) - return NULL; - - wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID"); - eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID, - data->peerid, data->peerid_len); - - eap_sake_state(data, CHALLENGE); - - return resp; -} - - -static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm, - struct eap_sake_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - const u8 *payload, - size_t payload_len) -{ - struct eap_sake_parse_attr attr; - struct wpabuf *resp; - u8 *rpos; - size_t rlen; - - if (data->state != IDENTITY && data->state != CHALLENGE) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received " - "in unexpected state (%d)", data->state); - ret->ignore = TRUE; - return NULL; - } - if (data->state == IDENTITY) - eap_sake_state(data, CHALLENGE); - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge"); - - if (eap_sake_parse_attributes(payload, payload_len, &attr)) - return NULL; - - if (!attr.rand_s) { - wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not " - "include AT_RAND_S"); - return NULL; - } - - os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)", - data->rand_s, EAP_SAKE_RAND_LEN); - - if (random_get_bytes(data->rand_p, EAP_SAKE_RAND_LEN)) { - wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data"); - return NULL; - } - wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)", - data->rand_p, EAP_SAKE_RAND_LEN); - - os_free(data->serverid); - data->serverid = NULL; - data->serverid_len = 0; - if (attr.serverid) { - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID", - attr.serverid, attr.serverid_len); - data->serverid = os_malloc(attr.serverid_len); - if (data->serverid == NULL) - return NULL; - os_memcpy(data->serverid, attr.serverid, attr.serverid_len); - data->serverid_len = attr.serverid_len; - } - - eap_sake_derive_keys(data->root_secret_a, data->root_secret_b, - data->rand_s, data->rand_p, - (u8 *) &data->tek, data->msk, data->emsk); - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge"); - - rlen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN; - if (data->peerid) - rlen += 2 + data->peerid_len; - resp = eap_sake_build_msg(data, eap_get_id(reqData), rlen, - EAP_SAKE_SUBTYPE_CHALLENGE); - if (resp == NULL) - return NULL; - - wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P"); - eap_sake_add_attr(resp, EAP_SAKE_AT_RAND_P, - data->rand_p, EAP_SAKE_RAND_LEN); - - if (data->peerid) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID"); - eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID, - data->peerid, data->peerid_len); - } - - wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P"); - wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P); - wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN); - rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN); - if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, - data->serverid, data->serverid_len, - data->peerid, data->peerid_len, 1, - wpabuf_head(resp), wpabuf_len(resp), rpos, - rpos)) { - wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC"); - wpabuf_free(resp); - return NULL; - } - - eap_sake_state(data, CONFIRM); - - return resp; -} - - -static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm, - struct eap_sake_data *data, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - const u8 *payload, - size_t payload_len) -{ - struct eap_sake_parse_attr attr; - u8 mic_s[EAP_SAKE_MIC_LEN]; - struct wpabuf *resp; - u8 *rpos; - - if (data->state != CONFIRM) { - ret->ignore = TRUE; - return NULL; - } - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm"); - - if (eap_sake_parse_attributes(payload, payload_len, &attr)) - return NULL; - - if (!attr.mic_s) { - wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not " - "include AT_MIC_S"); - return NULL; - } - - eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, - data->serverid, data->serverid_len, - data->peerid, data->peerid_len, 0, - wpabuf_head(reqData), wpabuf_len(reqData), - attr.mic_s, mic_s); - if (os_memcmp(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) { - wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S"); - eap_sake_state(data, FAILURE); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - ret->allowNotifications = FALSE; - wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending " - "Response/Auth-Reject"); - return eap_sake_build_msg(data, eap_get_id(reqData), 0, - EAP_SAKE_SUBTYPE_AUTH_REJECT); - } - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm"); - - resp = eap_sake_build_msg(data, eap_get_id(reqData), - 2 + EAP_SAKE_MIC_LEN, - EAP_SAKE_SUBTYPE_CONFIRM); - if (resp == NULL) - return NULL; - - wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P"); - wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P); - wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN); - rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN); - if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, - data->serverid, data->serverid_len, - data->peerid, data->peerid_len, 1, - wpabuf_head(resp), wpabuf_len(resp), rpos, - rpos)) { - wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC"); - wpabuf_free(resp); - return NULL; - } - - eap_sake_state(data, SUCCESS); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - ret->allowNotifications = FALSE; - - return resp; -} - - -static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_sake_data *data = priv; - const struct eap_sake_hdr *req; - struct wpabuf *resp; - const u8 *pos, *end; - size_t len; - u8 subtype, session_id; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len); - if (pos == NULL || len < sizeof(struct eap_sake_hdr)) { - ret->ignore = TRUE; - return NULL; - } - - req = (const struct eap_sake_hdr *) pos; - end = pos + len; - subtype = req->subtype; - session_id = req->session_id; - pos = (const u8 *) (req + 1); - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d " - "session_id %d", subtype, session_id); - wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes", - pos, end - pos); - - if (data->session_id_set && data->session_id != session_id) { - wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)", - session_id, data->session_id); - ret->ignore = TRUE; - return NULL; - } - data->session_id = session_id; - data->session_id_set = 1; - - ret->ignore = FALSE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - ret->allowNotifications = TRUE; - - switch (subtype) { - case EAP_SAKE_SUBTYPE_IDENTITY: - resp = eap_sake_process_identity(sm, data, ret, reqData, - pos, end - pos); - break; - case EAP_SAKE_SUBTYPE_CHALLENGE: - resp = eap_sake_process_challenge(sm, data, ret, reqData, - pos, end - pos); - break; - case EAP_SAKE_SUBTYPE_CONFIRM: - resp = eap_sake_process_confirm(sm, data, ret, reqData, - pos, end - pos); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with " - "unknown subtype %d", subtype); - ret->ignore = TRUE; - return NULL; - } - - if (ret->methodState == METHOD_DONE) - ret->allowNotifications = FALSE; - - return resp; -} - - -static Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_sake_data *data = priv; - return data->state == SUCCESS; -} - - -static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_sake_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->msk, EAP_MSK_LEN); - *len = EAP_MSK_LEN; - - return key; -} - - -static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_sake_data *data = priv; - u8 *id; - - if (data->state != SUCCESS) - return NULL; - - *len = 1 + 2 * EAP_SAKE_RAND_LEN; - id = os_malloc(*len); - if (id == NULL) - return NULL; - - id[0] = EAP_TYPE_SAKE; - os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN); - os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len); - - return id; -} - - -static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_sake_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - *len = EAP_EMSK_LEN; - - return key; -} - - -int eap_peer_sake_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE"); - if (eap == NULL) - return -1; - - eap->init = eap_sake_init; - eap->deinit = eap_sake_deinit; - eap->process = eap_sake_process; - eap->isKeyAvailable = eap_sake_isKeyAvailable; - eap->getKey = eap_sake_getKey; - eap->getSessionId = eap_sake_get_session_id; - eap->get_emsk = eap_sake_get_emsk; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_sim.c b/contrib/hostapd/src/eap_peer/eap_sim.c deleted file mode 100644 index d8560543fa..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_sim.c +++ /dev/null @@ -1,1243 +0,0 @@ -/* - * EAP peer method: EAP-SIM (RFC 4186) - * Copyright (c) 2004-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "pcsc_funcs.h" -#include "crypto/milenage.h" -#include "crypto/random.h" -#include "eap_peer/eap_i.h" -#include "eap_config.h" -#include "eap_common/eap_sim_common.h" - - -struct eap_sim_data { - u8 *ver_list; - size_t ver_list_len; - int selected_version; - size_t min_num_chal, num_chal; - - u8 kc[3][EAP_SIM_KC_LEN]; - u8 sres[3][EAP_SIM_SRES_LEN]; - u8 nonce_mt[EAP_SIM_NONCE_MT_LEN], nonce_s[EAP_SIM_NONCE_S_LEN]; - u8 mk[EAP_SIM_MK_LEN]; - u8 k_aut[EAP_SIM_K_AUT_LEN]; - u8 k_encr[EAP_SIM_K_ENCR_LEN]; - u8 msk[EAP_SIM_KEYING_DATA_LEN]; - u8 emsk[EAP_EMSK_LEN]; - u8 rand[3][GSM_RAND_LEN]; - - int num_id_req, num_notification; - u8 *pseudonym; - size_t pseudonym_len; - u8 *reauth_id; - size_t reauth_id_len; - int reauth; - unsigned int counter, counter_too_small; - u8 *last_eap_identity; - size_t last_eap_identity_len; - enum { - CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE - } state; - int result_ind, use_result_ind; -}; - - -#ifndef CONFIG_NO_STDOUT_DEBUG -static const char * eap_sim_state_txt(int state) -{ - switch (state) { - case CONTINUE: - return "CONTINUE"; - case RESULT_SUCCESS: - return "RESULT_SUCCESS"; - case RESULT_FAILURE: - return "RESULT_FAILURE"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "?"; - } -} -#endif /* CONFIG_NO_STDOUT_DEBUG */ - - -static void eap_sim_state(struct eap_sim_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s", - eap_sim_state_txt(data->state), - eap_sim_state_txt(state)); - data->state = state; -} - - -static void * eap_sim_init(struct eap_sm *sm) -{ - struct eap_sim_data *data; - struct eap_peer_config *config = eap_get_config(sm); - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - - if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) { - wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data " - "for NONCE_MT"); - os_free(data); - return NULL; - } - - data->min_num_chal = 2; - if (config && config->phase1) { - char *pos = os_strstr(config->phase1, "sim_min_num_chal="); - if (pos) { - data->min_num_chal = atoi(pos + 17); - if (data->min_num_chal < 2 || data->min_num_chal > 3) { - wpa_printf(MSG_WARNING, "EAP-SIM: Invalid " - "sim_min_num_chal configuration " - "(%lu, expected 2 or 3)", - (unsigned long) data->min_num_chal); - os_free(data); - return NULL; - } - wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of " - "challenges to %lu", - (unsigned long) data->min_num_chal); - } - - data->result_ind = os_strstr(config->phase1, "result_ind=1") != - NULL; - } - - if (config && config->anonymous_identity) { - data->pseudonym = os_malloc(config->anonymous_identity_len); - if (data->pseudonym) { - os_memcpy(data->pseudonym, config->anonymous_identity, - config->anonymous_identity_len); - data->pseudonym_len = config->anonymous_identity_len; - } - } - - eap_sim_state(data, CONTINUE); - - return data; -} - - -static void eap_sim_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_sim_data *data = priv; - if (data) { - os_free(data->ver_list); - os_free(data->pseudonym); - os_free(data->reauth_id); - os_free(data->last_eap_identity); - os_free(data); - } -} - - -static int eap_sim_ext_sim_req(struct eap_sm *sm, struct eap_sim_data *data) -{ - char req[200], *pos, *end; - size_t i; - - wpa_printf(MSG_DEBUG, "EAP-SIM: Use external SIM processing"); - pos = req; - end = pos + sizeof(req); - pos += os_snprintf(pos, end - pos, "GSM-AUTH"); - for (i = 0; i < data->num_chal; i++) { - pos += os_snprintf(pos, end - pos, ":"); - pos += wpa_snprintf_hex(pos, end - pos, data->rand[i], - GSM_RAND_LEN); - } - - eap_sm_request_sim(sm, req); - return 1; -} - - -static int eap_sim_ext_sim_result(struct eap_sm *sm, struct eap_sim_data *data, - struct eap_peer_config *conf) -{ - char *resp, *pos; - size_t i; - - wpa_printf(MSG_DEBUG, - "EAP-SIM: Use result from external SIM processing"); - - resp = conf->external_sim_resp; - conf->external_sim_resp = NULL; - - if (os_strncmp(resp, "GSM-AUTH:", 9) != 0) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized external SIM processing response"); - os_free(resp); - return -1; - } - - pos = resp + 9; - for (i = 0; i < data->num_chal; i++) { - wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND", - data->rand[i], GSM_RAND_LEN); - - if (hexstr2bin(pos, data->kc[i], EAP_SIM_KC_LEN) < 0) - goto invalid; - wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc", - data->kc[i], EAP_SIM_KC_LEN); - pos += EAP_SIM_KC_LEN * 2; - if (*pos != ':') - goto invalid; - pos++; - - if (hexstr2bin(pos, data->sres[i], EAP_SIM_SRES_LEN) < 0) - goto invalid; - wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES", - data->sres[i], EAP_SIM_SRES_LEN); - pos += EAP_SIM_SRES_LEN * 2; - if (i + 1 < data->num_chal) { - if (*pos != ':') - goto invalid; - pos++; - } - } - - os_free(resp); - return 0; - -invalid: - wpa_printf(MSG_DEBUG, "EAP-SIM: Invalid external SIM processing GSM-AUTH response"); - os_free(resp); - return -1; -} - - -static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data) -{ - struct eap_peer_config *conf; - - wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication algorithm"); - - conf = eap_get_config(sm); - if (conf == NULL) - return -1; - - if (sm->external_sim) { - if (conf->external_sim_resp) - return eap_sim_ext_sim_result(sm, data, conf); - else - return eap_sim_ext_sim_req(sm, data); - } - - if (conf->pcsc) { - if (scard_gsm_auth(sm->scard_ctx, data->rand[0], - data->sres[0], data->kc[0]) || - scard_gsm_auth(sm->scard_ctx, data->rand[1], - data->sres[1], data->kc[1]) || - (data->num_chal > 2 && - scard_gsm_auth(sm->scard_ctx, data->rand[2], - data->sres[2], data->kc[2]))) { - wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM " - "authentication could not be completed"); - return -1; - } - return 0; - } - -#ifdef CONFIG_SIM_SIMULATOR - if (conf->password) { - u8 opc[16], k[16]; - const char *pos; - size_t i; - wpa_printf(MSG_DEBUG, "EAP-SIM: Use internal GSM-Milenage " - "implementation for authentication"); - if (conf->password_len < 65) { - wpa_printf(MSG_DEBUG, "EAP-SIM: invalid GSM-Milenage " - "password"); - return -1; - } - pos = (const char *) conf->password; - if (hexstr2bin(pos, k, 16)) - return -1; - pos += 32; - if (*pos != ':') - return -1; - pos++; - - if (hexstr2bin(pos, opc, 16)) - return -1; - - for (i = 0; i < data->num_chal; i++) { - if (gsm_milenage(opc, k, data->rand[i], - data->sres[i], data->kc[i])) { - wpa_printf(MSG_DEBUG, "EAP-SIM: " - "GSM-Milenage authentication " - "could not be completed"); - return -1; - } - wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND", - data->rand[i], GSM_RAND_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES", - data->sres[i], EAP_SIM_SRES_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc", - data->kc[i], EAP_SIM_KC_LEN); - } - return 0; - } -#endif /* CONFIG_SIM_SIMULATOR */ - -#ifdef CONFIG_SIM_HARDCODED - /* These hardcoded Kc and SRES values are used for testing. RAND to - * KC/SREC mapping is very bogus as far as real authentication is - * concerned, but it is quite useful for cases where the AS is rotating - * the order of pre-configured values. */ - { - size_t i; - - wpa_printf(MSG_DEBUG, "EAP-SIM: Use hardcoded Kc and SRES " - "values for testing"); - - for (i = 0; i < data->num_chal; i++) { - if (data->rand[i][0] == 0xaa) { - os_memcpy(data->kc[i], - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7", - EAP_SIM_KC_LEN); - os_memcpy(data->sres[i], "\xd1\xd2\xd3\xd4", - EAP_SIM_SRES_LEN); - } else if (data->rand[i][0] == 0xbb) { - os_memcpy(data->kc[i], - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7", - EAP_SIM_KC_LEN); - os_memcpy(data->sres[i], "\xe1\xe2\xe3\xe4", - EAP_SIM_SRES_LEN); - } else { - os_memcpy(data->kc[i], - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7", - EAP_SIM_KC_LEN); - os_memcpy(data->sres[i], "\xf1\xf2\xf3\xf4", - EAP_SIM_SRES_LEN); - } - } - } - - return 0; - -#else /* CONFIG_SIM_HARDCODED */ - - wpa_printf(MSG_DEBUG, "EAP-SIM: No GSM authentication algorithm " - "enabled"); - return -1; - -#endif /* CONFIG_SIM_HARDCODED */ -} - - -static int eap_sim_supported_ver(int version) -{ - return version == EAP_SIM_VERSION; -} - - -#define CLEAR_PSEUDONYM 0x01 -#define CLEAR_REAUTH_ID 0x02 -#define CLEAR_EAP_ID 0x04 - -static void eap_sim_clear_identities(struct eap_sm *sm, - struct eap_sim_data *data, int id) -{ - 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; - eap_set_anon_id(sm, NULL, 0); - } - 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) && 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; - } -} - - -static int eap_sim_learn_ids(struct eap_sm *sm, struct eap_sim_data *data, - struct eap_sim_attrs *attr) -{ - if (attr->next_pseudonym) { - const u8 *identity = NULL; - size_t identity_len = 0; - const u8 *realm = NULL; - size_t realm_len = 0; - - wpa_hexdump_ascii(MSG_DEBUG, - "EAP-SIM: (encr) AT_NEXT_PSEUDONYM", - attr->next_pseudonym, - attr->next_pseudonym_len); - os_free(data->pseudonym); - /* Look for the realm of the permanent identity */ - identity = eap_get_config_identity(sm, &identity_len); - if (identity) { - for (realm = identity, realm_len = identity_len; - realm_len > 0; realm_len--, realm++) { - if (*realm == '@') - break; - } - } - data->pseudonym = os_malloc(attr->next_pseudonym_len + - realm_len); - if (data->pseudonym == NULL) { - wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for " - "next pseudonym"); - data->pseudonym_len = 0; - return -1; - } - os_memcpy(data->pseudonym, attr->next_pseudonym, - attr->next_pseudonym_len); - if (realm_len) { - os_memcpy(data->pseudonym + attr->next_pseudonym_len, - realm, realm_len); - } - data->pseudonym_len = attr->next_pseudonym_len + realm_len; - eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len); - } - - if (attr->next_reauth_id) { - os_free(data->reauth_id); - data->reauth_id = os_malloc(attr->next_reauth_id_len); - if (data->reauth_id == NULL) { - wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for " - "next reauth_id"); - data->reauth_id_len = 0; - return -1; - } - os_memcpy(data->reauth_id, attr->next_reauth_id, - attr->next_reauth_id_len); - data->reauth_id_len = attr->next_reauth_id_len; - wpa_hexdump_ascii(MSG_DEBUG, - "EAP-SIM: (encr) AT_NEXT_REAUTH_ID", - data->reauth_id, - data->reauth_id_len); - } - - return 0; -} - - -static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id, - int err) -{ - struct eap_sim_msg *msg; - - eap_sim_state(data, FAILURE); - data->num_id_req = 0; - data->num_notification = 0; - - wpa_printf(MSG_DEBUG, "EAP-SIM: Send Client-Error (error code %d)", - err); - msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM, - EAP_SIM_SUBTYPE_CLIENT_ERROR); - eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0); - return eap_sim_msg_finish(msg, NULL, NULL, 0); -} - - -static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, - struct eap_sim_data *data, u8 id, - enum eap_sim_id_req id_req) -{ - const u8 *identity = NULL; - size_t identity_len = 0; - struct eap_sim_msg *msg; - - data->reauth = 0; - if (id_req == ANY_ID && data->reauth_id) { - identity = data->reauth_id; - identity_len = data->reauth_id_len; - data->reauth = 1; - } else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) && - data->pseudonym) { - identity = data->pseudonym; - identity_len = data->pseudonym_len; - eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID); - } else if (id_req != NO_ID_REQ) { - identity = eap_get_config_identity(sm, &identity_len); - if (identity) { - eap_sim_clear_identities(sm, data, CLEAR_PSEUDONYM | - CLEAR_REAUTH_ID); - } - } - if (id_req != NO_ID_REQ) - eap_sim_clear_identities(sm, data, CLEAR_EAP_ID); - - wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id); - msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, - EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START); - if (!data->reauth) { - wpa_hexdump(MSG_DEBUG, " AT_NONCE_MT", - data->nonce_mt, EAP_SIM_NONCE_MT_LEN); - eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_MT, 0, - data->nonce_mt, EAP_SIM_NONCE_MT_LEN); - wpa_printf(MSG_DEBUG, " AT_SELECTED_VERSION %d", - data->selected_version); - eap_sim_msg_add(msg, EAP_SIM_AT_SELECTED_VERSION, - data->selected_version, NULL, 0); - } - - if (identity) { - wpa_hexdump_ascii(MSG_DEBUG, " AT_IDENTITY", - identity, identity_len); - eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len, - identity, identity_len); - } - - return eap_sim_msg_finish(msg, NULL, NULL, 0); -} - - -static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data, - u8 id) -{ - struct eap_sim_msg *msg; - - wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)", id); - msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM, - EAP_SIM_SUBTYPE_CHALLENGE); - if (data->use_result_ind) { - wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); - eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); - } - wpa_printf(MSG_DEBUG, " AT_MAC"); - eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, (u8 *) data->sres, - data->num_chal * EAP_SIM_SRES_LEN); -} - - -static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data, - u8 id, int counter_too_small, - const u8 *nonce_s) -{ - struct eap_sim_msg *msg; - unsigned int counter; - - wpa_printf(MSG_DEBUG, "Generating EAP-SIM Reauthentication (id=%d)", - id); - msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM, - EAP_SIM_SUBTYPE_REAUTHENTICATION); - wpa_printf(MSG_DEBUG, " AT_IV"); - wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); - eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); - - if (counter_too_small) { - wpa_printf(MSG_DEBUG, " *AT_COUNTER_TOO_SMALL"); - eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0); - counter = data->counter_too_small; - } else - counter = data->counter; - - wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", counter); - eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); - - if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { - wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt " - "AT_ENCR_DATA"); - eap_sim_msg_free(msg); - return NULL; - } - if (data->use_result_ind) { - wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); - eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); - } - wpa_printf(MSG_DEBUG, " AT_MAC"); - eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, nonce_s, - EAP_SIM_NONCE_S_LEN); -} - - -static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data, - u8 id, u16 notification) -{ - struct eap_sim_msg *msg; - u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL; - - wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id); - msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, - EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION); - if (k_aut && data->reauth) { - wpa_printf(MSG_DEBUG, " AT_IV"); - wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); - eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, - EAP_SIM_AT_ENCR_DATA); - wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", data->counter); - eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, - NULL, 0); - if (eap_sim_msg_add_encr_end(msg, data->k_encr, - EAP_SIM_AT_PADDING)) { - wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt " - "AT_ENCR_DATA"); - eap_sim_msg_free(msg); - return NULL; - } - } - if (k_aut) { - wpa_printf(MSG_DEBUG, " AT_MAC"); - eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - } - return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0); -} - - -static struct wpabuf * eap_sim_process_start(struct eap_sm *sm, - struct eap_sim_data *data, u8 id, - struct eap_sim_attrs *attr) -{ - int selected_version = -1, id_error; - size_t i; - u8 *pos; - - wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start"); - if (attr->version_list == NULL) { - wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in " - "SIM/Start"); - return eap_sim_client_error(data, id, - EAP_SIM_UNSUPPORTED_VERSION); - } - - os_free(data->ver_list); - data->ver_list = os_malloc(attr->version_list_len); - if (data->ver_list == NULL) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate " - "memory for version list"); - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - os_memcpy(data->ver_list, attr->version_list, attr->version_list_len); - data->ver_list_len = attr->version_list_len; - pos = data->ver_list; - for (i = 0; i < data->ver_list_len / 2; i++) { - int ver = pos[0] * 256 + pos[1]; - pos += 2; - if (eap_sim_supported_ver(ver)) { - selected_version = ver; - break; - } - } - if (selected_version < 0) { - wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported " - "version"); - return eap_sim_client_error(data, id, - EAP_SIM_UNSUPPORTED_VERSION); - } - wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d", - selected_version); - data->selected_version = selected_version; - - id_error = 0; - switch (attr->id_req) { - case NO_ID_REQ: - break; - case ANY_ID: - if (data->num_id_req > 0) - id_error++; - data->num_id_req++; - break; - case FULLAUTH_ID: - if (data->num_id_req > 1) - id_error++; - data->num_id_req++; - break; - case PERMANENT_ID: - if (data->num_id_req > 2) - id_error++; - data->num_id_req++; - break; - } - if (id_error) { - wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests " - "used within one authentication"); - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - - return eap_sim_response_start(sm, data, id, attr->id_req); -} - - -static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm, - struct eap_sim_data *data, - u8 id, - const struct wpabuf *reqData, - struct eap_sim_attrs *attr) -{ - const u8 *identity; - size_t identity_len; - struct eap_sim_attrs eattr; - int res; - - wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge"); - data->reauth = 0; - if (!attr->mac || !attr->rand) { - wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " - "did not include%s%s", - !attr->mac ? " AT_MAC" : "", - !attr->rand ? " AT_RAND" : ""); - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - - wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges", - (unsigned long) attr->num_chal); - if (attr->num_chal < data->min_num_chal) { - wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of " - "challenges (%lu)", (unsigned long) attr->num_chal); - return eap_sim_client_error(data, id, - EAP_SIM_INSUFFICIENT_NUM_OF_CHAL); - } - if (attr->num_chal > 3) { - wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges " - "(%lu)", (unsigned long) attr->num_chal); - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - - /* Verify that RANDs are different */ - if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN, - GSM_RAND_LEN) == 0 || - (attr->num_chal > 2 && - (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN, - GSM_RAND_LEN) == 0 || - os_memcmp(attr->rand + GSM_RAND_LEN, - attr->rand + 2 * GSM_RAND_LEN, - GSM_RAND_LEN) == 0))) { - wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times"); - return eap_sim_client_error(data, id, - EAP_SIM_RAND_NOT_FRESH); - } - - os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN); - data->num_chal = attr->num_chal; - - res = eap_sim_gsm_auth(sm, data); - if (res > 0) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Wait for external SIM processing"); - return NULL; - } - if (res) { - wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed"); - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - if (data->last_eap_identity) { - identity = data->last_eap_identity; - identity_len = data->last_eap_identity_len; - } else if (data->pseudonym) { - identity = data->pseudonym; - identity_len = data->pseudonym_len; - } else - identity = eap_get_config_identity(sm, &identity_len); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK " - "derivation", identity, identity_len); - eap_sim_derive_mk(identity, identity_len, data->nonce_mt, - data->selected_version, data->ver_list, - data->ver_list_len, data->num_chal, - (const u8 *) data->kc, data->mk); - eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, - data->emsk); - if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, data->nonce_mt, - EAP_SIM_NONCE_MT_LEN)) { - wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " - "used invalid AT_MAC"); - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - - /* 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(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); - - if (attr->encr_data) { - u8 *decrypted; - decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, - attr->encr_data_len, attr->iv, - &eattr, 0); - if (decrypted == NULL) { - return eap_sim_client_error( - data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - eap_sim_learn_ids(sm, data, &eattr); - os_free(decrypted); - } - - if (data->result_ind && attr->result_ind) - data->use_result_ind = 1; - - if (data->state != FAILURE && data->state != RESULT_FAILURE) { - eap_sim_state(data, data->use_result_ind ? - RESULT_SUCCESS : SUCCESS); - } - - data->num_id_req = 0; - data->num_notification = 0; - /* RFC 4186 specifies that counter is initialized to one after - * fullauth, but initializing it to zero makes it easier to implement - * reauth verification. */ - data->counter = 0; - return eap_sim_response_challenge(data, id); -} - - -static int eap_sim_process_notification_reauth(struct eap_sim_data *data, - struct eap_sim_attrs *attr) -{ - struct eap_sim_attrs eattr; - u8 *decrypted; - - if (attr->encr_data == NULL || attr->iv == NULL) { - wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after " - "reauth did not include encrypted data"); - return -1; - } - - decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, - attr->encr_data_len, attr->iv, &eattr, - 0); - if (decrypted == NULL) { - wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " - "data from notification message"); - return -1; - } - - if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) { - wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification " - "message does not match with counter in reauth " - "message"); - os_free(decrypted); - return -1; - } - - os_free(decrypted); - return 0; -} - - -static int eap_sim_process_notification_auth(struct eap_sim_data *data, - const struct wpabuf *reqData, - struct eap_sim_attrs *attr) -{ - if (attr->mac == NULL) { - wpa_printf(MSG_INFO, "EAP-SIM: no AT_MAC in after_auth " - "Notification message"); - return -1; - } - - if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0)) - { - wpa_printf(MSG_WARNING, "EAP-SIM: Notification message " - "used invalid AT_MAC"); - return -1; - } - - if (data->reauth && - eap_sim_process_notification_reauth(data, attr)) { - wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification " - "message after reauth"); - return -1; - } - - return 0; -} - - -static struct wpabuf * eap_sim_process_notification( - struct eap_sm *sm, struct eap_sim_data *data, u8 id, - const struct wpabuf *reqData, struct eap_sim_attrs *attr) -{ - wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification"); - if (data->num_notification > 0) { - wpa_printf(MSG_INFO, "EAP-SIM: too many notification " - "rounds (only one allowed)"); - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - data->num_notification++; - if (attr->notification == -1) { - wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in " - "Notification message"); - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - - if ((attr->notification & 0x4000) == 0 && - eap_sim_process_notification_auth(data, reqData, attr)) { - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - - eap_sim_report_notification(sm->msg_ctx, attr->notification, 0); - if (attr->notification >= 0 && attr->notification < 32768) { - eap_sim_state(data, FAILURE); - } else if (attr->notification == EAP_SIM_SUCCESS && - data->state == RESULT_SUCCESS) - eap_sim_state(data, SUCCESS); - return eap_sim_response_notification(data, id, attr->notification); -} - - -static struct wpabuf * eap_sim_process_reauthentication( - struct eap_sm *sm, struct eap_sim_data *data, u8 id, - const struct wpabuf *reqData, struct eap_sim_attrs *attr) -{ - struct eap_sim_attrs eattr; - u8 *decrypted; - - wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication"); - - if (data->reauth_id == NULL) { - wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying " - "reauthentication, but no reauth_id available"); - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - - data->reauth = 1; - if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0)) - { - wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " - "did not have valid AT_MAC"); - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - - if (attr->encr_data == NULL || attr->iv == NULL) { - wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " - "message did not include encrypted data"); - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - - decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, - attr->encr_data_len, attr->iv, &eattr, - 0); - if (decrypted == NULL) { - wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " - "data from reauthentication message"); - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - - if (eattr.nonce_s == NULL || eattr.counter < 0) { - wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet", - !eattr.nonce_s ? " AT_NONCE_S" : "", - eattr.counter < 0 ? " AT_COUNTER" : ""); - os_free(decrypted); - return eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - } - - if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) { - wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter " - "(%d <= %d)", eattr.counter, data->counter); - data->counter_too_small = eattr.counter; - /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current - * reauth_id must not be used to start a new reauthentication. - * However, since it was used in the last EAP-Response-Identity - * packet, it has to saved for the following fullauth to be - * used in MK derivation. */ - os_free(data->last_eap_identity); - data->last_eap_identity = data->reauth_id; - data->last_eap_identity_len = data->reauth_id_len; - data->reauth_id = NULL; - data->reauth_id_len = 0; - os_free(decrypted); - return eap_sim_response_reauth(data, id, 1, eattr.nonce_s); - } - data->counter = eattr.counter; - - os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S", - data->nonce_s, EAP_SIM_NONCE_S_LEN); - - eap_sim_derive_keys_reauth(data->counter, - data->reauth_id, data->reauth_id_len, - data->nonce_s, data->mk, data->msk, - data->emsk); - eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); - eap_sim_learn_ids(sm, data, &eattr); - - if (data->result_ind && attr->result_ind) - data->use_result_ind = 1; - - if (data->state != FAILURE && data->state != RESULT_FAILURE) { - eap_sim_state(data, data->use_result_ind ? - RESULT_SUCCESS : SUCCESS); - } - - data->num_id_req = 0; - data->num_notification = 0; - if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of " - "fast reauths performed - force fullauth"); - eap_sim_clear_identities(sm, data, - CLEAR_REAUTH_ID | CLEAR_EAP_ID); - } - os_free(decrypted); - return eap_sim_response_reauth(data, id, 0, data->nonce_s); -} - - -static struct wpabuf * eap_sim_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_sim_data *data = priv; - const struct eap_hdr *req; - u8 subtype, id; - struct wpabuf *res; - const u8 *pos; - struct eap_sim_attrs attr; - size_t len; - - wpa_hexdump_buf(MSG_DEBUG, "EAP-SIM: EAP data", reqData); - if (eap_get_config_identity(sm, &len) == NULL) { - wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured"); - eap_sm_request_identity(sm); - ret->ignore = TRUE; - return NULL; - } - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len); - if (pos == NULL || len < 1) { - ret->ignore = TRUE; - return NULL; - } - req = wpabuf_head(reqData); - id = req->identifier; - len = be_to_host16(req->length); - - ret->ignore = FALSE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - ret->allowNotifications = TRUE; - - subtype = *pos++; - wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype); - pos += 2; /* Reserved */ - - if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 0, - 0)) { - res = eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - goto done; - } - - switch (subtype) { - case EAP_SIM_SUBTYPE_START: - res = eap_sim_process_start(sm, data, id, &attr); - break; - case EAP_SIM_SUBTYPE_CHALLENGE: - res = eap_sim_process_challenge(sm, data, id, reqData, &attr); - break; - case EAP_SIM_SUBTYPE_NOTIFICATION: - res = eap_sim_process_notification(sm, data, id, reqData, - &attr); - break; - case EAP_SIM_SUBTYPE_REAUTHENTICATION: - res = eap_sim_process_reauthentication(sm, data, id, reqData, - &attr); - break; - case EAP_SIM_SUBTYPE_CLIENT_ERROR: - wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error"); - res = eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype); - res = eap_sim_client_error(data, id, - EAP_SIM_UNABLE_TO_PROCESS_PACKET); - break; - } - -done: - if (data->state == FAILURE) { - ret->decision = DECISION_FAIL; - ret->methodState = METHOD_DONE; - } else if (data->state == SUCCESS) { - ret->decision = data->use_result_ind ? - DECISION_UNCOND_SUCC : DECISION_COND_SUCC; - ret->methodState = data->use_result_ind ? - METHOD_DONE : METHOD_MAY_CONT; - } else if (data->state == RESULT_FAILURE) - ret->methodState = METHOD_CONT; - else if (data->state == RESULT_SUCCESS) - ret->methodState = METHOD_CONT; - - if (ret->methodState == METHOD_DONE) { - ret->allowNotifications = FALSE; - } - - return res; -} - - -static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv) -{ - struct eap_sim_data *data = priv; - return data->pseudonym || data->reauth_id; -} - - -static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_sim_data *data = priv; - eap_sim_clear_identities(sm, data, CLEAR_EAP_ID); - data->use_result_ind = 0; -} - - -static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_sim_data *data = priv; - if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) { - wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data " - "for NONCE_MT"); - os_free(data); - return NULL; - } - data->num_id_req = 0; - data->num_notification = 0; - eap_sim_state(data, CONTINUE); - return priv; -} - - -static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv, - size_t *len) -{ - struct eap_sim_data *data = priv; - - if (data->reauth_id) { - *len = data->reauth_id_len; - return data->reauth_id; - } - - if (data->pseudonym) { - *len = data->pseudonym_len; - return data->pseudonym; - } - - return NULL; -} - - -static Boolean eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_sim_data *data = priv; - return data->state == SUCCESS; -} - - -static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_sim_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_SIM_KEYING_DATA_LEN); - if (key == NULL) - return NULL; - - *len = EAP_SIM_KEYING_DATA_LEN; - os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); - - return key; -} - - -static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_sim_data *data = priv; - u8 *id; - - if (data->state != SUCCESS) - return NULL; - - *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN; - id = os_malloc(*len); - if (id == NULL) - return NULL; - - id[0] = EAP_TYPE_SIM; - os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN); - os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt, - EAP_SIM_NONCE_MT_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len); - - return id; -} - - -static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_sim_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - - *len = EAP_EMSK_LEN; - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - - return key; -} - - -int eap_peer_sim_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM"); - if (eap == NULL) - return -1; - - eap->init = eap_sim_init; - eap->deinit = eap_sim_deinit; - eap->process = eap_sim_process; - eap->isKeyAvailable = eap_sim_isKeyAvailable; - eap->getKey = eap_sim_getKey; - eap->getSessionId = eap_sim_get_session_id; - eap->has_reauth_data = eap_sim_has_reauth_data; - eap->deinit_for_reauth = eap_sim_deinit_for_reauth; - eap->init_for_reauth = eap_sim_init_for_reauth; - eap->get_identity = eap_sim_get_identity; - eap->get_emsk = eap_sim_get_emsk; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_tls.c b/contrib/hostapd/src/eap_peer/eap_tls.c deleted file mode 100644 index d2066cd852..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_tls.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * EAP peer method: EAP-TLS (RFC 2716) - * Copyright (c) 2004-2008, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/tls.h" -#include "eap_i.h" -#include "eap_tls_common.h" -#include "eap_config.h" - - -static void eap_tls_deinit(struct eap_sm *sm, void *priv); - - -struct eap_tls_data { - struct eap_ssl_data ssl; - u8 *key_data; - u8 *session_id; - size_t id_len; - void *ssl_ctx; - u8 eap_type; -}; - - -static void * eap_tls_init(struct eap_sm *sm) -{ - struct eap_tls_data *data; - struct eap_peer_config *config = eap_get_config(sm); - if (config == NULL || - ((sm->init_phase2 ? config->private_key2 : config->private_key) - == NULL && - (sm->init_phase2 ? config->engine2 : config->engine) == 0)) { - wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured"); - return NULL; - } - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - - data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : - sm->ssl_ctx; - - if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) { - wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); - eap_tls_deinit(sm, data); - if (config->engine) { - wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard " - "PIN"); - eap_sm_request_pin(sm); - sm->ignore = TRUE; - } else if (config->private_key && !config->private_key_passwd) - { - wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private " - "key passphrase"); - eap_sm_request_passphrase(sm); - sm->ignore = TRUE; - } - return NULL; - } - - data->eap_type = EAP_TYPE_TLS; - - return data; -} - - -#ifdef EAP_UNAUTH_TLS -static void * eap_unauth_tls_init(struct eap_sm *sm) -{ - struct eap_tls_data *data; - struct eap_peer_config *config = eap_get_config(sm); - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - - data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : - sm->ssl_ctx; - - if (eap_peer_tls_ssl_init(sm, &data->ssl, config, - EAP_UNAUTH_TLS_TYPE)) { - wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); - eap_tls_deinit(sm, data); - return NULL; - } - - data->eap_type = EAP_UNAUTH_TLS_TYPE; - - return data; -} -#endif /* EAP_UNAUTH_TLS */ - - -static void eap_tls_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_tls_data *data = priv; - if (data == NULL) - return; - eap_peer_tls_ssl_deinit(sm, &data->ssl); - os_free(data->key_data); - os_free(data->session_id); - os_free(data); -} - - -static struct wpabuf * eap_tls_failure(struct eap_sm *sm, - struct eap_tls_data *data, - struct eap_method_ret *ret, int res, - struct wpabuf *resp, u8 id) -{ - wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed"); - - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - - if (res == -1) { - struct eap_peer_config *config = eap_get_config(sm); - if (config) { - /* - * The TLS handshake failed. So better forget the old - * PIN. It may be wrong, we cannot be sure but trying - * the wrong one again might block it on the card--so - * better ask the user again. - */ - os_free(config->pin); - config->pin = NULL; - } - } - - if (resp) { - /* - * This is likely an alert message, so send it instead of just - * ACKing the error. - */ - return resp; - } - - return eap_peer_tls_build_ack(id, data->eap_type, 0); -} - - -static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data, - struct eap_method_ret *ret) -{ - wpa_printf(MSG_DEBUG, "EAP-TLS: Done"); - - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - - os_free(data->key_data); - data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, - "client EAP encryption", - EAP_TLS_KEY_LEN + - EAP_EMSK_LEN); - if (data->key_data) { - wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key", - data->key_data, EAP_TLS_KEY_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK", - data->key_data + EAP_TLS_KEY_LEN, - EAP_EMSK_LEN); - } else { - wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key"); - } - - os_free(data->session_id); - data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl, - EAP_TYPE_TLS, - &data->id_len); - if (data->session_id) { - wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived Session-Id", - data->session_id, data->id_len); - } else { - wpa_printf(MSG_ERROR, "EAP-TLS: Failed to derive Session-Id"); - } -} - - -static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - size_t left; - int res; - struct wpabuf *resp; - u8 flags, id; - const u8 *pos; - struct eap_tls_data *data = priv; - - pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret, - reqData, &left, &flags); - if (pos == NULL) - return NULL; - id = eap_get_id(reqData); - - if (flags & EAP_TLS_FLAGS_START) { - wpa_printf(MSG_DEBUG, "EAP-TLS: Start"); - left = 0; /* make sure that this frame is empty, even though it - * should always be, anyway */ - } - - resp = NULL; - res = eap_peer_tls_process_helper(sm, &data->ssl, data->eap_type, 0, - id, pos, left, &resp); - - if (res < 0) { - return eap_tls_failure(sm, data, ret, res, resp, id); - } - - if (tls_connection_established(data->ssl_ctx, data->ssl.conn)) - eap_tls_success(sm, data, ret); - - if (res == 1) { - wpabuf_free(resp); - return eap_peer_tls_build_ack(id, data->eap_type, 0); - } - - return resp; -} - - -static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv) -{ - struct eap_tls_data *data = priv; - return tls_connection_established(data->ssl_ctx, data->ssl.conn); -} - - -static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv) -{ -} - - -static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_tls_data *data = priv; - os_free(data->key_data); - data->key_data = NULL; - os_free(data->session_id); - data->session_id = NULL; - if (eap_peer_tls_reauth_init(sm, &data->ssl)) { - os_free(data); - return NULL; - } - return priv; -} - - -static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf, - size_t buflen, int verbose) -{ - struct eap_tls_data *data = priv; - return eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); -} - - -static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_tls_data *data = priv; - return data->key_data != NULL; -} - - -static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_tls_data *data = priv; - u8 *key; - - if (data->key_data == NULL) - return NULL; - - key = os_malloc(EAP_TLS_KEY_LEN); - if (key == NULL) - return NULL; - - *len = EAP_TLS_KEY_LEN; - os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); - - return key; -} - - -static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_tls_data *data = priv; - u8 *key; - - if (data->key_data == NULL) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - - *len = EAP_EMSK_LEN; - os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); - - return key; -} - - -static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_tls_data *data = priv; - u8 *id; - - if (data->session_id == NULL) - return NULL; - - id = os_malloc(data->id_len); - if (id == NULL) - return NULL; - - *len = data->id_len; - os_memcpy(id, data->session_id, data->id_len); - - return id; -} - - -int eap_peer_tls_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); - if (eap == NULL) - return -1; - - eap->init = eap_tls_init; - eap->deinit = eap_tls_deinit; - eap->process = eap_tls_process; - eap->isKeyAvailable = eap_tls_isKeyAvailable; - eap->getKey = eap_tls_getKey; - eap->getSessionId = eap_tls_get_session_id; - eap->get_status = eap_tls_get_status; - eap->has_reauth_data = eap_tls_has_reauth_data; - eap->deinit_for_reauth = eap_tls_deinit_for_reauth; - eap->init_for_reauth = eap_tls_init_for_reauth; - eap->get_emsk = eap_tls_get_emsk; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} - - -#ifdef EAP_UNAUTH_TLS -int eap_peer_unauth_tls_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_UNAUTH_TLS, - EAP_VENDOR_TYPE_UNAUTH_TLS, "UNAUTH-TLS"); - if (eap == NULL) - return -1; - - eap->init = eap_unauth_tls_init; - eap->deinit = eap_tls_deinit; - eap->process = eap_tls_process; - eap->isKeyAvailable = eap_tls_isKeyAvailable; - eap->getKey = eap_tls_getKey; - eap->get_status = eap_tls_get_status; - eap->has_reauth_data = eap_tls_has_reauth_data; - eap->deinit_for_reauth = eap_tls_deinit_for_reauth; - eap->init_for_reauth = eap_tls_init_for_reauth; - eap->get_emsk = eap_tls_get_emsk; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} -#endif /* EAP_UNAUTH_TLS */ diff --git a/contrib/hostapd/src/eap_peer/eap_tls_common.c b/contrib/hostapd/src/eap_peer/eap_tls_common.c deleted file mode 100644 index 008af37b17..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_tls_common.c +++ /dev/null @@ -1,1115 +0,0 @@ -/* - * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha1.h" -#include "crypto/tls.h" -#include "eap_i.h" -#include "eap_tls_common.h" -#include "eap_config.h" - - -static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len, - u8 code, u8 identifier) -{ - if (type == EAP_UNAUTH_TLS_TYPE) - return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS, - EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len, - code, identifier); - return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code, - identifier); -} - - -static int eap_tls_check_blob(struct eap_sm *sm, const char **name, - const u8 **data, size_t *data_len) -{ - const struct wpa_config_blob *blob; - - if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0) - return 0; - - blob = eap_get_config_blob(sm, *name + 7); - if (blob == NULL) { - wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not " - "found", __func__, *name + 7); - return -1; - } - - *name = NULL; - *data = blob->data; - *data_len = blob->len; - - return 0; -} - - -static void eap_tls_params_flags(struct tls_connection_params *params, - const char *txt) -{ - if (txt == NULL) - return; - if (os_strstr(txt, "tls_allow_md5=1")) - params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5; - if (os_strstr(txt, "tls_disable_time_checks=1")) - params->flags |= TLS_CONN_DISABLE_TIME_CHECKS; - if (os_strstr(txt, "tls_disable_session_ticket=1")) - params->flags |= TLS_CONN_DISABLE_SESSION_TICKET; - if (os_strstr(txt, "tls_disable_session_ticket=0")) - params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET; -} - - -static void eap_tls_params_from_conf1(struct tls_connection_params *params, - struct eap_peer_config *config) -{ - params->ca_cert = (char *) config->ca_cert; - params->ca_path = (char *) config->ca_path; - params->client_cert = (char *) config->client_cert; - params->private_key = (char *) config->private_key; - params->private_key_passwd = (char *) config->private_key_passwd; - params->dh_file = (char *) config->dh_file; - params->subject_match = (char *) config->subject_match; - params->altsubject_match = (char *) config->altsubject_match; - params->suffix_match = config->domain_suffix_match; - params->engine = config->engine; - params->engine_id = config->engine_id; - params->pin = config->pin; - params->key_id = config->key_id; - params->cert_id = config->cert_id; - params->ca_cert_id = config->ca_cert_id; - eap_tls_params_flags(params, config->phase1); -} - - -static void eap_tls_params_from_conf2(struct tls_connection_params *params, - struct eap_peer_config *config) -{ - params->ca_cert = (char *) config->ca_cert2; - params->ca_path = (char *) config->ca_path2; - params->client_cert = (char *) config->client_cert2; - params->private_key = (char *) config->private_key2; - params->private_key_passwd = (char *) config->private_key2_passwd; - params->dh_file = (char *) config->dh_file2; - params->subject_match = (char *) config->subject_match2; - params->altsubject_match = (char *) config->altsubject_match2; - params->suffix_match = config->domain_suffix_match2; - params->engine = config->engine2; - params->engine_id = config->engine2_id; - params->pin = config->pin2; - params->key_id = config->key2_id; - params->cert_id = config->cert2_id; - params->ca_cert_id = config->ca_cert2_id; - eap_tls_params_flags(params, config->phase2); -} - - -static int eap_tls_params_from_conf(struct eap_sm *sm, - struct eap_ssl_data *data, - struct tls_connection_params *params, - struct eap_peer_config *config, int phase2) -{ - os_memset(params, 0, sizeof(*params)); - if (sm->workaround && data->eap_type != EAP_TYPE_FAST) { - /* - * Some deployed authentication servers seem to be unable to - * handle the TLS Session Ticket extension (they are supposed - * to ignore unrecognized TLS extensions, but end up rejecting - * the ClientHello instead). As a workaround, disable use of - * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and - * EAP-TTLS (EAP-FAST uses session ticket, so any server that - * supports EAP-FAST does not need this workaround). - */ - params->flags |= TLS_CONN_DISABLE_SESSION_TICKET; - } - if (phase2) { - wpa_printf(MSG_DEBUG, "TLS: using phase2 config options"); - eap_tls_params_from_conf2(params, config); - } else { - wpa_printf(MSG_DEBUG, "TLS: using phase1 config options"); - eap_tls_params_from_conf1(params, config); - } - - /* - * Use blob data, if available. Otherwise, leave reference to external - * file as-is. - */ - if (eap_tls_check_blob(sm, ¶ms->ca_cert, ¶ms->ca_cert_blob, - ¶ms->ca_cert_blob_len) || - eap_tls_check_blob(sm, ¶ms->client_cert, - ¶ms->client_cert_blob, - ¶ms->client_cert_blob_len) || - eap_tls_check_blob(sm, ¶ms->private_key, - ¶ms->private_key_blob, - ¶ms->private_key_blob_len) || - eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob, - ¶ms->dh_blob_len)) { - wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs"); - return -1; - } - - return 0; -} - - -static int eap_tls_init_connection(struct eap_sm *sm, - struct eap_ssl_data *data, - struct eap_peer_config *config, - struct tls_connection_params *params) -{ - int res; - - if (config->ocsp) - params->flags |= TLS_CONN_REQUEST_OCSP; - if (config->ocsp == 2) - params->flags |= TLS_CONN_REQUIRE_OCSP; - data->conn = tls_connection_init(data->ssl_ctx); - if (data->conn == NULL) { - wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " - "connection"); - return -1; - } - - res = tls_connection_set_params(data->ssl_ctx, data->conn, params); - if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) { - /* - * At this point with the pkcs11 engine the PIN might be wrong. - * We reset the PIN in the configuration to be sure to not use - * it again and the calling function must request a new one. - */ - os_free(config->pin); - config->pin = NULL; - } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) { - wpa_printf(MSG_INFO, "TLS: Failed to load private key"); - /* - * We do not know exactly but maybe the PIN was wrong, - * so ask for a new one. - */ - os_free(config->pin); - config->pin = NULL; - eap_sm_request_pin(sm); - sm->ignore = TRUE; - tls_connection_deinit(data->ssl_ctx, data->conn); - data->conn = NULL; - return -1; - } else if (res) { - wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection " - "parameters"); - tls_connection_deinit(data->ssl_ctx, data->conn); - data->conn = NULL; - return -1; - } - - return 0; -} - - -/** - * eap_peer_tls_ssl_init - Initialize shared TLS functionality - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @config: Pointer to the network configuration - * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) - * Returns: 0 on success, -1 on failure - * - * This function is used to initialize shared TLS functionality for EAP-TLS, - * EAP-PEAP, EAP-TTLS, and EAP-FAST. - */ -int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, - struct eap_peer_config *config, u8 eap_type) -{ - struct tls_connection_params params; - - if (config == NULL) - return -1; - - data->eap = sm; - data->eap_type = eap_type; - data->phase2 = sm->init_phase2; - data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : - sm->ssl_ctx; - if (eap_tls_params_from_conf(sm, data, ¶ms, config, data->phase2) < - 0) - return -1; - - if (eap_tls_init_connection(sm, data, config, ¶ms) < 0) - return -1; - - data->tls_out_limit = config->fragment_size; - if (data->phase2) { - /* Limit the fragment size in the inner TLS authentication - * since the outer authentication with EAP-PEAP does not yet - * support fragmentation */ - if (data->tls_out_limit > 100) - data->tls_out_limit -= 100; - } - - if (config->phase1 && - os_strstr(config->phase1, "include_tls_length=1")) { - wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in " - "unfragmented packets"); - data->include_tls_length = 1; - } - - return 0; -} - - -/** - * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * - * This function deinitializes shared TLS functionality that was initialized - * with eap_peer_tls_ssl_init(). - */ -void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) -{ - tls_connection_deinit(data->ssl_ctx, data->conn); - eap_peer_tls_reset_input(data); - eap_peer_tls_reset_output(data); -} - - -/** - * eap_peer_tls_derive_key - Derive a key based on TLS session data - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @label: Label string for deriving the keys, e.g., "client EAP encryption" - * @len: Length of the key material to generate (usually 64 for MSK) - * Returns: Pointer to allocated key on success or %NULL on failure - * - * This function uses TLS-PRF to generate pseudo-random data based on the TLS - * session data (client/server random and master key). Each key type may use a - * different label to bind the key usage into the generated material. - * - * The caller is responsible for freeing the returned buffer. - */ -u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, - const char *label, size_t len) -{ -#ifndef CONFIG_FIPS - struct tls_keys keys; -#endif /* CONFIG_FIPS */ - u8 *rnd = NULL, *out; - - out = os_malloc(len); - if (out == NULL) - return NULL; - - /* First, try to use TLS library function for PRF, if available. */ - if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len) - == 0) - return out; - -#ifndef CONFIG_FIPS - /* - * TLS library did not support key generation, so get the needed TLS - * session parameters and use an internal implementation of TLS PRF to - * derive the key. - */ - if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys)) - goto fail; - - if (keys.client_random == NULL || keys.server_random == NULL || - keys.master_key == NULL) - goto fail; - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - if (rnd == NULL) - goto fail; - 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_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); - return out; - -fail: -#endif /* CONFIG_FIPS */ - os_free(out); - os_free(rnd); - return NULL; -} - - -/** - * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) - * @len: Pointer to length of the session ID generated - * Returns: Pointer to allocated Session-Id on success or %NULL on failure - * - * This function derive the Session-Id based on the TLS session data - * (client/server random and method type). - * - * The caller is responsible for freeing the returned buffer. - */ -u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm, - struct eap_ssl_data *data, u8 eap_type, - size_t *len) -{ - struct tls_keys keys; - u8 *out; - - /* - * TLS library did not support session ID generation, - * so get the needed TLS session parameters - */ - if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) - return NULL; - - if (keys.client_random == NULL || keys.server_random == NULL || - keys.master_key == NULL) - return NULL; - - *len = 1 + keys.client_random_len + keys.server_random_len; - out = os_malloc(*len); - if (out == NULL) - return NULL; - - /* Session-Id = EAP type || client.random || server.random */ - out[0] = eap_type; - os_memcpy(out + 1, keys.client_random, keys.client_random_len); - os_memcpy(out + 1 + keys.client_random_len, keys.server_random, - keys.server_random_len); - - return out; -} - - -/** - * eap_peer_tls_reassemble_fragment - Reassemble a received fragment - * @data: Data for TLS processing - * @in_data: Next incoming TLS segment - * Returns: 0 on success, 1 if more data is needed for the full message, or - * -1 on error - */ -static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, - const struct wpabuf *in_data) -{ - size_t tls_in_len, in_len; - - tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0; - in_len = in_data ? wpabuf_len(in_data) : 0; - - if (tls_in_len + in_len == 0) { - /* No message data received?! */ - wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: " - "tls_in_left=%lu tls_in_len=%lu in_len=%lu", - (unsigned long) data->tls_in_left, - (unsigned long) tls_in_len, - (unsigned long) in_len); - eap_peer_tls_reset_input(data); - return -1; - } - - if (tls_in_len + in_len > 65536) { - /* - * Limit length to avoid rogue servers from causing large - * memory allocations. - */ - wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over " - "64 kB)"); - eap_peer_tls_reset_input(data); - return -1; - } - - if (in_len > data->tls_in_left) { - /* Sender is doing something odd - reject message */ - wpa_printf(MSG_INFO, "SSL: more data than TLS message length " - "indicated"); - eap_peer_tls_reset_input(data); - return -1; - } - - if (wpabuf_resize(&data->tls_in, in_len) < 0) { - wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS " - "data"); - eap_peer_tls_reset_input(data); - return -1; - } - if (in_data) - wpabuf_put_buf(data->tls_in, in_data); - data->tls_in_left -= in_len; - - if (data->tls_in_left > 0) { - wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input " - "data", (unsigned long) data->tls_in_left); - return 1; - } - - return 0; -} - - -/** - * eap_peer_tls_data_reassemble - Reassemble TLS data - * @data: Data for TLS processing - * @in_data: Next incoming TLS segment - * @need_more_input: Variable for returning whether more input data is needed - * to reassemble this TLS packet - * Returns: Pointer to output data, %NULL on error or when more data is needed - * for the full message (in which case, *need_more_input is also set to 1). - * - * This function reassembles TLS fragments. Caller must not free the returned - * data buffer since an internal pointer to it is maintained. - */ -static const struct wpabuf * eap_peer_tls_data_reassemble( - struct eap_ssl_data *data, const struct wpabuf *in_data, - int *need_more_input) -{ - *need_more_input = 0; - - if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) { - /* Message has fragments */ - int res = eap_peer_tls_reassemble_fragment(data, in_data); - if (res) { - if (res == 1) - *need_more_input = 1; - return NULL; - } - - /* Message is now fully reassembled. */ - } else { - /* No fragments in this message, so just make a copy of it. */ - data->tls_in_left = 0; - data->tls_in = wpabuf_dup(in_data); - if (data->tls_in == NULL) - return NULL; - } - - return data->tls_in; -} - - -/** - * eap_tls_process_input - Process incoming TLS message - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @in_data: Message received from the server - * @in_len: Length of in_data - * @out_data: Buffer for returning a pointer to application data (if available) - * Returns: 0 on success, 1 if more input data is needed, 2 if application data - * is available, -1 on failure - */ -static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data, - const u8 *in_data, size_t in_len, - struct wpabuf **out_data) -{ - const struct wpabuf *msg; - int need_more_input; - struct wpabuf *appl_data; - struct wpabuf buf; - - wpabuf_set(&buf, in_data, in_len); - msg = eap_peer_tls_data_reassemble(data, &buf, &need_more_input); - if (msg == NULL) - return need_more_input ? 1 : -1; - - /* Full TLS message reassembled - continue handshake processing */ - if (data->tls_out) { - /* This should not happen.. */ - wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending " - "tls_out data even though tls_out_len = 0"); - wpabuf_free(data->tls_out); - WPA_ASSERT(data->tls_out == NULL); - } - appl_data = NULL; - data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn, - msg, &appl_data); - - eap_peer_tls_reset_input(data); - - if (appl_data && - tls_connection_established(data->ssl_ctx, data->conn) && - !tls_connection_get_failed(data->ssl_ctx, data->conn)) { - wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data", - appl_data); - *out_data = appl_data; - return 2; - } - - wpabuf_free(appl_data); - - return 0; -} - - -/** - * eap_tls_process_output - Process outgoing TLS message - * @data: Data for TLS processing - * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) - * @peap_version: Version number for EAP-PEAP/TTLS - * @id: EAP identifier for the response - * @ret: Return value to use on success - * @out_data: Buffer for returning the allocated output buffer - * Returns: ret (0 or 1) on success, -1 on failure - */ -static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, - int peap_version, u8 id, int ret, - struct wpabuf **out_data) -{ - size_t len; - u8 *flags; - int more_fragments, length_included; - - if (data->tls_out == NULL) - return -1; - len = wpabuf_len(data->tls_out) - data->tls_out_pos; - wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total " - "%lu bytes)", - (unsigned long) len, - (unsigned long) wpabuf_len(data->tls_out)); - - /* - * Limit outgoing message to the configured maximum size. Fragment - * message if needed. - */ - if (len > data->tls_out_limit) { - more_fragments = 1; - len = data->tls_out_limit; - wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments " - "will follow", (unsigned long) len); - } else - more_fragments = 0; - - length_included = data->tls_out_pos == 0 && - (wpabuf_len(data->tls_out) > data->tls_out_limit || - data->include_tls_length); - if (!length_included && - eap_type == EAP_TYPE_PEAP && peap_version == 0 && - !tls_connection_established(data->eap->ssl_ctx, data->conn)) { - /* - * Windows Server 2008 NPS really wants to have the TLS Message - * length included in phase 0 even for unfragmented frames or - * it will get very confused with Compound MAC calculation and - * Outer TLVs. - */ - length_included = 1; - } - - *out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len, - EAP_CODE_RESPONSE, id); - if (*out_data == NULL) - return -1; - - flags = wpabuf_put(*out_data, 1); - *flags = peap_version; - if (more_fragments) - *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; - if (length_included) { - *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; - wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out)); - } - - wpabuf_put_data(*out_data, - wpabuf_head_u8(data->tls_out) + data->tls_out_pos, - len); - data->tls_out_pos += len; - - if (!more_fragments) - eap_peer_tls_reset_output(data); - - return ret; -} - - -/** - * eap_peer_tls_process_helper - Process TLS handshake message - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) - * @peap_version: Version number for EAP-PEAP/TTLS - * @id: EAP identifier for the response - * @in_data: Message received from the server - * @in_len: Length of in_data - * @out_data: Buffer for returning a pointer to the response message - * Returns: 0 on success, 1 if more input data is needed, 2 if application data - * is available, or -1 on failure - * - * This function can be used to process TLS handshake messages. It reassembles - * the received fragments and uses a TLS library to process the messages. The - * response data from the TLS library is fragmented to suitable output messages - * that the caller can send out. - * - * out_data is used to return the response message if the return value of this - * function is 0, 2, or -1. In case of failure, the message is likely a TLS - * alarm message. The caller is responsible for freeing the allocated buffer if - * *out_data is not %NULL. - * - * This function is called for each received TLS message during the TLS - * handshake after eap_peer_tls_process_init() call and possible processing of - * TLS Flags field. Once the handshake has been completed, i.e., when - * tls_connection_established() returns 1, EAP method specific decrypting of - * the tunneled data is used. - */ -int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, - EapType eap_type, int peap_version, - u8 id, const u8 *in_data, size_t in_len, - struct wpabuf **out_data) -{ - int ret = 0; - - *out_data = NULL; - - if (data->tls_out && wpabuf_len(data->tls_out) > 0 && in_len > 0) { - wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output " - "fragments are waiting to be sent out"); - return -1; - } - - if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { - /* - * No more data to send out - expect to receive more data from - * the AS. - */ - int res = eap_tls_process_input(sm, data, in_data, in_len, - out_data); - if (res) { - /* - * Input processing failed (res = -1) or more data is - * needed (res = 1). - */ - return res; - } - - /* - * The incoming message has been reassembled and processed. The - * response was allocated into data->tls_out buffer. - */ - } - - if (data->tls_out == NULL) { - /* - * No outgoing fragments remaining from the previous message - * and no new message generated. This indicates an error in TLS - * processing. - */ - eap_peer_tls_reset_output(data); - return -1; - } - - if (tls_connection_get_failed(data->ssl_ctx, data->conn)) { - /* TLS processing has failed - return error */ - wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " - "report error"); - ret = -1; - /* TODO: clean pin if engine used? */ - } - - if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { - /* - * TLS negotiation should now be complete since all other cases - * needing more data should have been caught above based on - * the TLS Message Length field. - */ - wpa_printf(MSG_DEBUG, "SSL: No data to be sent out"); - wpabuf_free(data->tls_out); - data->tls_out = NULL; - return 1; - } - - /* Send the pending message (in fragments, if needed). */ - return eap_tls_process_output(data, eap_type, peap_version, id, ret, - out_data); -} - - -/** - * eap_peer_tls_build_ack - Build a TLS ACK frame - * @id: EAP identifier for the response - * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) - * @peap_version: Version number for EAP-PEAP/TTLS - * Returns: Pointer to the allocated ACK frame or %NULL on failure - */ -struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, - int peap_version) -{ - struct wpabuf *resp; - - resp = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)", - (int) eap_type, id, peap_version); - wpabuf_put_u8(resp, peap_version); /* Flags */ - return resp; -} - - -/** - * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * Returns: 0 on success, -1 on failure - */ -int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data) -{ - eap_peer_tls_reset_input(data); - eap_peer_tls_reset_output(data); - return tls_connection_shutdown(data->ssl_ctx, data->conn); -} - - -/** - * eap_peer_tls_status - Get TLS status - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @buf: Buffer for status information - * @buflen: Maximum buffer length - * @verbose: Whether to include verbose status information - * Returns: Number of bytes written to buf. - */ -int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, - char *buf, size_t buflen, int verbose) -{ - char name[128]; - int len = 0, ret; - - if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) == 0) - { - ret = os_snprintf(buf + len, buflen - len, - "EAP TLS cipher=%s\n", name); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - } - - return len; -} - - -/** - * eap_peer_tls_process_init - Initial validation/processing of EAP requests - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) - * @ret: Return values from EAP request validation and processing - * @reqData: EAP request to be processed (eapReqData) - * @len: Buffer for returning length of the remaining payload - * @flags: Buffer for returning TLS flags - * Returns: Pointer to payload after TLS flags and length or %NULL on failure - * - * This function validates the EAP header and processes the optional TLS - * Message Length field. If this is the first fragment of a TLS message, the - * TLS reassembly code is initialized to receive the indicated number of bytes. - * - * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this - * function as the first step in processing received messages. They will need - * to process the flags (apart from Message Length Included) that are returned - * through the flags pointer and the message payload that will be returned (and - * the length is returned through the len pointer). Return values (ret) are set - * for continuation of EAP method processing. The caller is responsible for - * setting these to indicate completion (either success or failure) based on - * the authentication result. - */ -const u8 * eap_peer_tls_process_init(struct eap_sm *sm, - struct eap_ssl_data *data, - EapType eap_type, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - size_t *len, u8 *flags) -{ - const u8 *pos; - size_t left; - unsigned int tls_msg_len; - - if (tls_get_errors(data->ssl_ctx)) { - wpa_printf(MSG_INFO, "SSL: TLS errors detected"); - ret->ignore = TRUE; - return NULL; - } - - if (eap_type == EAP_UNAUTH_TLS_TYPE) - pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, - EAP_VENDOR_TYPE_UNAUTH_TLS, reqData, - &left); - else - pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, - &left); - if (pos == NULL) { - ret->ignore = TRUE; - return NULL; - } - if (left == 0) { - wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags " - "octet included"); - if (!sm->workaround) { - ret->ignore = TRUE; - return NULL; - } - - wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags " - "indicates ACK frame"); - *flags = 0; - } else { - *flags = *pos++; - left--; - } - wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - " - "Flags 0x%02x", (unsigned long) wpabuf_len(reqData), - *flags); - if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { - if (left < 4) { - wpa_printf(MSG_INFO, "SSL: Short frame with TLS " - "length"); - ret->ignore = TRUE; - return NULL; - } - tls_msg_len = WPA_GET_BE32(pos); - wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", - tls_msg_len); - if (data->tls_in_left == 0) { - data->tls_in_total = tls_msg_len; - data->tls_in_left = tls_msg_len; - wpabuf_free(data->tls_in); - data->tls_in = NULL; - } - pos += 4; - left -= 4; - - if (left > tls_msg_len) { - wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d " - "bytes) smaller than this fragment (%d " - "bytes)", (int) tls_msg_len, (int) left); - ret->ignore = TRUE; - return NULL; - } - } - - ret->ignore = FALSE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - ret->allowNotifications = TRUE; - - *len = left; - return pos; -} - - -/** - * eap_peer_tls_reset_input - Reset input buffers - * @data: Data for TLS processing - * - * This function frees any allocated memory for input buffers and resets input - * state. - */ -void eap_peer_tls_reset_input(struct eap_ssl_data *data) -{ - data->tls_in_left = data->tls_in_total = 0; - wpabuf_free(data->tls_in); - data->tls_in = NULL; -} - - -/** - * eap_peer_tls_reset_output - Reset output buffers - * @data: Data for TLS processing - * - * This function frees any allocated memory for output buffers and resets - * output state. - */ -void eap_peer_tls_reset_output(struct eap_ssl_data *data) -{ - data->tls_out_pos = 0; - wpabuf_free(data->tls_out); - data->tls_out = NULL; -} - - -/** - * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @in_data: Message received from the server - * @in_decrypted: Buffer for returning a pointer to the decrypted message - * Returns: 0 on success, 1 if more input data is needed, or -1 on failure - */ -int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, - const struct wpabuf *in_data, - struct wpabuf **in_decrypted) -{ - const struct wpabuf *msg; - int need_more_input; - - msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input); - if (msg == NULL) - return need_more_input ? 1 : -1; - - *in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg); - eap_peer_tls_reset_input(data); - if (*in_decrypted == NULL) { - wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data"); - return -1; - } - return 0; -} - - -/** - * eap_peer_tls_encrypt - Encrypt phase 2 TLS message - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) - * @peap_version: Version number for EAP-PEAP/TTLS - * @id: EAP identifier for the response - * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments - * @out_data: Buffer for returning a pointer to the encrypted response message - * Returns: 0 on success, -1 on failure - */ -int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, - EapType eap_type, int peap_version, u8 id, - const struct wpabuf *in_data, - struct wpabuf **out_data) -{ - if (in_data) { - eap_peer_tls_reset_output(data); - data->tls_out = tls_connection_encrypt(data->ssl_ctx, - data->conn, in_data); - if (data->tls_out == NULL) { - wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 " - "data (in_len=%lu)", - (unsigned long) wpabuf_len(in_data)); - eap_peer_tls_reset_output(data); - return -1; - } - } - - return eap_tls_process_output(data, eap_type, peap_version, id, 0, - out_data); -} - - -/** - * eap_peer_select_phase2_methods - Select phase 2 EAP method - * @config: Pointer to the network configuration - * @prefix: 'phase2' configuration prefix, e.g., "auth=" - * @types: Buffer for returning allocated list of allowed EAP methods - * @num_types: Buffer for returning number of allocated EAP methods - * Returns: 0 on success, -1 on failure - * - * This function is used to parse EAP method list and select allowed methods - * for Phase2 authentication. - */ -int eap_peer_select_phase2_methods(struct eap_peer_config *config, - const char *prefix, - struct eap_method_type **types, - size_t *num_types) -{ - char *start, *pos, *buf; - struct eap_method_type *methods = NULL, *_methods; - u8 method; - size_t num_methods = 0, prefix_len; - - if (config == NULL || config->phase2 == NULL) - goto get_defaults; - - start = buf = os_strdup(config->phase2); - if (buf == NULL) - return -1; - - prefix_len = os_strlen(prefix); - - while (start && *start != '\0') { - int vendor; - pos = os_strstr(start, prefix); - if (pos == NULL) - break; - if (start != pos && *(pos - 1) != ' ') { - start = pos + prefix_len; - continue; - } - - start = pos + prefix_len; - pos = os_strchr(start, ' '); - if (pos) - *pos++ = '\0'; - method = eap_get_phase2_type(start, &vendor); - if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) { - wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP " - "method '%s'", start); - } else { - num_methods++; - _methods = os_realloc_array(methods, num_methods, - sizeof(*methods)); - if (_methods == NULL) { - os_free(methods); - os_free(buf); - return -1; - } - methods = _methods; - methods[num_methods - 1].vendor = vendor; - methods[num_methods - 1].method = method; - } - - start = pos; - } - - os_free(buf); - -get_defaults: - if (methods == NULL) - methods = eap_get_phase2_types(config, &num_methods); - - if (methods == NULL) { - wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available"); - return -1; - } - wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types", - (u8 *) methods, - num_methods * sizeof(struct eap_method_type)); - - *types = methods; - *num_types = num_methods; - - return 0; -} - - -/** - * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2 - * @types: Buffer for returning allocated list of allowed EAP methods - * @num_types: Buffer for returning number of allocated EAP methods - * @hdr: EAP-Request header (and the following EAP type octet) - * @resp: Buffer for returning the EAP-Nak message - * Returns: 0 on success, -1 on failure - */ -int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, - struct eap_hdr *hdr, struct wpabuf **resp) -{ - u8 *pos = (u8 *) (hdr + 1); - size_t i; - - /* TODO: add support for expanded Nak */ - wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos); - wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types", - (u8 *) types, num_types * sizeof(struct eap_method_type)); - *resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types, - EAP_CODE_RESPONSE, hdr->identifier); - if (*resp == NULL) - return -1; - - for (i = 0; i < num_types; i++) { - if (types[i].vendor == EAP_VENDOR_IETF && - types[i].method < 256) - wpabuf_put_u8(*resp, types[i].method); - } - - eap_update_len(*resp); - - return 0; -} diff --git a/contrib/hostapd/src/eap_peer/eap_tls_common.h b/contrib/hostapd/src/eap_peer/eap_tls_common.h deleted file mode 100644 index 1a5e0f89e4..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_tls_common.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2009, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_TLS_COMMON_H -#define EAP_TLS_COMMON_H - -/** - * struct eap_ssl_data - TLS data for EAP methods - */ -struct eap_ssl_data { - /** - * conn - TLS connection context data from tls_connection_init() - */ - struct tls_connection *conn; - - /** - * tls_out - TLS message to be sent out in fragments - */ - struct wpabuf *tls_out; - - /** - * tls_out_pos - The current position in the outgoing TLS message - */ - size_t tls_out_pos; - - /** - * tls_out_limit - Maximum fragment size for outgoing TLS messages - */ - size_t tls_out_limit; - - /** - * tls_in - Received TLS message buffer for re-assembly - */ - struct wpabuf *tls_in; - - /** - * tls_in_left - Number of remaining bytes in the incoming TLS message - */ - size_t tls_in_left; - - /** - * tls_in_total - Total number of bytes in the incoming TLS message - */ - size_t tls_in_total; - - /** - * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel) - */ - int phase2; - - /** - * include_tls_length - Whether the TLS length field is included even - * if the TLS data is not fragmented - */ - int include_tls_length; - - /** - * eap - EAP state machine allocated with eap_peer_sm_init() - */ - struct eap_sm *eap; - - /** - * ssl_ctx - TLS library context to use for the connection - */ - void *ssl_ctx; - - /** - * eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) - */ - u8 eap_type; -}; - - -/* EAP TLS Flags */ -#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80 -#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40 -#define EAP_TLS_FLAGS_START 0x20 -#define EAP_TLS_VERSION_MASK 0x07 - - /* could be up to 128 bytes, but only the first 64 bytes are used */ -#define EAP_TLS_KEY_LEN 64 - -/* dummy type used as a flag for UNAUTH-TLS */ -#define EAP_UNAUTH_TLS_TYPE 255 - - -int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, - struct eap_peer_config *config, u8 eap_type); -void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); -u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, - const char *label, size_t len); -u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm, - struct eap_ssl_data *data, u8 eap_type, - size_t *len); -int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, - EapType eap_type, int peap_version, - u8 id, const u8 *in_data, size_t in_len, - struct wpabuf **out_data); -struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, - int peap_version); -int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data); -int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, - char *buf, size_t buflen, int verbose); -const u8 * eap_peer_tls_process_init(struct eap_sm *sm, - struct eap_ssl_data *data, - EapType eap_type, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - size_t *len, u8 *flags); -void eap_peer_tls_reset_input(struct eap_ssl_data *data); -void eap_peer_tls_reset_output(struct eap_ssl_data *data); -int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, - const struct wpabuf *in_data, - struct wpabuf **in_decrypted); -int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, - EapType eap_type, int peap_version, u8 id, - const struct wpabuf *in_data, - struct wpabuf **out_data); -int eap_peer_select_phase2_methods(struct eap_peer_config *config, - const char *prefix, - struct eap_method_type **types, - size_t *num_types); -int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, - struct eap_hdr *hdr, struct wpabuf **resp); - -#endif /* EAP_TLS_COMMON_H */ diff --git a/contrib/hostapd/src/eap_peer/eap_tnc.c b/contrib/hostapd/src/eap_peer/eap_tnc.c deleted file mode 100644 index bc136470b3..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_tnc.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * EAP peer method: EAP-TNC (Trusted Network Connect) - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" -#include "tncc.h" - - -struct eap_tnc_data { - enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state; - struct tncc_data *tncc; - struct wpabuf *in_buf; - struct wpabuf *out_buf; - size_t out_used; - size_t fragment_size; -}; - - -/* EAP-TNC Flags */ -#define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80 -#define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40 -#define EAP_TNC_FLAGS_START 0x20 -#define EAP_TNC_VERSION_MASK 0x07 - -#define EAP_TNC_VERSION 1 - - -static void * eap_tnc_init(struct eap_sm *sm) -{ - struct eap_tnc_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = WAIT_START; - data->fragment_size = 1300; - data->tncc = tncc_init(); - if (data->tncc == NULL) { - os_free(data); - return NULL; - } - - return data; -} - - -static void eap_tnc_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_tnc_data *data = priv; - - wpabuf_free(data->in_buf); - wpabuf_free(data->out_buf); - tncc_deinit(data->tncc); - os_free(data); -} - - -static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code) -{ - struct wpabuf *msg; - - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory " - "for fragment ack"); - return NULL; - } - wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */ - - wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack"); - - return msg; -} - - -static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data, - struct eap_method_ret *ret, u8 id) -{ - struct wpabuf *resp; - u8 flags; - size_t send_len, plen; - - ret->ignore = FALSE; - wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response"); - ret->allowNotifications = TRUE; - - flags = EAP_TNC_VERSION; - send_len = wpabuf_len(data->out_buf) - data->out_used; - if (1 + send_len > data->fragment_size) { - send_len = data->fragment_size - 1; - flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS; - if (data->out_used == 0) { - flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED; - send_len -= 4; - } - } - - plen = 1 + send_len; - if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) - plen += 4; - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen, - EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - - wpabuf_put_u8(resp, flags); /* Flags */ - if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) - wpabuf_put_be32(resp, wpabuf_len(data->out_buf)); - - wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, - send_len); - data->out_used += send_len; - - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - - if (data->out_used == wpabuf_len(data->out_buf)) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " - "(message sent completely)", - (unsigned long) send_len); - wpabuf_free(data->out_buf); - data->out_buf = NULL; - data->out_used = 0; - } else { - wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " - "(%lu more to send)", (unsigned long) send_len, - (unsigned long) wpabuf_len(data->out_buf) - - data->out_used); - data->state = WAIT_FRAG_ACK; - } - - return resp; -} - - -static int eap_tnc_process_cont(struct eap_tnc_data *data, - const u8 *buf, size_t len) -{ - /* Process continuation of a pending message */ - if (len > wpabuf_tailroom(data->in_buf)) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow"); - data->state = FAIL; - return -1; - } - - wpabuf_put_data(data->in_buf, buf, len); - wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for " - "%lu bytes more", (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); - - return 0; -} - - -static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data, - struct eap_method_ret *ret, - u8 id, u8 flags, - u32 message_length, - const u8 *buf, size_t len) -{ - /* Process a fragment that is not the last one of the message */ - if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) { - wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a " - "fragmented packet"); - ret->ignore = TRUE; - return NULL; - } - - if (data->in_buf == NULL) { - /* First fragment of the message */ - data->in_buf = wpabuf_alloc(message_length); - if (data->in_buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for " - "message"); - ret->ignore = TRUE; - return NULL; - } - wpabuf_put_data(data->in_buf, buf, len); - wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first " - "fragment, waiting for %lu bytes more", - (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); - } - - return eap_tnc_build_frag_ack(id, EAP_CODE_RESPONSE); -} - - -static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_tnc_data *data = priv; - struct wpabuf *resp; - const u8 *pos, *end; - u8 *rpos, *rpos1; - size_t len, rlen; - size_t imc_len; - char *start_buf, *end_buf; - size_t start_len, end_len; - int tncs_done = 0; - u8 flags, id; - u32 message_length = 0; - struct wpabuf tmpbuf; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len); - if (pos == NULL) { - wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)", - pos, (unsigned long) len); - ret->ignore = TRUE; - return NULL; - } - - id = eap_get_id(reqData); - - end = pos + len; - - if (len == 0) - flags = 0; /* fragment ack */ - else - flags = *pos++; - - if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d", - flags & EAP_TNC_VERSION_MASK); - ret->ignore = TRUE; - return NULL; - } - - if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) { - if (end - pos < 4) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow"); - ret->ignore = TRUE; - return NULL; - } - message_length = WPA_GET_BE32(pos); - pos += 4; - - if (message_length < (u32) (end - pos)) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message " - "Length (%d; %ld remaining in this msg)", - message_length, (long) (end - pos)); - ret->ignore = TRUE; - return NULL; - } - } - - wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x " - "Message Length %u", flags, message_length); - - if (data->state == WAIT_FRAG_ACK) { - if (len > 1) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in " - "WAIT_FRAG_ACK state"); - ret->ignore = TRUE; - return NULL; - } - wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged"); - data->state = PROC_MSG; - return eap_tnc_build_msg(data, ret, id); - } - - if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) { - ret->ignore = TRUE; - return NULL; - } - - if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) { - return eap_tnc_process_fragment(data, ret, id, flags, - message_length, pos, - end - pos); - } - - if (data->in_buf == NULL) { - /* Wrap unfragmented messages as wpabuf without extra copy */ - wpabuf_set(&tmpbuf, pos, end - pos); - data->in_buf = &tmpbuf; - } - - if (data->state == WAIT_START) { - if (!(flags & EAP_TNC_FLAGS_START)) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use " - "start flag in the first message"); - ret->ignore = TRUE; - goto fail; - } - - tncc_init_connection(data->tncc); - - data->state = PROC_MSG; - } else { - enum tncc_process_res res; - - if (flags & EAP_TNC_FLAGS_START) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start " - "flag again"); - ret->ignore = TRUE; - goto fail; - } - - res = tncc_process_if_tnccs(data->tncc, - wpabuf_head(data->in_buf), - wpabuf_len(data->in_buf)); - switch (res) { - case TNCCS_PROCESS_ERROR: - ret->ignore = TRUE; - goto fail; - case TNCCS_PROCESS_OK_NO_RECOMMENDATION: - case TNCCS_RECOMMENDATION_ERROR: - wpa_printf(MSG_DEBUG, "EAP-TNC: No " - "TNCCS-Recommendation received"); - break; - case TNCCS_RECOMMENDATION_ALLOW: - wpa_msg(sm->msg_ctx, MSG_INFO, - "TNC: Recommendation = allow"); - tncs_done = 1; - break; - case TNCCS_RECOMMENDATION_NONE: - wpa_msg(sm->msg_ctx, MSG_INFO, - "TNC: Recommendation = none"); - tncs_done = 1; - break; - case TNCCS_RECOMMENDATION_ISOLATE: - wpa_msg(sm->msg_ctx, MSG_INFO, - "TNC: Recommendation = isolate"); - tncs_done = 1; - break; - } - } - - if (data->in_buf != &tmpbuf) - wpabuf_free(data->in_buf); - data->in_buf = NULL; - - ret->ignore = FALSE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_UNCOND_SUCC; - ret->allowNotifications = TRUE; - - if (data->out_buf) { - data->state = PROC_MSG; - return eap_tnc_build_msg(data, ret, id); - } - - if (tncs_done) { - resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, - EAP_CODE_RESPONSE, eap_get_id(reqData)); - if (resp == NULL) - return NULL; - - wpabuf_put_u8(resp, EAP_TNC_VERSION); - wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an " - "empty ACK message"); - return resp; - } - - imc_len = tncc_total_send_len(data->tncc); - - start_buf = tncc_if_tnccs_start(data->tncc); - if (start_buf == NULL) - return NULL; - start_len = os_strlen(start_buf); - end_buf = tncc_if_tnccs_end(); - if (end_buf == NULL) { - os_free(start_buf); - return NULL; - } - end_len = os_strlen(end_buf); - - rlen = start_len + imc_len + end_len; - resp = wpabuf_alloc(rlen); - if (resp == NULL) { - os_free(start_buf); - os_free(end_buf); - return NULL; - } - - wpabuf_put_data(resp, start_buf, start_len); - os_free(start_buf); - - rpos1 = wpabuf_put(resp, 0); - rpos = tncc_copy_send_buf(data->tncc, rpos1); - wpabuf_put(resp, rpos - rpos1); - - wpabuf_put_data(resp, end_buf, end_len); - os_free(end_buf); - - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response", - wpabuf_head(resp), wpabuf_len(resp)); - - data->out_buf = resp; - data->state = PROC_MSG; - return eap_tnc_build_msg(data, ret, id); - -fail: - if (data->in_buf == &tmpbuf) - data->in_buf = NULL; - return NULL; -} - - -int eap_peer_tnc_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC"); - if (eap == NULL) - return -1; - - eap->init = eap_tnc_init; - eap->deinit = eap_tnc_deinit; - eap->process = eap_tnc_process; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_ttls.c b/contrib/hostapd/src/eap_peer/eap_ttls.c deleted file mode 100644 index 5091bf0844..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_ttls.c +++ /dev/null @@ -1,1675 +0,0 @@ -/* - * EAP peer method: EAP-TTLS (RFC 5281) - * Copyright (c) 2004-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/ms_funcs.h" -#include "crypto/sha1.h" -#include "crypto/tls.h" -#include "eap_common/chap.h" -#include "eap_common/eap_ttls.h" -#include "mschapv2.h" -#include "eap_i.h" -#include "eap_tls_common.h" -#include "eap_config.h" - - -#define EAP_TTLS_VERSION 0 - - -static void eap_ttls_deinit(struct eap_sm *sm, void *priv); - - -struct eap_ttls_data { - struct eap_ssl_data ssl; - - int ttls_version; - - const struct eap_method *phase2_method; - void *phase2_priv; - int phase2_success; - int phase2_start; - - enum phase2_types { - EAP_TTLS_PHASE2_EAP, - EAP_TTLS_PHASE2_MSCHAPV2, - EAP_TTLS_PHASE2_MSCHAP, - EAP_TTLS_PHASE2_PAP, - EAP_TTLS_PHASE2_CHAP - } phase2_type; - struct eap_method_type phase2_eap_type; - struct eap_method_type *phase2_eap_types; - size_t num_phase2_eap_types; - - u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN]; - int auth_response_valid; - u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */ - u8 ident; - int resuming; /* starting a resumed session */ - int reauth; /* reauthentication */ - u8 *key_data; - u8 *session_id; - size_t id_len; - - struct wpabuf *pending_phase2_req; - -#ifdef EAP_TNC - int ready_for_tnc; - int tnc_started; -#endif /* EAP_TNC */ -}; - - -static void * eap_ttls_init(struct eap_sm *sm) -{ - struct eap_ttls_data *data; - struct eap_peer_config *config = eap_get_config(sm); - char *selected; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->ttls_version = EAP_TTLS_VERSION; - selected = "EAP"; - data->phase2_type = EAP_TTLS_PHASE2_EAP; - - if (config && config->phase2) { - if (os_strstr(config->phase2, "autheap=")) { - selected = "EAP"; - data->phase2_type = EAP_TTLS_PHASE2_EAP; - } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) { - selected = "MSCHAPV2"; - data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; - } else if (os_strstr(config->phase2, "auth=MSCHAP")) { - selected = "MSCHAP"; - data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; - } else if (os_strstr(config->phase2, "auth=PAP")) { - selected = "PAP"; - data->phase2_type = EAP_TTLS_PHASE2_PAP; - } else if (os_strstr(config->phase2, "auth=CHAP")) { - selected = "CHAP"; - data->phase2_type = EAP_TTLS_PHASE2_CHAP; - } - } - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected); - - if (data->phase2_type == EAP_TTLS_PHASE2_EAP) { - if (eap_peer_select_phase2_methods(config, "autheap=", - &data->phase2_eap_types, - &data->num_phase2_eap_types) - < 0) { - eap_ttls_deinit(sm, data); - return NULL; - } - - data->phase2_eap_type.vendor = EAP_VENDOR_IETF; - data->phase2_eap_type.method = EAP_TYPE_NONE; - } - - if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) { - wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); - eap_ttls_deinit(sm, data); - return NULL; - } - - return data; -} - - -static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm, - struct eap_ttls_data *data) -{ - if (data->phase2_priv && data->phase2_method) { - data->phase2_method->deinit(sm, data->phase2_priv); - data->phase2_method = NULL; - data->phase2_priv = NULL; - } -} - - -static void eap_ttls_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_ttls_data *data = priv; - if (data == NULL) - return; - eap_ttls_phase2_eap_deinit(sm, data); - os_free(data->phase2_eap_types); - eap_peer_tls_ssl_deinit(sm, &data->ssl); - os_free(data->key_data); - os_free(data->session_id); - wpabuf_free(data->pending_phase2_req); - os_free(data); -} - - -static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, - int mandatory, size_t len) -{ - struct ttls_avp_vendor *avp; - u8 flags; - size_t hdrlen; - - avp = (struct ttls_avp_vendor *) avphdr; - flags = mandatory ? AVP_FLAGS_MANDATORY : 0; - if (vendor_id) { - flags |= AVP_FLAGS_VENDOR; - hdrlen = sizeof(*avp); - avp->vendor_id = host_to_be32(vendor_id); - } else { - hdrlen = sizeof(struct ttls_avp); - } - - avp->avp_code = host_to_be32(avp_code); - avp->avp_length = host_to_be32((flags << 24) | (u32) (hdrlen + len)); - - return avphdr + hdrlen; -} - - -static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code, - u32 vendor_id, int mandatory, - const u8 *data, size_t len) -{ - u8 *pos; - pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len); - os_memcpy(pos, data, len); - pos += len; - AVP_PAD(start, pos); - return pos; -} - - -static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, - int mandatory) -{ - struct wpabuf *msg; - u8 *avp, *pos; - - msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4); - if (msg == NULL) { - wpabuf_free(*resp); - *resp = NULL; - return -1; - } - - avp = wpabuf_mhead(msg); - pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp)); - os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp)); - pos += wpabuf_len(*resp); - AVP_PAD(avp, pos); - wpabuf_free(*resp); - wpabuf_put(msg, pos - avp); - *resp = msg; - return 0; -} - - -static int eap_ttls_v0_derive_key(struct eap_sm *sm, - struct eap_ttls_data *data) -{ - os_free(data->key_data); - data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, - "ttls keying material", - EAP_TLS_KEY_LEN); - if (!data->key_data) { - wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key"); - return -1; - } - - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", - data->key_data, EAP_TLS_KEY_LEN); - - os_free(data->session_id); - data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl, - EAP_TYPE_TTLS, - &data->id_len); - if (data->session_id) { - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id", - data->session_id, data->id_len); - } else { - wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id"); - } - - return 0; -} - - -static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, - struct eap_ttls_data *data, size_t len) -{ - return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len); -} - - -static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data, - u8 method) -{ - size_t i; - for (i = 0; i < data->num_phase2_eap_types; i++) { - if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF || - data->phase2_eap_types[i].method != method) - continue; - - data->phase2_eap_type.vendor = - data->phase2_eap_types[i].vendor; - data->phase2_eap_type.method = - data->phase2_eap_types[i].method; - wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " - "Phase 2 EAP vendor %d method %d", - data->phase2_eap_type.vendor, - data->phase2_eap_type.method); - break; - } -} - - -static int eap_ttls_phase2_eap_process(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, size_t len, - struct wpabuf **resp) -{ - struct wpabuf msg; - struct eap_method_ret iret; - - os_memset(&iret, 0, sizeof(iret)); - wpabuf_set(&msg, hdr, len); - *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, - &msg); - if ((iret.methodState == METHOD_DONE || - iret.methodState == METHOD_MAY_CONT) && - (iret.decision == DECISION_UNCOND_SUCC || - iret.decision == DECISION_COND_SUCC || - iret.decision == DECISION_FAIL)) { - ret->methodState = iret.methodState; - ret->decision = iret.decision; - } - - return 0; -} - - -static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, size_t len, - u8 method, struct wpabuf **resp) -{ -#ifdef EAP_TNC - if (data->tnc_started && data->phase2_method && - data->phase2_priv && method == EAP_TYPE_TNC && - data->phase2_eap_type.method == EAP_TYPE_TNC) - return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, - resp); - - if (data->ready_for_tnc && !data->tnc_started && - method == EAP_TYPE_TNC) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " - "EAP method"); - data->tnc_started = 1; - } - - if (data->tnc_started) { - if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF || - data->phase2_eap_type.method == EAP_TYPE_TNC) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP " - "type %d for TNC", method); - return -1; - } - - data->phase2_eap_type.vendor = EAP_VENDOR_IETF; - data->phase2_eap_type.method = method; - wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " - "Phase 2 EAP vendor %d method %d (TNC)", - data->phase2_eap_type.vendor, - data->phase2_eap_type.method); - - if (data->phase2_type == EAP_TTLS_PHASE2_EAP) - eap_ttls_phase2_eap_deinit(sm, data); - } -#endif /* EAP_TNC */ - - if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF && - data->phase2_eap_type.method == EAP_TYPE_NONE) - eap_ttls_phase2_select_eap_method(data, method); - - if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE) - { - if (eap_peer_tls_phase2_nak(data->phase2_eap_types, - data->num_phase2_eap_types, - hdr, resp)) - return -1; - return 0; - } - - if (data->phase2_priv == NULL) { - data->phase2_method = eap_peer_get_eap_method( - EAP_VENDOR_IETF, method); - if (data->phase2_method) { - sm->init_phase2 = 1; - data->phase2_priv = data->phase2_method->init(sm); - sm->init_phase2 = 0; - } - } - if (data->phase2_priv == NULL || data->phase2_method == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize " - "Phase 2 EAP method %d", method); - return -1; - } - - return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp); -} - - -static int eap_ttls_phase2_request_eap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, - struct wpabuf **resp) -{ - size_t len = be_to_host16(hdr->length); - u8 *pos; - struct eap_peer_config *config = eap_get_config(sm); - - if (len <= sizeof(struct eap_hdr)) { - wpa_printf(MSG_INFO, "EAP-TTLS: too short " - "Phase 2 request (len=%lu)", (unsigned long) len); - return -1; - } - pos = (u8 *) (hdr + 1); - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos); - switch (*pos) { - case EAP_TYPE_IDENTITY: - *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); - break; - default: - if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len, - *pos, resp) < 0) - return -1; - break; - } - - if (*resp == NULL && - (config->pending_req_identity || config->pending_req_password || - config->pending_req_otp)) { - return 0; - } - - if (*resp == NULL) - return -1; - - wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response", - *resp); - return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1); -} - - -static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ -#ifdef EAP_MSCHAPv2 - struct wpabuf *msg; - u8 *buf, *pos, *challenge, *peer_challenge; - const u8 *identity, *password; - size_t identity_len, password_len; - int pwhash; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password2(sm, &password_len, &pwhash); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + 1000); - if (msg == NULL) { - wpa_printf(MSG_ERROR, - "EAP-TTLS/MSCHAPV2: Failed to allocate memory"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - /* User-Name */ - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - /* MS-CHAP-Challenge */ - challenge = eap_ttls_implicit_challenge( - sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1); - if (challenge == NULL) { - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " - "implicit challenge"); - return -1; - } - - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, - RADIUS_VENDOR_ID_MICROSOFT, 1, - challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); - - /* MS-CHAP2-Response */ - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE, - RADIUS_VENDOR_ID_MICROSOFT, 1, - EAP_TTLS_MSCHAPV2_RESPONSE_LEN); - data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]; - *pos++ = data->ident; - *pos++ = 0; /* Flags */ - if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) { - os_free(challenge); - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get " - "random data for peer challenge"); - return -1; - } - peer_challenge = pos; - pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; - os_memset(pos, 0, 8); /* Reserved, must be zero */ - pos += 8; - if (mschapv2_derive_response(identity, identity_len, password, - password_len, pwhash, challenge, - peer_challenge, pos, data->auth_response, - data->master_key)) { - os_free(challenge); - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " - "response"); - return -1; - } - data->auth_response_valid = 1; - - pos += 24; - os_free(challenge); - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - if (sm->workaround) { - /* At least FreeRADIUS seems to be terminating - * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success - * packet. */ - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - " - "allow success without tunneled response"); - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_COND_SUCC; - } - - return 0; -#else /* EAP_MSCHAPv2 */ - wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); - return -1; -#endif /* EAP_MSCHAPv2 */ -} - - -static int eap_ttls_phase2_request_mschap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ - struct wpabuf *msg; - u8 *buf, *pos, *challenge; - const u8 *identity, *password; - size_t identity_len, password_len; - int pwhash; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password2(sm, &password_len, &pwhash); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + 1000); - if (msg == NULL) { - wpa_printf(MSG_ERROR, - "EAP-TTLS/MSCHAP: Failed to allocate memory"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - /* User-Name */ - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - /* MS-CHAP-Challenge */ - challenge = eap_ttls_implicit_challenge( - sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); - if (challenge == NULL) { - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive " - "implicit challenge"); - return -1; - } - - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, - RADIUS_VENDOR_ID_MICROSOFT, 1, - challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); - - /* MS-CHAP-Response */ - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE, - RADIUS_VENDOR_ID_MICROSOFT, 1, - EAP_TTLS_MSCHAP_RESPONSE_LEN); - data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN]; - *pos++ = data->ident; - *pos++ = 1; /* Flags: Use NT style passwords */ - os_memset(pos, 0, 24); /* LM-Response */ - pos += 24; - if (pwhash) { - challenge_response(challenge, password, pos); /* NT-Response */ - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash", - password, 16); - } else { - nt_challenge_response(challenge, password, password_len, - pos); /* NT-Response */ - wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password", - password, password_len); - } - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge", - challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24); - pos += 24; - os_free(challenge); - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - /* 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; -} - - -static int eap_ttls_phase2_request_pap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ - struct wpabuf *msg; - u8 *buf, *pos; - size_t pad; - const u8 *identity, *password; - size_t identity_len, password_len; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password(sm, &password_len); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + password_len + 100); - if (msg == NULL) { - wpa_printf(MSG_ERROR, - "EAP-TTLS/PAP: Failed to allocate memory"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - /* User-Name */ - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - /* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts - * the data, so no separate encryption is used in the AVP itself. - * However, the password is padded to obfuscate its length. */ - pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15; - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1, - password_len + pad); - os_memcpy(pos, password, password_len); - pos += password_len; - os_memset(pos, 0, pad); - pos += pad; - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - /* 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; -} - - -static int eap_ttls_phase2_request_chap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ - struct wpabuf *msg; - u8 *buf, *pos, *challenge; - const u8 *identity, *password; - size_t identity_len, password_len; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password(sm, &password_len); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + 1000); - if (msg == NULL) { - wpa_printf(MSG_ERROR, - "EAP-TTLS/CHAP: Failed to allocate memory"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - /* User-Name */ - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - /* CHAP-Challenge */ - challenge = eap_ttls_implicit_challenge( - sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1); - if (challenge == NULL) { - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive " - "implicit challenge"); - return -1; - } - - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1, - challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); - - /* CHAP-Password */ - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1, - 1 + EAP_TTLS_CHAP_PASSWORD_LEN); - data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN]; - *pos++ = data->ident; - - /* MD5(Ident + Password + Challenge) */ - chap_md5(data->ident, password, password_len, challenge, - EAP_TTLS_CHAP_CHALLENGE_LEN, pos); - - wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username", - identity, identity_len); - wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password", - password, password_len); - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge", - challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password", - pos, EAP_TTLS_CHAP_PASSWORD_LEN); - pos += EAP_TTLS_CHAP_PASSWORD_LEN; - os_free(challenge); - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - /* 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; -} - - -static int eap_ttls_phase2_request(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, - struct wpabuf **resp) -{ - int res = 0; - size_t len; - enum phase2_types phase2_type = data->phase2_type; - -#ifdef EAP_TNC - if (data->tnc_started) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC"); - phase2_type = EAP_TTLS_PHASE2_EAP; - } -#endif /* EAP_TNC */ - - if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 || - phase2_type == EAP_TTLS_PHASE2_MSCHAP || - phase2_type == EAP_TTLS_PHASE2_PAP || - phase2_type == EAP_TTLS_PHASE2_CHAP) { - if (eap_get_config_identity(sm, &len) == NULL) { - wpa_printf(MSG_INFO, - "EAP-TTLS: Identity not configured"); - eap_sm_request_identity(sm); - if (eap_get_config_password(sm, &len) == NULL) - eap_sm_request_password(sm); - return 0; - } - - if (eap_get_config_password(sm, &len) == NULL) { - wpa_printf(MSG_INFO, - "EAP-TTLS: Password not configured"); - eap_sm_request_password(sm); - return 0; - } - } - - switch (phase2_type) { - case EAP_TTLS_PHASE2_EAP: - res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp); - break; - case EAP_TTLS_PHASE2_MSCHAPV2: - res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp); - break; - case EAP_TTLS_PHASE2_MSCHAP: - res = eap_ttls_phase2_request_mschap(sm, data, ret, resp); - break; - case EAP_TTLS_PHASE2_PAP: - res = eap_ttls_phase2_request_pap(sm, data, ret, resp); - break; - case EAP_TTLS_PHASE2_CHAP: - res = eap_ttls_phase2_request_chap(sm, data, ret, resp); - break; - default: - wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown"); - res = -1; - break; - } - - if (res < 0) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - } - - return res; -} - - -struct ttls_parse_avp { - u8 *mschapv2; - u8 *eapdata; - size_t eap_len; - int mschapv2_error; -}; - - -static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen, - struct ttls_parse_avp *parse) -{ - wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message"); - if (parse->eapdata == NULL) { - parse->eapdata = os_malloc(dlen); - if (parse->eapdata == NULL) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " - "memory for Phase 2 EAP data"); - return -1; - } - os_memcpy(parse->eapdata, dpos, dlen); - parse->eap_len = dlen; - } else { - u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen); - if (neweap == NULL) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " - "memory for Phase 2 EAP data"); - return -1; - } - os_memcpy(neweap + parse->eap_len, dpos, dlen); - parse->eapdata = neweap; - parse->eap_len += dlen; - } - - return 0; -} - - -static int eap_ttls_parse_avp(u8 *pos, size_t left, - struct ttls_parse_avp *parse) -{ - struct ttls_avp *avp; - u32 avp_code, avp_length, vendor_id = 0; - u8 avp_flags, *dpos; - size_t dlen; - - avp = (struct ttls_avp *) pos; - avp_code = be_to_host32(avp->avp_code); - avp_length = be_to_host32(avp->avp_length); - avp_flags = (avp_length >> 24) & 0xff; - avp_length &= 0xffffff; - wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x " - "length=%d", (int) avp_code, avp_flags, - (int) avp_length); - - if (avp_length > left) { - wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow " - "(len=%d, left=%lu) - dropped", - (int) avp_length, (unsigned long) left); - return -1; - } - - if (avp_length < sizeof(*avp)) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d", - avp_length); - return -1; - } - - dpos = (u8 *) (avp + 1); - dlen = avp_length - sizeof(*avp); - if (avp_flags & AVP_FLAGS_VENDOR) { - if (dlen < 4) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Vendor AVP " - "underflow"); - return -1; - } - vendor_id = WPA_GET_BE32(dpos); - wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d", - (int) vendor_id); - dpos += 4; - dlen -= 4; - } - - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen); - - if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) { - if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0) - return -1; - } else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) { - /* This is an optional message that can be displayed to - * the user. */ - wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message", - dpos, dlen); - } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && - avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success", - dpos, dlen); - if (dlen != 43) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected " - "MS-CHAP2-Success length " - "(len=%lu, expected 43)", - (unsigned long) dlen); - return -1; - } - parse->mschapv2 = dpos; - } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && - avp_code == RADIUS_ATTR_MS_CHAP_ERROR) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error", - dpos, dlen); - parse->mschapv2_error = 1; - } else if (avp_flags & AVP_FLAGS_MANDATORY) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported mandatory AVP " - "code %d vendor_id %d - dropped", - (int) avp_code, (int) vendor_id); - return -1; - } else { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP " - "code %d vendor_id %d", - (int) avp_code, (int) vendor_id); - } - - return avp_length; -} - - -static int eap_ttls_parse_avps(struct wpabuf *in_decrypted, - struct ttls_parse_avp *parse) -{ - u8 *pos; - size_t left, pad; - int avp_length; - - pos = wpabuf_mhead(in_decrypted); - left = wpabuf_len(in_decrypted); - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left); - if (left < sizeof(struct ttls_avp)) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame" - " len=%lu expected %lu or more - dropped", - (unsigned long) left, - (unsigned long) sizeof(struct ttls_avp)); - return -1; - } - - /* Parse AVPs */ - os_memset(parse, 0, sizeof(*parse)); - - while (left > 0) { - avp_length = eap_ttls_parse_avp(pos, left, parse); - if (avp_length < 0) - return -1; - - pad = (4 - (avp_length & 3)) & 3; - pos += avp_length + pad; - if (left < avp_length + pad) - left = 0; - else - left -= avp_length + pad; - } - - return 0; -} - - -static u8 * eap_ttls_fake_identity_request(void) -{ - struct eap_hdr *hdr; - u8 *buf; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of " - "Phase 2 - use fake EAP-Request Identity"); - buf = os_malloc(sizeof(*hdr) + 1); - if (buf == NULL) { - wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate " - "memory for fake EAP-Identity Request"); - return NULL; - } - - hdr = (struct eap_hdr *) buf; - hdr->code = EAP_CODE_REQUEST; - hdr->identifier = 0; - hdr->length = host_to_be16(sizeof(*hdr) + 1); - buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY; - - return buf; -} - - -static int eap_ttls_encrypt_response(struct eap_sm *sm, - struct eap_ttls_data *data, - struct wpabuf *resp, u8 identifier, - struct wpabuf **out_data) -{ - if (resp == NULL) - return 0; - - wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data", - resp); - if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, - data->ttls_version, identifier, - resp, out_data)) { - wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 " - "frame"); - return -1; - } - wpabuf_free(resp); - - return 0; -} - - -static int eap_ttls_process_phase2_eap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct ttls_parse_avp *parse, - struct wpabuf **resp) -{ - struct eap_hdr *hdr; - size_t len; - - if (parse->eapdata == NULL) { - wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the " - "packet - dropped"); - return -1; - } - - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP", - parse->eapdata, parse->eap_len); - hdr = (struct eap_hdr *) parse->eapdata; - - if (parse->eap_len < sizeof(*hdr)) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP " - "frame (len=%lu, expected %lu or more) - dropped", - (unsigned long) parse->eap_len, - (unsigned long) sizeof(*hdr)); - return -1; - } - len = be_to_host16(hdr->length); - if (len > parse->eap_len) { - wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 " - "EAP frame (EAP hdr len=%lu, EAP data len in " - "AVP=%lu)", - (unsigned long) len, - (unsigned long) parse->eap_len); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d " - "identifier=%d length=%lu", - hdr->code, hdr->identifier, (unsigned long) len); - switch (hdr->code) { - case EAP_CODE_REQUEST: - if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) { - wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " - "processing failed"); - return -1; - } - break; - default: - wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in " - "Phase 2 EAP header", hdr->code); - return -1; - } - - return 0; -} - - -static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct ttls_parse_avp *parse) -{ -#ifdef EAP_MSCHAPv2 - if (parse->mschapv2_error) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received " - "MS-CHAP-Error - failed"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - /* Reply with empty data to ACK error */ - return 1; - } - - if (parse->mschapv2 == NULL) { -#ifdef EAP_TNC - if (data->phase2_success && parse->eapdata) { - /* - * Allow EAP-TNC to be started after successfully - * completed MSCHAPV2. - */ - return 1; - } -#endif /* EAP_TNC */ - wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP " - "received for Phase2 MSCHAPV2"); - return -1; - } - if (parse->mschapv2[0] != data->ident) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 " - "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)", - parse->mschapv2[0], data->ident); - return -1; - } - if (!data->auth_response_valid || - mschapv2_verify_auth_response(data->auth_response, - parse->mschapv2 + 1, 42)) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator " - "response in Phase 2 MSCHAPV2 success request"); - return -1; - } - - wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 " - "authentication succeeded"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - data->phase2_success = 1; - - /* - * Reply with empty data; authentication server will reply - * with EAP-Success after this. - */ - return 1; -#else /* EAP_MSCHAPv2 */ - wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); - return -1; -#endif /* EAP_MSCHAPv2 */ -} - - -#ifdef EAP_TNC -static int eap_ttls_process_tnc_start(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct ttls_parse_avp *parse, - struct wpabuf **resp) -{ - /* TNC uses inner EAP method after non-EAP TTLS phase 2. */ - if (parse->eapdata == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " - "unexpected tunneled data (no EAP)"); - return -1; - } - - if (!data->ready_for_tnc) { - wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " - "EAP after non-EAP, but not ready for TNC"); - return -1; - } - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " - "non-EAP method"); - data->tnc_started = 1; - - if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0) - return -1; - - return 0; -} -#endif /* EAP_TNC */ - - -static int eap_ttls_process_decrypted(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - u8 identifier, - struct ttls_parse_avp *parse, - struct wpabuf *in_decrypted, - struct wpabuf **out_data) -{ - struct wpabuf *resp = NULL; - struct eap_peer_config *config = eap_get_config(sm); - int res; - enum phase2_types phase2_type = data->phase2_type; - -#ifdef EAP_TNC - if (data->tnc_started) - phase2_type = EAP_TTLS_PHASE2_EAP; -#endif /* EAP_TNC */ - - switch (phase2_type) { - case EAP_TTLS_PHASE2_EAP: - if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) < - 0) - return -1; - break; - case EAP_TTLS_PHASE2_MSCHAPV2: - res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse); -#ifdef EAP_TNC - if (res == 1 && parse->eapdata && data->phase2_success) { - /* - * TNC may be required as the next - * authentication method within the tunnel. - */ - ret->methodState = METHOD_MAY_CONT; - data->ready_for_tnc = 1; - if (eap_ttls_process_tnc_start(sm, data, ret, parse, - &resp) == 0) - break; - } -#endif /* EAP_TNC */ - return res; - case EAP_TTLS_PHASE2_MSCHAP: - case EAP_TTLS_PHASE2_PAP: - case EAP_TTLS_PHASE2_CHAP: -#ifdef EAP_TNC - if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) < - 0) - return -1; - break; -#else /* EAP_TNC */ - /* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled - * requests to the supplicant */ - wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected " - "tunneled data"); - return -1; -#endif /* EAP_TNC */ - } - - if (resp) { - if (eap_ttls_encrypt_response(sm, data, resp, identifier, - out_data) < 0) - return -1; - } else if (config->pending_req_identity || - config->pending_req_password || - config->pending_req_otp || - config->pending_req_new_password) { - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = wpabuf_dup(in_decrypted); - } - - return 0; -} - - -static int eap_ttls_implicit_identity_request(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - u8 identifier, - struct wpabuf **out_data) -{ - int retval = 0; - struct eap_hdr *hdr; - struct wpabuf *resp; - - hdr = (struct eap_hdr *) eap_ttls_fake_identity_request(); - if (hdr == NULL) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return -1; - } - - resp = NULL; - if (eap_ttls_phase2_request(sm, data, ret, hdr, &resp)) { - wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " - "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); - } - - os_free(hdr); - - if (retval < 0) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - } - - return retval; -} - - -static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data, - struct eap_method_ret *ret, u8 identifier, - struct wpabuf **out_data) -{ - data->phase2_start = 0; - - /* - * EAP-TTLS does not use Phase2 on fast re-auth; this must be done only - * if TLS part was indeed resuming a previous session. Most - * Authentication Servers terminate EAP-TTLS before reaching this - * point, but some do not. Make wpa_supplicant stop phase 2 here, if - * needed. - */ - if (data->reauth && - tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - " - "skip phase 2"); - *out_data = eap_peer_tls_build_ack(identifier, EAP_TYPE_TTLS, - data->ttls_version); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - data->phase2_success = 1; - return 0; - } - - return eap_ttls_implicit_identity_request(sm, data, ret, identifier, - out_data); -} - - -static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data, - struct eap_method_ret *ret, u8 identifier, - const struct wpabuf *in_data, - struct wpabuf **out_data) -{ - struct wpabuf *in_decrypted = NULL; - int retval = 0; - struct ttls_parse_avp parse; - - os_memset(&parse, 0, sizeof(parse)); - - wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" - " Phase 2", - in_data ? (unsigned long) wpabuf_len(in_data) : 0); - - if (data->pending_phase2_req) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - " - "skip decryption and use old data"); - /* Clear TLS reassembly state. */ - eap_peer_tls_reset_input(&data->ssl); - - in_decrypted = data->pending_phase2_req; - data->pending_phase2_req = NULL; - if (wpabuf_len(in_decrypted) == 0) { - wpabuf_free(in_decrypted); - return eap_ttls_implicit_identity_request( - sm, data, ret, identifier, out_data); - } - goto continue_req; - } - - if ((in_data == NULL || wpabuf_len(in_data) == 0) && - data->phase2_start) { - return eap_ttls_phase2_start(sm, data, ret, identifier, - out_data); - } - - if (in_data == NULL || wpabuf_len(in_data) == 0) { - /* Received TLS ACK - requesting more fragments */ - return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, - data->ttls_version, - identifier, NULL, out_data); - } - - retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); - if (retval) - goto done; - -continue_req: - data->phase2_start = 0; - - if (eap_ttls_parse_avps(in_decrypted, &parse) < 0) { - retval = -1; - goto done; - } - - retval = eap_ttls_process_decrypted(sm, data, ret, identifier, - &parse, in_decrypted, out_data); - -done: - wpabuf_free(in_decrypted); - os_free(parse.eapdata); - - if (retval < 0) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - } - - return retval; -} - - -static int eap_ttls_process_handshake(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - u8 identifier, - const u8 *in_data, size_t in_len, - struct wpabuf **out_data) -{ - int res; - - res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS, - data->ttls_version, identifier, - in_data, in_len, out_data); - - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to " - "Phase 2"); - if (data->resuming) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth - may " - "skip Phase 2"); - ret->decision = DECISION_COND_SUCC; - ret->methodState = METHOD_MAY_CONT; - } - data->phase2_start = 1; - eap_ttls_v0_derive_key(sm, data); - - if (*out_data == NULL || wpabuf_len(*out_data) == 0) { - if (eap_ttls_decrypt(sm, data, ret, identifier, - NULL, out_data)) { - wpa_printf(MSG_WARNING, "EAP-TTLS: " - "failed to process early " - "start for Phase 2"); - } - res = 0; - } - data->resuming = 0; - } - - if (res == 2) { - struct wpabuf msg; - /* - * Application data included in the handshake message. - */ - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = *out_data; - *out_data = NULL; - wpabuf_set(&msg, in_data, in_len); - res = eap_ttls_decrypt(sm, data, ret, identifier, &msg, - out_data); - } - - return res; -} - - -static void eap_ttls_check_auth_status(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret) -{ - if (ret->methodState == METHOD_DONE) { - ret->allowNotifications = FALSE; - if (ret->decision == DECISION_UNCOND_SUCC || - ret->decision == DECISION_COND_SUCC) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " - "completed successfully"); - data->phase2_success = 1; -#ifdef EAP_TNC - if (!data->ready_for_tnc && !data->tnc_started) { - /* - * TNC may be required as the next - * authentication method within the tunnel. - */ - ret->methodState = METHOD_MAY_CONT; - data->ready_for_tnc = 1; - } -#endif /* EAP_TNC */ - } - } else if (ret->methodState == METHOD_MAY_CONT && - (ret->decision == DECISION_UNCOND_SUCC || - ret->decision == DECISION_COND_SUCC)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " - "completed successfully (MAY_CONT)"); - data->phase2_success = 1; - } -} - - -static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - size_t left; - int res; - u8 flags, id; - struct wpabuf *resp; - const u8 *pos; - struct eap_ttls_data *data = priv; - - pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret, - reqData, &left, &flags); - if (pos == NULL) - return NULL; - id = eap_get_id(reqData); - - if (flags & EAP_TLS_FLAGS_START) { - 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 - * of AVPs, which may provide useful hints to the client" - * For now, ignore any potential extra data. - */ - left = 0; - } - - resp = NULL; - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && - !data->resuming) { - struct wpabuf msg; - wpabuf_set(&msg, pos, left); - res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp); - } else { - res = eap_ttls_process_handshake(sm, data, ret, id, - pos, left, &resp); - } - - eap_ttls_check_auth_status(sm, data, ret); - - /* FIX: what about res == -1? Could just move all error processing into - * the other functions and get rid of this res==1 case here. */ - if (res == 1) { - wpabuf_free(resp); - return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS, - data->ttls_version); - } - return resp; -} - - -static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv) -{ - struct eap_ttls_data *data = priv; - return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && - data->phase2_success; -} - - -static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_ttls_data *data = priv; - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = NULL; -#ifdef EAP_TNC - data->ready_for_tnc = 0; - data->tnc_started = 0; -#endif /* EAP_TNC */ -} - - -static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_ttls_data *data = priv; - os_free(data->key_data); - data->key_data = NULL; - os_free(data->session_id); - data->session_id = NULL; - if (eap_peer_tls_reauth_init(sm, &data->ssl)) { - os_free(data); - return NULL; - } - if (data->phase2_priv && data->phase2_method && - data->phase2_method->init_for_reauth) - data->phase2_method->init_for_reauth(sm, data->phase2_priv); - data->phase2_start = 0; - data->phase2_success = 0; - data->resuming = 1; - data->reauth = 1; - return priv; -} - - -static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf, - size_t buflen, int verbose) -{ - struct eap_ttls_data *data = priv; - int len, ret; - - len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); - ret = os_snprintf(buf + len, buflen - len, - "EAP-TTLSv%d Phase2 method=", - data->ttls_version); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - switch (data->phase2_type) { - case EAP_TTLS_PHASE2_EAP: - ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n", - data->phase2_method ? - data->phase2_method->name : "?"); - break; - case EAP_TTLS_PHASE2_MSCHAPV2: - ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n"); - break; - case EAP_TTLS_PHASE2_MSCHAP: - ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n"); - break; - case EAP_TTLS_PHASE2_PAP: - ret = os_snprintf(buf + len, buflen - len, "PAP\n"); - break; - case EAP_TTLS_PHASE2_CHAP: - ret = os_snprintf(buf + len, buflen - len, "CHAP\n"); - break; - default: - ret = 0; - break; - } - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - return len; -} - - -static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_ttls_data *data = priv; - return data->key_data != NULL && data->phase2_success; -} - - -static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_ttls_data *data = priv; - u8 *key; - - if (data->key_data == NULL || !data->phase2_success) - return NULL; - - key = os_malloc(EAP_TLS_KEY_LEN); - if (key == NULL) - return NULL; - - *len = EAP_TLS_KEY_LEN; - os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); - - return key; -} - - -static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_ttls_data *data = priv; - u8 *id; - - if (data->session_id == NULL || !data->phase2_success) - return NULL; - - id = os_malloc(data->id_len); - if (id == NULL) - return NULL; - - *len = data->id_len; - os_memcpy(id, data->session_id, data->id_len); - - return id; -} - - -int eap_peer_ttls_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); - if (eap == NULL) - return -1; - - eap->init = eap_ttls_init; - eap->deinit = eap_ttls_deinit; - eap->process = eap_ttls_process; - eap->isKeyAvailable = eap_ttls_isKeyAvailable; - eap->getKey = eap_ttls_getKey; - eap->getSessionId = eap_ttls_get_session_id; - eap->get_status = eap_ttls_get_status; - eap->has_reauth_data = eap_ttls_has_reauth_data; - eap->deinit_for_reauth = eap_ttls_deinit_for_reauth; - eap->init_for_reauth = eap_ttls_init_for_reauth; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_vendor_test.c b/contrib/hostapd/src/eap_peer/eap_vendor_test.c deleted file mode 100644 index 040d1e7f9a..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_vendor_test.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * EAP peer method: Test method for vendor specific (expanded) EAP type - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file implements a vendor specific test method using EAP expanded types. - * This is only for test use and must not be used for authentication since no - * security is provided. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" -#ifdef TEST_PENDING_REQUEST -#include "eloop.h" -#endif /* TEST_PENDING_REQUEST */ - - -#define EAP_VENDOR_ID EAP_VENDOR_HOSTAP -#define EAP_VENDOR_TYPE 0xfcfbfaf9 - - -/* #define TEST_PENDING_REQUEST */ - -struct eap_vendor_test_data { - enum { INIT, CONFIRM, SUCCESS } state; - int first_try; -}; - - -static void * eap_vendor_test_init(struct eap_sm *sm) -{ - struct eap_vendor_test_data *data; - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = INIT; - data->first_try = 1; - return data; -} - - -static void eap_vendor_test_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_vendor_test_data *data = priv; - os_free(data); -} - - -#ifdef TEST_PENDING_REQUEST -static void eap_vendor_ready(void *eloop_ctx, void *timeout_ctx) -{ - struct eap_sm *sm = eloop_ctx; - wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Ready to re-process pending " - "request"); - eap_notify_pending(sm); -} -#endif /* TEST_PENDING_REQUEST */ - - -static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_vendor_test_data *data = priv; - struct wpabuf *resp; - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, reqData, &len); - if (pos == NULL || len < 1) { - ret->ignore = TRUE; - return NULL; - } - - if (data->state == INIT && *pos != 1) { - wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message " - "%d in INIT state", *pos); - ret->ignore = TRUE; - return NULL; - } - - if (data->state == CONFIRM && *pos != 3) { - wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message " - "%d in CONFIRM state", *pos); - ret->ignore = TRUE; - return NULL; - } - - if (data->state == SUCCESS) { - wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message " - "in SUCCESS state"); - ret->ignore = TRUE; - return NULL; - } - - if (data->state == CONFIRM) { -#ifdef TEST_PENDING_REQUEST - if (data->first_try) { - data->first_try = 0; - wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Testing " - "pending request"); - ret->ignore = TRUE; - eloop_register_timeout(1, 0, eap_vendor_ready, sm, - NULL); - return NULL; - } -#endif /* TEST_PENDING_REQUEST */ - } - - ret->ignore = FALSE; - - wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Generating Response"); - ret->allowNotifications = TRUE; - - resp = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, 1, - EAP_CODE_RESPONSE, eap_get_id(reqData)); - if (resp == NULL) - return NULL; - - if (data->state == INIT) { - wpabuf_put_u8(resp, 2); - data->state = CONFIRM; - ret->methodState = METHOD_CONT; - ret->decision = DECISION_FAIL; - } else { - wpabuf_put_u8(resp, 4); - data->state = SUCCESS; - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - } - - return resp; -} - - -static Boolean eap_vendor_test_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_vendor_test_data *data = priv; - return data->state == SUCCESS; -} - - -static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_vendor_test_data *data = priv; - u8 *key; - const int key_len = 64; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(key_len); - if (key == NULL) - return NULL; - - os_memset(key, 0x11, key_len / 2); - os_memset(key + key_len / 2, 0x22, key_len / 2); - *len = key_len; - - return key; -} - - -int eap_peer_vendor_test_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_ID, EAP_VENDOR_TYPE, - "VENDOR-TEST"); - if (eap == NULL) - return -1; - - eap->init = eap_vendor_test_init; - eap->deinit = eap_vendor_test_deinit; - eap->process = eap_vendor_test_process; - eap->isKeyAvailable = eap_vendor_test_isKeyAvailable; - eap->getKey = eap_vendor_test_getKey; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/eap_wsc.c b/contrib/hostapd/src/eap_peer/eap_wsc.c deleted file mode 100644 index 6bdd341182..0000000000 --- a/contrib/hostapd/src/eap_peer/eap_wsc.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - * EAP-WSC peer for Wi-Fi Protected Setup - * Copyright (c) 2007-2009, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "uuid.h" -#include "eap_i.h" -#include "eap_common/eap_wsc_common.h" -#include "wps/wps.h" -#include "wps/wps_defs.h" - - -struct eap_wsc_data { - enum { WAIT_START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; - int registrar; - struct wpabuf *in_buf; - struct wpabuf *out_buf; - enum wsc_op_code in_op_code, out_op_code; - size_t out_used; - size_t fragment_size; - struct wps_data *wps; - struct wps_context *wps_ctx; -}; - - -static const char * eap_wsc_state_txt(int state) -{ - switch (state) { - case WAIT_START: - return "WAIT_START"; - case MESG: - return "MESG"; - case FRAG_ACK: - return "FRAG_ACK"; - case WAIT_FRAG_ACK: - return "WAIT_FRAG_ACK"; - case DONE: - return "DONE"; - case FAIL: - return "FAIL"; - default: - return "?"; - } -} - - -static void eap_wsc_state(struct eap_wsc_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s", - eap_wsc_state_txt(data->state), - eap_wsc_state_txt(state)); - data->state = state; -} - - -static int eap_wsc_new_ap_settings(struct wps_credential *cred, - const char *params) -{ - const char *pos, *end; - size_t len; - - os_memset(cred, 0, sizeof(*cred)); - - pos = os_strstr(params, "new_ssid="); - if (pos == NULL) - return 0; - pos += 9; - end = os_strchr(pos, ' '); - if (end == NULL) - len = os_strlen(pos); - else - len = end - pos; - if ((len & 1) || len > 2 * sizeof(cred->ssid) || - hexstr2bin(pos, cred->ssid, len / 2)) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_ssid"); - return -1; - } - cred->ssid_len = len / 2; - - pos = os_strstr(params, "new_auth="); - if (pos == NULL) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_auth"); - return -1; - } - if (os_strncmp(pos + 9, "OPEN", 4) == 0) - cred->auth_type = WPS_AUTH_OPEN; - else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0) - cred->auth_type = WPS_AUTH_WPAPSK; - else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0) - cred->auth_type = WPS_AUTH_WPA2PSK; - else { - wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_auth"); - return -1; - } - - pos = os_strstr(params, "new_encr="); - if (pos == NULL) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_encr"); - return -1; - } - if (os_strncmp(pos + 9, "NONE", 4) == 0) - cred->encr_type = WPS_ENCR_NONE; - else if (os_strncmp(pos + 9, "WEP", 3) == 0) - cred->encr_type = WPS_ENCR_WEP; - else if (os_strncmp(pos + 9, "TKIP", 4) == 0) - cred->encr_type = WPS_ENCR_TKIP; - else if (os_strncmp(pos + 9, "CCMP", 4) == 0) - cred->encr_type = WPS_ENCR_AES; - else { - wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_encr"); - return -1; - } - - pos = os_strstr(params, "new_key="); - if (pos == NULL) - return 0; - pos += 8; - end = os_strchr(pos, ' '); - if (end == NULL) - len = os_strlen(pos); - else - len = end - pos; - if ((len & 1) || len > 2 * sizeof(cred->key) || - hexstr2bin(pos, cred->key, len / 2)) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_key"); - return -1; - } - cred->key_len = len / 2; - - return 1; -} - - -static void * eap_wsc_init(struct eap_sm *sm) -{ - struct eap_wsc_data *data; - const u8 *identity; - size_t identity_len; - int registrar; - struct wps_config cfg; - const char *pos, *end; - const char *phase1; - struct wps_context *wps; - struct wps_credential new_ap_settings; - int res; - int nfc = 0; - u8 pkhash[WPS_OOB_PUBKEY_HASH_LEN]; - - wps = sm->wps; - if (wps == NULL) { - wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available"); - return NULL; - } - - identity = eap_get_config_identity(sm, &identity_len); - - if (identity && identity_len == WSC_ID_REGISTRAR_LEN && - os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) - registrar = 1; /* Supplicant is Registrar */ - else if (identity && identity_len == WSC_ID_ENROLLEE_LEN && - os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) - registrar = 0; /* Supplicant is Enrollee */ - else { - wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity", - identity, identity_len); - return NULL; - } - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = registrar ? MESG : WAIT_START; - data->registrar = registrar; - data->wps_ctx = wps; - - os_memset(&cfg, 0, sizeof(cfg)); - cfg.wps = wps; - cfg.registrar = registrar; - - phase1 = eap_get_config_phase1(sm); - if (phase1 == NULL) { - wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not " - "set"); - os_free(data); - return NULL; - } - - pos = os_strstr(phase1, "pin="); - if (pos) { - pos += 4; - cfg.pin = (const u8 *) pos; - while (*pos != '\0' && *pos != ' ') - pos++; - cfg.pin_len = pos - (const char *) cfg.pin; - if (cfg.pin_len == 6 && - os_strncmp((const char *) cfg.pin, "nfc-pw", 6) == 0) { - cfg.pin = NULL; - cfg.pin_len = 0; - nfc = 1; - } - } else { - pos = os_strstr(phase1, "pbc=1"); - if (pos) - cfg.pbc = 1; - } - - pos = os_strstr(phase1, "dev_pw_id="); - if (pos) { - u16 id = atoi(pos + 10); - if (id == DEV_PW_NFC_CONNECTION_HANDOVER) - nfc = 1; - if (cfg.pin || id == DEV_PW_NFC_CONNECTION_HANDOVER) - cfg.dev_pw_id = id; - } - - if (cfg.pin == NULL && !cfg.pbc && !nfc) { - wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 " - "configuration data"); - os_free(data); - return NULL; - } - - pos = os_strstr(phase1, " pkhash="); - if (pos) { - size_t len; - pos += 8; - end = os_strchr(pos, ' '); - if (end) - len = end - pos; - else - len = os_strlen(pos); - if (len != 2 * WPS_OOB_PUBKEY_HASH_LEN || - hexstr2bin(pos, pkhash, WPS_OOB_PUBKEY_HASH_LEN)) { - wpa_printf(MSG_INFO, "EAP-WSC: Invalid pkhash"); - os_free(data); - return NULL; - } - cfg.peer_pubkey_hash = pkhash; - } - - res = eap_wsc_new_ap_settings(&new_ap_settings, phase1); - if (res < 0) { - os_free(data); - wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to parse new AP " - "settings"); - return NULL; - } - if (res == 1) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for " - "WPS"); - cfg.new_ap_settings = &new_ap_settings; - } - - data->wps = wps_init(&cfg); - if (data->wps == NULL) { - os_free(data); - wpa_printf(MSG_DEBUG, "EAP-WSC: wps_init failed"); - return NULL; - } - res = eap_get_config_fragment_size(sm); - if (res > 0) - data->fragment_size = res; - else - data->fragment_size = WSC_FRAGMENT_SIZE; - wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment size limit %u", - (unsigned int) data->fragment_size); - - if (registrar && cfg.pin) { - wps_registrar_add_pin(data->wps_ctx->registrar, NULL, NULL, - cfg.pin, cfg.pin_len, 0); - } - - /* Use reduced client timeout for WPS to avoid long wait */ - if (sm->ClientTimeout > 30) - sm->ClientTimeout = 30; - - return data; -} - - -static void eap_wsc_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_wsc_data *data = priv; - wpabuf_free(data->in_buf); - wpabuf_free(data->out_buf); - wps_deinit(data->wps); - os_free(data->wps_ctx->network_key); - data->wps_ctx->network_key = NULL; - os_free(data); -} - - -static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, - struct eap_method_ret *ret, u8 id) -{ - struct wpabuf *resp; - u8 flags; - size_t send_len, plen; - - ret->ignore = FALSE; - wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response"); - ret->allowNotifications = TRUE; - - flags = 0; - send_len = wpabuf_len(data->out_buf) - data->out_used; - if (2 + send_len > data->fragment_size) { - send_len = data->fragment_size - 2; - flags |= WSC_FLAGS_MF; - if (data->out_used == 0) { - flags |= WSC_FLAGS_LF; - send_len -= 2; - } - } - plen = 2 + send_len; - if (flags & WSC_FLAGS_LF) - plen += 2; - resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen, - EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - - wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */ - wpabuf_put_u8(resp, flags); /* Flags */ - if (flags & WSC_FLAGS_LF) - wpabuf_put_be16(resp, wpabuf_len(data->out_buf)); - - wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, - send_len); - data->out_used += send_len; - - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - - if (data->out_used == wpabuf_len(data->out_buf)) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " - "(message sent completely)", - (unsigned long) send_len); - wpabuf_free(data->out_buf); - data->out_buf = NULL; - data->out_used = 0; - if ((data->state == FAIL && data->out_op_code == WSC_ACK) || - data->out_op_code == WSC_NACK || - data->out_op_code == WSC_Done) { - eap_wsc_state(data, FAIL); - ret->methodState = METHOD_DONE; - } else - eap_wsc_state(data, MESG); - } else { - wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " - "(%lu more to send)", (unsigned long) send_len, - (unsigned long) wpabuf_len(data->out_buf) - - data->out_used); - eap_wsc_state(data, WAIT_FRAG_ACK); - } - - return resp; -} - - -static int eap_wsc_process_cont(struct eap_wsc_data *data, - const u8 *buf, size_t len, u8 op_code) -{ - /* Process continuation of a pending message */ - if (op_code != data->in_op_code) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " - "fragment (expected %d)", - op_code, data->in_op_code); - return -1; - } - - if (len > wpabuf_tailroom(data->in_buf)) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); - eap_wsc_state(data, FAIL); - return -1; - } - - wpabuf_put_data(data->in_buf, buf, len); - wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting " - "for %lu bytes more", (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); - - return 0; -} - - -static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data, - struct eap_method_ret *ret, - u8 id, u8 flags, u8 op_code, - u16 message_length, - const u8 *buf, size_t len) -{ - /* Process a fragment that is not the last one of the message */ - if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { - wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a " - "fragmented packet"); - ret->ignore = TRUE; - return NULL; - } - - if (data->in_buf == NULL) { - /* First fragment of the message */ - data->in_buf = wpabuf_alloc(message_length); - if (data->in_buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for " - "message"); - ret->ignore = TRUE; - return NULL; - } - data->in_op_code = op_code; - wpabuf_put_data(data->in_buf, buf, len); - wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first " - "fragment, waiting for %lu bytes more", - (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); - } - - return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE); -} - - -static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - struct eap_wsc_data *data = priv; - const u8 *start, *pos, *end; - size_t len; - u8 op_code, flags, id; - u16 message_length = 0; - enum wps_process_res res; - struct wpabuf tmpbuf; - struct wpabuf *r; - - pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData, - &len); - if (pos == NULL || len < 2) { - ret->ignore = TRUE; - return NULL; - } - - id = eap_get_id(reqData); - - start = pos; - end = start + len; - - op_code = *pos++; - flags = *pos++; - if (flags & WSC_FLAGS_LF) { - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); - ret->ignore = TRUE; - return NULL; - } - message_length = WPA_GET_BE16(pos); - pos += 2; - - if (message_length < end - pos) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " - "Length"); - ret->ignore = TRUE; - return NULL; - } - } - - wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " - "Flags 0x%x Message Length %d", - op_code, flags, message_length); - - if (data->state == WAIT_FRAG_ACK) { - if (op_code != WSC_FRAG_ACK) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " - "in WAIT_FRAG_ACK state", op_code); - ret->ignore = TRUE; - return NULL; - } - wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); - eap_wsc_state(data, MESG); - return eap_wsc_build_msg(data, ret, id); - } - - if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && - op_code != WSC_Done && op_code != WSC_Start) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", - op_code); - ret->ignore = TRUE; - return NULL; - } - - if (data->state == WAIT_START) { - if (op_code != WSC_Start) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " - "in WAIT_START state", op_code); - ret->ignore = TRUE; - return NULL; - } - wpa_printf(MSG_DEBUG, "EAP-WSC: Received start"); - eap_wsc_state(data, MESG); - /* Start message has empty payload, skip processing */ - goto send_msg; - } else if (op_code == WSC_Start) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", - op_code); - ret->ignore = TRUE; - return NULL; - } - - if (data->in_buf && - eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { - ret->ignore = TRUE; - return NULL; - } - - if (flags & WSC_FLAGS_MF) { - return eap_wsc_process_fragment(data, ret, id, flags, op_code, - message_length, pos, - end - pos); - } - - if (data->in_buf == NULL) { - /* Wrap unfragmented messages as wpabuf without extra copy */ - wpabuf_set(&tmpbuf, pos, end - pos); - data->in_buf = &tmpbuf; - } - - res = wps_process_msg(data->wps, op_code, data->in_buf); - switch (res) { - case WPS_DONE: - wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " - "successfully - wait for EAP failure"); - eap_wsc_state(data, FAIL); - break; - case WPS_CONTINUE: - eap_wsc_state(data, MESG); - break; - case WPS_FAILURE: - case WPS_PENDING: - wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); - eap_wsc_state(data, FAIL); - break; - } - - if (data->in_buf != &tmpbuf) - wpabuf_free(data->in_buf); - data->in_buf = NULL; - -send_msg: - if (data->out_buf == NULL) { - data->out_buf = wps_get_msg(data->wps, &data->out_op_code); - if (data->out_buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive " - "message from WPS"); - return NULL; - } - data->out_used = 0; - } - - eap_wsc_state(data, MESG); - r = eap_wsc_build_msg(data, ret, id); - if (data->state == FAIL && ret->methodState == METHOD_DONE) { - /* Use reduced client timeout for WPS to avoid long wait */ - if (sm->ClientTimeout > 2) - sm->ClientTimeout = 2; - } - return r; -} - - -int eap_peer_wsc_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, - "WSC"); - if (eap == NULL) - return -1; - - eap->init = eap_wsc_init; - eap->deinit = eap_wsc_deinit; - eap->process = eap_wsc_process; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_peer/ikev2.c b/contrib/hostapd/src/eap_peer/ikev2.c deleted file mode 100644 index 1ccc35230e..0000000000 --- a/contrib/hostapd/src/eap_peer/ikev2.c +++ /dev/null @@ -1,1299 +0,0 @@ -/* - * IKEv2 responder (RFC 4306) for EAP-IKEV2 - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/dh_groups.h" -#include "crypto/random.h" -#include "ikev2.h" - - -void ikev2_responder_deinit(struct ikev2_responder_data *data) -{ - ikev2_free_keys(&data->keys); - wpabuf_free(data->i_dh_public); - wpabuf_free(data->r_dh_private); - os_free(data->IDi); - os_free(data->IDr); - os_free(data->shared_secret); - wpabuf_free(data->i_sign_msg); - wpabuf_free(data->r_sign_msg); - os_free(data->key_pad); -} - - -static int ikev2_derive_keys(struct ikev2_responder_data *data) -{ - u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN]; - size_t buf_len, pad_len; - struct wpabuf *shared; - const struct ikev2_integ_alg *integ; - const struct ikev2_prf_alg *prf; - const struct ikev2_encr_alg *encr; - int ret; - const u8 *addr[2]; - size_t len[2]; - - /* RFC 4306, Sect. 2.14 */ - - integ = ikev2_get_integ(data->proposal.integ); - prf = ikev2_get_prf(data->proposal.prf); - encr = ikev2_get_encr(data->proposal.encr); - if (integ == NULL || prf == NULL || encr == NULL) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal"); - return -1; - } - - shared = dh_derive_shared(data->i_dh_public, data->r_dh_private, - data->dh); - if (shared == NULL) - return -1; - - /* Construct Ni | Nr | SPIi | SPIr */ - - buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN; - buf = os_malloc(buf_len); - if (buf == NULL) { - wpabuf_free(shared); - return -1; - } - - pos = buf; - os_memcpy(pos, data->i_nonce, data->i_nonce_len); - pos += data->i_nonce_len; - os_memcpy(pos, data->r_nonce, data->r_nonce_len); - pos += data->r_nonce_len; - os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN); - pos += IKEV2_SPI_LEN; - os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN); -#ifdef CCNS_PL -#if __BYTE_ORDER == __LITTLE_ENDIAN - { - int i; - u8 *tmp = pos - IKEV2_SPI_LEN; - /* Incorrect byte re-ordering on little endian hosts.. */ - for (i = 0; i < IKEV2_SPI_LEN; i++) - *tmp++ = data->i_spi[IKEV2_SPI_LEN - 1 - i]; - for (i = 0; i < IKEV2_SPI_LEN; i++) - *tmp++ = data->r_spi[IKEV2_SPI_LEN - 1 - i]; - } -#endif -#endif /* CCNS_PL */ - - /* SKEYSEED = prf(Ni | Nr, g^ir) */ - /* Use zero-padding per RFC 4306, Sect. 2.14 */ - pad_len = data->dh->prime_len - wpabuf_len(shared); -#ifdef CCNS_PL - /* Shared secret is not zero-padded correctly */ - pad_len = 0; -#endif /* CCNS_PL */ - pad = os_zalloc(pad_len ? pad_len : 1); - if (pad == NULL) { - wpabuf_free(shared); - os_free(buf); - return -1; - } - - addr[0] = pad; - len[0] = pad_len; - addr[1] = wpabuf_head(shared); - len[1] = wpabuf_len(shared); - if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len, - 2, addr, len, skeyseed) < 0) { - wpabuf_free(shared); - os_free(buf); - os_free(pad); - return -1; - } - os_free(pad); - wpabuf_free(shared); - - /* DH parameters are not needed anymore, so free them */ - wpabuf_free(data->i_dh_public); - data->i_dh_public = NULL; - wpabuf_free(data->r_dh_private); - data->r_dh_private = NULL; - - wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED", - skeyseed, prf->hash_len); - - ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len, - &data->keys); - os_free(buf); - return ret; -} - - -static int ikev2_parse_transform(struct ikev2_proposal_data *prop, - const u8 *pos, const u8 *end) -{ - int transform_len; - const struct ikev2_transform *t; - u16 transform_id; - const u8 *tend; - - if (end - pos < (int) sizeof(*t)) { - wpa_printf(MSG_INFO, "IKEV2: Too short transform"); - return -1; - } - - t = (const struct ikev2_transform *) pos; - transform_len = WPA_GET_BE16(t->transform_length); - if (transform_len < (int) sizeof(*t) || pos + transform_len > end) { - wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d", - transform_len); - return -1; - } - tend = pos + transform_len; - - transform_id = WPA_GET_BE16(t->transform_id); - - wpa_printf(MSG_DEBUG, "IKEV2: Transform:"); - wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Transform Length: %d " - "Transform Type: %d Transform ID: %d", - t->type, transform_len, t->transform_type, transform_id); - - if (t->type != 0 && t->type != 3) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type"); - return -1; - } - - pos = (const u8 *) (t + 1); - if (pos < tend) { - wpa_hexdump(MSG_DEBUG, "IKEV2: Transform Attributes", - pos, tend - pos); - } - - switch (t->transform_type) { - case IKEV2_TRANSFORM_ENCR: - if (ikev2_get_encr(transform_id)) { - if (transform_id == ENCR_AES_CBC) { - if (tend - pos != 4) { - wpa_printf(MSG_DEBUG, "IKEV2: No " - "Transform Attr for AES"); - break; - } -#ifdef CCNS_PL - if (WPA_GET_BE16(pos) != 0x001d /* ?? */) { - wpa_printf(MSG_DEBUG, "IKEV2: Not a " - "Key Size attribute for " - "AES"); - break; - } -#else /* CCNS_PL */ - if (WPA_GET_BE16(pos) != 0x800e) { - wpa_printf(MSG_DEBUG, "IKEV2: Not a " - "Key Size attribute for " - "AES"); - break; - } -#endif /* CCNS_PL */ - if (WPA_GET_BE16(pos + 2) != 128) { - wpa_printf(MSG_DEBUG, "IKEV2: " - "Unsupported AES key size " - "%d bits", - WPA_GET_BE16(pos + 2)); - break; - } - } - prop->encr = transform_id; - } - break; - case IKEV2_TRANSFORM_PRF: - if (ikev2_get_prf(transform_id)) - prop->prf = transform_id; - break; - case IKEV2_TRANSFORM_INTEG: - if (ikev2_get_integ(transform_id)) - prop->integ = transform_id; - break; - case IKEV2_TRANSFORM_DH: - if (dh_groups_get(transform_id)) - prop->dh = transform_id; - break; - } - - return transform_len; -} - - -static int ikev2_parse_proposal(struct ikev2_proposal_data *prop, - const u8 *pos, const u8 *end) -{ - const u8 *pend, *ppos; - int proposal_len, i; - const struct ikev2_proposal *p; - - if (end - pos < (int) sizeof(*p)) { - wpa_printf(MSG_INFO, "IKEV2: Too short proposal"); - return -1; - } - - /* FIX: AND processing if multiple proposals use the same # */ - - p = (const struct ikev2_proposal *) pos; - proposal_len = WPA_GET_BE16(p->proposal_length); - if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) { - wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d", - proposal_len); - return -1; - } - wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d", - p->proposal_num); - wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Proposal Length: %d " - " Protocol ID: %d", - p->type, proposal_len, p->protocol_id); - wpa_printf(MSG_DEBUG, "IKEV2: SPI Size: %d Transforms: %d", - p->spi_size, p->num_transforms); - - if (p->type != 0 && p->type != 2) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type"); - return -1; - } - - if (p->protocol_id != IKEV2_PROTOCOL_IKE) { - wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID " - "(only IKE allowed for EAP-IKEv2)"); - return -1; - } - - if (p->proposal_num != prop->proposal_num) { - if (p->proposal_num == prop->proposal_num + 1) - prop->proposal_num = p->proposal_num; - else { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #"); - return -1; - } - } - - ppos = (const u8 *) (p + 1); - pend = pos + proposal_len; - if (ppos + p->spi_size > pend) { - wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI " - "in proposal"); - return -1; - } - if (p->spi_size) { - wpa_hexdump(MSG_DEBUG, "IKEV2: SPI", - ppos, p->spi_size); - ppos += p->spi_size; - } - - /* - * For initial IKE_SA negotiation, SPI Size MUST be zero; for - * subsequent negotiations, it must be 8 for IKE. We only support - * initial case for now. - */ - if (p->spi_size != 0) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size"); - return -1; - } - - if (p->num_transforms == 0) { - wpa_printf(MSG_INFO, "IKEV2: At least one transform required"); - return -1; - } - - for (i = 0; i < (int) p->num_transforms; i++) { - int tlen = ikev2_parse_transform(prop, ppos, pend); - if (tlen < 0) - return -1; - ppos += tlen; - } - - if (ppos != pend) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected data after " - "transforms"); - return -1; - } - - return proposal_len; -} - - -static int ikev2_process_sai1(struct ikev2_responder_data *data, - const u8 *sai1, size_t sai1_len) -{ - struct ikev2_proposal_data prop; - const u8 *pos, *end; - int found = 0; - - /* Security Association Payloads: */ - - if (sai1 == NULL) { - wpa_printf(MSG_INFO, "IKEV2: SAi1 not received"); - return -1; - } - - os_memset(&prop, 0, sizeof(prop)); - prop.proposal_num = 1; - - pos = sai1; - end = sai1 + sai1_len; - - while (pos < end) { - int plen; - - prop.integ = -1; - prop.prf = -1; - prop.encr = -1; - prop.dh = -1; - plen = ikev2_parse_proposal(&prop, pos, end); - if (plen < 0) - return -1; - - if (!found && prop.integ != -1 && prop.prf != -1 && - prop.encr != -1 && prop.dh != -1) { - os_memcpy(&data->proposal, &prop, sizeof(prop)); - data->dh = dh_groups_get(prop.dh); - found = 1; - } - - pos += plen; - } - - if (pos != end) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposals"); - return -1; - } - - if (!found) { - wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found"); - return -1; - } - - wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d " - "INTEG:%d D-H:%d", data->proposal.proposal_num, - data->proposal.encr, data->proposal.prf, - data->proposal.integ, data->proposal.dh); - - return 0; -} - - -static int ikev2_process_kei(struct ikev2_responder_data *data, - const u8 *kei, size_t kei_len) -{ - u16 group; - - /* - * Key Exchange Payload: - * DH Group # (16 bits) - * RESERVED (16 bits) - * Key Exchange Data (Diffie-Hellman public value) - */ - - if (kei == NULL) { - wpa_printf(MSG_INFO, "IKEV2: KEi not received"); - return -1; - } - - if (kei_len < 4 + 96) { - wpa_printf(MSG_INFO, "IKEV2: Too show Key Exchange Payload"); - return -1; - } - - group = WPA_GET_BE16(kei); - wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u", group); - - if (group != data->proposal.dh) { - wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u does not match " - "with the selected proposal (%u)", - group, data->proposal.dh); - /* Reject message with Notify payload of type - * INVALID_KE_PAYLOAD (RFC 4306, Sect. 3.4) */ - data->error_type = INVALID_KE_PAYLOAD; - data->state = NOTIFY; - return -1; - } - - if (data->dh == NULL) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group"); - return -1; - } - - /* RFC 4306, Section 3.4: - * The length of DH public value MUST be equal to the length of the - * prime modulus. - */ - if (kei_len - 4 != data->dh->prime_len) { - wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length " - "%ld (expected %ld)", - (long) (kei_len - 4), (long) data->dh->prime_len); - return -1; - } - - wpabuf_free(data->i_dh_public); - data->i_dh_public = wpabuf_alloc(kei_len - 4); - if (data->i_dh_public == NULL) - return -1; - wpabuf_put_data(data->i_dh_public, kei + 4, kei_len - 4); - - wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEi Diffie-Hellman Public Value", - data->i_dh_public); - - return 0; -} - - -static int ikev2_process_ni(struct ikev2_responder_data *data, - const u8 *ni, size_t ni_len) -{ - if (ni == NULL) { - wpa_printf(MSG_INFO, "IKEV2: Ni not received"); - return -1; - } - - if (ni_len < IKEV2_NONCE_MIN_LEN || ni_len > IKEV2_NONCE_MAX_LEN) { - wpa_printf(MSG_INFO, "IKEV2: Invalid Ni length %ld", - (long) ni_len); - return -1; - } - -#ifdef CCNS_PL - /* Zeros are removed incorrectly from the beginning of the nonces */ - while (ni_len > 1 && *ni == 0) { - ni_len--; - ni++; - } -#endif /* CCNS_PL */ - - data->i_nonce_len = ni_len; - os_memcpy(data->i_nonce, ni, ni_len); - wpa_hexdump(MSG_MSGDUMP, "IKEV2: Ni", - data->i_nonce, data->i_nonce_len); - - return 0; -} - - -static int ikev2_process_sa_init(struct ikev2_responder_data *data, - const struct ikev2_hdr *hdr, - struct ikev2_payloads *pl) -{ - if (ikev2_process_sai1(data, pl->sa, pl->sa_len) < 0 || - ikev2_process_kei(data, pl->ke, pl->ke_len) < 0 || - ikev2_process_ni(data, pl->nonce, pl->nonce_len) < 0) - return -1; - - os_memcpy(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN); - - return 0; -} - - -static int ikev2_process_idi(struct ikev2_responder_data *data, - const u8 *idi, size_t idi_len) -{ - u8 id_type; - - if (idi == NULL) { - wpa_printf(MSG_INFO, "IKEV2: No IDi received"); - return -1; - } - - if (idi_len < 4) { - wpa_printf(MSG_INFO, "IKEV2: Too short IDi payload"); - return -1; - } - - id_type = idi[0]; - idi += 4; - idi_len -= 4; - - wpa_printf(MSG_DEBUG, "IKEV2: IDi ID Type %d", id_type); - wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDi", idi, idi_len); - os_free(data->IDi); - data->IDi = os_malloc(idi_len); - if (data->IDi == NULL) - return -1; - os_memcpy(data->IDi, idi, idi_len); - data->IDi_len = idi_len; - data->IDi_type = id_type; - - return 0; -} - - -static int ikev2_process_cert(struct ikev2_responder_data *data, - const u8 *cert, size_t cert_len) -{ - u8 cert_encoding; - - if (cert == NULL) { - if (data->peer_auth == PEER_AUTH_CERT) { - wpa_printf(MSG_INFO, "IKEV2: No Certificate received"); - return -1; - } - return 0; - } - - if (cert_len < 1) { - wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field"); - return -1; - } - - cert_encoding = cert[0]; - cert++; - cert_len--; - - wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding); - wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len); - - /* TODO: validate certificate */ - - return 0; -} - - -static int ikev2_process_auth_cert(struct ikev2_responder_data *data, - u8 method, const u8 *auth, size_t auth_len) -{ - if (method != AUTH_RSA_SIGN) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " - "method %d", method); - return -1; - } - - /* TODO: validate AUTH */ - return 0; -} - - -static int ikev2_process_auth_secret(struct ikev2_responder_data *data, - u8 method, const u8 *auth, - size_t auth_len) -{ - u8 auth_data[IKEV2_MAX_HASH_LEN]; - const struct ikev2_prf_alg *prf; - - if (method != AUTH_SHARED_KEY_MIC) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " - "method %d", method); - return -1; - } - - /* msg | Nr | prf(SK_pi,IDi') */ - if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg, - data->IDi, data->IDi_len, data->IDi_type, - &data->keys, 1, data->shared_secret, - data->shared_secret_len, - data->r_nonce, data->r_nonce_len, - data->key_pad, data->key_pad_len, - auth_data) < 0) { - wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); - return -1; - } - - wpabuf_free(data->i_sign_msg); - data->i_sign_msg = NULL; - - prf = ikev2_get_prf(data->proposal.prf); - if (prf == NULL) - return -1; - - if (auth_len != prf->hash_len || - os_memcmp(auth, auth_data, auth_len) != 0) { - wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data"); - wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data", - auth, auth_len); - wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data", - auth_data, prf->hash_len); - data->error_type = AUTHENTICATION_FAILED; - data->state = NOTIFY; - return -1; - } - - wpa_printf(MSG_DEBUG, "IKEV2: Server authenticated successfully " - "using shared keys"); - - return 0; -} - - -static int ikev2_process_auth(struct ikev2_responder_data *data, - const u8 *auth, size_t auth_len) -{ - u8 auth_method; - - if (auth == NULL) { - wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload"); - return -1; - } - - if (auth_len < 4) { - wpa_printf(MSG_INFO, "IKEV2: Too short Authentication " - "Payload"); - return -1; - } - - auth_method = auth[0]; - auth += 4; - auth_len -= 4; - - wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method); - wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len); - - switch (data->peer_auth) { - case PEER_AUTH_CERT: - return ikev2_process_auth_cert(data, auth_method, auth, - auth_len); - case PEER_AUTH_SECRET: - return ikev2_process_auth_secret(data, auth_method, auth, - auth_len); - } - - return -1; -} - - -static int ikev2_process_sa_auth_decrypted(struct ikev2_responder_data *data, - u8 next_payload, - u8 *payload, size_t payload_len) -{ - struct ikev2_payloads pl; - - wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads"); - - if (ikev2_parse_payloads(&pl, next_payload, payload, payload + - payload_len) < 0) { - wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted " - "payloads"); - return -1; - } - - if (ikev2_process_idi(data, pl.idi, pl.idi_len) < 0 || - ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 || - ikev2_process_auth(data, pl.auth, pl.auth_len) < 0) - return -1; - - return 0; -} - - -static int ikev2_process_sa_auth(struct ikev2_responder_data *data, - const struct ikev2_hdr *hdr, - struct ikev2_payloads *pl) -{ - u8 *decrypted; - size_t decrypted_len; - int ret; - - decrypted = ikev2_decrypt_payload(data->proposal.encr, - data->proposal.integ, - &data->keys, 1, hdr, pl->encrypted, - pl->encrypted_len, &decrypted_len); - if (decrypted == NULL) - return -1; - - ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload, - decrypted, decrypted_len); - os_free(decrypted); - - return ret; -} - - -static int ikev2_validate_rx_state(struct ikev2_responder_data *data, - u8 exchange_type, u32 message_id) -{ - switch (data->state) { - case SA_INIT: - /* Expect to receive IKE_SA_INIT: HDR, SAi1, KEi, Ni */ - if (exchange_type != IKE_SA_INIT) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " - "%u in SA_INIT state", exchange_type); - return -1; - } - if (message_id != 0) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " - "in SA_INIT state", message_id); - return -1; - } - break; - case SA_AUTH: - /* Expect to receive IKE_SA_AUTH: - * HDR, SK {IDi, [CERT,] [CERTREQ,] [IDr,] - * AUTH, SAi2, TSi, TSr} - */ - if (exchange_type != IKE_SA_AUTH) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " - "%u in SA_AUTH state", exchange_type); - return -1; - } - if (message_id != 1) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " - "in SA_AUTH state", message_id); - return -1; - } - break; - case CHILD_SA: - if (exchange_type != CREATE_CHILD_SA) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " - "%u in CHILD_SA state", exchange_type); - return -1; - } - if (message_id != 2) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " - "in CHILD_SA state", message_id); - return -1; - } - break; - case NOTIFY: - case IKEV2_DONE: - case IKEV2_FAILED: - return -1; - } - - return 0; -} - - -int ikev2_responder_process(struct ikev2_responder_data *data, - const struct wpabuf *buf) -{ - const struct ikev2_hdr *hdr; - u32 length, message_id; - const u8 *pos, *end; - struct ikev2_payloads pl; - - wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)", - (unsigned long) wpabuf_len(buf)); - - if (wpabuf_len(buf) < sizeof(*hdr)) { - wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR"); - return -1; - } - - data->error_type = 0; - hdr = (const struct ikev2_hdr *) wpabuf_head(buf); - end = wpabuf_head_u8(buf) + wpabuf_len(buf); - message_id = WPA_GET_BE32(hdr->message_id); - length = WPA_GET_BE32(hdr->length); - - wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", - hdr->i_spi, IKEV2_SPI_LEN); - wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI", - hdr->r_spi, IKEV2_SPI_LEN); - wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Version: 0x%x " - "Exchange Type: %u", - hdr->next_payload, hdr->version, hdr->exchange_type); - wpa_printf(MSG_DEBUG, "IKEV2: Message ID: %u Length: %u", - message_id, length); - - if (hdr->version != IKEV2_VERSION) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x " - "(expected 0x%x)", hdr->version, IKEV2_VERSION); - return -1; - } - - if (length != wpabuf_len(buf)) { - wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != " - "RX: %lu)", (unsigned long) length, - (unsigned long) wpabuf_len(buf)); - return -1; - } - - if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0) - return -1; - - if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) != - IKEV2_HDR_INITIATOR) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x", - hdr->flags); - return -1; - } - - if (data->state != SA_INIT) { - if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " - "Initiator's SPI"); - return -1; - } - if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " - "Responder's SPI"); - return -1; - } - } - - pos = (const u8 *) (hdr + 1); - if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0) - return -1; - - if (data->state == SA_INIT) { - data->last_msg = LAST_MSG_SA_INIT; - if (ikev2_process_sa_init(data, hdr, &pl) < 0) { - if (data->state == NOTIFY) - return 0; - return -1; - } - wpabuf_free(data->i_sign_msg); - data->i_sign_msg = wpabuf_dup(buf); - } - - if (data->state == SA_AUTH) { - data->last_msg = LAST_MSG_SA_AUTH; - if (ikev2_process_sa_auth(data, hdr, &pl) < 0) { - if (data->state == NOTIFY) - return 0; - return -1; - } - } - - return 0; -} - - -static void ikev2_build_hdr(struct ikev2_responder_data *data, - struct wpabuf *msg, u8 exchange_type, - u8 next_payload, u32 message_id) -{ - struct ikev2_hdr *hdr; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR"); - - /* HDR - RFC 4306, Sect. 3.1 */ - hdr = wpabuf_put(msg, sizeof(*hdr)); - os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN); - os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN); - hdr->next_payload = next_payload; - hdr->version = IKEV2_VERSION; - hdr->exchange_type = exchange_type; - hdr->flags = IKEV2_HDR_RESPONSE; - WPA_PUT_BE32(hdr->message_id, message_id); -} - - -static int ikev2_build_sar1(struct ikev2_responder_data *data, - struct wpabuf *msg, u8 next_payload) -{ - struct ikev2_payload_hdr *phdr; - size_t plen; - struct ikev2_proposal *p; - struct ikev2_transform *t; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding SAr1 payload"); - - /* SAr1 - RFC 4306, Sect. 2.7 and 3.3 */ - phdr = wpabuf_put(msg, sizeof(*phdr)); - phdr->next_payload = next_payload; - phdr->flags = 0; - - p = wpabuf_put(msg, sizeof(*p)); -#ifdef CCNS_PL - /* Seems to require that the Proposal # is 1 even though RFC 4306 - * Sect 3.3.1 has following requirement "When a proposal is accepted, - * all of the proposal numbers in the SA payload MUST be the same and - * MUST match the number on the proposal sent that was accepted.". - */ - p->proposal_num = 1; -#else /* CCNS_PL */ - p->proposal_num = data->proposal.proposal_num; -#endif /* CCNS_PL */ - p->protocol_id = IKEV2_PROTOCOL_IKE; - p->num_transforms = 4; - - t = wpabuf_put(msg, sizeof(*t)); - t->type = 3; - t->transform_type = IKEV2_TRANSFORM_ENCR; - WPA_PUT_BE16(t->transform_id, data->proposal.encr); - if (data->proposal.encr == ENCR_AES_CBC) { - /* Transform Attribute: Key Len = 128 bits */ -#ifdef CCNS_PL - wpabuf_put_be16(msg, 0x001d); /* ?? */ -#else /* CCNS_PL */ - wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */ -#endif /* CCNS_PL */ - wpabuf_put_be16(msg, 128); /* 128-bit key */ - } - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t; - WPA_PUT_BE16(t->transform_length, plen); - - t = wpabuf_put(msg, sizeof(*t)); - t->type = 3; - WPA_PUT_BE16(t->transform_length, sizeof(*t)); - t->transform_type = IKEV2_TRANSFORM_PRF; - WPA_PUT_BE16(t->transform_id, data->proposal.prf); - - t = wpabuf_put(msg, sizeof(*t)); - t->type = 3; - WPA_PUT_BE16(t->transform_length, sizeof(*t)); - t->transform_type = IKEV2_TRANSFORM_INTEG; - WPA_PUT_BE16(t->transform_id, data->proposal.integ); - - t = wpabuf_put(msg, sizeof(*t)); - WPA_PUT_BE16(t->transform_length, sizeof(*t)); - t->transform_type = IKEV2_TRANSFORM_DH; - WPA_PUT_BE16(t->transform_id, data->proposal.dh); - - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p; - WPA_PUT_BE16(p->proposal_length, plen); - - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; - WPA_PUT_BE16(phdr->payload_length, plen); - - return 0; -} - - -static int ikev2_build_ker(struct ikev2_responder_data *data, - struct wpabuf *msg, u8 next_payload) -{ - struct ikev2_payload_hdr *phdr; - size_t plen; - struct wpabuf *pv; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding KEr payload"); - - pv = dh_init(data->dh, &data->r_dh_private); - if (pv == NULL) { - wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH"); - return -1; - } - - /* KEr - RFC 4306, Sect. 3.4 */ - phdr = wpabuf_put(msg, sizeof(*phdr)); - phdr->next_payload = next_payload; - phdr->flags = 0; - - wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */ - wpabuf_put(msg, 2); /* RESERVED */ - /* - * RFC 4306, Sect. 3.4: possible zero padding for public value to - * match the length of the prime. - */ - wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv)); - wpabuf_put_buf(msg, pv); - wpabuf_free(pv); - - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; - WPA_PUT_BE16(phdr->payload_length, plen); - return 0; -} - - -static int ikev2_build_nr(struct ikev2_responder_data *data, - struct wpabuf *msg, u8 next_payload) -{ - struct ikev2_payload_hdr *phdr; - size_t plen; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding Nr payload"); - - /* Nr - RFC 4306, Sect. 3.9 */ - phdr = wpabuf_put(msg, sizeof(*phdr)); - phdr->next_payload = next_payload; - phdr->flags = 0; - wpabuf_put_data(msg, data->r_nonce, data->r_nonce_len); - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; - WPA_PUT_BE16(phdr->payload_length, plen); - return 0; -} - - -static int ikev2_build_idr(struct ikev2_responder_data *data, - struct wpabuf *msg, u8 next_payload) -{ - struct ikev2_payload_hdr *phdr; - size_t plen; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding IDr payload"); - - if (data->IDr == NULL) { - wpa_printf(MSG_INFO, "IKEV2: No IDr available"); - return -1; - } - - /* IDr - RFC 4306, Sect. 3.5 */ - phdr = wpabuf_put(msg, sizeof(*phdr)); - phdr->next_payload = next_payload; - phdr->flags = 0; - wpabuf_put_u8(msg, ID_KEY_ID); - wpabuf_put(msg, 3); /* RESERVED */ - wpabuf_put_data(msg, data->IDr, data->IDr_len); - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; - WPA_PUT_BE16(phdr->payload_length, plen); - return 0; -} - - -static int ikev2_build_auth(struct ikev2_responder_data *data, - struct wpabuf *msg, u8 next_payload) -{ - struct ikev2_payload_hdr *phdr; - size_t plen; - const struct ikev2_prf_alg *prf; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload"); - - prf = ikev2_get_prf(data->proposal.prf); - if (prf == NULL) - return -1; - - /* Authentication - RFC 4306, Sect. 3.8 */ - phdr = wpabuf_put(msg, sizeof(*phdr)); - phdr->next_payload = next_payload; - phdr->flags = 0; - wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC); - wpabuf_put(msg, 3); /* RESERVED */ - - /* msg | Ni | prf(SK_pr,IDr') */ - if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg, - data->IDr, data->IDr_len, ID_KEY_ID, - &data->keys, 0, data->shared_secret, - data->shared_secret_len, - data->i_nonce, data->i_nonce_len, - data->key_pad, data->key_pad_len, - wpabuf_put(msg, prf->hash_len)) < 0) { - wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); - return -1; - } - wpabuf_free(data->r_sign_msg); - data->r_sign_msg = NULL; - - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; - WPA_PUT_BE16(phdr->payload_length, plen); - return 0; -} - - -static int ikev2_build_notification(struct ikev2_responder_data *data, - struct wpabuf *msg, u8 next_payload) -{ - struct ikev2_payload_hdr *phdr; - size_t plen; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding Notification payload"); - - if (data->error_type == 0) { - wpa_printf(MSG_INFO, "IKEV2: No Notify Message Type " - "available"); - return -1; - } - - /* Notify - RFC 4306, Sect. 3.10 */ - phdr = wpabuf_put(msg, sizeof(*phdr)); - phdr->next_payload = next_payload; - phdr->flags = 0; -#ifdef CCNS_PL - wpabuf_put_u8(msg, 1); /* Protocol ID: IKE_SA notification */ -#else /* CCNS_PL */ - wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */ -#endif /* CCNS_PL */ - wpabuf_put_u8(msg, 0); /* SPI Size */ - wpabuf_put_be16(msg, data->error_type); - - switch (data->error_type) { - case INVALID_KE_PAYLOAD: - if (data->proposal.dh == -1) { - wpa_printf(MSG_INFO, "IKEV2: No DH Group selected for " - "INVALID_KE_PAYLOAD notifications"); - return -1; - } - wpabuf_put_be16(msg, data->proposal.dh); - wpa_printf(MSG_DEBUG, "IKEV2: INVALID_KE_PAYLOAD - request " - "DH Group #%d", data->proposal.dh); - break; - case AUTHENTICATION_FAILED: - /* no associated data */ - break; - default: - wpa_printf(MSG_INFO, "IKEV2: Unsupported Notify Message Type " - "%d", data->error_type); - return -1; - } - - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; - WPA_PUT_BE16(phdr->payload_length, plen); - return 0; -} - - -static struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data) -{ - struct wpabuf *msg; - - /* build IKE_SA_INIT: HDR, SAr1, KEr, Nr, [CERTREQ], [SK{IDr}] */ - - if (os_get_random(data->r_spi, IKEV2_SPI_LEN)) - return NULL; - wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI", - data->r_spi, IKEV2_SPI_LEN); - - data->r_nonce_len = IKEV2_NONCE_MIN_LEN; - if (random_get_bytes(data->r_nonce, data->r_nonce_len)) - return NULL; -#ifdef CCNS_PL - /* Zeros are removed incorrectly from the beginning of the nonces in - * key derivation; as a workaround, make sure Nr does not start with - * zero.. */ - if (data->r_nonce[0] == 0) - data->r_nonce[0] = 1; -#endif /* CCNS_PL */ - wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len); - - msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500); - if (msg == NULL) - return NULL; - - ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0); - if (ikev2_build_sar1(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) || - ikev2_build_ker(data, msg, IKEV2_PAYLOAD_NONCE) || - ikev2_build_nr(data, msg, data->peer_auth == PEER_AUTH_SECRET ? - IKEV2_PAYLOAD_ENCRYPTED : - IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { - wpabuf_free(msg); - return NULL; - } - - if (ikev2_derive_keys(data)) { - wpabuf_free(msg); - return NULL; - } - - if (data->peer_auth == PEER_AUTH_CERT) { - /* TODO: CERTREQ with SHA-1 hashes of Subject Public Key Info - * for trust agents */ - } - - if (data->peer_auth == PEER_AUTH_SECRET) { - struct wpabuf *plain = wpabuf_alloc(data->IDr_len + 1000); - if (plain == NULL) { - wpabuf_free(msg); - return NULL; - } - if (ikev2_build_idr(data, plain, - IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || - ikev2_build_encrypted(data->proposal.encr, - data->proposal.integ, - &data->keys, 0, msg, plain, - IKEV2_PAYLOAD_IDr)) { - wpabuf_free(plain); - wpabuf_free(msg); - return NULL; - } - wpabuf_free(plain); - } - - ikev2_update_hdr(msg); - - wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg); - - data->state = SA_AUTH; - - wpabuf_free(data->r_sign_msg); - data->r_sign_msg = wpabuf_dup(msg); - - return msg; -} - - -static struct wpabuf * ikev2_build_sa_auth(struct ikev2_responder_data *data) -{ - struct wpabuf *msg, *plain; - - /* build IKE_SA_AUTH: HDR, SK {IDr, [CERT,] AUTH} */ - - msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000); - if (msg == NULL) - return NULL; - ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1); - - plain = wpabuf_alloc(data->IDr_len + 1000); - if (plain == NULL) { - wpabuf_free(msg); - return NULL; - } - - if (ikev2_build_idr(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) || - ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || - ikev2_build_encrypted(data->proposal.encr, data->proposal.integ, - &data->keys, 0, msg, plain, - IKEV2_PAYLOAD_IDr)) { - wpabuf_free(plain); - wpabuf_free(msg); - return NULL; - } - wpabuf_free(plain); - - wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg); - - data->state = IKEV2_DONE; - - return msg; -} - - -static struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data) -{ - struct wpabuf *msg; - - msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000); - if (msg == NULL) - return NULL; - if (data->last_msg == LAST_MSG_SA_AUTH) { - /* HDR, SK{N} */ - struct wpabuf *plain = wpabuf_alloc(100); - if (plain == NULL) { - wpabuf_free(msg); - return NULL; - } - ikev2_build_hdr(data, msg, IKE_SA_AUTH, - IKEV2_PAYLOAD_ENCRYPTED, 1); - if (ikev2_build_notification(data, plain, - IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || - ikev2_build_encrypted(data->proposal.encr, - data->proposal.integ, - &data->keys, 0, msg, plain, - IKEV2_PAYLOAD_NOTIFICATION)) { - wpabuf_free(plain); - wpabuf_free(msg); - return NULL; - } - wpabuf_free(plain); - data->state = IKEV2_FAILED; - } else { - /* HDR, N */ - ikev2_build_hdr(data, msg, IKE_SA_INIT, - IKEV2_PAYLOAD_NOTIFICATION, 0); - if (ikev2_build_notification(data, msg, - IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { - wpabuf_free(msg); - return NULL; - } - data->state = SA_INIT; - } - - ikev2_update_hdr(msg); - - wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (Notification)", - msg); - - return msg; -} - - -struct wpabuf * ikev2_responder_build(struct ikev2_responder_data *data) -{ - switch (data->state) { - case SA_INIT: - return ikev2_build_sa_init(data); - case SA_AUTH: - return ikev2_build_sa_auth(data); - case CHILD_SA: - return NULL; - case NOTIFY: - return ikev2_build_notify(data); - case IKEV2_DONE: - case IKEV2_FAILED: - return NULL; - } - return NULL; -} diff --git a/contrib/hostapd/src/eap_peer/ikev2.h b/contrib/hostapd/src/eap_peer/ikev2.h deleted file mode 100644 index 627a2cbbb0..0000000000 --- a/contrib/hostapd/src/eap_peer/ikev2.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * IKEv2 responder (RFC 4306) for EAP-IKEV2 - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef IKEV2_H -#define IKEV2_H - -#include "eap_common/ikev2_common.h" - -struct ikev2_proposal_data { - u8 proposal_num; - int integ; - int prf; - int encr; - int dh; -}; - - -struct ikev2_responder_data { - enum { SA_INIT, SA_AUTH, CHILD_SA, NOTIFY, IKEV2_DONE, IKEV2_FAILED } - state; - u8 i_spi[IKEV2_SPI_LEN]; - u8 r_spi[IKEV2_SPI_LEN]; - u8 i_nonce[IKEV2_NONCE_MAX_LEN]; - size_t i_nonce_len; - u8 r_nonce[IKEV2_NONCE_MAX_LEN]; - size_t r_nonce_len; - struct wpabuf *i_dh_public; - struct wpabuf *r_dh_private; - struct ikev2_proposal_data proposal; - const struct dh_group *dh; - struct ikev2_keys keys; - u8 *IDi; - size_t IDi_len; - u8 IDi_type; - u8 *IDr; - size_t IDr_len; - struct wpabuf *r_sign_msg; - struct wpabuf *i_sign_msg; - u8 *shared_secret; - size_t shared_secret_len; - enum { PEER_AUTH_CERT, PEER_AUTH_SECRET } peer_auth; - u8 *key_pad; - size_t key_pad_len; - u16 error_type; - enum { LAST_MSG_SA_INIT, LAST_MSG_SA_AUTH } last_msg; -}; - - -void ikev2_responder_deinit(struct ikev2_responder_data *data); -int ikev2_responder_process(struct ikev2_responder_data *data, - const struct wpabuf *buf); -struct wpabuf * ikev2_responder_build(struct ikev2_responder_data *data); - -#endif /* IKEV2_H */ diff --git a/contrib/hostapd/src/eap_peer/mschapv2.c b/contrib/hostapd/src/eap_peer/mschapv2.c deleted file mode 100644 index 37e6735efb..0000000000 --- a/contrib/hostapd/src/eap_peer/mschapv2.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * MSCHAPV2 (RFC 2759) - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/ms_funcs.h" -#include "mschapv2.h" - -const u8 * mschapv2_remove_domain(const u8 *username, size_t *len) -{ - size_t i; - - /* - * MSCHAPv2 does not include optional domain name in the - * challenge-response calculation, so remove domain prefix - * (if present). - */ - - for (i = 0; i < *len; i++) { - if (username[i] == '\\') { - *len -= i + 1; - return username + i + 1; - } - } - - return username; -} - - -int mschapv2_derive_response(const u8 *identity, size_t identity_len, - const u8 *password, size_t password_len, - int pwhash, - const u8 *auth_challenge, - const u8 *peer_challenge, - u8 *nt_response, u8 *auth_response, - u8 *master_key) -{ - const u8 *username; - size_t username_len; - u8 password_hash[16], password_hash_hash[16]; - - wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity", - identity, identity_len); - username_len = identity_len; - username = mschapv2_remove_domain(identity, &username_len); - wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username", - username, username_len); - - wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge", - auth_challenge, MSCHAPV2_CHAL_LEN); - wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge", - peer_challenge, MSCHAPV2_CHAL_LEN); - wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username", - username, username_len); - /* Authenticator response is not really needed yet, but calculate it - * here so that challenges need not be saved. */ - if (pwhash) { - wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash", - password, password_len); - if (generate_nt_response_pwhash(auth_challenge, peer_challenge, - username, username_len, - password, nt_response) || - generate_authenticator_response_pwhash( - password, peer_challenge, auth_challenge, - username, username_len, nt_response, - auth_response)) - return -1; - } else { - wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password", - password, password_len); - if (generate_nt_response(auth_challenge, peer_challenge, - username, username_len, - password, password_len, - nt_response) || - generate_authenticator_response(password, password_len, - peer_challenge, - auth_challenge, - username, username_len, - nt_response, - auth_response)) - return -1; - } - wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response", - nt_response, MSCHAPV2_NT_RESPONSE_LEN); - wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response", - auth_response, MSCHAPV2_AUTH_RESPONSE_LEN); - - /* Generate master_key here since we have the needed data available. */ - if (pwhash) { - if (hash_nt_password_hash(password, password_hash_hash)) - return -1; - } else { - if (nt_password_hash(password, password_len, password_hash) || - hash_nt_password_hash(password_hash, password_hash_hash)) - return -1; - } - if (get_master_key(password_hash_hash, nt_response, master_key)) - return -1; - wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key", - master_key, MSCHAPV2_MASTER_KEY_LEN); - - return 0; -} - - -int mschapv2_verify_auth_response(const u8 *auth_response, - const u8 *buf, size_t buf_len) -{ - u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN]; - if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN || - buf[0] != 'S' || buf[1] != '=' || - hexstr2bin((char *) (buf + 2), recv_response, - MSCHAPV2_AUTH_RESPONSE_LEN) || - os_memcmp(auth_response, recv_response, - MSCHAPV2_AUTH_RESPONSE_LEN) != 0) - return -1; - return 0; -} diff --git a/contrib/hostapd/src/eap_peer/mschapv2.h b/contrib/hostapd/src/eap_peer/mschapv2.h deleted file mode 100644 index edd458b402..0000000000 --- a/contrib/hostapd/src/eap_peer/mschapv2.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * MSCHAPV2 (RFC 2759) - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef MSCHAPV2_H -#define MSCHAPV2_H - -#define MSCHAPV2_CHAL_LEN 16 -#define MSCHAPV2_NT_RESPONSE_LEN 24 -#define MSCHAPV2_AUTH_RESPONSE_LEN 20 -#define MSCHAPV2_MASTER_KEY_LEN 16 - -const u8 * mschapv2_remove_domain(const u8 *username, size_t *len); -int mschapv2_derive_response(const u8 *username, size_t username_len, - const u8 *password, size_t password_len, - int pwhash, - const u8 *auth_challenge, - const u8 *peer_challenge, - u8 *nt_response, u8 *auth_response, - u8 *master_key); -int mschapv2_verify_auth_response(const u8 *auth_response, - const u8 *buf, size_t buf_len); - -#endif /* MSCHAPV2_H */ diff --git a/contrib/hostapd/src/eap_peer/tncc.c b/contrib/hostapd/src/eap_peer/tncc.c deleted file mode 100644 index a3ec395140..0000000000 --- a/contrib/hostapd/src/eap_peer/tncc.c +++ /dev/null @@ -1,1361 +0,0 @@ -/* - * EAP-TNC - TNCC (IF-IMC and IF-TNCCS) - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#ifndef CONFIG_NATIVE_WINDOWS -#include -#endif /* CONFIG_NATIVE_WINDOWS */ - -#include "common.h" -#include "base64.h" -#include "tncc.h" -#include "eap_common/eap_tlv_common.h" -#include "eap_common/eap_defs.h" - - -#ifdef UNICODE -#define TSTR "%S" -#else /* UNICODE */ -#define TSTR "%s" -#endif /* UNICODE */ - - -#define TNC_CONFIG_FILE "/etc/tnc_config" -#define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs") -#define IF_TNCCS_START \ -"\n" \ -"\n" -#define IF_TNCCS_END "\n" - -/* TNC IF-IMC */ - -typedef unsigned long TNC_UInt32; -typedef unsigned char *TNC_BufferReference; - -typedef TNC_UInt32 TNC_IMCID; -typedef TNC_UInt32 TNC_ConnectionID; -typedef TNC_UInt32 TNC_ConnectionState; -typedef TNC_UInt32 TNC_RetryReason; -typedef TNC_UInt32 TNC_MessageType; -typedef TNC_MessageType *TNC_MessageTypeList; -typedef TNC_UInt32 TNC_VendorID; -typedef TNC_UInt32 TNC_MessageSubtype; -typedef TNC_UInt32 TNC_Version; -typedef TNC_UInt32 TNC_Result; - -typedef TNC_Result (*TNC_TNCC_BindFunctionPointer)( - TNC_IMCID imcID, - char *functionName, - void **pOutfunctionPointer); - -#define TNC_RESULT_SUCCESS 0 -#define TNC_RESULT_NOT_INITIALIZED 1 -#define TNC_RESULT_ALREADY_INITIALIZED 2 -#define TNC_RESULT_NO_COMMON_VERSION 3 -#define TNC_RESULT_CANT_RETRY 4 -#define TNC_RESULT_WONT_RETRY 5 -#define TNC_RESULT_INVALID_PARAMETER 6 -#define TNC_RESULT_CANT_RESPOND 7 -#define TNC_RESULT_ILLEGAL_OPERATION 8 -#define TNC_RESULT_OTHER 9 -#define TNC_RESULT_FATAL 10 - -#define TNC_CONNECTION_STATE_CREATE 0 -#define TNC_CONNECTION_STATE_HANDSHAKE 1 -#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2 -#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3 -#define TNC_CONNECTION_STATE_ACCESS_NONE 4 -#define TNC_CONNECTION_STATE_DELETE 5 - -#define TNC_IFIMC_VERSION_1 1 - -#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff) -#define TNC_SUBTYPE_ANY ((TNC_MessageSubtype) 0xff) - -/* TNCC-TNCS Message Types */ -#define TNC_TNCCS_RECOMMENDATION 0x00000001 -#define TNC_TNCCS_ERROR 0x00000002 -#define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003 -#define TNC_TNCCS_REASONSTRINGS 0x00000004 - - -/* IF-TNCCS-SOH - SSoH and SSoHR Attributes */ -enum { - SSOH_MS_MACHINE_INVENTORY = 1, - SSOH_MS_QUARANTINE_STATE = 2, - SSOH_MS_PACKET_INFO = 3, - SSOH_MS_SYSTEMGENERATED_IDS = 4, - SSOH_MS_MACHINENAME = 5, - SSOH_MS_CORRELATIONID = 6, - SSOH_MS_INSTALLED_SHVS = 7, - SSOH_MS_MACHINE_INVENTORY_EX = 8 -}; - -struct tnc_if_imc { - struct tnc_if_imc *next; - char *name; - char *path; - void *dlhandle; /* from dlopen() */ - TNC_IMCID imcID; - TNC_ConnectionID connectionID; - TNC_MessageTypeList supported_types; - size_t num_supported_types; - u8 *imc_send; - size_t imc_send_len; - - /* Functions implemented by IMCs (with TNC_IMC_ prefix) */ - TNC_Result (*Initialize)( - TNC_IMCID imcID, - TNC_Version minVersion, - TNC_Version maxVersion, - TNC_Version *pOutActualVersion); - TNC_Result (*NotifyConnectionChange)( - TNC_IMCID imcID, - TNC_ConnectionID connectionID, - TNC_ConnectionState newState); - TNC_Result (*BeginHandshake)( - TNC_IMCID imcID, - TNC_ConnectionID connectionID); - TNC_Result (*ReceiveMessage)( - TNC_IMCID imcID, - TNC_ConnectionID connectionID, - TNC_BufferReference messageBuffer, - TNC_UInt32 messageLength, - TNC_MessageType messageType); - TNC_Result (*BatchEnding)( - TNC_IMCID imcID, - TNC_ConnectionID connectionID); - TNC_Result (*Terminate)(TNC_IMCID imcID); - TNC_Result (*ProvideBindFunction)( - TNC_IMCID imcID, - TNC_TNCC_BindFunctionPointer bindFunction); -}; - -struct tncc_data { - struct tnc_if_imc *imc; - unsigned int last_batchid; -}; - -#define TNC_MAX_IMC_ID 10 -static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL }; - - -/* TNCC functions that IMCs can call */ - -TNC_Result TNC_TNCC_ReportMessageTypes( - TNC_IMCID imcID, - TNC_MessageTypeList supportedTypes, - TNC_UInt32 typeCount) -{ - TNC_UInt32 i; - struct tnc_if_imc *imc; - - wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu " - "typeCount=%lu)", - (unsigned long) imcID, (unsigned long) typeCount); - - for (i = 0; i < typeCount; i++) { - wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu", - i, supportedTypes[i]); - } - - if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) - return TNC_RESULT_INVALID_PARAMETER; - - imc = tnc_imc[imcID]; - os_free(imc->supported_types); - imc->supported_types = - os_malloc(typeCount * sizeof(TNC_MessageType)); - if (imc->supported_types == NULL) - return TNC_RESULT_FATAL; - os_memcpy(imc->supported_types, supportedTypes, - typeCount * sizeof(TNC_MessageType)); - imc->num_supported_types = typeCount; - - return TNC_RESULT_SUCCESS; -} - - -TNC_Result TNC_TNCC_SendMessage( - TNC_IMCID imcID, - TNC_ConnectionID connectionID, - TNC_BufferReference message, - TNC_UInt32 messageLength, - TNC_MessageType messageType) -{ - struct tnc_if_imc *imc; - unsigned char *b64; - size_t b64len; - - wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu " - "connectionID=%lu messageType=%lu)", - imcID, connectionID, messageType); - wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage", - message, messageLength); - - if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) - return TNC_RESULT_INVALID_PARAMETER; - - b64 = base64_encode(message, messageLength, &b64len); - if (b64 == NULL) - return TNC_RESULT_FATAL; - - imc = tnc_imc[imcID]; - os_free(imc->imc_send); - imc->imc_send_len = 0; - imc->imc_send = os_zalloc(b64len + 100); - if (imc->imc_send == NULL) { - os_free(b64); - return TNC_RESULT_OTHER; - } - - imc->imc_send_len = - os_snprintf((char *) imc->imc_send, b64len + 100, - "%08X" - "%s", - (unsigned int) messageType, b64); - - os_free(b64); - - return TNC_RESULT_SUCCESS; -} - - -TNC_Result TNC_TNCC_RequestHandshakeRetry( - TNC_IMCID imcID, - TNC_ConnectionID connectionID, - TNC_RetryReason reason) -{ - wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry"); - - if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) - return TNC_RESULT_INVALID_PARAMETER; - - /* - * TODO: trigger a call to eapol_sm_request_reauth(). This would - * require that the IMC continues to be loaded in memory afer - * authentication.. - */ - - return TNC_RESULT_SUCCESS; -} - - -TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity, - const char *message) -{ - wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu " - "severity==%lu message='%s')", - imcID, severity, message); - return TNC_RESULT_SUCCESS; -} - - -TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID, TNC_ConnectionID connectionID, - const char *message) -{ - wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu " - "connectionID==%lu message='%s')", - imcID, connectionID, message); - return TNC_RESULT_SUCCESS; -} - - -TNC_Result TNC_TNCC_BindFunction( - TNC_IMCID imcID, - char *functionName, - void **pOutfunctionPointer) -{ - wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, " - "functionName='%s')", (unsigned long) imcID, functionName); - - if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) - return TNC_RESULT_INVALID_PARAMETER; - - if (pOutfunctionPointer == NULL) - return TNC_RESULT_INVALID_PARAMETER; - - if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0) - *pOutfunctionPointer = TNC_TNCC_ReportMessageTypes; - else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0) - *pOutfunctionPointer = TNC_TNCC_SendMessage; - else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") == - 0) - *pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry; - else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0) - *pOutfunctionPointer = TNC_9048_LogMessage; - else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0) - *pOutfunctionPointer = TNC_9048_UserMessage; - else - *pOutfunctionPointer = NULL; - - return TNC_RESULT_SUCCESS; -} - - -static void * tncc_get_sym(void *handle, char *func) -{ - void *fptr; - -#ifdef CONFIG_NATIVE_WINDOWS -#ifdef _WIN32_WCE - fptr = GetProcAddressA(handle, func); -#else /* _WIN32_WCE */ - fptr = GetProcAddress(handle, func); -#endif /* _WIN32_WCE */ -#else /* CONFIG_NATIVE_WINDOWS */ - fptr = dlsym(handle, func); -#endif /* CONFIG_NATIVE_WINDOWS */ - - return fptr; -} - - -static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc) -{ - void *handle = imc->dlhandle; - - /* Mandatory IMC functions */ - imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize"); - if (imc->Initialize == NULL) { - wpa_printf(MSG_ERROR, "TNC: IMC does not export " - "TNC_IMC_Initialize"); - return -1; - } - - imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake"); - if (imc->BeginHandshake == NULL) { - wpa_printf(MSG_ERROR, "TNC: IMC does not export " - "TNC_IMC_BeginHandshake"); - return -1; - } - - imc->ProvideBindFunction = - tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction"); - if (imc->ProvideBindFunction == NULL) { - wpa_printf(MSG_ERROR, "TNC: IMC does not export " - "TNC_IMC_ProvideBindFunction"); - return -1; - } - - /* Optional IMC functions */ - imc->NotifyConnectionChange = - tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange"); - imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage"); - imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding"); - imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate"); - - return 0; -} - - -static int tncc_imc_initialize(struct tnc_if_imc *imc) -{ - TNC_Result res; - TNC_Version imc_ver; - - wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'", - imc->name); - res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1, - TNC_IFIMC_VERSION_1, &imc_ver); - wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu", - (unsigned long) res, (unsigned long) imc_ver); - - return res == TNC_RESULT_SUCCESS ? 0 : -1; -} - - -static int tncc_imc_terminate(struct tnc_if_imc *imc) -{ - TNC_Result res; - - if (imc->Terminate == NULL) - return 0; - - wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'", - imc->name); - res = imc->Terminate(imc->imcID); - wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu", - (unsigned long) res); - - return res == TNC_RESULT_SUCCESS ? 0 : -1; -} - - -static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc) -{ - TNC_Result res; - - wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for " - "IMC '%s'", imc->name); - res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction); - wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu", - (unsigned long) res); - - return res == TNC_RESULT_SUCCESS ? 0 : -1; -} - - -static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc, - TNC_ConnectionState state) -{ - TNC_Result res; - - if (imc->NotifyConnectionChange == NULL) - return 0; - - wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)" - " for IMC '%s'", (int) state, imc->name); - res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID, - state); - wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu", - (unsigned long) res); - - return res == TNC_RESULT_SUCCESS ? 0 : -1; -} - - -static int tncc_imc_begin_handshake(struct tnc_if_imc *imc) -{ - TNC_Result res; - - wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC " - "'%s'", imc->name); - res = imc->BeginHandshake(imc->imcID, imc->connectionID); - wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu", - (unsigned long) res); - - return res == TNC_RESULT_SUCCESS ? 0 : -1; -} - - -static int tncc_load_imc(struct tnc_if_imc *imc) -{ - if (imc->path == NULL) { - wpa_printf(MSG_DEBUG, "TNC: No IMC configured"); - return -1; - } - - wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)", - imc->name, imc->path); -#ifdef CONFIG_NATIVE_WINDOWS -#ifdef UNICODE - { - TCHAR *lib = wpa_strdup_tchar(imc->path); - if (lib == NULL) - return -1; - imc->dlhandle = LoadLibrary(lib); - os_free(lib); - } -#else /* UNICODE */ - imc->dlhandle = LoadLibrary(imc->path); -#endif /* UNICODE */ - if (imc->dlhandle == NULL) { - wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d", - imc->name, imc->path, (int) GetLastError()); - return -1; - } -#else /* CONFIG_NATIVE_WINDOWS */ - imc->dlhandle = dlopen(imc->path, RTLD_LAZY); - if (imc->dlhandle == NULL) { - wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s", - imc->name, imc->path, dlerror()); - return -1; - } -#endif /* CONFIG_NATIVE_WINDOWS */ - - if (tncc_imc_resolve_funcs(imc) < 0) { - wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions"); - return -1; - } - - if (tncc_imc_initialize(imc) < 0 || - tncc_imc_provide_bind_function(imc) < 0) { - wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC"); - return -1; - } - - return 0; -} - - -static void tncc_unload_imc(struct tnc_if_imc *imc) -{ - tncc_imc_terminate(imc); - tnc_imc[imc->imcID] = NULL; - - if (imc->dlhandle) { -#ifdef CONFIG_NATIVE_WINDOWS - FreeLibrary(imc->dlhandle); -#else /* CONFIG_NATIVE_WINDOWS */ - dlclose(imc->dlhandle); -#endif /* CONFIG_NATIVE_WINDOWS */ - } - os_free(imc->name); - os_free(imc->path); - os_free(imc->supported_types); - os_free(imc->imc_send); -} - - -static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type) -{ - size_t i; - unsigned int vendor, subtype; - - if (imc == NULL || imc->supported_types == NULL) - return 0; - - vendor = type >> 8; - subtype = type & 0xff; - - for (i = 0; i < imc->num_supported_types; i++) { - unsigned int svendor, ssubtype; - svendor = imc->supported_types[i] >> 8; - ssubtype = imc->supported_types[i] & 0xff; - if ((vendor == svendor || svendor == TNC_VENDORID_ANY) && - (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY)) - return 1; - } - - return 0; -} - - -static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type, - const u8 *msg, size_t len) -{ - struct tnc_if_imc *imc; - TNC_Result res; - - wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len); - - for (imc = tncc->imc; imc; imc = imc->next) { - if (imc->ReceiveMessage == NULL || - !tncc_supported_type(imc, type)) - continue; - - wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'", - imc->name); - res = imc->ReceiveMessage(imc->imcID, imc->connectionID, - (TNC_BufferReference) msg, len, - type); - wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu", - (unsigned long) res); - } -} - - -void tncc_init_connection(struct tncc_data *tncc) -{ - struct tnc_if_imc *imc; - - for (imc = tncc->imc; imc; imc = imc->next) { - tncc_imc_notify_connection_change( - imc, TNC_CONNECTION_STATE_CREATE); - tncc_imc_notify_connection_change( - imc, TNC_CONNECTION_STATE_HANDSHAKE); - - os_free(imc->imc_send); - imc->imc_send = NULL; - imc->imc_send_len = 0; - - tncc_imc_begin_handshake(imc); - } -} - - -size_t tncc_total_send_len(struct tncc_data *tncc) -{ - struct tnc_if_imc *imc; - - size_t len = 0; - for (imc = tncc->imc; imc; imc = imc->next) - len += imc->imc_send_len; - return len; -} - - -u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos) -{ - struct tnc_if_imc *imc; - - for (imc = tncc->imc; imc; imc = imc->next) { - if (imc->imc_send == NULL) - continue; - - os_memcpy(pos, imc->imc_send, imc->imc_send_len); - pos += imc->imc_send_len; - os_free(imc->imc_send); - imc->imc_send = NULL; - imc->imc_send_len = 0; - } - - return pos; -} - - -char * tncc_if_tnccs_start(struct tncc_data *tncc) -{ - char *buf = os_malloc(1000); - if (buf == NULL) - return NULL; - tncc->last_batchid++; - os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid); - return buf; -} - - -char * tncc_if_tnccs_end(void) -{ - char *buf = os_malloc(100); - if (buf == NULL) - return NULL; - os_snprintf(buf, 100, IF_TNCCS_END); - return buf; -} - - -static void tncc_notify_recommendation(struct tncc_data *tncc, - enum tncc_process_res res) -{ - TNC_ConnectionState state; - struct tnc_if_imc *imc; - - switch (res) { - case TNCCS_RECOMMENDATION_ALLOW: - state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; - break; - case TNCCS_RECOMMENDATION_NONE: - state = TNC_CONNECTION_STATE_ACCESS_NONE; - break; - case TNCCS_RECOMMENDATION_ISOLATE: - state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; - break; - default: - state = TNC_CONNECTION_STATE_ACCESS_NONE; - break; - } - - for (imc = tncc->imc; imc; imc = imc->next) - tncc_imc_notify_connection_change(imc, state); -} - - -static int tncc_get_type(char *start, unsigned int *type) -{ - char *pos = os_strstr(start, ""); - if (pos == NULL) - return -1; - pos += 6; - *type = strtoul(pos, NULL, 16); - return 0; -} - - -static unsigned char * tncc_get_base64(char *start, size_t *decoded_len) -{ - char *pos, *pos2; - unsigned char *decoded; - - pos = os_strstr(start, ""); - if (pos == NULL) - return NULL; - - pos += 8; - pos2 = os_strstr(pos, ""); - if (pos2 == NULL) - return NULL; - *pos2 = '\0'; - - decoded = base64_decode((unsigned char *) pos, os_strlen(pos), - decoded_len); - *pos2 = '<'; - if (decoded == NULL) { - wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data"); - } - - return decoded; -} - - -static enum tncc_process_res tncc_get_recommendation(char *start) -{ - char *pos, *pos2, saved; - int recom; - - pos = os_strstr(start, ""); - if (start == NULL || end == NULL || start > end) { - os_free(buf); - return TNCCS_PROCESS_ERROR; - } - - start += 13; - while (*start == ' ') - start++; - *end = '\0'; - - pos = os_strstr(start, "BatchId="); - if (pos == NULL) { - os_free(buf); - return TNCCS_PROCESS_ERROR; - } - - pos += 8; - if (*pos == '"') - pos++; - batch_id = atoi(pos); - wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u", - batch_id); - if (batch_id != tncc->last_batchid + 1) { - wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId " - "%u (expected %u)", - batch_id, tncc->last_batchid + 1); - os_free(buf); - return TNCCS_PROCESS_ERROR; - } - tncc->last_batchid = batch_id; - - while (*pos != '\0' && *pos != '>') - pos++; - if (*pos == '\0') { - os_free(buf); - return TNCCS_PROCESS_ERROR; - } - pos++; - payload = start; - - /* - * - * 01234567 - * foo== - * - */ - - while (*start) { - char *endpos; - unsigned int type; - - pos = os_strstr(start, ""); - if (pos == NULL) - break; - start = pos + 17; - end = os_strstr(start, ""); - if (end == NULL) - break; - *end = '\0'; - endpos = end; - end += 18; - - if (tncc_get_type(start, &type) < 0) { - *endpos = '<'; - start = end; - continue; - } - wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type); - - decoded = tncc_get_base64(start, &decoded_len); - if (decoded == NULL) { - *endpos = '<'; - start = end; - continue; - } - - tncc_send_to_imcs(tncc, type, decoded, decoded_len); - - os_free(decoded); - - start = end; - } - - /* - * - * 01234567 - * - * foo== - * - */ - - start = payload; - while (*start) { - unsigned int type; - char *xml, *xmlend, *endpos; - - pos = os_strstr(start, ""); - if (pos == NULL) - break; - start = pos + 19; - end = os_strstr(start, ""); - if (end == NULL) - break; - *end = '\0'; - endpos = end; - end += 20; - - if (tncc_get_type(start, &type) < 0) { - *endpos = '<'; - start = end; - continue; - } - wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x", - type); - - /* Base64 OR XML */ - decoded = NULL; - xml = NULL; - xmlend = NULL; - pos = os_strstr(start, ""); - if (pos) { - pos += 5; - pos2 = os_strstr(pos, ""); - if (pos2 == NULL) { - *endpos = '<'; - start = end; - continue; - } - xmlend = pos2; - xml = pos; - } else { - decoded = tncc_get_base64(start, &decoded_len); - if (decoded == NULL) { - *endpos = '<'; - start = end; - continue; - } - } - - if (decoded) { - wpa_hexdump_ascii(MSG_MSGDUMP, - "TNC: TNCC-TNCS-Message Base64", - decoded, decoded_len); - os_free(decoded); - } - - if (xml) { - wpa_hexdump_ascii(MSG_MSGDUMP, - "TNC: TNCC-TNCS-Message XML", - (unsigned char *) xml, - xmlend - xml); - } - - if (type == TNC_TNCCS_RECOMMENDATION && xml) { - /* - * - * - */ - *xmlend = '\0'; - res = tncc_get_recommendation(xml); - *xmlend = '<'; - recommendation_msg = 1; - } - - start = end; - } - - os_free(buf); - - if (recommendation_msg) - tncc_notify_recommendation(tncc, res); - - return res; -} - - -#ifdef CONFIG_NATIVE_WINDOWS -static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive) -{ - HKEY hk, hk2; - LONG ret; - DWORD i; - struct tnc_if_imc *imc, *last; - int j; - - last = tncc->imc; - while (last && last->next) - last = last->next; - - ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS, - &hk); - if (ret != ERROR_SUCCESS) - return 0; - - for (i = 0; ; i++) { - TCHAR name[255], *val; - DWORD namelen, buflen; - - namelen = 255; - ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL, - NULL); - - if (ret == ERROR_NO_MORE_ITEMS) - break; - - if (ret != ERROR_SUCCESS) { - wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x", - (unsigned int) ret); - break; - } - - if (namelen >= 255) - namelen = 255 - 1; - name[namelen] = '\0'; - - wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name); - - ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2); - if (ret != ERROR_SUCCESS) { - wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR - "'", name); - continue; - } - - ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL, - &buflen); - if (ret != ERROR_SUCCESS) { - wpa_printf(MSG_DEBUG, "TNC: Could not read Path from " - "IMC key '" TSTR "'", name); - RegCloseKey(hk2); - continue; - } - - val = os_malloc(buflen); - if (val == NULL) { - RegCloseKey(hk2); - continue; - } - - ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, - (LPBYTE) val, &buflen); - if (ret != ERROR_SUCCESS) { - os_free(val); - RegCloseKey(hk2); - continue; - } - - RegCloseKey(hk2); - - wpa_unicode2ascii_inplace(val); - wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val); - - for (j = 0; j < TNC_MAX_IMC_ID; j++) { - if (tnc_imc[j] == NULL) - break; - } - if (j >= TNC_MAX_IMC_ID) { - wpa_printf(MSG_DEBUG, "TNC: Too many IMCs"); - os_free(val); - continue; - } - - imc = os_zalloc(sizeof(*imc)); - if (imc == NULL) { - os_free(val); - break; - } - - imc->imcID = j; - - wpa_unicode2ascii_inplace(name); - imc->name = os_strdup((char *) name); - imc->path = os_strdup((char *) val); - - os_free(val); - - if (last == NULL) - tncc->imc = imc; - else - last->next = imc; - last = imc; - - tnc_imc[imc->imcID] = imc; - } - - RegCloseKey(hk); - - return 0; -} - - -static int tncc_read_config(struct tncc_data *tncc) -{ - if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 || - tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0) - return -1; - return 0; -} - -#else /* CONFIG_NATIVE_WINDOWS */ - -static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error) -{ - struct tnc_if_imc *imc; - char *pos, *pos2; - int i; - - for (i = 0; i < TNC_MAX_IMC_ID; i++) { - if (tnc_imc[i] == NULL) - break; - } - if (i >= TNC_MAX_IMC_ID) { - wpa_printf(MSG_DEBUG, "TNC: Too many IMCs"); - return NULL; - } - - imc = os_zalloc(sizeof(*imc)); - if (imc == NULL) { - *error = 1; - return NULL; - } - - imc->imcID = i; - - pos = start; - wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos); - if (pos + 1 >= end || *pos != '"') { - wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' " - "(no starting quotation mark)", start); - os_free(imc); - return NULL; - } - - pos++; - pos2 = pos; - while (pos2 < end && *pos2 != '"') - pos2++; - if (pos2 >= end) { - wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' " - "(no ending quotation mark)", start); - os_free(imc); - return NULL; - } - *pos2 = '\0'; - wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos); - imc->name = os_strdup(pos); - - pos = pos2 + 1; - if (pos >= end || *pos != ' ') { - wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' " - "(no space after name)", start); - os_free(imc->name); - os_free(imc); - return NULL; - } - - pos++; - wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos); - imc->path = os_strdup(pos); - tnc_imc[imc->imcID] = imc; - - return imc; -} - - -static int tncc_read_config(struct tncc_data *tncc) -{ - char *config, *end, *pos, *line_end; - size_t config_len; - struct tnc_if_imc *imc, *last; - - last = NULL; - - config = os_readfile(TNC_CONFIG_FILE, &config_len); - if (config == NULL) { - wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration " - "file '%s'", TNC_CONFIG_FILE); - return -1; - } - - end = config + config_len; - for (pos = config; pos < end; pos = line_end + 1) { - line_end = pos; - while (*line_end != '\n' && *line_end != '\r' && - line_end < end) - line_end++; - *line_end = '\0'; - - if (os_strncmp(pos, "IMC ", 4) == 0) { - int error = 0; - - imc = tncc_parse_imc(pos + 4, line_end, &error); - if (error) - return -1; - if (imc) { - if (last == NULL) - tncc->imc = imc; - else - last->next = imc; - last = imc; - } - } - } - - os_free(config); - - return 0; -} - -#endif /* CONFIG_NATIVE_WINDOWS */ - - -struct tncc_data * tncc_init(void) -{ - struct tncc_data *tncc; - struct tnc_if_imc *imc; - - tncc = os_zalloc(sizeof(*tncc)); - if (tncc == NULL) - return NULL; - - /* TODO: - * move loading and Initialize() to a location that is not - * re-initialized for every EAP-TNC session (?) - */ - - if (tncc_read_config(tncc) < 0) { - wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration"); - goto failed; - } - - for (imc = tncc->imc; imc; imc = imc->next) { - if (tncc_load_imc(imc)) { - wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'", - imc->name); - goto failed; - } - } - - return tncc; - -failed: - tncc_deinit(tncc); - return NULL; -} - - -void tncc_deinit(struct tncc_data *tncc) -{ - struct tnc_if_imc *imc, *prev; - - imc = tncc->imc; - while (imc) { - tncc_unload_imc(imc); - - prev = imc; - imc = imc->next; - os_free(prev); - } - - os_free(tncc); -} - - -static struct wpabuf * tncc_build_soh(int ver) -{ - struct wpabuf *buf; - u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end; - u8 correlation_id[24]; - /* TODO: get correct name */ - char *machinename = "wpa_supplicant@w1.fi"; - - if (os_get_random(correlation_id, sizeof(correlation_id))) - return NULL; - wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID", - correlation_id, sizeof(correlation_id)); - - buf = wpabuf_alloc(200); - if (buf == NULL) - return NULL; - - /* Vendor-Specific TLV (Microsoft) - SoH */ - wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */ - tlv_len = wpabuf_put(buf, 2); /* Length */ - wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */ - wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */ - tlv_len2 = wpabuf_put(buf, 2); /* Length */ - - /* SoH Header */ - wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */ - outer_len = wpabuf_put(buf, 2); - wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ - wpabuf_put_be16(buf, ver); /* Inner Type */ - inner_len = wpabuf_put(buf, 2); - - if (ver == 2) { - /* SoH Mode Sub-Header */ - /* Outer Type */ - wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); - wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */ - wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ - /* Value: */ - wpabuf_put_data(buf, correlation_id, sizeof(correlation_id)); - wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */ - wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */ - } - - /* SSoH TLV */ - /* System-Health-Id */ - wpabuf_put_be16(buf, 0x0002); /* Type */ - wpabuf_put_be16(buf, 4); /* Length */ - wpabuf_put_be32(buf, 79616); - /* Vendor-Specific Attribute */ - wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); - ssoh_len = wpabuf_put(buf, 2); - wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ - - /* MS-Packet-Info */ - wpabuf_put_u8(buf, SSOH_MS_PACKET_INFO); - /* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be: - * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP - * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit - * would not be in the specified location. - * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits) - */ - wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */ - - /* MS-Machine-Inventory */ - /* TODO: get correct values; 0 = not applicable for OS */ - wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY); - wpabuf_put_be32(buf, 0); /* osVersionMajor */ - wpabuf_put_be32(buf, 0); /* osVersionMinor */ - wpabuf_put_be32(buf, 0); /* osVersionBuild */ - wpabuf_put_be16(buf, 0); /* spVersionMajor */ - wpabuf_put_be16(buf, 0); /* spVersionMinor */ - wpabuf_put_be16(buf, 0); /* procArch */ - - /* MS-MachineName */ - wpabuf_put_u8(buf, SSOH_MS_MACHINENAME); - wpabuf_put_be16(buf, os_strlen(machinename) + 1); - wpabuf_put_data(buf, machinename, os_strlen(machinename) + 1); - - /* MS-CorrelationId */ - wpabuf_put_u8(buf, SSOH_MS_CORRELATIONID); - wpabuf_put_data(buf, correlation_id, sizeof(correlation_id)); - - /* MS-Quarantine-State */ - wpabuf_put_u8(buf, SSOH_MS_QUARANTINE_STATE); - wpabuf_put_be16(buf, 1); /* Flags: ExtState=0, f=0, qState=1 */ - wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (hi) */ - wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (lo) */ - wpabuf_put_be16(buf, 1); /* urlLenInBytes */ - wpabuf_put_u8(buf, 0); /* null termination for the url */ - - /* MS-Machine-Inventory-Ex */ - wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY_EX); - wpabuf_put_be32(buf, 0); /* Reserved - * (note: Windows XP SP3 uses 0xdecafbad) */ - wpabuf_put_u8(buf, 1); /* ProductType: Client */ - - /* Update SSoH Length */ - end = wpabuf_put(buf, 0); - WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2); - - /* TODO: SoHReportEntry TLV (zero or more) */ - - /* Update length fields */ - end = wpabuf_put(buf, 0); - WPA_PUT_BE16(tlv_len, end - tlv_len - 2); - WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2); - WPA_PUT_BE16(outer_len, end - outer_len - 2); - WPA_PUT_BE16(inner_len, end - inner_len - 2); - - return buf; -} - - -struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len) -{ - const u8 *pos; - - wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len); - - if (len < 12) - return NULL; - - /* SoH Request */ - pos = data; - - /* TLV Type */ - if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV) - return NULL; - pos += 2; - - /* Length */ - if (WPA_GET_BE16(pos) < 8) - return NULL; - pos += 2; - - /* Vendor_Id */ - if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT) - return NULL; - pos += 4; - - /* TLV Type */ - if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */) - return NULL; - - wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received"); - - return tncc_build_soh(2); -} diff --git a/contrib/hostapd/src/eap_peer/tncc.h b/contrib/hostapd/src/eap_peer/tncc.h deleted file mode 100644 index df2a2870f9..0000000000 --- a/contrib/hostapd/src/eap_peer/tncc.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * EAP-TNC - TNCC (IF-IMC and IF-TNCCS) - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef TNCC_H -#define TNCC_H - -struct tncc_data; - -struct tncc_data * tncc_init(void); -void tncc_deinit(struct tncc_data *tncc); -void tncc_init_connection(struct tncc_data *tncc); -size_t tncc_total_send_len(struct tncc_data *tncc); -u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos); -char * tncc_if_tnccs_start(struct tncc_data *tncc); -char * tncc_if_tnccs_end(void); - -enum tncc_process_res { - TNCCS_PROCESS_ERROR = -1, - TNCCS_PROCESS_OK_NO_RECOMMENDATION = 0, - TNCCS_RECOMMENDATION_ERROR, - TNCCS_RECOMMENDATION_ALLOW, - TNCCS_RECOMMENDATION_NONE, - TNCCS_RECOMMENDATION_ISOLATE -}; - -enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc, - const u8 *msg, size_t len); - -struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len); - -#endif /* TNCC_H */ diff --git a/contrib/hostapd/src/eap_server/eap.h b/contrib/hostapd/src/eap_server/eap.h deleted file mode 100644 index 36b230b48c..0000000000 --- a/contrib/hostapd/src/eap_server/eap.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * hostapd / EAP Full Authenticator state machine (RFC 4137) - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_H -#define EAP_H - -#include "common/defs.h" -#include "eap_common/eap_defs.h" -#include "eap_server/eap_methods.h" -#include "wpabuf.h" - -struct eap_sm; - -#define EAP_TTLS_AUTH_PAP 1 -#define EAP_TTLS_AUTH_CHAP 2 -#define EAP_TTLS_AUTH_MSCHAP 4 -#define EAP_TTLS_AUTH_MSCHAPV2 8 - -struct eap_user { - struct { - int vendor; - u32 method; - } methods[EAP_MAX_METHODS]; - u8 *password; - size_t password_len; - int password_hash; /* whether password is hashed with - * nt_password_hash() */ - int phase2; - int force_version; - int ttls_auth; /* bitfield of - * EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */ -}; - -struct eap_eapol_interface { - /* Lower layer to full authenticator variables */ - Boolean eapResp; /* shared with EAPOL Backend Authentication */ - struct wpabuf *eapRespData; - Boolean portEnabled; - int retransWhile; - Boolean eapRestart; /* shared with EAPOL Authenticator PAE */ - int eapSRTT; - int eapRTTVAR; - - /* Full authenticator to lower layer variables */ - Boolean eapReq; /* shared with EAPOL Backend Authentication */ - Boolean eapNoReq; /* shared with EAPOL Backend Authentication */ - Boolean eapSuccess; - Boolean eapFail; - Boolean eapTimeout; - struct wpabuf *eapReqData; - u8 *eapKeyData; - size_t eapKeyDataLen; - Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */ - - /* AAA interface to full authenticator variables */ - Boolean aaaEapReq; - Boolean aaaEapNoReq; - Boolean aaaSuccess; - Boolean aaaFail; - struct wpabuf *aaaEapReqData; - u8 *aaaEapKeyData; - size_t aaaEapKeyDataLen; - Boolean aaaEapKeyAvailable; - int aaaMethodTimeout; - - /* Full authenticator to AAA interface variables */ - Boolean aaaEapResp; - struct wpabuf *aaaEapRespData; - /* aaaIdentity -> eap_get_identity() */ - Boolean aaaTimeout; -}; - -struct eapol_callbacks { - int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, - int phase2, struct eap_user *user); - const char * (*get_eap_req_id_text)(void *ctx, size_t *len); -}; - -struct eap_config { - void *ssl_ctx; - void *msg_ctx; - void *eap_sim_db_priv; - Boolean backend_auth; - int eap_server; - u16 pwd_group; - u8 *pac_opaque_encr_key; - u8 *eap_fast_a_id; - size_t eap_fast_a_id_len; - char *eap_fast_a_id_info; - int eap_fast_prov; - int pac_key_lifetime; - int pac_key_refresh_time; - int eap_sim_aka_result_ind; - int tnc; - struct wps_context *wps; - const struct wpabuf *assoc_wps_ie; - const struct wpabuf *assoc_p2p_ie; - const u8 *peer_addr; - int fragment_size; - - int pbc_in_m1; - - const u8 *server_id; - size_t server_id_len; -}; - - -struct eap_sm * eap_server_sm_init(void *eapol_ctx, - struct eapol_callbacks *eapol_cb, - struct eap_config *eap_conf); -void eap_server_sm_deinit(struct eap_sm *sm); -int eap_server_sm_step(struct eap_sm *sm); -void eap_sm_notify_cached(struct eap_sm *sm); -void eap_sm_pending_cb(struct eap_sm *sm); -int eap_sm_method_pending(struct eap_sm *sm); -const u8 * eap_get_identity(struct eap_sm *sm, size_t *len); -struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm); -void eap_server_clear_identity(struct eap_sm *sm); - -#endif /* EAP_H */ diff --git a/contrib/hostapd/src/eap_server/eap_i.h b/contrib/hostapd/src/eap_server/eap_i.h deleted file mode 100644 index 003e20205f..0000000000 --- a/contrib/hostapd/src/eap_server/eap_i.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * hostapd / EAP Authenticator state machine internal structures (RFC 4137) - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_I_H -#define EAP_I_H - -#include "wpabuf.h" -#include "eap_server/eap.h" -#include "eap_common/eap_common.h" - -/* RFC 4137 - EAP Standalone Authenticator */ - -/** - * struct eap_method - EAP method interface - * This structure defines the EAP method interface. Each method will need to - * register its own EAP type, EAP name, and set of function pointers for method - * specific operations. This interface is based on section 5.4 of RFC 4137. - */ -struct eap_method { - int vendor; - EapType method; - const char *name; - - void * (*init)(struct eap_sm *sm); - void * (*initPickUp)(struct eap_sm *sm); - void (*reset)(struct eap_sm *sm, void *priv); - - struct wpabuf * (*buildReq)(struct eap_sm *sm, void *priv, u8 id); - int (*getTimeout)(struct eap_sm *sm, void *priv); - Boolean (*check)(struct eap_sm *sm, void *priv, - struct wpabuf *respData); - void (*process)(struct eap_sm *sm, void *priv, - struct wpabuf *respData); - Boolean (*isDone)(struct eap_sm *sm, void *priv); - u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len); - /* isSuccess is not specified in draft-ietf-eap-statemachine-05.txt, - * but it is useful in implementing Policy.getDecision() */ - Boolean (*isSuccess)(struct eap_sm *sm, void *priv); - - /** - * free - Free EAP method data - * @method: Pointer to the method data registered with - * eap_server_method_register(). - * - * This function will be called when the EAP method is being - * unregistered. If the EAP method allocated resources during - * registration (e.g., allocated struct eap_method), they should be - * freed in this function. No other method functions will be called - * after this call. If this function is not defined (i.e., function - * pointer is %NULL), a default handler is used to release the method - * data with free(method). This is suitable for most cases. - */ - void (*free)(struct eap_method *method); - -#define EAP_SERVER_METHOD_INTERFACE_VERSION 1 - /** - * version - Version of the EAP server method interface - * - * The EAP server method implementation should set this variable to - * EAP_SERVER_METHOD_INTERFACE_VERSION. This is used to verify that the - * EAP method is using supported API version when using dynamically - * loadable EAP methods. - */ - int version; - - /** - * next - Pointer to the next EAP method - * - * This variable is used internally in the EAP method registration code - * to create a linked list of registered EAP methods. - */ - struct eap_method *next; - - /** - * get_emsk - Get EAP method specific keying extended material (EMSK) - * @sm: Pointer to EAP state machine allocated with eap_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * @len: Pointer to a variable to store EMSK length - * Returns: EMSK or %NULL if not available - * - * This function can be used to get the extended keying material from - * the EAP method. The key may already be stored in the method-specific - * private data or this function may derive the key. - */ - u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len); -}; - -/** - * struct eap_sm - EAP server state machine data - */ -struct eap_sm { - enum { - EAP_DISABLED, EAP_INITIALIZE, EAP_IDLE, EAP_RECEIVED, - EAP_INTEGRITY_CHECK, EAP_METHOD_RESPONSE, EAP_METHOD_REQUEST, - EAP_PROPOSE_METHOD, EAP_SELECT_ACTION, EAP_SEND_REQUEST, - EAP_DISCARD, EAP_NAK, EAP_RETRANSMIT, EAP_SUCCESS, EAP_FAILURE, - EAP_TIMEOUT_FAILURE, EAP_PICK_UP_METHOD, - EAP_INITIALIZE_PASSTHROUGH, EAP_IDLE2, EAP_RETRANSMIT2, - EAP_RECEIVED2, EAP_DISCARD2, EAP_SEND_REQUEST2, - EAP_AAA_REQUEST, EAP_AAA_RESPONSE, EAP_AAA_IDLE, - EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2 - } EAP_state; - - /* Constants */ - int MaxRetrans; - - struct eap_eapol_interface eap_if; - - /* Full authenticator state machine local variables */ - - /* Long-term (maintained between packets) */ - EapType currentMethod; - int currentId; - enum { - METHOD_PROPOSED, METHOD_CONTINUE, METHOD_END - } methodState; - int retransCount; - struct wpabuf *lastReqData; - int methodTimeout; - - /* Short-term (not maintained between packets) */ - Boolean rxResp; - int respId; - EapType respMethod; - int respVendor; - u32 respVendorMethod; - Boolean ignore; - enum { - DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE, - DECISION_PASSTHROUGH - } decision; - - /* Miscellaneous variables */ - const struct eap_method *m; /* selected EAP method */ - /* not defined in RFC 4137 */ - Boolean changed; - void *eapol_ctx, *msg_ctx; - struct eapol_callbacks *eapol_cb; - void *eap_method_priv; - u8 *identity; - size_t identity_len; - /* Whether Phase 2 method should validate identity match */ - int require_identity_match; - int lastId; /* Identifier used in the last EAP-Packet */ - struct eap_user *user; - int user_eap_method_index; - int init_phase2; - void *ssl_ctx; - struct eap_sim_db_data *eap_sim_db_priv; - Boolean backend_auth; - Boolean update_user; - int eap_server; - - int num_rounds; - enum { - METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT - } method_pending; - - u8 *auth_challenge; - u8 *peer_challenge; - - u8 *pac_opaque_encr_key; - u8 *eap_fast_a_id; - size_t eap_fast_a_id_len; - char *eap_fast_a_id_info; - enum { - NO_PROV, ANON_PROV, AUTH_PROV, BOTH_PROV - } eap_fast_prov; - int pac_key_lifetime; - int pac_key_refresh_time; - int eap_sim_aka_result_ind; - int tnc; - u16 pwd_group; - struct wps_context *wps; - struct wpabuf *assoc_wps_ie; - struct wpabuf *assoc_p2p_ie; - - Boolean start_reauth; - - u8 peer_addr[ETH_ALEN]; - - /* Fragmentation size for EAP method init() handler */ - int fragment_size; - - int pbc_in_m1; - - const u8 *server_id; - size_t server_id_len; -}; - -int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, - int phase2); -void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len); - -#endif /* EAP_I_H */ diff --git a/contrib/hostapd/src/eap_server/eap_methods.h b/contrib/hostapd/src/eap_server/eap_methods.h deleted file mode 100644 index 429cb72b22..0000000000 --- a/contrib/hostapd/src/eap_server/eap_methods.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * EAP server method registration - * Copyright (c) 2004-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_SERVER_METHODS_H -#define EAP_SERVER_METHODS_H - -#include "eap_common/eap_defs.h" - -const struct eap_method * eap_server_get_eap_method(int vendor, - EapType method); -struct eap_method * eap_server_method_alloc(int version, int vendor, - EapType method, const char *name); -void eap_server_method_free(struct eap_method *method); -int eap_server_method_register(struct eap_method *method); - -EapType eap_server_get_type(const char *name, int *vendor); -void eap_server_unregister_methods(void); -const char * eap_server_get_name(int vendor, EapType type); - -/* EAP server method registration calls for statically linked in methods */ -int eap_server_identity_register(void); -int eap_server_md5_register(void); -int eap_server_tls_register(void); -int eap_server_unauth_tls_register(void); -int eap_server_mschapv2_register(void); -int eap_server_peap_register(void); -int eap_server_tlv_register(void); -int eap_server_gtc_register(void); -int eap_server_ttls_register(void); -int eap_server_sim_register(void); -int eap_server_aka_register(void); -int eap_server_aka_prime_register(void); -int eap_server_pax_register(void); -int eap_server_psk_register(void); -int eap_server_sake_register(void); -int eap_server_gpsk_register(void); -int eap_server_vendor_test_register(void); -int eap_server_fast_register(void); -int eap_server_wsc_register(void); -int eap_server_ikev2_register(void); -int eap_server_tnc_register(void); -int eap_server_pwd_register(void); -int eap_server_eke_register(void); - -#endif /* EAP_SERVER_METHODS_H */ diff --git a/contrib/hostapd/src/eap_server/eap_server.c b/contrib/hostapd/src/eap_server/eap_server.c deleted file mode 100644 index 233e2726e1..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server.c +++ /dev/null @@ -1,1419 +0,0 @@ -/* - * hostapd / EAP Full Authenticator state machine (RFC 4137) - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This state machine is based on the full authenticator state machine defined - * in RFC 4137. However, to support backend authentication in RADIUS - * authentication server functionality, parts of backend authenticator (also - * from RFC 4137) are mixed in. This functionality is enabled by setting - * backend_auth configuration variable to TRUE. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" -#include "state_machine.h" -#include "common/wpa_ctrl.h" - -#define STATE_MACHINE_DATA struct eap_sm -#define STATE_MACHINE_DEBUG_PREFIX "EAP" - -#define EAP_MAX_AUTH_ROUNDS 50 - -static void eap_user_free(struct eap_user *user); - - -/* EAP state machines are described in RFC 4137 */ - -static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, - int eapSRTT, int eapRTTVAR, - int methodTimeout); -static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp); -static int eap_sm_getId(const struct wpabuf *data); -static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id); -static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id); -static int eap_sm_nextId(struct eap_sm *sm, int id); -static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list, - size_t len); -static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor); -static int eap_sm_Policy_getDecision(struct eap_sm *sm); -static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method); - - -static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src) -{ - if (src == NULL) - return -1; - - wpabuf_free(*dst); - *dst = wpabuf_dup(src); - return *dst ? 0 : -1; -} - - -static int eap_copy_data(u8 **dst, size_t *dst_len, - const u8 *src, size_t src_len) -{ - if (src == NULL) - return -1; - - os_free(*dst); - *dst = os_malloc(src_len); - if (*dst) { - os_memcpy(*dst, src, src_len); - *dst_len = src_len; - return 0; - } else { - *dst_len = 0; - return -1; - } -} - -#define EAP_COPY(dst, src) \ - eap_copy_data((dst), (dst ## Len), (src), (src ## Len)) - - -/** - * eap_user_get - Fetch user information from the database - * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() - * @identity: Identity (User-Name) of the user - * @identity_len: Length of identity in bytes - * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user - * Returns: 0 on success, or -1 on failure - * - * This function is used to fetch user information for EAP. The user will be - * selected based on the specified identity. sm->user and - * sm->user_eap_method_index are updated for the new user when a matching user - * is found. sm->user can be used to get user information (e.g., password). - */ -int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, - int phase2) -{ - struct eap_user *user; - - if (sm == NULL || sm->eapol_cb == NULL || - sm->eapol_cb->get_eap_user == NULL) - return -1; - - eap_user_free(sm->user); - sm->user = NULL; - - user = os_zalloc(sizeof(*user)); - if (user == NULL) - return -1; - - if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity, - identity_len, phase2, user) != 0) { - eap_user_free(user); - return -1; - } - - sm->user = user; - sm->user_eap_method_index = 0; - - return 0; -} - - -SM_STATE(EAP, DISABLED) -{ - SM_ENTRY(EAP, DISABLED); - sm->num_rounds = 0; -} - - -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; - sm->eap_if.eapTimeout = FALSE; - os_free(sm->eap_if.eapKeyData); - sm->eap_if.eapKeyData = NULL; - sm->eap_if.eapKeyDataLen = 0; - sm->eap_if.eapKeyAvailable = FALSE; - sm->eap_if.eapRestart = FALSE; - - /* - * This is not defined in RFC 4137, but method state needs to be - * reseted here so that it does not remain in success state when - * re-authentication starts. - */ - if (sm->m && sm->eap_method_priv) { - sm->m->reset(sm, sm->eap_method_priv); - sm->eap_method_priv = NULL; - } - sm->m = NULL; - sm->user_eap_method_index = 0; - - if (sm->backend_auth) { - sm->currentMethod = EAP_TYPE_NONE; - /* parse rxResp, respId, respMethod */ - eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); - if (sm->rxResp) { - sm->currentId = sm->respId; - } - } - sm->num_rounds = 0; - sm->method_pending = METHOD_PENDING_NONE; - - wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED - MACSTR, MAC2STR(sm->peer_addr)); -} - - -SM_STATE(EAP, PICK_UP_METHOD) -{ - SM_ENTRY(EAP, PICK_UP_METHOD); - - if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) { - sm->currentMethod = sm->respMethod; - if (sm->m && sm->eap_method_priv) { - sm->m->reset(sm, sm->eap_method_priv); - sm->eap_method_priv = NULL; - } - sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF, - sm->currentMethod); - if (sm->m && sm->m->initPickUp) { - sm->eap_method_priv = sm->m->initPickUp(sm); - if (sm->eap_method_priv == NULL) { - wpa_printf(MSG_DEBUG, "EAP: Failed to " - "initialize EAP method %d", - sm->currentMethod); - sm->m = NULL; - sm->currentMethod = EAP_TYPE_NONE; - } - } else { - sm->m = NULL; - sm->currentMethod = EAP_TYPE_NONE; - } - } - - wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD - "method=%u", sm->currentMethod); -} - - -SM_STATE(EAP, IDLE) -{ - SM_ENTRY(EAP, IDLE); - - sm->eap_if.retransWhile = eap_sm_calculateTimeout( - sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, - sm->methodTimeout); -} - - -SM_STATE(EAP, RETRANSMIT) -{ - SM_ENTRY(EAP, RETRANSMIT); - - sm->retransCount++; - if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) { - if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0) - sm->eap_if.eapReq = TRUE; - } -} - - -SM_STATE(EAP, RECEIVED) -{ - SM_ENTRY(EAP, RECEIVED); - - /* parse rxResp, respId, respMethod */ - eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); - sm->num_rounds++; -} - - -SM_STATE(EAP, DISCARD) -{ - SM_ENTRY(EAP, DISCARD); - sm->eap_if.eapResp = FALSE; - sm->eap_if.eapNoReq = TRUE; -} - - -SM_STATE(EAP, SEND_REQUEST) -{ - SM_ENTRY(EAP, SEND_REQUEST); - - sm->retransCount = 0; - if (sm->eap_if.eapReqData) { - if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) - { - sm->eap_if.eapResp = FALSE; - sm->eap_if.eapReq = TRUE; - } else { - sm->eap_if.eapResp = FALSE; - sm->eap_if.eapReq = FALSE; - } - } else { - wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData"); - sm->eap_if.eapResp = FALSE; - sm->eap_if.eapReq = FALSE; - sm->eap_if.eapNoReq = TRUE; - } -} - - -SM_STATE(EAP, INTEGRITY_CHECK) -{ - SM_ENTRY(EAP, INTEGRITY_CHECK); - - if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) { - sm->ignore = TRUE; - return; - } - - if (sm->m->check) { - sm->ignore = sm->m->check(sm, sm->eap_method_priv, - sm->eap_if.eapRespData); - } -} - - -SM_STATE(EAP, METHOD_REQUEST) -{ - SM_ENTRY(EAP, METHOD_REQUEST); - - if (sm->m == NULL) { - wpa_printf(MSG_DEBUG, "EAP: method not initialized"); - return; - } - - sm->currentId = eap_sm_nextId(sm, sm->currentId); - wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d", - sm->currentId); - sm->lastId = sm->currentId; - wpabuf_free(sm->eap_if.eapReqData); - sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv, - sm->currentId); - if (sm->m->getTimeout) - sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv); - else - sm->methodTimeout = 0; -} - - -SM_STATE(EAP, METHOD_RESPONSE) -{ - SM_ENTRY(EAP, METHOD_RESPONSE); - - if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) - return; - - sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData); - if (sm->m->isDone(sm, sm->eap_method_priv)) { - eap_sm_Policy_update(sm, NULL, 0); - os_free(sm->eap_if.eapKeyData); - if (sm->m->getKey) { - sm->eap_if.eapKeyData = sm->m->getKey( - sm, sm->eap_method_priv, - &sm->eap_if.eapKeyDataLen); - } else { - sm->eap_if.eapKeyData = NULL; - sm->eap_if.eapKeyDataLen = 0; - } - sm->methodState = METHOD_END; - } else { - sm->methodState = METHOD_CONTINUE; - } -} - - -SM_STATE(EAP, PROPOSE_METHOD) -{ - int vendor; - EapType type; - - SM_ENTRY(EAP, PROPOSE_METHOD); - -try_another_method: - type = eap_sm_Policy_getNextMethod(sm, &vendor); - if (vendor == EAP_VENDOR_IETF) - sm->currentMethod = type; - else - sm->currentMethod = EAP_TYPE_EXPANDED; - if (sm->m && sm->eap_method_priv) { - sm->m->reset(sm, sm->eap_method_priv); - sm->eap_method_priv = NULL; - } - sm->m = eap_server_get_eap_method(vendor, type); - if (sm->m) { - sm->eap_method_priv = sm->m->init(sm); - if (sm->eap_method_priv == NULL) { - wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP " - "method %d", sm->currentMethod); - sm->m = NULL; - sm->currentMethod = EAP_TYPE_NONE; - goto try_another_method; - } - } - if (sm->m == NULL) { - wpa_printf(MSG_DEBUG, "EAP: Could not find suitable EAP method"); - sm->decision = DECISION_FAILURE; - return; - } - if (sm->currentMethod == EAP_TYPE_IDENTITY || - sm->currentMethod == EAP_TYPE_NOTIFICATION) - sm->methodState = METHOD_CONTINUE; - else - sm->methodState = METHOD_PROPOSED; - - wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD - "vendor=%u method=%u", vendor, sm->currentMethod); -} - - -SM_STATE(EAP, NAK) -{ - const struct eap_hdr *nak; - size_t len = 0; - const u8 *pos; - const u8 *nak_list = NULL; - - SM_ENTRY(EAP, NAK); - - if (sm->eap_method_priv) { - sm->m->reset(sm, sm->eap_method_priv); - sm->eap_method_priv = NULL; - } - sm->m = NULL; - - if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) - return; - - nak = wpabuf_head(sm->eap_if.eapRespData); - if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) { - len = be_to_host16(nak->length); - if (len > wpabuf_len(sm->eap_if.eapRespData)) - len = wpabuf_len(sm->eap_if.eapRespData); - pos = (const u8 *) (nak + 1); - len -= sizeof(*nak); - if (*pos == EAP_TYPE_NAK) { - pos++; - len--; - nak_list = pos; - } - } - eap_sm_Policy_update(sm, nak_list, len); -} - - -SM_STATE(EAP, SELECT_ACTION) -{ - SM_ENTRY(EAP, SELECT_ACTION); - - sm->decision = eap_sm_Policy_getDecision(sm); -} - - -SM_STATE(EAP, TIMEOUT_FAILURE) -{ - SM_ENTRY(EAP, TIMEOUT_FAILURE); - - sm->eap_if.eapTimeout = TRUE; -} - - -SM_STATE(EAP, FAILURE) -{ - SM_ENTRY(EAP, FAILURE); - - wpabuf_free(sm->eap_if.eapReqData); - sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId); - wpabuf_free(sm->lastReqData); - sm->lastReqData = NULL; - sm->eap_if.eapFail = TRUE; - - wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE - MACSTR, MAC2STR(sm->peer_addr)); -} - - -SM_STATE(EAP, SUCCESS) -{ - SM_ENTRY(EAP, SUCCESS); - - wpabuf_free(sm->eap_if.eapReqData); - sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId); - wpabuf_free(sm->lastReqData); - sm->lastReqData = NULL; - if (sm->eap_if.eapKeyData) - sm->eap_if.eapKeyAvailable = TRUE; - sm->eap_if.eapSuccess = TRUE; - - wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS - MACSTR, MAC2STR(sm->peer_addr)); -} - - -SM_STATE(EAP, INITIALIZE_PASSTHROUGH) -{ - SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH); - - wpabuf_free(sm->eap_if.aaaEapRespData); - sm->eap_if.aaaEapRespData = NULL; -} - - -SM_STATE(EAP, IDLE2) -{ - SM_ENTRY(EAP, IDLE2); - - sm->eap_if.retransWhile = eap_sm_calculateTimeout( - sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, - sm->methodTimeout); -} - - -SM_STATE(EAP, RETRANSMIT2) -{ - SM_ENTRY(EAP, RETRANSMIT2); - - sm->retransCount++; - if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) { - if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0) - sm->eap_if.eapReq = TRUE; - } -} - - -SM_STATE(EAP, RECEIVED2) -{ - SM_ENTRY(EAP, RECEIVED2); - - /* parse rxResp, respId, respMethod */ - eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); -} - - -SM_STATE(EAP, DISCARD2) -{ - SM_ENTRY(EAP, DISCARD2); - sm->eap_if.eapResp = FALSE; - sm->eap_if.eapNoReq = TRUE; -} - - -SM_STATE(EAP, SEND_REQUEST2) -{ - SM_ENTRY(EAP, SEND_REQUEST2); - - sm->retransCount = 0; - if (sm->eap_if.eapReqData) { - if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) - { - sm->eap_if.eapResp = FALSE; - sm->eap_if.eapReq = TRUE; - } else { - sm->eap_if.eapResp = FALSE; - sm->eap_if.eapReq = FALSE; - } - } else { - wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData"); - sm->eap_if.eapResp = FALSE; - sm->eap_if.eapReq = FALSE; - sm->eap_if.eapNoReq = TRUE; - } -} - - -SM_STATE(EAP, AAA_REQUEST) -{ - SM_ENTRY(EAP, AAA_REQUEST); - - if (sm->eap_if.eapRespData == NULL) { - wpa_printf(MSG_INFO, "EAP: AAA_REQUEST - no eapRespData"); - return; - } - - /* - * if (respMethod == IDENTITY) - * aaaIdentity = eapRespData - * This is already taken care of by the EAP-Identity method which - * stores the identity into sm->identity. - */ - - eap_copy_buf(&sm->eap_if.aaaEapRespData, sm->eap_if.eapRespData); -} - - -SM_STATE(EAP, AAA_RESPONSE) -{ - SM_ENTRY(EAP, AAA_RESPONSE); - - eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); - sm->currentId = eap_sm_getId(sm->eap_if.eapReqData); - sm->methodTimeout = sm->eap_if.aaaMethodTimeout; -} - - -SM_STATE(EAP, AAA_IDLE) -{ - SM_ENTRY(EAP, AAA_IDLE); - - sm->eap_if.aaaFail = FALSE; - sm->eap_if.aaaSuccess = FALSE; - sm->eap_if.aaaEapReq = FALSE; - sm->eap_if.aaaEapNoReq = FALSE; - sm->eap_if.aaaEapResp = TRUE; -} - - -SM_STATE(EAP, TIMEOUT_FAILURE2) -{ - SM_ENTRY(EAP, TIMEOUT_FAILURE2); - - sm->eap_if.eapTimeout = TRUE; -} - - -SM_STATE(EAP, FAILURE2) -{ - SM_ENTRY(EAP, FAILURE2); - - eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); - sm->eap_if.eapFail = TRUE; -} - - -SM_STATE(EAP, SUCCESS2) -{ - SM_ENTRY(EAP, SUCCESS2); - - eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); - - sm->eap_if.eapKeyAvailable = sm->eap_if.aaaEapKeyAvailable; - if (sm->eap_if.aaaEapKeyAvailable) { - EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData); - } else { - os_free(sm->eap_if.eapKeyData); - sm->eap_if.eapKeyData = NULL; - sm->eap_if.eapKeyDataLen = 0; - } - - sm->eap_if.eapSuccess = TRUE; - - /* - * Start reauthentication with identity request even though we know the - * previously used identity. This is needed to get reauthentication - * started properly. - */ - sm->start_reauth = TRUE; -} - - -SM_STEP(EAP) -{ - if (sm->eap_if.eapRestart && sm->eap_if.portEnabled) - SM_ENTER_GLOBAL(EAP, INITIALIZE); - else if (!sm->eap_if.portEnabled) - SM_ENTER_GLOBAL(EAP, DISABLED); - else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) { - if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) { - wpa_printf(MSG_DEBUG, "EAP: more than %d " - "authentication rounds - abort", - EAP_MAX_AUTH_ROUNDS); - sm->num_rounds++; - SM_ENTER_GLOBAL(EAP, FAILURE); - } - } else switch (sm->EAP_state) { - case EAP_INITIALIZE: - if (sm->backend_auth) { - if (!sm->rxResp) - SM_ENTER(EAP, SELECT_ACTION); - else if (sm->rxResp && - (sm->respMethod == EAP_TYPE_NAK || - (sm->respMethod == EAP_TYPE_EXPANDED && - sm->respVendor == EAP_VENDOR_IETF && - sm->respVendorMethod == EAP_TYPE_NAK))) - SM_ENTER(EAP, NAK); - else - SM_ENTER(EAP, PICK_UP_METHOD); - } else { - SM_ENTER(EAP, SELECT_ACTION); - } - break; - case EAP_PICK_UP_METHOD: - if (sm->currentMethod == EAP_TYPE_NONE) { - SM_ENTER(EAP, SELECT_ACTION); - } else { - SM_ENTER(EAP, METHOD_RESPONSE); - } - break; - case EAP_DISABLED: - if (sm->eap_if.portEnabled) - SM_ENTER(EAP, INITIALIZE); - break; - case EAP_IDLE: - if (sm->eap_if.retransWhile == 0) - SM_ENTER(EAP, RETRANSMIT); - else if (sm->eap_if.eapResp) - SM_ENTER(EAP, RECEIVED); - break; - case EAP_RETRANSMIT: - if (sm->retransCount > sm->MaxRetrans) - SM_ENTER(EAP, TIMEOUT_FAILURE); - else - SM_ENTER(EAP, IDLE); - break; - case EAP_RECEIVED: - if (sm->rxResp && (sm->respId == sm->currentId) && - (sm->respMethod == EAP_TYPE_NAK || - (sm->respMethod == EAP_TYPE_EXPANDED && - sm->respVendor == EAP_VENDOR_IETF && - sm->respVendorMethod == EAP_TYPE_NAK)) - && (sm->methodState == METHOD_PROPOSED)) - SM_ENTER(EAP, NAK); - else if (sm->rxResp && (sm->respId == sm->currentId) && - ((sm->respMethod == sm->currentMethod) || - (sm->respMethod == EAP_TYPE_EXPANDED && - sm->respVendor == EAP_VENDOR_IETF && - sm->respVendorMethod == sm->currentMethod))) - SM_ENTER(EAP, INTEGRITY_CHECK); - else { - wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: " - "rxResp=%d respId=%d currentId=%d " - "respMethod=%d currentMethod=%d", - sm->rxResp, sm->respId, sm->currentId, - sm->respMethod, sm->currentMethod); - SM_ENTER(EAP, DISCARD); - } - break; - case EAP_DISCARD: - SM_ENTER(EAP, IDLE); - break; - case EAP_SEND_REQUEST: - SM_ENTER(EAP, IDLE); - break; - case EAP_INTEGRITY_CHECK: - if (sm->ignore) - SM_ENTER(EAP, DISCARD); - else - SM_ENTER(EAP, METHOD_RESPONSE); - break; - case EAP_METHOD_REQUEST: - if (sm->m == NULL) { - /* - * This transition is not mentioned in RFC 4137, but it - * is needed to handle cleanly a case where EAP method - * initialization fails. - */ - SM_ENTER(EAP, FAILURE); - break; - } - SM_ENTER(EAP, SEND_REQUEST); - break; - case EAP_METHOD_RESPONSE: - /* - * Note: Mechanism to allow EAP methods to wait while going - * through pending processing is an extension to RFC 4137 - * which only defines the transits to SELECT_ACTION and - * METHOD_REQUEST from this METHOD_RESPONSE state. - */ - if (sm->methodState == METHOD_END) - SM_ENTER(EAP, SELECT_ACTION); - else if (sm->method_pending == METHOD_PENDING_WAIT) { - wpa_printf(MSG_DEBUG, "EAP: Method has pending " - "processing - wait before proceeding to " - "METHOD_REQUEST state"); - } else if (sm->method_pending == METHOD_PENDING_CONT) { - wpa_printf(MSG_DEBUG, "EAP: Method has completed " - "pending processing - reprocess pending " - "EAP message"); - sm->method_pending = METHOD_PENDING_NONE; - SM_ENTER(EAP, METHOD_RESPONSE); - } else - SM_ENTER(EAP, METHOD_REQUEST); - break; - case EAP_PROPOSE_METHOD: - /* - * Note: Mechanism to allow EAP methods to wait while going - * through pending processing is an extension to RFC 4137 - * which only defines the transit to METHOD_REQUEST from this - * PROPOSE_METHOD state. - */ - if (sm->method_pending == METHOD_PENDING_WAIT) { - wpa_printf(MSG_DEBUG, "EAP: Method has pending " - "processing - wait before proceeding to " - "METHOD_REQUEST state"); - if (sm->user_eap_method_index > 0) - sm->user_eap_method_index--; - } else if (sm->method_pending == METHOD_PENDING_CONT) { - wpa_printf(MSG_DEBUG, "EAP: Method has completed " - "pending processing - reprocess pending " - "EAP message"); - sm->method_pending = METHOD_PENDING_NONE; - SM_ENTER(EAP, PROPOSE_METHOD); - } else - SM_ENTER(EAP, METHOD_REQUEST); - break; - case EAP_NAK: - SM_ENTER(EAP, SELECT_ACTION); - break; - case EAP_SELECT_ACTION: - if (sm->decision == DECISION_FAILURE) - SM_ENTER(EAP, FAILURE); - else if (sm->decision == DECISION_SUCCESS) - SM_ENTER(EAP, SUCCESS); - else if (sm->decision == DECISION_PASSTHROUGH) - SM_ENTER(EAP, INITIALIZE_PASSTHROUGH); - else - SM_ENTER(EAP, PROPOSE_METHOD); - break; - case EAP_TIMEOUT_FAILURE: - break; - case EAP_FAILURE: - break; - case EAP_SUCCESS: - break; - - case EAP_INITIALIZE_PASSTHROUGH: - if (sm->currentId == -1) - SM_ENTER(EAP, AAA_IDLE); - else - SM_ENTER(EAP, AAA_REQUEST); - break; - case EAP_IDLE2: - if (sm->eap_if.eapResp) - SM_ENTER(EAP, RECEIVED2); - else if (sm->eap_if.retransWhile == 0) - SM_ENTER(EAP, RETRANSMIT2); - break; - case EAP_RETRANSMIT2: - if (sm->retransCount > sm->MaxRetrans) - SM_ENTER(EAP, TIMEOUT_FAILURE2); - else - SM_ENTER(EAP, IDLE2); - break; - case EAP_RECEIVED2: - if (sm->rxResp && (sm->respId == sm->currentId)) - SM_ENTER(EAP, AAA_REQUEST); - else - SM_ENTER(EAP, DISCARD2); - break; - case EAP_DISCARD2: - SM_ENTER(EAP, IDLE2); - break; - case EAP_SEND_REQUEST2: - SM_ENTER(EAP, IDLE2); - break; - case EAP_AAA_REQUEST: - SM_ENTER(EAP, AAA_IDLE); - break; - case EAP_AAA_RESPONSE: - SM_ENTER(EAP, SEND_REQUEST2); - break; - case EAP_AAA_IDLE: - if (sm->eap_if.aaaFail) - SM_ENTER(EAP, FAILURE2); - else if (sm->eap_if.aaaSuccess) - SM_ENTER(EAP, SUCCESS2); - else if (sm->eap_if.aaaEapReq) - SM_ENTER(EAP, AAA_RESPONSE); - else if (sm->eap_if.aaaTimeout) - SM_ENTER(EAP, TIMEOUT_FAILURE2); - break; - case EAP_TIMEOUT_FAILURE2: - break; - case EAP_FAILURE2: - break; - case EAP_SUCCESS2: - break; - } -} - - -static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, - int eapSRTT, int eapRTTVAR, - int methodTimeout) -{ - int rto, i; - - if (methodTimeout) { - /* - * EAP method (either internal or through AAA server, provided - * timeout hint. Use that as-is as a timeout for retransmitting - * the EAP request if no response is received. - */ - wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds " - "(from EAP method hint)", methodTimeout); - return methodTimeout; - } - - /* - * RFC 3748 recommends algorithms described in RFC 2988 for estimation - * of the retransmission timeout. This should be implemented once - * round-trip time measurements are available. For nowm a simple - * backoff mechanism is used instead if there are no EAP method - * specific hints. - * - * SRTT = smoothed round-trip time - * RTTVAR = round-trip time variation - * RTO = retransmission timeout - */ - - /* - * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for - * initial retransmission and then double the RTO to provide back off - * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3 - * modified RTOmax. - */ - rto = 3; - for (i = 0; i < retransCount; i++) { - rto *= 2; - if (rto >= 20) { - rto = 20; - break; - } - } - - wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds " - "(from dynamic back off; retransCount=%d)", - rto, retransCount); - - return rto; -} - - -static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp) -{ - const struct eap_hdr *hdr; - size_t plen; - - /* parse rxResp, respId, respMethod */ - sm->rxResp = FALSE; - sm->respId = -1; - sm->respMethod = EAP_TYPE_NONE; - sm->respVendor = EAP_VENDOR_IETF; - sm->respVendorMethod = EAP_TYPE_NONE; - - if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) { - wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p " - "len=%lu", resp, - resp ? (unsigned long) wpabuf_len(resp) : 0); - return; - } - - hdr = wpabuf_head(resp); - plen = be_to_host16(hdr->length); - if (plen > wpabuf_len(resp)) { - wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet " - "(len=%lu plen=%lu)", - (unsigned long) wpabuf_len(resp), - (unsigned long) plen); - return; - } - - sm->respId = hdr->identifier; - - if (hdr->code == EAP_CODE_RESPONSE) - sm->rxResp = TRUE; - - if (plen > sizeof(*hdr)) { - u8 *pos = (u8 *) (hdr + 1); - sm->respMethod = *pos++; - if (sm->respMethod == EAP_TYPE_EXPANDED) { - if (plen < sizeof(*hdr) + 8) { - wpa_printf(MSG_DEBUG, "EAP: Ignored truncated " - "expanded EAP-Packet (plen=%lu)", - (unsigned long) plen); - return; - } - sm->respVendor = WPA_GET_BE24(pos); - pos += 3; - sm->respVendorMethod = WPA_GET_BE32(pos); - } - } - - wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d " - "respMethod=%u respVendor=%u respVendorMethod=%u", - sm->rxResp, sm->respId, sm->respMethod, sm->respVendor, - sm->respVendorMethod); -} - - -static int eap_sm_getId(const struct wpabuf *data) -{ - const struct eap_hdr *hdr; - - if (data == NULL || wpabuf_len(data) < sizeof(*hdr)) - return -1; - - hdr = wpabuf_head(data); - wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier); - return hdr->identifier; -} - - -static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id) -{ - struct wpabuf *msg; - struct eap_hdr *resp; - wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id); - - msg = wpabuf_alloc(sizeof(*resp)); - if (msg == NULL) - return NULL; - resp = wpabuf_put(msg, sizeof(*resp)); - resp->code = EAP_CODE_SUCCESS; - resp->identifier = id; - resp->length = host_to_be16(sizeof(*resp)); - - return msg; -} - - -static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id) -{ - struct wpabuf *msg; - struct eap_hdr *resp; - wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id); - - msg = wpabuf_alloc(sizeof(*resp)); - if (msg == NULL) - return NULL; - resp = wpabuf_put(msg, sizeof(*resp)); - resp->code = EAP_CODE_FAILURE; - resp->identifier = id; - resp->length = host_to_be16(sizeof(*resp)); - - return msg; -} - - -static int eap_sm_nextId(struct eap_sm *sm, int id) -{ - if (id < 0) { - /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a - * random number */ - id = rand() & 0xff; - if (id != sm->lastId) - return id; - } - return (id + 1) & 0xff; -} - - -/** - * eap_sm_process_nak - Process EAP-Response/Nak - * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() - * @nak_list: Nak list (allowed methods) from the supplicant - * @len: Length of nak_list in bytes - * - * This function is called when EAP-Response/Nak is received from the - * supplicant. This can happen for both phase 1 and phase 2 authentications. - */ -void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len) -{ - int i; - size_t j; - - if (sm->user == NULL) - return; - - wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method " - "index %d)", sm->user_eap_method_index); - - wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods", - (u8 *) sm->user->methods, - EAP_MAX_METHODS * sizeof(sm->user->methods[0])); - wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer", - nak_list, len); - - i = sm->user_eap_method_index; - while (i < EAP_MAX_METHODS && - (sm->user->methods[i].vendor != EAP_VENDOR_IETF || - sm->user->methods[i].method != EAP_TYPE_NONE)) { - if (sm->user->methods[i].vendor != EAP_VENDOR_IETF) - goto not_found; - for (j = 0; j < len; j++) { - if (nak_list[j] == sm->user->methods[i].method) { - break; - } - } - - if (j < len) { - /* found */ - i++; - continue; - } - - not_found: - /* not found - remove from the list */ - 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; - } - - wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods", - (u8 *) sm->user->methods, EAP_MAX_METHODS * - sizeof(sm->user->methods[0])); -} - - -static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list, - size_t len) -{ - if (nak_list == NULL || sm == NULL || sm->user == NULL) - return; - - if (sm->user->phase2) { - wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user" - " info was selected - reject"); - sm->decision = DECISION_FAILURE; - return; - } - - eap_sm_process_nak(sm, nak_list, len); -} - - -static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor) -{ - EapType next; - int idx = sm->user_eap_method_index; - - /* In theory, there should be no problems with starting - * re-authentication with something else than EAP-Request/Identity and - * this does indeed work with wpa_supplicant. However, at least Funk - * Supplicant seemed to ignore re-auth if it skipped - * EAP-Request/Identity. - * Re-auth sets currentId == -1, so that can be used here to select - * whether Identity needs to be requested again. */ - if (sm->identity == NULL || sm->currentId == -1) { - *vendor = EAP_VENDOR_IETF; - next = EAP_TYPE_IDENTITY; - sm->update_user = TRUE; - } else if (sm->user && idx < EAP_MAX_METHODS && - (sm->user->methods[idx].vendor != EAP_VENDOR_IETF || - sm->user->methods[idx].method != EAP_TYPE_NONE)) { - *vendor = sm->user->methods[idx].vendor; - next = sm->user->methods[idx].method; - sm->user_eap_method_index++; - } else { - *vendor = EAP_VENDOR_IETF; - next = EAP_TYPE_NONE; - } - wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d", - *vendor, next); - return next; -} - - -static int eap_sm_Policy_getDecision(struct eap_sm *sm) -{ - if (!sm->eap_server && sm->identity && !sm->start_reauth) { - wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH"); - return DECISION_PASSTHROUGH; - } - - if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY && - sm->m->isSuccess(sm, sm->eap_method_priv)) { - wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> " - "SUCCESS"); - sm->update_user = TRUE; - return DECISION_SUCCESS; - } - - if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) && - !sm->m->isSuccess(sm, sm->eap_method_priv)) { - wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> " - "FAILURE"); - sm->update_user = TRUE; - return DECISION_FAILURE; - } - - if ((sm->user == NULL || sm->update_user) && sm->identity && - !sm->start_reauth) { - /* - * Allow Identity method to be started once to allow identity - * selection hint to be sent from the authentication server, - * but prevent a loop of Identity requests by only allowing - * this to happen once. - */ - int id_req = 0; - if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY && - sm->user->methods[0].vendor == EAP_VENDOR_IETF && - sm->user->methods[0].method == EAP_TYPE_IDENTITY) - id_req = 1; - if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) { - wpa_printf(MSG_DEBUG, "EAP: getDecision: user not " - "found from database -> FAILURE"); - return DECISION_FAILURE; - } - if (id_req && sm->user && - sm->user->methods[0].vendor == EAP_VENDOR_IETF && - sm->user->methods[0].method == EAP_TYPE_IDENTITY) { - wpa_printf(MSG_DEBUG, "EAP: getDecision: stop " - "identity request loop -> FAILURE"); - sm->update_user = TRUE; - return DECISION_FAILURE; - } - sm->update_user = FALSE; - } - sm->start_reauth = FALSE; - - if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && - (sm->user->methods[sm->user_eap_method_index].vendor != - EAP_VENDOR_IETF || - sm->user->methods[sm->user_eap_method_index].method != - EAP_TYPE_NONE)) { - wpa_printf(MSG_DEBUG, "EAP: getDecision: another method " - "available -> CONTINUE"); - return DECISION_CONTINUE; - } - - if (sm->identity == NULL || sm->currentId == -1) { - wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known " - "yet -> CONTINUE"); - return DECISION_CONTINUE; - } - - wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> " - "FAILURE"); - return DECISION_FAILURE; -} - - -static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method) -{ - return method == EAP_TYPE_IDENTITY ? TRUE : FALSE; -} - - -/** - * eap_server_sm_step - Step EAP server state machine - * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() - * Returns: 1 if EAP state was changed or 0 if not - * - * This function advances EAP state machine to a new state to match with the - * current variables. This should be called whenever variables used by the EAP - * state machine have changed. - */ -int eap_server_sm_step(struct eap_sm *sm) -{ - int res = 0; - do { - sm->changed = FALSE; - SM_STEP_RUN(EAP); - if (sm->changed) - res = 1; - } while (sm->changed); - return res; -} - - -static void eap_user_free(struct eap_user *user) -{ - if (user == NULL) - return; - os_free(user->password); - user->password = NULL; - os_free(user); -} - - -/** - * eap_server_sm_init - Allocate and initialize EAP server state machine - * @eapol_ctx: Context data to be used with eapol_cb calls - * @eapol_cb: Pointer to EAPOL callback functions - * @conf: EAP configuration - * Returns: Pointer to the allocated EAP state machine or %NULL on failure - * - * This function allocates and initializes an EAP state machine. - */ -struct eap_sm * eap_server_sm_init(void *eapol_ctx, - struct eapol_callbacks *eapol_cb, - struct eap_config *conf) -{ - struct eap_sm *sm; - - sm = os_zalloc(sizeof(*sm)); - if (sm == NULL) - return NULL; - sm->eapol_ctx = eapol_ctx; - sm->eapol_cb = eapol_cb; - sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */ - sm->ssl_ctx = conf->ssl_ctx; - sm->msg_ctx = conf->msg_ctx; - sm->eap_sim_db_priv = conf->eap_sim_db_priv; - sm->backend_auth = conf->backend_auth; - sm->eap_server = conf->eap_server; - if (conf->pac_opaque_encr_key) { - sm->pac_opaque_encr_key = os_malloc(16); - if (sm->pac_opaque_encr_key) { - os_memcpy(sm->pac_opaque_encr_key, - conf->pac_opaque_encr_key, 16); - } - } - if (conf->eap_fast_a_id) { - sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len); - if (sm->eap_fast_a_id) { - os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id, - conf->eap_fast_a_id_len); - sm->eap_fast_a_id_len = conf->eap_fast_a_id_len; - } - } - if (conf->eap_fast_a_id_info) - sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info); - sm->eap_fast_prov = conf->eap_fast_prov; - sm->pac_key_lifetime = conf->pac_key_lifetime; - sm->pac_key_refresh_time = conf->pac_key_refresh_time; - sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; - sm->tnc = conf->tnc; - sm->wps = conf->wps; - if (conf->assoc_wps_ie) - sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie); - if (conf->assoc_p2p_ie) - sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie); - if (conf->peer_addr) - os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN); - sm->fragment_size = conf->fragment_size; - sm->pwd_group = conf->pwd_group; - sm->pbc_in_m1 = conf->pbc_in_m1; - sm->server_id = conf->server_id; - sm->server_id_len = conf->server_id_len; - - wpa_printf(MSG_DEBUG, "EAP: Server state machine created"); - - return sm; -} - - -/** - * eap_server_sm_deinit - Deinitialize and free an EAP server state machine - * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() - * - * This function deinitializes EAP state machine and frees all allocated - * resources. - */ -void eap_server_sm_deinit(struct eap_sm *sm) -{ - if (sm == NULL) - return; - wpa_printf(MSG_DEBUG, "EAP: Server state machine removed"); - if (sm->m && sm->eap_method_priv) - sm->m->reset(sm, sm->eap_method_priv); - wpabuf_free(sm->eap_if.eapReqData); - os_free(sm->eap_if.eapKeyData); - wpabuf_free(sm->lastReqData); - wpabuf_free(sm->eap_if.eapRespData); - os_free(sm->identity); - os_free(sm->pac_opaque_encr_key); - os_free(sm->eap_fast_a_id); - os_free(sm->eap_fast_a_id_info); - wpabuf_free(sm->eap_if.aaaEapReqData); - wpabuf_free(sm->eap_if.aaaEapRespData); - os_free(sm->eap_if.aaaEapKeyData); - eap_user_free(sm->user); - wpabuf_free(sm->assoc_wps_ie); - wpabuf_free(sm->assoc_p2p_ie); - os_free(sm); -} - - -/** - * eap_sm_notify_cached - Notify EAP state machine of cached PMK - * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() - * - * This function is called when PMKSA caching is used to skip EAP - * authentication. - */ -void eap_sm_notify_cached(struct eap_sm *sm) -{ - if (sm == NULL) - return; - - sm->EAP_state = EAP_SUCCESS; -} - - -/** - * eap_sm_pending_cb - EAP state machine callback for a pending EAP request - * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() - * - * This function is called when data for a pending EAP-Request is received. - */ -void eap_sm_pending_cb(struct eap_sm *sm) -{ - if (sm == NULL) - return; - wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received"); - if (sm->method_pending == METHOD_PENDING_WAIT) - sm->method_pending = METHOD_PENDING_CONT; -} - - -/** - * eap_sm_method_pending - Query whether EAP method is waiting for pending data - * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() - * Returns: 1 if method is waiting for pending data or 0 if not - */ -int eap_sm_method_pending(struct eap_sm *sm) -{ - if (sm == NULL) - return 0; - return sm->method_pending == METHOD_PENDING_WAIT; -} - - -/** - * eap_get_identity - Get the user identity (from EAP-Response/Identity) - * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() - * @len: Buffer for returning identity length - * Returns: Pointer to the user identity or %NULL if not available - */ -const u8 * eap_get_identity(struct eap_sm *sm, size_t *len) -{ - *len = sm->identity_len; - return sm->identity; -} - - -/** - * eap_get_interface - Get pointer to EAP-EAPOL interface data - * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() - * Returns: Pointer to the EAP-EAPOL interface data - */ -struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm) -{ - return &sm->eap_if; -} - - -/** - * eap_server_clear_identity - Clear EAP identity information - * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() - * - * This function can be used to clear the EAP identity information in the EAP - * server context. This allows the EAP/Identity method to be used again after - * EAPOL-Start or EAPOL-Logoff. - */ -void eap_server_clear_identity(struct eap_sm *sm) -{ - os_free(sm->identity); - sm->identity = NULL; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_aka.c b/contrib/hostapd/src/eap_server/eap_server_aka.c deleted file mode 100644 index 46fc45847f..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_aka.c +++ /dev/null @@ -1,1352 +0,0 @@ -/* - * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448) - * Copyright (c) 2005-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha256.h" -#include "crypto/crypto.h" -#include "crypto/random.h" -#include "eap_common/eap_sim_common.h" -#include "eap_server/eap_i.h" -#include "eap_server/eap_sim_db.h" - - -struct eap_aka_data { - u8 mk[EAP_SIM_MK_LEN]; - u8 nonce_s[EAP_SIM_NONCE_S_LEN]; - u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN]; - u8 k_encr[EAP_SIM_K_ENCR_LEN]; - u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */ - u8 msk[EAP_SIM_KEYING_DATA_LEN]; - u8 emsk[EAP_EMSK_LEN]; - u8 rand[EAP_AKA_RAND_LEN]; - u8 autn[EAP_AKA_AUTN_LEN]; - u8 ck[EAP_AKA_CK_LEN]; - u8 ik[EAP_AKA_IK_LEN]; - u8 res[EAP_AKA_RES_MAX_LEN]; - size_t res_len; - enum { - IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE - } state; - char *next_pseudonym; - char *next_reauth_id; - u16 counter; - struct eap_sim_reauth *reauth; - int auts_reported; /* whether the current AUTS has been reported to the - * eap_sim_db */ - u16 notification; - int use_result_ind; - - struct wpabuf *id_msgs; - int pending_id; - u8 eap_method; - u8 *network_name; - size_t network_name_len; - u16 kdf; - int identity_round; - char permanent[20]; /* Permanent username */ -}; - - -static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data); - - -static const char * eap_aka_state_txt(int state) -{ - switch (state) { - case IDENTITY: - return "IDENTITY"; - case CHALLENGE: - return "CHALLENGE"; - case REAUTH: - return "REAUTH"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - case NOTIFICATION: - return "NOTIFICATION"; - default: - return "Unknown?!"; - } -} - - -static void eap_aka_state(struct eap_aka_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s", - eap_aka_state_txt(data->state), - eap_aka_state_txt(state)); - data->state = state; -} - - -static int eap_aka_check_identity_reauth(struct eap_sm *sm, - struct eap_aka_data *data, - const char *username) -{ - if (data->eap_method == EAP_TYPE_AKA_PRIME && - username[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX) - return 0; - if (data->eap_method == EAP_TYPE_AKA && - username[0] != EAP_AKA_REAUTH_ID_PREFIX) - return 0; - - wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username); - data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv, - username); - if (data->reauth == NULL) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - " - "request full auth identity"); - /* Remain in IDENTITY state for another round */ - return 0; - } - - wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast re-authentication"); - os_strlcpy(data->permanent, data->reauth->permanent, - sizeof(data->permanent)); - data->counter = data->reauth->counter; - if (data->eap_method == EAP_TYPE_AKA_PRIME) { - os_memcpy(data->k_encr, data->reauth->k_encr, - EAP_SIM_K_ENCR_LEN); - os_memcpy(data->k_aut, data->reauth->k_aut, - EAP_AKA_PRIME_K_AUT_LEN); - os_memcpy(data->k_re, data->reauth->k_re, - EAP_AKA_PRIME_K_RE_LEN); - } else { - os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN); - } - - eap_aka_state(data, REAUTH); - return 1; -} - - -static void eap_aka_check_identity(struct eap_sm *sm, - struct eap_aka_data *data) -{ - char *username; - - /* Check if we already know the identity from EAP-Response/Identity */ - - username = sim_get_username(sm->identity, sm->identity_len); - if (username == NULL) - return; - - if (eap_aka_check_identity_reauth(sm, data, username) > 0) { - os_free(username); - /* - * Since re-auth username was recognized, skip AKA/Identity - * exchange. - */ - return; - } - - if ((data->eap_method == EAP_TYPE_AKA_PRIME && - username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) || - (data->eap_method == EAP_TYPE_AKA && - username[0] == EAP_AKA_PSEUDONYM_PREFIX)) { - const char *permanent; - wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'", - username); - permanent = eap_sim_db_get_permanent( - sm->eap_sim_db_priv, username); - if (permanent == NULL) { - os_free(username); - wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym " - "identity - request permanent identity"); - /* Remain in IDENTITY state for another round */ - return; - } - os_strlcpy(data->permanent, permanent, - sizeof(data->permanent)); - /* - * Since pseudonym username was recognized, skip AKA/Identity - * exchange. - */ - eap_aka_fullauth(sm, data); - } - - os_free(username); -} - - -static void * eap_aka_init(struct eap_sm *sm) -{ - struct eap_aka_data *data; - - if (sm->eap_sim_db_priv == NULL) { - wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured"); - return NULL; - } - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - - data->eap_method = EAP_TYPE_AKA; - - data->state = IDENTITY; - data->pending_id = -1; - eap_aka_check_identity(sm, data); - - return data; -} - - -#ifdef EAP_SERVER_AKA_PRIME -static void * eap_aka_prime_init(struct eap_sm *sm) -{ - struct eap_aka_data *data; - /* TODO: make ANID configurable; see 3GPP TS 24.302 */ - char *network_name = "WLAN"; - - if (sm->eap_sim_db_priv == NULL) { - wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured"); - return NULL; - } - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - - data->eap_method = EAP_TYPE_AKA_PRIME; - 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); - - data->state = IDENTITY; - data->pending_id = -1; - eap_aka_check_identity(sm, data); - - return data; -} -#endif /* EAP_SERVER_AKA_PRIME */ - - -static void eap_aka_reset(struct eap_sm *sm, void *priv) -{ - struct eap_aka_data *data = priv; - os_free(data->next_pseudonym); - os_free(data->next_reauth_id); - wpabuf_free(data->id_msgs); - os_free(data->network_name); - os_free(data); -} - - -static int eap_aka_add_id_msg(struct eap_aka_data *data, - const struct wpabuf *msg) -{ - if (msg == NULL) - return -1; - - if (data->id_msgs == NULL) { - data->id_msgs = wpabuf_dup(msg); - return data->id_msgs == NULL ? -1 : 0; - } - - if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0) - return -1; - wpabuf_put_buf(data->id_msgs, msg); - - return 0; -} - - -static void eap_aka_add_checkcode(struct eap_aka_data *data, - struct eap_sim_msg *msg) -{ - const u8 *addr; - size_t len; - u8 hash[SHA256_MAC_LEN]; - - wpa_printf(MSG_DEBUG, " AT_CHECKCODE"); - - if (data->id_msgs == NULL) { - /* - * No EAP-AKA/Identity packets were exchanged - send empty - * checkcode. - */ - eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0); - return; - } - - /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */ - addr = wpabuf_head(data->id_msgs); - len = wpabuf_len(data->id_msgs); - wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len); - if (data->eap_method == EAP_TYPE_AKA_PRIME) - sha256_vector(1, &addr, &len, hash); - else - sha1_vector(1, &addr, &len, hash); - - eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash, - data->eap_method == EAP_TYPE_AKA_PRIME ? - EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN); -} - - -static int eap_aka_verify_checkcode(struct eap_aka_data *data, - const u8 *checkcode, size_t checkcode_len) -{ - const u8 *addr; - size_t len; - u8 hash[SHA256_MAC_LEN]; - size_t hash_len; - - if (checkcode == NULL) - return -1; - - if (data->id_msgs == NULL) { - if (checkcode_len != 0) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer " - "indicates that AKA/Identity messages were " - "used, but they were not"); - return -1; - } - return 0; - } - - hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ? - EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN; - - if (checkcode_len != hash_len) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates " - "that AKA/Identity message were not used, but they " - "were"); - return -1; - } - - /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */ - addr = wpabuf_head(data->id_msgs); - len = wpabuf_len(data->id_msgs); - if (data->eap_method == EAP_TYPE_AKA_PRIME) - sha256_vector(1, &addr, &len, hash); - else - sha1_vector(1, &addr, &len, hash); - - if (os_memcmp(hash, checkcode, hash_len) != 0) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE"); - return -1; - } - - return 0; -} - - -static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm, - struct eap_aka_data *data, u8 id) -{ - struct eap_sim_msg *msg; - struct wpabuf *buf; - - wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity"); - msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, - EAP_AKA_SUBTYPE_IDENTITY); - data->identity_round++; - if (data->identity_round == 1) { - /* - * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is - * ignored and the AKA/Identity is used to request the - * identity. - */ - wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ"); - eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0); - } else if (data->identity_round > 3) { - /* Cannot use more than three rounds of Identity messages */ - eap_sim_msg_free(msg); - return NULL; - } else if (sm->identity && sm->identity_len > 0 && - (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX || - sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) { - /* Reauth id may have expired - try fullauth */ - wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ"); - eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0); - } else { - wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); - eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); - } - buf = eap_sim_msg_finish(msg, NULL, NULL, 0); - if (eap_aka_add_id_msg(data, buf) < 0) { - wpabuf_free(buf); - return NULL; - } - data->pending_id = id; - return buf; -} - - -static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data, - struct eap_sim_msg *msg, u16 counter, - const u8 *nonce_s) -{ - os_free(data->next_pseudonym); - if (nonce_s == NULL) { - data->next_pseudonym = - eap_sim_db_get_next_pseudonym( - sm->eap_sim_db_priv, - data->eap_method == EAP_TYPE_AKA_PRIME ? - EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA); - } else { - /* Do not update pseudonym during re-authentication */ - data->next_pseudonym = NULL; - } - os_free(data->next_reauth_id); - if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) { - data->next_reauth_id = - eap_sim_db_get_next_reauth_id( - sm->eap_sim_db_priv, - data->eap_method == EAP_TYPE_AKA_PRIME ? - EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA); - } else { - wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication " - "count exceeded - force full authentication"); - data->next_reauth_id = NULL; - } - - if (data->next_pseudonym == NULL && data->next_reauth_id == NULL && - counter == 0 && nonce_s == NULL) - return 0; - - wpa_printf(MSG_DEBUG, " AT_IV"); - wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); - eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); - - if (counter > 0) { - wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter); - eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); - } - - if (nonce_s) { - wpa_printf(MSG_DEBUG, " *AT_NONCE_S"); - eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s, - EAP_SIM_NONCE_S_LEN); - } - - if (data->next_pseudonym) { - wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)", - data->next_pseudonym); - eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM, - os_strlen(data->next_pseudonym), - (u8 *) data->next_pseudonym, - os_strlen(data->next_pseudonym)); - } - - if (data->next_reauth_id) { - wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)", - data->next_reauth_id); - eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID, - os_strlen(data->next_reauth_id), - (u8 *) data->next_reauth_id, - os_strlen(data->next_reauth_id)); - } - - if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt " - "AT_ENCR_DATA"); - return -1; - } - - return 0; -} - - -static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm, - struct eap_aka_data *data, - u8 id) -{ - struct eap_sim_msg *msg; - - wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge"); - msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, - EAP_AKA_SUBTYPE_CHALLENGE); - wpa_printf(MSG_DEBUG, " AT_RAND"); - eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN); - wpa_printf(MSG_DEBUG, " AT_AUTN"); - eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN); - if (data->eap_method == EAP_TYPE_AKA_PRIME) { - if (data->kdf) { - /* Add the selected KDF into the beginning */ - wpa_printf(MSG_DEBUG, " AT_KDF"); - eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf, - NULL, 0); - } - wpa_printf(MSG_DEBUG, " AT_KDF"); - eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF, - NULL, 0); - wpa_printf(MSG_DEBUG, " AT_KDF_INPUT"); - eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT, - data->network_name_len, - data->network_name, data->network_name_len); - } - - if (eap_aka_build_encr(sm, data, msg, 0, NULL)) { - eap_sim_msg_free(msg); - return NULL; - } - - eap_aka_add_checkcode(data, msg); - - if (sm->eap_sim_aka_result_ind) { - wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); - eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); - } - -#ifdef EAP_SERVER_AKA_PRIME - if (data->eap_method == EAP_TYPE_AKA) { - u16 flags = 0; - int i; - int aka_prime_preferred = 0; - - i = 0; - while (sm->user && i < EAP_MAX_METHODS && - (sm->user->methods[i].vendor != EAP_VENDOR_IETF || - sm->user->methods[i].method != EAP_TYPE_NONE)) { - if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) { - if (sm->user->methods[i].method == - EAP_TYPE_AKA) - break; - if (sm->user->methods[i].method == - EAP_TYPE_AKA_PRIME) { - aka_prime_preferred = 1; - break; - } - } - i++; - } - - if (aka_prime_preferred) - flags |= EAP_AKA_BIDDING_FLAG_D; - eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0); - } -#endif /* EAP_SERVER_AKA_PRIME */ - - wpa_printf(MSG_DEBUG, " AT_MAC"); - eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); -} - - -static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm, - struct eap_aka_data *data, u8 id) -{ - struct eap_sim_msg *msg; - - wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication"); - - if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN)) - return NULL; - wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S", - data->nonce_s, EAP_SIM_NONCE_S_LEN); - - if (data->eap_method == EAP_TYPE_AKA_PRIME) { - eap_aka_prime_derive_keys_reauth(data->k_re, data->counter, - sm->identity, - sm->identity_len, - data->nonce_s, - data->msk, data->emsk); - } else { - eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, - data->msk, data->emsk); - eap_sim_derive_keys_reauth(data->counter, sm->identity, - sm->identity_len, data->nonce_s, - data->mk, data->msk, data->emsk); - } - - msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, - EAP_AKA_SUBTYPE_REAUTHENTICATION); - - if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) { - eap_sim_msg_free(msg); - return NULL; - } - - eap_aka_add_checkcode(data, msg); - - if (sm->eap_sim_aka_result_ind) { - wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); - eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); - } - - wpa_printf(MSG_DEBUG, " AT_MAC"); - eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); -} - - -static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm, - struct eap_aka_data *data, - u8 id) -{ - struct eap_sim_msg *msg; - - wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification"); - msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, - EAP_AKA_SUBTYPE_NOTIFICATION); - wpa_printf(MSG_DEBUG, " AT_NOTIFICATION (%d)", data->notification); - eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification, - NULL, 0); - if (data->use_result_ind) { - if (data->reauth) { - wpa_printf(MSG_DEBUG, " AT_IV"); - wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); - eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, - EAP_SIM_AT_ENCR_DATA); - wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", - data->counter); - eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, - NULL, 0); - - if (eap_sim_msg_add_encr_end(msg, data->k_encr, - EAP_SIM_AT_PADDING)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Failed to " - "encrypt AT_ENCR_DATA"); - eap_sim_msg_free(msg); - return NULL; - } - } - - wpa_printf(MSG_DEBUG, " AT_MAC"); - eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - } - return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); -} - - -static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_aka_data *data = priv; - - data->auts_reported = 0; - switch (data->state) { - case IDENTITY: - return eap_aka_build_identity(sm, data, id); - case CHALLENGE: - return eap_aka_build_challenge(sm, data, id); - case REAUTH: - return eap_aka_build_reauth(sm, data, id); - case NOTIFICATION: - return eap_aka_build_notification(sm, data, id); - default: - wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in " - "buildReq", data->state); - break; - } - return NULL; -} - - -static Boolean eap_aka_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_aka_data *data = priv; - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData, - &len); - if (pos == NULL || len < 3) { - wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame"); - return TRUE; - } - - return FALSE; -} - - -static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype) -{ - if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR || - subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) - return FALSE; - - switch (data->state) { - case IDENTITY: - if (subtype != EAP_AKA_SUBTYPE_IDENTITY) { - wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " - "subtype %d", subtype); - return TRUE; - } - break; - case CHALLENGE: - if (subtype != EAP_AKA_SUBTYPE_CHALLENGE && - subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) { - wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " - "subtype %d", subtype); - return TRUE; - } - break; - case REAUTH: - if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) { - wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " - "subtype %d", subtype); - return TRUE; - } - break; - case NOTIFICATION: - if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) { - wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " - "subtype %d", subtype); - return TRUE; - } - break; - default: - wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for " - "processing a response", data->state); - return TRUE; - } - - return FALSE; -} - - -static void eap_aka_determine_identity(struct eap_sm *sm, - struct eap_aka_data *data) -{ - char *username; - - wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity", - sm->identity, sm->identity_len); - - username = sim_get_username(sm->identity, sm->identity_len); - if (username == NULL) { - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - - if (eap_aka_check_identity_reauth(sm, data, username) > 0) { - os_free(username); - return; - } - - if (((data->eap_method == EAP_TYPE_AKA_PRIME && - username[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) || - (data->eap_method == EAP_TYPE_AKA && - username[0] == EAP_AKA_REAUTH_ID_PREFIX)) && - data->identity_round == 1) { - /* Remain in IDENTITY state for another round to request full - * auth identity since we did not recognize reauth id */ - os_free(username); - return; - } - - if ((data->eap_method == EAP_TYPE_AKA_PRIME && - username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) || - (data->eap_method == EAP_TYPE_AKA && - username[0] == EAP_AKA_PSEUDONYM_PREFIX)) { - const char *permanent; - wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'", - username); - permanent = eap_sim_db_get_permanent( - sm->eap_sim_db_priv, username); - os_free(username); - if (permanent == NULL) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym " - "identity - request permanent identity"); - /* Remain in IDENTITY state for another round */ - return; - } - os_strlcpy(data->permanent, permanent, - sizeof(data->permanent)); - } else if ((data->eap_method == EAP_TYPE_AKA_PRIME && - username[0] == EAP_AKA_PRIME_PERMANENT_PREFIX) || - (data->eap_method == EAP_TYPE_AKA && - username[0] == EAP_AKA_PERMANENT_PREFIX)) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent username '%s'", - username); - os_strlcpy(data->permanent, username, sizeof(data->permanent)); - os_free(username); - } else { - wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'", - username); - os_free(username); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - - eap_aka_fullauth(sm, data); -} - - -static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data) -{ - size_t identity_len; - int res; - - res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent, - data->rand, data->autn, data->ik, - data->ck, data->res, &data->res_len, sm); - if (res == EAP_SIM_DB_PENDING) { - wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " - "not yet available - pending request"); - sm->method_pending = METHOD_PENDING_WAIT; - return; - } - -#ifdef EAP_SERVER_AKA_PRIME - if (data->eap_method == EAP_TYPE_AKA_PRIME) { - /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the - * needed 6-octet SQN ^AK for CK',IK' derivation */ - eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik, - data->autn, - data->network_name, - data->network_name_len); - } -#endif /* EAP_SERVER_AKA_PRIME */ - - data->reauth = NULL; - data->counter = 0; /* reset re-auth counter since this is full auth */ - - if (res != 0) { - wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA " - "authentication data for the peer"); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - if (sm->method_pending == METHOD_PENDING_WAIT) { - wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " - "available - abort pending wait"); - sm->method_pending = METHOD_PENDING_NONE; - } - - identity_len = sm->identity_len; - while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { - wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null " - "character from identity"); - identity_len--; - } - wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation", - sm->identity, identity_len); - - if (data->eap_method == EAP_TYPE_AKA_PRIME) { - eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik, - data->ck, data->k_encr, data->k_aut, - data->k_re, data->msk, data->emsk); - } else { - eap_aka_derive_mk(sm->identity, identity_len, data->ik, - data->ck, data->mk); - eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, - data->msk, data->emsk); - } - - eap_aka_state(data, CHALLENGE); -} - - -static void eap_aka_process_identity(struct eap_sm *sm, - struct eap_aka_data *data, - struct wpabuf *respData, - struct eap_sim_attrs *attr) -{ - u8 *new_identity; - - wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity"); - - if (attr->mac || attr->iv || attr->encr_data) { - wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute " - "received in EAP-Response/AKA-Identity"); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - - /* - * We always request identity with AKA/Identity, so the peer is - * required to have replied with one. - */ - if (!attr->identity || attr->identity_len == 0) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Peer did not provide any " - "identity"); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - - new_identity = os_malloc(attr->identity_len); - if (new_identity == NULL) { - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - os_free(sm->identity); - sm->identity = new_identity; - os_memcpy(sm->identity, attr->identity, attr->identity_len); - sm->identity_len = attr->identity_len; - - eap_aka_determine_identity(sm, data); - if (eap_get_id(respData) == data->pending_id) { - data->pending_id = -1; - eap_aka_add_id_msg(data, respData); - } -} - - -static int eap_aka_verify_mac(struct eap_aka_data *data, - const struct wpabuf *req, - const u8 *mac, const u8 *extra, - size_t extra_len) -{ - if (data->eap_method == EAP_TYPE_AKA_PRIME) - return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra, - extra_len); - return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len); -} - - -static void eap_aka_process_challenge(struct eap_sm *sm, - struct eap_aka_data *data, - struct wpabuf *respData, - struct eap_sim_attrs *attr) -{ - wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge"); - -#ifdef EAP_SERVER_AKA_PRIME -#if 0 - /* KDF negotiation; to be enabled only after more than one KDF is - * supported */ - if (data->eap_method == EAP_TYPE_AKA_PRIME && - attr->kdf_count == 1 && attr->mac == NULL) { - if (attr->kdf[0] != EAP_AKA_PRIME_KDF) { - wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected " - "unknown KDF"); - data->notification = - EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - - data->kdf = attr->kdf[0]; - - /* Allow negotiation to continue with the selected KDF by - * sending another Challenge message */ - wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf); - return; - } -#endif -#endif /* EAP_SERVER_AKA_PRIME */ - - if (attr->checkcode && - eap_aka_verify_checkcode(data, attr->checkcode, - attr->checkcode_len)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the " - "message"); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - if (attr->mac == NULL || - eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message " - "did not include valid AT_MAC"); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - - /* - * AT_RES is padded, so verify that there is enough room for RES and - * that the RES length in bits matches with the expected RES. - */ - if (attr->res == NULL || attr->res_len < data->res_len || - attr->res_len_bits != data->res_len * 8 || - os_memcmp(attr->res, data->res, data->res_len) != 0) { - wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not " - "include valid AT_RES (attr len=%lu, res len=%lu " - "bits, expected %lu bits)", - (unsigned long) attr->res_len, - (unsigned long) attr->res_len_bits, - (unsigned long) data->res_len * 8); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - - wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the " - "correct AT_MAC"); - if (sm->eap_sim_aka_result_ind && attr->result_ind) { - data->use_result_ind = 1; - data->notification = EAP_SIM_SUCCESS; - eap_aka_state(data, NOTIFICATION); - } else - eap_aka_state(data, SUCCESS); - - if (data->next_pseudonym) { - eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent, - data->next_pseudonym); - data->next_pseudonym = NULL; - } - if (data->next_reauth_id) { - if (data->eap_method == EAP_TYPE_AKA_PRIME) { -#ifdef EAP_SERVER_AKA_PRIME - eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, - data->permanent, - data->next_reauth_id, - data->counter + 1, - data->k_encr, data->k_aut, - data->k_re); -#endif /* EAP_SERVER_AKA_PRIME */ - } else { - eap_sim_db_add_reauth(sm->eap_sim_db_priv, - data->permanent, - data->next_reauth_id, - data->counter + 1, - data->mk); - } - data->next_reauth_id = NULL; - } -} - - -static void eap_aka_process_sync_failure(struct eap_sm *sm, - struct eap_aka_data *data, - struct wpabuf *respData, - struct eap_sim_attrs *attr) -{ - wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure"); - - if (attr->auts == NULL) { - wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure " - "message did not include valid AT_AUTS"); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - - /* Avoid re-reporting AUTS when processing pending EAP packet by - * maintaining a local flag stating whether this AUTS has already been - * reported. */ - if (!data->auts_reported && - eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent, - attr->auts, data->rand)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed"); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - data->auts_reported = 1; - - /* Remain in CHALLENGE state to re-try after resynchronization */ - eap_aka_fullauth(sm, data); -} - - -static void eap_aka_process_reauth(struct eap_sm *sm, - struct eap_aka_data *data, - struct wpabuf *respData, - struct eap_sim_attrs *attr) -{ - struct eap_sim_attrs eattr; - u8 *decrypted = NULL; - - wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication"); - - if (attr->mac == NULL || - eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s, - EAP_SIM_NONCE_S_LEN)) { - wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " - "did not include valid AT_MAC"); - goto fail; - } - - if (attr->encr_data == NULL || attr->iv == NULL) { - wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication " - "message did not include encrypted data"); - goto fail; - } - - decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, - attr->encr_data_len, attr->iv, &eattr, - 0); - if (decrypted == NULL) { - wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted " - "data from reauthentication message"); - goto fail; - } - - if (eattr.counter != data->counter) { - wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " - "used incorrect counter %u, expected %u", - eattr.counter, data->counter); - goto fail; - } - os_free(decrypted); - decrypted = NULL; - - wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes " - "the correct AT_MAC"); - - if (eattr.counter_too_small) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response " - "included AT_COUNTER_TOO_SMALL - starting full " - "authentication"); - eap_aka_fullauth(sm, data); - return; - } - - if (sm->eap_sim_aka_result_ind && attr->result_ind) { - data->use_result_ind = 1; - data->notification = EAP_SIM_SUCCESS; - eap_aka_state(data, NOTIFICATION); - } else - eap_aka_state(data, SUCCESS); - - if (data->next_reauth_id) { - if (data->eap_method == EAP_TYPE_AKA_PRIME) { -#ifdef EAP_SERVER_AKA_PRIME - eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, - data->permanent, - data->next_reauth_id, - data->counter + 1, - data->k_encr, data->k_aut, - data->k_re); -#endif /* EAP_SERVER_AKA_PRIME */ - } else { - eap_sim_db_add_reauth(sm->eap_sim_db_priv, - data->permanent, - data->next_reauth_id, - data->counter + 1, - data->mk); - } - data->next_reauth_id = NULL; - } else { - eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); - data->reauth = NULL; - } - - return; - -fail: - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); - data->reauth = NULL; - os_free(decrypted); -} - - -static void eap_aka_process_client_error(struct eap_sm *sm, - struct eap_aka_data *data, - struct wpabuf *respData, - struct eap_sim_attrs *attr) -{ - wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d", - attr->client_error_code); - if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) - eap_aka_state(data, SUCCESS); - else - eap_aka_state(data, FAILURE); -} - - -static void eap_aka_process_authentication_reject( - struct eap_sm *sm, struct eap_aka_data *data, - struct wpabuf *respData, struct eap_sim_attrs *attr) -{ - wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication"); - eap_aka_state(data, FAILURE); -} - - -static void eap_aka_process_notification(struct eap_sm *sm, - struct eap_aka_data *data, - struct wpabuf *respData, - struct eap_sim_attrs *attr) -{ - wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification"); - if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) - eap_aka_state(data, SUCCESS); - else - eap_aka_state(data, FAILURE); -} - - -static void eap_aka_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_aka_data *data = priv; - const u8 *pos, *end; - u8 subtype; - size_t len; - struct eap_sim_attrs attr; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData, - &len); - if (pos == NULL || len < 3) - return; - - end = pos + len; - subtype = *pos; - pos += 3; - - if (eap_aka_subtype_ok(data, subtype)) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected " - "EAP-AKA Subtype in EAP Response"); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - - if (eap_sim_parse_attr(pos, end, &attr, - data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1, - 0)) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes"); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } - - if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) { - eap_aka_process_client_error(sm, data, respData, &attr); - return; - } - - if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) { - eap_aka_process_authentication_reject(sm, data, respData, - &attr); - return; - } - - switch (data->state) { - case IDENTITY: - eap_aka_process_identity(sm, data, respData, &attr); - break; - case CHALLENGE: - if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) { - eap_aka_process_sync_failure(sm, data, respData, - &attr); - } else { - eap_aka_process_challenge(sm, data, respData, &attr); - } - break; - case REAUTH: - eap_aka_process_reauth(sm, data, respData, &attr); - break; - case NOTIFICATION: - eap_aka_process_notification(sm, data, respData, &attr); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in " - "process", data->state); - break; - } -} - - -static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_aka_data *data = priv; - return data->state == SUCCESS || data->state == FAILURE; -} - - -static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_aka_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_SIM_KEYING_DATA_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); - *len = EAP_SIM_KEYING_DATA_LEN; - return key; -} - - -static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_aka_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - *len = EAP_EMSK_LEN; - return key; -} - - -static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_aka_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_aka_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA"); - if (eap == NULL) - return -1; - - eap->init = eap_aka_init; - eap->reset = eap_aka_reset; - eap->buildReq = eap_aka_buildReq; - eap->check = eap_aka_check; - eap->process = eap_aka_process; - eap->isDone = eap_aka_isDone; - eap->getKey = eap_aka_getKey; - eap->isSuccess = eap_aka_isSuccess; - eap->get_emsk = eap_aka_get_emsk; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} - - -#ifdef EAP_SERVER_AKA_PRIME -int eap_server_aka_prime_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME, - "AKA'"); - if (eap == NULL) - return -1; - - eap->init = eap_aka_prime_init; - eap->reset = eap_aka_reset; - eap->buildReq = eap_aka_buildReq; - eap->check = eap_aka_check; - eap->process = eap_aka_process; - eap->isDone = eap_aka_isDone; - eap->getKey = eap_aka_getKey; - eap->isSuccess = eap_aka_isSuccess; - eap->get_emsk = eap_aka_get_emsk; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - - return ret; -} -#endif /* EAP_SERVER_AKA_PRIME */ diff --git a/contrib/hostapd/src/eap_server/eap_server_eke.c b/contrib/hostapd/src/eap_server/eap_server_eke.c deleted file mode 100644 index b19a321af4..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_eke.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * hostapd / EAP-EKE (RFC 6124) server - * Copyright (c) 2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/random.h" -#include "eap_server/eap_i.h" -#include "eap_common/eap_eke_common.h" - - -struct eap_eke_data { - enum { - IDENTITY, COMMIT, CONFIRM, FAILURE_REPORT, SUCCESS, FAILURE - } state; - u8 msk[EAP_MSK_LEN]; - u8 emsk[EAP_EMSK_LEN]; - u8 *peerid; - size_t peerid_len; - u8 peerid_type; - u8 serverid_type; - u8 dh_priv[EAP_EKE_MAX_DH_LEN]; - u8 key[EAP_EKE_MAX_KEY_LEN]; - struct eap_eke_session sess; - u8 nonce_p[EAP_EKE_MAX_NONCE_LEN]; - u8 nonce_s[EAP_EKE_MAX_NONCE_LEN]; - struct wpabuf *msgs; - int phase2; - u32 failure_code; -}; - - -static const char * eap_eke_state_txt(int state) -{ - switch (state) { - case IDENTITY: - return "IDENTITY"; - case COMMIT: - return "COMMIT"; - case CONFIRM: - return "CONFIRM"; - case FAILURE_REPORT: - return "FAILURE_REPORT"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "?"; - } -} - - -static void eap_eke_state(struct eap_eke_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s", - eap_eke_state_txt(data->state), - eap_eke_state_txt(state)); - data->state = state; -} - - -static void eap_eke_fail(struct eap_eke_data *data, u32 code) -{ - wpa_printf(MSG_DEBUG, "EAP-EKE: Failure - code 0x%x", code); - data->failure_code = code; - eap_eke_state(data, FAILURE_REPORT); -} - - -static void * eap_eke_init(struct eap_sm *sm) -{ - struct eap_eke_data *data; - size_t i; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - eap_eke_state(data, IDENTITY); - - data->serverid_type = EAP_EKE_ID_OPAQUE; - for (i = 0; i < sm->server_id_len; i++) { - if (sm->server_id[i] == '.' && - data->serverid_type == EAP_EKE_ID_OPAQUE) - data->serverid_type = EAP_EKE_ID_FQDN; - if (sm->server_id[i] == '@') - data->serverid_type = EAP_EKE_ID_NAI; - } - - data->phase2 = sm->init_phase2; - - return data; -} - - -static void eap_eke_reset(struct eap_sm *sm, void *priv) -{ - struct eap_eke_data *data = priv; - eap_eke_session_clean(&data->sess); - os_free(data->peerid); - wpabuf_free(data->msgs); - os_free(data); -} - - -static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, - u8 id, size_t length, u8 eke_exch) -{ - struct wpabuf *msg; - size_t plen; - - plen = 1 + length; - - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen, - EAP_CODE_REQUEST, id); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory"); - return NULL; - } - - wpabuf_put_u8(msg, eke_exch); - - return msg; -} - - -static int supported_proposal(const u8 *pos) -{ - if (pos[0] == EAP_EKE_DHGROUP_EKE_16 && - pos[1] == EAP_EKE_ENCR_AES128_CBC && - pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 && - pos[3] == EAP_EKE_MAC_HMAC_SHA2_256) - return 1; - - if (pos[0] == EAP_EKE_DHGROUP_EKE_15 && - pos[1] == EAP_EKE_ENCR_AES128_CBC && - pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 && - pos[3] == EAP_EKE_MAC_HMAC_SHA2_256) - return 1; - - if (pos[0] == EAP_EKE_DHGROUP_EKE_14 && - pos[1] == EAP_EKE_ENCR_AES128_CBC && - pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 && - pos[3] == EAP_EKE_MAC_HMAC_SHA2_256) - return 1; - - if (pos[0] == EAP_EKE_DHGROUP_EKE_14 && - pos[1] == EAP_EKE_ENCR_AES128_CBC && - pos[2] == EAP_EKE_PRF_HMAC_SHA1 && - pos[3] == EAP_EKE_MAC_HMAC_SHA1) - return 1; - - return 0; -} - - -static struct wpabuf * eap_eke_build_failure(struct eap_eke_data *data, u8 id) -{ - struct wpabuf *msg; - - wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Failure: Failure-Code=0x%x", - data->failure_code); - - msg = eap_eke_build_msg(data, id, 4, EAP_EKE_FAILURE); - if (msg == NULL) { - eap_eke_state(data, FAILURE); - return NULL; - } - wpabuf_put_be32(msg, data->failure_code); - - return msg; -} - - -static struct wpabuf * eap_eke_build_identity(struct eap_sm *sm, - struct eap_eke_data *data, - u8 id) -{ - struct wpabuf *msg; - size_t plen; - - wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Identity"); - - plen = 2 + 4 * 4 + 1 + sm->server_id_len; - msg = eap_eke_build_msg(data, id, plen, EAP_EKE_ID); - if (msg == NULL) - return NULL; - - wpabuf_put_u8(msg, 4); /* NumProposals */ - wpabuf_put_u8(msg, 0); /* Reserved */ - - /* Proposal - DH Group 16 with AES128-CBC and SHA256 */ - wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_16); /* Group Description */ - wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */ - wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */ - wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */ - - /* Proposal - DH Group 15 with AES128-CBC and SHA256 */ - wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_15); /* Group Description */ - wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */ - wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */ - wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */ - - /* Proposal - DH Group 14 with AES128-CBC and SHA256 */ - wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */ - wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */ - wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */ - wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */ - - /* - * Proposal - DH Group 14 with AES128-CBC and SHA1 - * (mandatory to implement algorithms) - */ - wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */ - wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */ - wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA1); /* PRF */ - wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA1); /* MAC */ - - /* Server IDType + Identity */ - wpabuf_put_u8(msg, data->serverid_type); - wpabuf_put_data(msg, sm->server_id, sm->server_id_len); - - wpabuf_free(data->msgs); - data->msgs = wpabuf_dup(msg); - if (data->msgs == NULL) { - wpabuf_free(msg); - return NULL; - } - - return msg; -} - - -static struct wpabuf * eap_eke_build_commit(struct eap_sm *sm, - struct eap_eke_data *data, u8 id) -{ - struct wpabuf *msg; - u8 pub[EAP_EKE_MAX_DH_LEN]; - - wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Commit"); - - if (sm->user == NULL || sm->user->password == NULL) { - wpa_printf(MSG_INFO, "EAP-EKE: Password with not configured"); - eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND); - return eap_eke_build_failure(data, id); - } - - if (eap_eke_derive_key(&data->sess, sm->user->password, - sm->user->password_len, - sm->server_id, sm->server_id_len, - data->peerid, data->peerid_len, data->key) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key"); - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return eap_eke_build_failure(data, id); - } - - msg = eap_eke_build_msg(data, id, data->sess.dhcomp_len, - EAP_EKE_COMMIT); - if (msg == NULL) { - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return eap_eke_build_failure(data, id); - } - - /* - * y_s = g ^ x_s (mod p) - * x_s = random number 2 .. p-1 - * temp = prf(0+, password) - * key = prf+(temp, ID_S | ID_P) - * DHComponent_S = Encr(key, y_s) - */ - - if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH"); - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return eap_eke_build_failure(data, id); - } - - if (eap_eke_dhcomp(&data->sess, data->key, pub, - wpabuf_put(msg, data->sess.dhcomp_len)) - < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S"); - wpabuf_free(msg); - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return eap_eke_build_failure(data, id); - } - - if (wpabuf_resize(&data->msgs, wpabuf_len(msg)) < 0) { - wpabuf_free(msg); - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return eap_eke_build_failure(data, id); - } - wpabuf_put_buf(data->msgs, msg); - - return msg; -} - - -static struct wpabuf * eap_eke_build_confirm(struct eap_sm *sm, - struct eap_eke_data *data, u8 id) -{ - struct wpabuf *msg; - size_t plen, prot_len; - u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN]; - u8 *auth; - - wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Confirm"); - - plen = data->sess.pnonce_ps_len + data->sess.prf_len; - msg = eap_eke_build_msg(data, id, plen, EAP_EKE_CONFIRM); - if (msg == NULL) { - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return eap_eke_build_failure(data, id); - } - - if (random_get_bytes(data->nonce_s, data->sess.nonce_len)) { - wpabuf_free(msg); - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return eap_eke_build_failure(data, id); - } - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S", - data->nonce_s, data->sess.nonce_len); - - os_memcpy(nonces, data->nonce_p, data->sess.nonce_len); - os_memcpy(nonces + data->sess.nonce_len, data->nonce_s, - data->sess.nonce_len); - prot_len = wpabuf_tailroom(msg); - if (eap_eke_prot(&data->sess, nonces, 2 * data->sess.nonce_len, - wpabuf_put(msg, 0), &prot_len) < 0) { - wpabuf_free(msg); - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return eap_eke_build_failure(data, id); - } - wpabuf_put(msg, prot_len); - - if (eap_eke_derive_ka(&data->sess, - sm->server_id, sm->server_id_len, - data->peerid, data->peerid_len, - data->nonce_p, data->nonce_s) < 0) { - wpabuf_free(msg); - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return eap_eke_build_failure(data, id); - } - - auth = wpabuf_put(msg, data->sess.prf_len); - if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth) < 0) { - wpabuf_free(msg); - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return eap_eke_build_failure(data, id); - } - wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth, data->sess.prf_len); - - return msg; -} - - -static struct wpabuf * eap_eke_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_eke_data *data = priv; - - switch (data->state) { - case IDENTITY: - return eap_eke_build_identity(sm, data, id); - case COMMIT: - return eap_eke_build_commit(sm, data, id); - case CONFIRM: - return eap_eke_build_confirm(sm, data, id); - case FAILURE_REPORT: - return eap_eke_build_failure(data, id); - default: - wpa_printf(MSG_DEBUG, "EAP-EKE: Unknown state %d in buildReq", - data->state); - break; - } - return NULL; -} - - -static Boolean eap_eke_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_eke_data *data = priv; - size_t len; - const u8 *pos; - u8 eke_exch; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len); - if (pos == NULL || len < 1) { - wpa_printf(MSG_INFO, "EAP-EKE: Invalid frame"); - return TRUE; - } - - eke_exch = *pos; - wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: EKE-Exch=%d", eke_exch); - - if (data->state == IDENTITY && eke_exch == EAP_EKE_ID) - return FALSE; - - if (data->state == COMMIT && eke_exch == EAP_EKE_COMMIT) - return FALSE; - - if (data->state == CONFIRM && eke_exch == EAP_EKE_CONFIRM) - return FALSE; - - if (eke_exch == EAP_EKE_FAILURE) - return FALSE; - - wpa_printf(MSG_INFO, "EAP-EKE: Unexpected EKE-Exch=%d in state=%d", - eke_exch, data->state); - - return TRUE; -} - - -static void eap_eke_process_identity(struct eap_sm *sm, - struct eap_eke_data *data, - const struct wpabuf *respData, - const u8 *payload, size_t payloadlen) -{ - const u8 *pos, *end; - int i; - - wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Identity"); - - if (data->state != IDENTITY) { - eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); - return; - } - - pos = payload; - end = payload + payloadlen; - - if (pos + 2 + 4 + 1 > end) { - wpa_printf(MSG_INFO, "EAP-EKE: Too short EAP-EKE-ID payload"); - eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); - return; - } - - if (*pos != 1) { - wpa_printf(MSG_INFO, "EAP-EKE: Unexpected NumProposals %d (expected 1)", - *pos); - eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); - return; - } - - pos += 2; - - if (!supported_proposal(pos)) { - wpa_printf(MSG_INFO, "EAP-EKE: Unexpected Proposal (%u:%u:%u:%u)", - pos[0], pos[1], pos[2], pos[3]); - eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); - return; - } - - wpa_printf(MSG_DEBUG, "EAP-EKE: Selected Proposal (%u:%u:%u:%u)", - pos[0], pos[1], pos[2], pos[3]); - if (eap_eke_session_init(&data->sess, pos[0], pos[1], pos[2], pos[3]) < - 0) { - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return; - } - pos += 4; - - data->peerid_type = *pos++; - os_free(data->peerid); - data->peerid = os_malloc(end - pos); - if (data->peerid == NULL) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to allocate memory for peerid"); - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return; - } - os_memcpy(data->peerid, pos, end - pos); - data->peerid_len = end - pos; - wpa_printf(MSG_DEBUG, "EAP-EKE: Peer IDType %u", data->peerid_type); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Peer Identity", - data->peerid, data->peerid_len); - - if (eap_user_get(sm, data->peerid, data->peerid_len, data->phase2)) { - wpa_printf(MSG_INFO, "EAP-EKE: Peer Identity not found from user database"); - eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND); - return; - } - - for (i = 0; i < EAP_MAX_METHODS; i++) { - if (sm->user->methods[i].vendor == EAP_VENDOR_IETF && - sm->user->methods[i].method == EAP_TYPE_EKE) - break; - } - if (i == EAP_MAX_METHODS) { - wpa_printf(MSG_INFO, "EAP-EKE: Matching user entry does not allow EAP-EKE"); - eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND); - return; - } - - if (sm->user->password == NULL || sm->user->password_len == 0) { - wpa_printf(MSG_INFO, "EAP-EKE: No password configured for peer"); - eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND); - return; - } - - if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) { - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return; - } - wpabuf_put_buf(data->msgs, respData); - - eap_eke_state(data, COMMIT); -} - - -static void eap_eke_process_commit(struct eap_sm *sm, - struct eap_eke_data *data, - const struct wpabuf *respData, - const u8 *payload, size_t payloadlen) -{ - const u8 *pos, *end, *dhcomp, *pnonce; - size_t decrypt_len; - - wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Commit"); - - if (data->state != COMMIT) { - eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); - return; - } - - pos = payload; - end = payload + payloadlen; - - if (pos + data->sess.dhcomp_len + data->sess.pnonce_len > end) { - wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit"); - eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); - return; - } - - wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P", - pos, data->sess.dhcomp_len); - dhcomp = pos; - pos += data->sess.dhcomp_len; - wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", pos, data->sess.pnonce_len); - pnonce = pos; - pos += data->sess.pnonce_len; - wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos); - - if (eap_eke_shared_secret(&data->sess, data->key, data->dh_priv, dhcomp) - < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret"); - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return; - } - - if (eap_eke_derive_ke_ki(&data->sess, - sm->server_id, sm->server_id_len, - data->peerid, data->peerid_len) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki"); - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return; - } - - decrypt_len = sizeof(data->nonce_p); - if (eap_eke_decrypt_prot(&data->sess, pnonce, data->sess.pnonce_len, - data->nonce_p, &decrypt_len) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_P"); - eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); - return; - } - if (decrypt_len < (size_t) data->sess.nonce_len) { - wpa_printf(MSG_INFO, "EAP-EKE: PNonce_P protected data too short to include Nonce_P"); - eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); - return; - } - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P", - data->nonce_p, data->sess.nonce_len); - - if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) { - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return; - } - wpabuf_put_buf(data->msgs, respData); - - eap_eke_state(data, CONFIRM); -} - - -static void eap_eke_process_confirm(struct eap_sm *sm, - struct eap_eke_data *data, - const struct wpabuf *respData, - const u8 *payload, size_t payloadlen) -{ - size_t decrypt_len; - u8 nonce[EAP_EKE_MAX_NONCE_LEN]; - u8 auth_p[EAP_EKE_MAX_HASH_LEN]; - - wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm"); - - if (data->state != CONFIRM) { - eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); - return; - } - - wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm"); - - if (payloadlen < (size_t) data->sess.pnonce_len + data->sess.prf_len) { - wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm"); - eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); - return; - } - - decrypt_len = sizeof(nonce); - if (eap_eke_decrypt_prot(&data->sess, payload, data->sess.pnonce_len, - nonce, &decrypt_len) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_S"); - eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); - return; - } - if (decrypt_len < (size_t) data->sess.nonce_len) { - wpa_printf(MSG_INFO, "EAP-EKE: PNonce_S protected data too short to include Nonce_S"); - eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); - return; - } - wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_S", - nonce, data->sess.nonce_len); - if (os_memcmp(nonce, data->nonce_s, data->sess.nonce_len) != 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_S does not match previously sent Nonce_S"); - eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); - return; - } - - if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth_p) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Could not derive Auth_P"); - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return; - } - wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth_p, data->sess.prf_len); - if (os_memcmp(auth_p, payload + data->sess.pnonce_len, - data->sess.prf_len) != 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Auth_P does not match"); - eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); - return; - } - - if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len, - data->peerid, data->peerid_len, - data->nonce_s, data->nonce_p, - data->msk, data->emsk) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK"); - eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); - return; - } - - os_memset(data->dh_priv, 0, sizeof(data->dh_priv)); - os_memset(data->key, 0, sizeof(data->key)); - eap_eke_session_clean(&data->sess); - - eap_eke_state(data, SUCCESS); -} - - -static void eap_eke_process_failure(struct eap_sm *sm, - struct eap_eke_data *data, - const struct wpabuf *respData, - const u8 *payload, size_t payloadlen) -{ - u32 code; - - wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Failure"); - - if (payloadlen < 4) { - wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure"); - eap_eke_state(data, FAILURE); - return; - } - - code = WPA_GET_BE32(payload); - wpa_printf(MSG_DEBUG, "EAP-EKE: Peer reported failure code 0x%x", code); - - eap_eke_state(data, FAILURE); -} - - -static void eap_eke_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_eke_data *data = priv; - u8 eke_exch; - size_t len; - const u8 *pos, *end; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len); - if (pos == NULL || len < 1) - return; - - eke_exch = *pos; - end = pos + len; - pos++; - - wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received payload", pos, end - pos); - - switch (eke_exch) { - case EAP_EKE_ID: - eap_eke_process_identity(sm, data, respData, pos, end - pos); - break; - case EAP_EKE_COMMIT: - eap_eke_process_commit(sm, data, respData, pos, end - pos); - break; - case EAP_EKE_CONFIRM: - eap_eke_process_confirm(sm, data, respData, pos, end - pos); - break; - case EAP_EKE_FAILURE: - eap_eke_process_failure(sm, data, respData, pos, end - pos); - break; - } -} - - -static Boolean eap_eke_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_eke_data *data = priv; - return data->state == SUCCESS || data->state == FAILURE; -} - - -static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_eke_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->msk, EAP_MSK_LEN); - *len = EAP_MSK_LEN; - - return key; -} - - -static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_eke_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - *len = EAP_EMSK_LEN; - - return key; -} - - -static Boolean eap_eke_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_eke_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_eke_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE"); - if (eap == NULL) - return -1; - - eap->init = eap_eke_init; - eap->reset = eap_eke_reset; - eap->buildReq = eap_eke_buildReq; - eap->check = eap_eke_check; - eap->process = eap_eke_process; - eap->isDone = eap_eke_isDone; - eap->getKey = eap_eke_getKey; - eap->isSuccess = eap_eke_isSuccess; - eap->get_emsk = eap_eke_get_emsk; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_fast.c b/contrib/hostapd/src/eap_server/eap_server_fast.c deleted file mode 100644 index fcb80dc756..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_fast.c +++ /dev/null @@ -1,1614 +0,0 @@ -/* - * EAP-FAST server (RFC 4851) - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/aes_wrap.h" -#include "crypto/sha1.h" -#include "crypto/tls.h" -#include "crypto/random.h" -#include "eap_common/eap_tlv_common.h" -#include "eap_common/eap_fast_common.h" -#include "eap_i.h" -#include "eap_tls_common.h" - - -static void eap_fast_reset(struct eap_sm *sm, void *priv); - - -/* Private PAC-Opaque TLV types */ -#define PAC_OPAQUE_TYPE_PAD 0 -#define PAC_OPAQUE_TYPE_KEY 1 -#define PAC_OPAQUE_TYPE_LIFETIME 2 -#define PAC_OPAQUE_TYPE_IDENTITY 3 - -struct eap_fast_data { - struct eap_ssl_data ssl; - enum { - START, PHASE1, PHASE2_START, PHASE2_ID, PHASE2_METHOD, - CRYPTO_BINDING, REQUEST_PAC, SUCCESS, FAILURE - } state; - - int fast_version; - const struct eap_method *phase2_method; - void *phase2_priv; - int force_version; - int peer_version; - - u8 crypto_binding_nonce[32]; - int final_result; - - struct eap_fast_key_block_provisioning *key_block_p; - - u8 simck[EAP_FAST_SIMCK_LEN]; - u8 cmk[EAP_FAST_CMK_LEN]; - int simck_idx; - - u8 pac_opaque_encr[16]; - u8 *srv_id; - size_t srv_id_len; - char *srv_id_info; - - int anon_provisioning; - int send_new_pac; /* server triggered re-keying of Tunnel PAC */ - struct wpabuf *pending_phase2_resp; - u8 *identity; /* from PAC-Opaque */ - size_t identity_len; - int eap_seq; - int tnc_started; - - int pac_key_lifetime; - int pac_key_refresh_time; -}; - - -static int eap_fast_process_phase2_start(struct eap_sm *sm, - struct eap_fast_data *data); - - -static const char * eap_fast_state_txt(int state) -{ - switch (state) { - case START: - return "START"; - case PHASE1: - return "PHASE1"; - case PHASE2_START: - return "PHASE2_START"; - case PHASE2_ID: - return "PHASE2_ID"; - case PHASE2_METHOD: - return "PHASE2_METHOD"; - case CRYPTO_BINDING: - return "CRYPTO_BINDING"; - case REQUEST_PAC: - return "REQUEST_PAC"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "Unknown?!"; - } -} - - -static void eap_fast_state(struct eap_fast_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-FAST: %s -> %s", - eap_fast_state_txt(data->state), - eap_fast_state_txt(state)); - data->state = state; -} - - -static EapType eap_fast_req_failure(struct eap_sm *sm, - struct eap_fast_data *data) -{ - /* TODO: send Result TLV(FAILURE) */ - eap_fast_state(data, FAILURE); - return EAP_TYPE_NONE; -} - - -static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len, - const u8 *client_random, - const u8 *server_random, - u8 *master_secret) -{ - struct eap_fast_data *data = ctx; - const u8 *pac_opaque; - size_t pac_opaque_len; - u8 *buf, *pos, *end, *pac_key = NULL; - os_time_t lifetime = 0; - struct os_time now; - u8 *identity = NULL; - size_t identity_len = 0; - - wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback"); - wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket (PAC-Opaque)", - ticket, len); - - if (len < 4 || WPA_GET_BE16(ticket) != PAC_TYPE_PAC_OPAQUE) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid " - "SessionTicket"); - return 0; - } - - pac_opaque_len = WPA_GET_BE16(ticket + 2); - pac_opaque = ticket + 4; - if (pac_opaque_len < 8 || pac_opaque_len % 8 || - pac_opaque_len > len - 4) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid PAC-Opaque " - "(len=%lu left=%lu)", - (unsigned long) pac_opaque_len, - (unsigned long) len); - return 0; - } - wpa_hexdump(MSG_DEBUG, "EAP-FAST: Received PAC-Opaque", - pac_opaque, pac_opaque_len); - - buf = os_malloc(pac_opaque_len - 8); - if (buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory " - "for decrypting PAC-Opaque"); - return 0; - } - - if (aes_unwrap(data->pac_opaque_encr, (pac_opaque_len - 8) / 8, - pac_opaque, buf) < 0) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to decrypt " - "PAC-Opaque"); - os_free(buf); - /* - * This may have been caused by server changing the PAC-Opaque - * encryption key, so just ignore this PAC-Opaque instead of - * failing the authentication completely. Provisioning can now - * be used to provision a new PAC. - */ - return 0; - } - - end = buf + pac_opaque_len - 8; - wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Decrypted PAC-Opaque", - buf, end - buf); - - pos = buf; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - - switch (*pos) { - case PAC_OPAQUE_TYPE_PAD: - pos = end; - break; - case PAC_OPAQUE_TYPE_KEY: - if (pos[1] != EAP_FAST_PAC_KEY_LEN) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid " - "PAC-Key length %d", pos[1]); - os_free(buf); - return -1; - } - pac_key = pos + 2; - wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key from " - "decrypted PAC-Opaque", - pac_key, EAP_FAST_PAC_KEY_LEN); - break; - case PAC_OPAQUE_TYPE_LIFETIME: - if (pos[1] != 4) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid " - "PAC-Key lifetime length %d", - pos[1]); - os_free(buf); - return -1; - } - lifetime = WPA_GET_BE32(pos + 2); - break; - case PAC_OPAQUE_TYPE_IDENTITY: - identity = pos + 2; - identity_len = pos[1]; - break; - } - - pos += 2 + pos[1]; - } - - if (pac_key == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key included in " - "PAC-Opaque"); - os_free(buf); - return -1; - } - - if (identity) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Identity from " - "PAC-Opaque", identity, identity_len); - os_free(data->identity); - data->identity = os_malloc(identity_len); - if (data->identity) { - os_memcpy(data->identity, identity, identity_len); - data->identity_len = identity_len; - } - } - - if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) { - wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key not valid anymore " - "(lifetime=%ld now=%ld)", lifetime, now.sec); - data->send_new_pac = 2; - /* - * Allow PAC to be used to allow a PAC update with some level - * of server authentication (i.e., do not fall back to full TLS - * handshake since we cannot be sure that the peer would be - * able to validate server certificate now). However, reject - * the authentication since the PAC was not valid anymore. Peer - * can connect again with the newly provisioned PAC after this. - */ - } else if (lifetime - now.sec < data->pac_key_refresh_time) { - wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key soft timeout; send " - "an update if authentication succeeds"); - data->send_new_pac = 1; - } - - eap_fast_derive_master_secret(pac_key, server_random, client_random, - master_secret); - - os_free(buf); - - return 1; -} - - -static void eap_fast_derive_key_auth(struct eap_sm *sm, - struct eap_fast_data *data) -{ - u8 *sks; - - /* RFC 4851, Section 5.1: - * Extra key material after TLS key_block: session_key_seed[40] - */ - - sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion", - EAP_FAST_SKS_LEN); - if (sks == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive " - "session_key_seed"); - return; - } - - /* - * RFC 4851, Section 5.2: - * S-IMCK[0] = session_key_seed - */ - wpa_hexdump_key(MSG_DEBUG, - "EAP-FAST: session_key_seed (SKS = S-IMCK[0])", - sks, EAP_FAST_SKS_LEN); - data->simck_idx = 0; - os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN); - os_free(sks); -} - - -static void eap_fast_derive_key_provisioning(struct eap_sm *sm, - struct eap_fast_data *data) -{ - os_free(data->key_block_p); - data->key_block_p = (struct eap_fast_key_block_provisioning *) - eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, - "key expansion", - sizeof(*data->key_block_p)); - if (data->key_block_p == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block"); - return; - } - /* - * RFC 4851, Section 5.2: - * S-IMCK[0] = session_key_seed - */ - wpa_hexdump_key(MSG_DEBUG, - "EAP-FAST: session_key_seed (SKS = S-IMCK[0])", - data->key_block_p->session_key_seed, - sizeof(data->key_block_p->session_key_seed)); - data->simck_idx = 0; - os_memcpy(data->simck, data->key_block_p->session_key_seed, - EAP_FAST_SIMCK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge", - data->key_block_p->server_challenge, - sizeof(data->key_block_p->server_challenge)); - wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge", - data->key_block_p->client_challenge, - sizeof(data->key_block_p->client_challenge)); -} - - -static int eap_fast_get_phase2_key(struct eap_sm *sm, - struct eap_fast_data *data, - u8 *isk, size_t isk_len) -{ - u8 *key; - size_t key_len; - - os_memset(isk, 0, isk_len); - - if (data->phase2_method == NULL || data->phase2_priv == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not " - "available"); - return -1; - } - - if (data->phase2_method->getKey == NULL) - return 0; - - if ((key = data->phase2_method->getKey(sm, data->phase2_priv, - &key_len)) == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material " - "from Phase 2"); - return -1; - } - - if (key_len > isk_len) - key_len = isk_len; - if (key_len == 32 && - data->phase2_method->vendor == EAP_VENDOR_IETF && - data->phase2_method->method == EAP_TYPE_MSCHAPV2) { - /* - * EAP-FAST uses reverse order for MS-MPPE keys when deriving - * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct - * ISK for EAP-FAST cryptobinding. - */ - os_memcpy(isk, key + 16, 16); - os_memcpy(isk + 16, key, 16); - } else - os_memcpy(isk, key, key_len); - os_free(key); - - return 0; -} - - -static int eap_fast_update_icmk(struct eap_sm *sm, struct eap_fast_data *data) -{ - u8 isk[32], imck[60]; - - wpa_printf(MSG_DEBUG, "EAP-FAST: Deriving ICMK[%d] (S-IMCK and CMK)", - data->simck_idx + 1); - - /* - * RFC 4851, Section 5.2: - * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys", - * MSK[j], 60) - * S-IMCK[j] = first 40 octets of IMCK[j] - * CMK[j] = last 20 octets of IMCK[j] - */ - - if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0) - return -1; - wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk)); - sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN, - "Inner Methods Compound Keys", - isk, sizeof(isk), imck, sizeof(imck)); - data->simck_idx++; - os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN); - wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]", - data->simck, EAP_FAST_SIMCK_LEN); - os_memcpy(data->cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN); - wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", - data->cmk, EAP_FAST_CMK_LEN); - - return 0; -} - - -static void * eap_fast_init(struct eap_sm *sm) -{ - struct eap_fast_data *data; - u8 ciphers[5] = { - TLS_CIPHER_ANON_DH_AES128_SHA, - TLS_CIPHER_AES128_SHA, - TLS_CIPHER_RSA_DHE_AES128_SHA, - TLS_CIPHER_RC4_SHA, - TLS_CIPHER_NONE - }; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->fast_version = EAP_FAST_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-FAST: forcing version %d", - data->force_version); - data->fast_version = data->force_version; - } - data->state = START; - - if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) { - wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL."); - eap_fast_reset(sm, data); - return NULL; - } - - if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn, - ciphers) < 0) { - wpa_printf(MSG_INFO, "EAP-FAST: Failed to set TLS cipher " - "suites"); - eap_fast_reset(sm, data); - return NULL; - } - - if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn, - eap_fast_session_ticket_cb, - data) < 0) { - wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket " - "callback"); - eap_fast_reset(sm, data); - return NULL; - } - - if (sm->pac_opaque_encr_key == NULL) { - wpa_printf(MSG_INFO, "EAP-FAST: No PAC-Opaque encryption key " - "configured"); - eap_fast_reset(sm, data); - return NULL; - } - os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key, - sizeof(data->pac_opaque_encr)); - - if (sm->eap_fast_a_id == NULL) { - wpa_printf(MSG_INFO, "EAP-FAST: No A-ID configured"); - eap_fast_reset(sm, data); - return NULL; - } - data->srv_id = os_malloc(sm->eap_fast_a_id_len); - if (data->srv_id == NULL) { - eap_fast_reset(sm, data); - return NULL; - } - os_memcpy(data->srv_id, sm->eap_fast_a_id, sm->eap_fast_a_id_len); - data->srv_id_len = sm->eap_fast_a_id_len; - - if (sm->eap_fast_a_id_info == NULL) { - wpa_printf(MSG_INFO, "EAP-FAST: No A-ID-Info configured"); - eap_fast_reset(sm, data); - return NULL; - } - data->srv_id_info = os_strdup(sm->eap_fast_a_id_info); - if (data->srv_id_info == NULL) { - eap_fast_reset(sm, data); - return NULL; - } - - /* PAC-Key lifetime in seconds (hard limit) */ - data->pac_key_lifetime = sm->pac_key_lifetime; - - /* - * PAC-Key refresh time in seconds (soft limit on remaining hard - * limit). The server will generate a new PAC-Key when this number of - * seconds (or fewer) of the lifetime remains. - */ - data->pac_key_refresh_time = sm->pac_key_refresh_time; - - return data; -} - - -static void eap_fast_reset(struct eap_sm *sm, void *priv) -{ - struct eap_fast_data *data = priv; - if (data == NULL) - return; - if (data->phase2_priv && data->phase2_method) - data->phase2_method->reset(sm, data->phase2_priv); - eap_server_tls_ssl_deinit(sm, &data->ssl); - os_free(data->srv_id); - os_free(data->srv_id_info); - os_free(data->key_block_p); - wpabuf_free(data->pending_phase2_resp); - os_free(data->identity); - os_free(data); -} - - -static struct wpabuf * eap_fast_build_start(struct eap_sm *sm, - struct eap_fast_data *data, u8 id) -{ - struct wpabuf *req; - - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_FAST, - 1 + sizeof(struct pac_tlv_hdr) + data->srv_id_len, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-FAST: Failed to allocate memory for" - " request"); - eap_fast_state(data, FAILURE); - return NULL; - } - - wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->fast_version); - - /* RFC 4851, 4.1.1. Authority ID Data */ - eap_fast_put_tlv(req, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len); - - eap_fast_state(data, PHASE1); - - return req; -} - - -static int eap_fast_phase1_done(struct eap_sm *sm, struct eap_fast_data *data) -{ - char cipher[64]; - - wpa_printf(MSG_DEBUG, "EAP-FAST: Phase1 done, starting Phase2"); - - if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher)) - < 0) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to get cipher " - "information"); - eap_fast_state(data, FAILURE); - return -1; - } - data->anon_provisioning = os_strstr(cipher, "ADH") != NULL; - - if (data->anon_provisioning) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Anonymous provisioning"); - eap_fast_derive_key_provisioning(sm, data); - } else - eap_fast_derive_key_auth(sm, data); - - eap_fast_state(data, PHASE2_START); - - return 0; -} - - -static struct wpabuf * eap_fast_build_phase2_req(struct eap_sm *sm, - struct eap_fast_data *data, - u8 id) -{ - struct wpabuf *req; - - if (data->phase2_priv == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not " - "initialized"); - return NULL; - } - req = data->phase2_method->buildReq(sm, data->phase2_priv, id); - if (req == NULL) - return NULL; - - wpa_hexdump_buf_key(MSG_MSGDUMP, "EAP-FAST: Phase 2 EAP-Request", req); - return eap_fast_tlv_eap_payload(req); -} - - -static struct wpabuf * eap_fast_build_crypto_binding( - struct eap_sm *sm, struct eap_fast_data *data) -{ - struct wpabuf *buf; - struct eap_tlv_result_tlv *result; - struct eap_tlv_crypto_binding_tlv *binding; - - buf = wpabuf_alloc(2 * sizeof(*result) + sizeof(*binding)); - if (buf == NULL) - return NULL; - - if (data->send_new_pac || data->anon_provisioning || - data->phase2_method) - data->final_result = 0; - else - data->final_result = 1; - - if (!data->final_result || data->eap_seq > 1) { - /* Intermediate-Result */ - wpa_printf(MSG_DEBUG, "EAP-FAST: Add Intermediate-Result TLV " - "(status=SUCCESS)"); - result = wpabuf_put(buf, sizeof(*result)); - result->tlv_type = host_to_be16( - EAP_TLV_TYPE_MANDATORY | - EAP_TLV_INTERMEDIATE_RESULT_TLV); - result->length = host_to_be16(2); - result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS); - } - - if (data->final_result) { - /* Result TLV */ - wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV " - "(status=SUCCESS)"); - result = wpabuf_put(buf, sizeof(*result)); - result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | - EAP_TLV_RESULT_TLV); - result->length = host_to_be16(2); - result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS); - } - - /* Crypto-Binding TLV */ - binding = wpabuf_put(buf, sizeof(*binding)); - binding->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | - EAP_TLV_CRYPTO_BINDING_TLV); - binding->length = host_to_be16(sizeof(*binding) - - sizeof(struct eap_tlv_hdr)); - binding->version = EAP_FAST_VERSION; - binding->received_version = data->peer_version; - binding->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST; - if (random_get_bytes(binding->nonce, sizeof(binding->nonce)) < 0) { - wpabuf_free(buf); - return NULL; - } - - /* - * RFC 4851, Section 4.2.8: - * The nonce in a request MUST have its least significant bit set to 0. - */ - binding->nonce[sizeof(binding->nonce) - 1] &= ~0x01; - - os_memcpy(data->crypto_binding_nonce, binding->nonce, - sizeof(binding->nonce)); - - /* - * RFC 4851, Section 5.3: - * CMK = CMK[j] - * Compound-MAC = HMAC-SHA1( CMK, Crypto-Binding TLV ) - */ - - hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, - (u8 *) binding, sizeof(*binding), - binding->compound_mac); - - wpa_printf(MSG_DEBUG, "EAP-FAST: Add Crypto-Binding TLV: Version %d " - "Received Version %d SubType %d", - binding->version, binding->received_version, - binding->subtype); - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", - binding->nonce, sizeof(binding->nonce)); - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", - binding->compound_mac, sizeof(binding->compound_mac)); - - return buf; -} - - -static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm, - struct eap_fast_data *data) -{ - u8 pac_key[EAP_FAST_PAC_KEY_LEN]; - u8 *pac_buf, *pac_opaque; - struct wpabuf *buf; - u8 *pos; - size_t buf_len, srv_id_info_len, pac_len; - struct eap_tlv_hdr *pac_tlv; - struct pac_tlv_hdr *pac_info; - struct eap_tlv_result_tlv *result; - struct os_time now; - - if (random_get_bytes(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 || - os_get_time(&now) < 0) - return NULL; - wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key", - pac_key, EAP_FAST_PAC_KEY_LEN); - - pac_len = (2 + EAP_FAST_PAC_KEY_LEN) + (2 + 4) + - (2 + sm->identity_len) + 8; - pac_buf = os_malloc(pac_len); - if (pac_buf == NULL) - return NULL; - - srv_id_info_len = os_strlen(data->srv_id_info); - - pos = pac_buf; - *pos++ = PAC_OPAQUE_TYPE_KEY; - *pos++ = EAP_FAST_PAC_KEY_LEN; - os_memcpy(pos, pac_key, EAP_FAST_PAC_KEY_LEN); - pos += EAP_FAST_PAC_KEY_LEN; - - *pos++ = PAC_OPAQUE_TYPE_LIFETIME; - *pos++ = 4; - WPA_PUT_BE32(pos, now.sec + data->pac_key_lifetime); - pos += 4; - - if (sm->identity) { - *pos++ = PAC_OPAQUE_TYPE_IDENTITY; - *pos++ = sm->identity_len; - os_memcpy(pos, sm->identity, sm->identity_len); - pos += sm->identity_len; - } - - pac_len = pos - pac_buf; - while (pac_len % 8) { - *pos++ = PAC_OPAQUE_TYPE_PAD; - pac_len++; - } - - pac_opaque = os_malloc(pac_len + 8); - if (pac_opaque == NULL) { - os_free(pac_buf); - return NULL; - } - if (aes_wrap(data->pac_opaque_encr, pac_len / 8, pac_buf, - pac_opaque) < 0) { - os_free(pac_buf); - os_free(pac_opaque); - return NULL; - } - os_free(pac_buf); - - pac_len += 8; - wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque", - pac_opaque, pac_len); - - buf_len = sizeof(*pac_tlv) + - sizeof(struct pac_tlv_hdr) + EAP_FAST_PAC_KEY_LEN + - sizeof(struct pac_tlv_hdr) + pac_len + - data->srv_id_len + srv_id_info_len + 100 + sizeof(*result); - buf = wpabuf_alloc(buf_len); - if (buf == NULL) { - os_free(pac_opaque); - return NULL; - } - - /* Result TLV */ - wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)"); - result = wpabuf_put(buf, sizeof(*result)); - WPA_PUT_BE16((u8 *) &result->tlv_type, - EAP_TLV_TYPE_MANDATORY | EAP_TLV_RESULT_TLV); - WPA_PUT_BE16((u8 *) &result->length, 2); - WPA_PUT_BE16((u8 *) &result->status, EAP_TLV_RESULT_SUCCESS); - - /* PAC TLV */ - wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV"); - pac_tlv = wpabuf_put(buf, sizeof(*pac_tlv)); - pac_tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | - EAP_TLV_PAC_TLV); - - /* PAC-Key */ - eap_fast_put_tlv(buf, PAC_TYPE_PAC_KEY, pac_key, EAP_FAST_PAC_KEY_LEN); - - /* PAC-Opaque */ - eap_fast_put_tlv(buf, PAC_TYPE_PAC_OPAQUE, pac_opaque, pac_len); - os_free(pac_opaque); - - /* PAC-Info */ - pac_info = wpabuf_put(buf, sizeof(*pac_info)); - pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO); - - /* PAC-Lifetime (inside PAC-Info) */ - eap_fast_put_tlv_hdr(buf, PAC_TYPE_CRED_LIFETIME, 4); - wpabuf_put_be32(buf, now.sec + data->pac_key_lifetime); - - /* A-ID (inside PAC-Info) */ - eap_fast_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len); - - /* Note: headers may be misaligned after A-ID */ - - if (sm->identity) { - eap_fast_put_tlv(buf, PAC_TYPE_I_ID, sm->identity, - sm->identity_len); - } - - /* A-ID-Info (inside PAC-Info) */ - eap_fast_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id_info, - srv_id_info_len); - - /* PAC-Type (inside PAC-Info) */ - eap_fast_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2); - wpabuf_put_be16(buf, PAC_TYPE_TUNNEL_PAC); - - /* Update PAC-Info and PAC TLV Length fields */ - pos = wpabuf_put(buf, 0); - pac_info->len = host_to_be16(pos - (u8 *) (pac_info + 1)); - pac_tlv->length = host_to_be16(pos - (u8 *) (pac_tlv + 1)); - - return buf; -} - - -static int eap_fast_encrypt_phase2(struct eap_sm *sm, - struct eap_fast_data *data, - struct wpabuf *plain, int piggyback) -{ - struct wpabuf *encr; - - wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs", - plain); - encr = eap_server_tls_encrypt(sm, &data->ssl, plain); - wpabuf_free(plain); - - if (data->ssl.tls_out && piggyback) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data " - "(len=%d) with last Phase 1 Message (len=%d " - "used=%d)", - (int) wpabuf_len(encr), - (int) wpabuf_len(data->ssl.tls_out), - (int) data->ssl.tls_out_pos); - if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) { - wpa_printf(MSG_WARNING, "EAP-FAST: Failed to resize " - "output buffer"); - wpabuf_free(encr); - return -1; - } - wpabuf_put_buf(data->ssl.tls_out, encr); - wpabuf_free(encr); - } else { - wpabuf_free(data->ssl.tls_out); - data->ssl.tls_out_pos = 0; - data->ssl.tls_out = encr; - } - - return 0; -} - - -static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_fast_data *data = priv; - struct wpabuf *req = NULL; - int piggyback = 0; - - if (data->ssl.state == FRAG_ACK) { - return eap_server_tls_build_ack(id, EAP_TYPE_FAST, - data->fast_version); - } - - if (data->ssl.state == WAIT_FRAG_ACK) { - return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST, - data->fast_version, id); - } - - switch (data->state) { - case START: - return eap_fast_build_start(sm, data, id); - case PHASE1: - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { - if (eap_fast_phase1_done(sm, data) < 0) - return NULL; - if (data->state == PHASE2_START) { - /* - * Try to generate Phase 2 data to piggyback - * with the end of Phase 1 to avoid extra - * roundtrip. - */ - wpa_printf(MSG_DEBUG, "EAP-FAST: Try to start " - "Phase 2"); - if (eap_fast_process_phase2_start(sm, data)) - break; - req = eap_fast_build_phase2_req(sm, data, id); - piggyback = 1; - } - } - break; - case PHASE2_ID: - case PHASE2_METHOD: - req = eap_fast_build_phase2_req(sm, data, id); - break; - case CRYPTO_BINDING: - req = eap_fast_build_crypto_binding(sm, data); - if (data->phase2_method) { - /* - * Include the start of the next EAP method in the - * sequence in the same message with Crypto-Binding to - * save a round-trip. - */ - struct wpabuf *eap; - eap = eap_fast_build_phase2_req(sm, data, id); - req = wpabuf_concat(req, eap); - eap_fast_state(data, PHASE2_METHOD); - } - break; - case REQUEST_PAC: - req = eap_fast_build_pac(sm, data); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d", - __func__, data->state); - return NULL; - } - - if (req && - eap_fast_encrypt_phase2(sm, data, req, piggyback) < 0) - return NULL; - - return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST, - data->fast_version, id); -} - - -static Boolean eap_fast_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData, &len); - if (pos == NULL || len < 1) { - wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame"); - return TRUE; - } - - return FALSE; -} - - -static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data, - EapType eap_type) -{ - if (data->phase2_priv && data->phase2_method) { - data->phase2_method->reset(sm, data->phase2_priv); - data->phase2_method = NULL; - data->phase2_priv = NULL; - } - data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF, - eap_type); - if (!data->phase2_method) - return -1; - - if (data->key_block_p) { - sm->auth_challenge = data->key_block_p->server_challenge; - sm->peer_challenge = data->key_block_p->client_challenge; - } - sm->init_phase2 = 1; - data->phase2_priv = data->phase2_method->init(sm); - sm->init_phase2 = 0; - sm->auth_challenge = NULL; - sm->peer_challenge = NULL; - - return data->phase2_priv == NULL ? -1 : 0; -} - - -static void eap_fast_process_phase2_response(struct eap_sm *sm, - struct eap_fast_data *data, - u8 *in_data, size_t in_len) -{ - u8 next_type = EAP_TYPE_NONE; - struct eap_hdr *hdr; - u8 *pos; - size_t left; - struct wpabuf buf; - const struct eap_method *m = data->phase2_method; - void *priv = data->phase2_priv; - - if (priv == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: %s - Phase2 not " - "initialized?!", __func__); - return; - } - - hdr = (struct eap_hdr *) in_data; - pos = (u8 *) (hdr + 1); - - if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { - left = in_len - sizeof(*hdr); - wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; " - "allowed types", pos + 1, left - 1); -#ifdef EAP_SERVER_TNC - if (m && m->vendor == EAP_VENDOR_IETF && - m->method == EAP_TYPE_TNC) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required " - "TNC negotiation"); - next_type = eap_fast_req_failure(sm, data); - eap_fast_phase2_init(sm, data, next_type); - return; - } -#endif /* EAP_SERVER_TNC */ - eap_sm_process_nak(sm, pos + 1, left - 1); - if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && - sm->user->methods[sm->user_eap_method_index].method != - EAP_TYPE_NONE) { - next_type = sm->user->methods[ - sm->user_eap_method_index++].method; - wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", - next_type); - } else { - next_type = eap_fast_req_failure(sm, data); - } - eap_fast_phase2_init(sm, data, next_type); - return; - } - - wpabuf_set(&buf, in_data, in_len); - - if (m->check(sm, priv, &buf)) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to " - "ignore the packet"); - next_type = eap_fast_req_failure(sm, data); - return; - } - - m->process(sm, priv, &buf); - - if (!m->isDone(sm, priv)) - return; - - if (!m->isSuccess(sm, priv)) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed"); - next_type = eap_fast_req_failure(sm, data); - eap_fast_phase2_init(sm, data, next_type); - return; - } - - switch (data->state) { - case PHASE2_ID: - if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Phase2 " - "Identity not found in the user " - "database", - sm->identity, sm->identity_len); - next_type = eap_fast_req_failure(sm, data); - break; - } - - eap_fast_state(data, PHASE2_METHOD); - if (data->anon_provisioning) { - /* - * Only EAP-MSCHAPv2 is allowed for anonymous - * provisioning. - */ - next_type = EAP_TYPE_MSCHAPV2; - sm->user_eap_method_index = 0; - } else { - next_type = sm->user->methods[0].method; - sm->user_eap_method_index = 1; - } - wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type); - break; - case PHASE2_METHOD: - case CRYPTO_BINDING: - eap_fast_update_icmk(sm, data); - eap_fast_state(data, CRYPTO_BINDING); - data->eap_seq++; - next_type = EAP_TYPE_NONE; -#ifdef EAP_SERVER_TNC - if (sm->tnc && !data->tnc_started) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC"); - next_type = EAP_TYPE_TNC; - data->tnc_started = 1; - } -#endif /* EAP_SERVER_TNC */ - break; - case FAILURE: - break; - default: - wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d", - __func__, data->state); - break; - } - - eap_fast_phase2_init(sm, data, next_type); -} - - -static void eap_fast_process_phase2_eap(struct eap_sm *sm, - struct eap_fast_data *data, - u8 *in_data, size_t in_len) -{ - struct eap_hdr *hdr; - size_t len; - - hdr = (struct eap_hdr *) in_data; - if (in_len < (int) sizeof(*hdr)) { - wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 " - "EAP frame (len=%lu)", (unsigned long) in_len); - eap_fast_req_failure(sm, data); - return; - } - len = be_to_host16(hdr->length); - if (len > in_len) { - wpa_printf(MSG_INFO, "EAP-FAST: Length mismatch in " - "Phase 2 EAP frame (len=%lu hdr->length=%lu)", - (unsigned long) in_len, (unsigned long) len); - eap_fast_req_failure(sm, data); - return; - } - wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: code=%d " - "identifier=%d length=%lu", hdr->code, hdr->identifier, - (unsigned long) len); - switch (hdr->code) { - case EAP_CODE_RESPONSE: - eap_fast_process_phase2_response(sm, data, (u8 *) hdr, len); - break; - default: - wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in " - "Phase 2 EAP header", hdr->code); - break; - } -} - - -static int eap_fast_parse_tlvs(struct wpabuf *data, - struct eap_fast_tlv_parse *tlv) -{ - int mandatory, tlv_type, len, res; - u8 *pos, *end; - - os_memset(tlv, 0, sizeof(*tlv)); - - pos = wpabuf_mhead(data); - end = pos + wpabuf_len(data); - while (pos + 4 < end) { - mandatory = pos[0] & 0x80; - tlv_type = WPA_GET_BE16(pos) & 0x3fff; - pos += 2; - len = WPA_GET_BE16(pos); - pos += 2; - if (pos + len > end) { - wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow"); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: " - "TLV type %d length %d%s", - tlv_type, len, mandatory ? " (mandatory)" : ""); - - res = eap_fast_parse_tlv(tlv, tlv_type, pos, len); - if (res == -2) - break; - if (res < 0) { - if (mandatory) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown " - "mandatory TLV type %d", tlv_type); - /* TODO: generate Nak TLV */ - break; - } else { - wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored " - "unknown optional TLV type %d", - tlv_type); - } - } - - pos += len; - } - - return 0; -} - - -static int eap_fast_validate_crypto_binding( - struct eap_fast_data *data, struct eap_tlv_crypto_binding_tlv *b, - size_t bind_len) -{ - u8 cmac[SHA1_MAC_LEN]; - - wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: " - "Version %d Received Version %d SubType %d", - b->version, b->received_version, b->subtype); - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", - b->nonce, sizeof(b->nonce)); - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", - b->compound_mac, sizeof(b->compound_mac)); - - if (b->version != EAP_FAST_VERSION || - b->received_version != EAP_FAST_VERSION) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected version " - "in Crypto-Binding: version %d " - "received_version %d", b->version, - b->received_version); - return -1; - } - - if (b->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected subtype in " - "Crypto-Binding: %d", b->subtype); - return -1; - } - - if (os_memcmp(data->crypto_binding_nonce, b->nonce, 31) != 0 || - (data->crypto_binding_nonce[31] | 1) != b->nonce[31]) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in " - "Crypto-Binding"); - return -1; - } - - os_memcpy(cmac, b->compound_mac, sizeof(cmac)); - os_memset(b->compound_mac, 0, sizeof(cmac)); - wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for " - "Compound MAC calculation", - (u8 *) b, bind_len); - hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) b, bind_len, - b->compound_mac); - if (os_memcmp(cmac, b->compound_mac, sizeof(cmac)) != 0) { - wpa_hexdump(MSG_MSGDUMP, - "EAP-FAST: Calculated Compound MAC", - b->compound_mac, sizeof(cmac)); - wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not " - "match"); - return -1; - } - - return 0; -} - - -static int eap_fast_pac_type(u8 *pac, size_t len, u16 type) -{ - struct eap_tlv_pac_type_tlv *tlv; - - if (pac == NULL || len != sizeof(*tlv)) - return 0; - - tlv = (struct eap_tlv_pac_type_tlv *) pac; - - return be_to_host16(tlv->tlv_type) == PAC_TYPE_PAC_TYPE && - be_to_host16(tlv->length) == 2 && - be_to_host16(tlv->pac_type) == type; -} - - -static void eap_fast_process_phase2_tlvs(struct eap_sm *sm, - struct eap_fast_data *data, - struct wpabuf *in_data) -{ - struct eap_fast_tlv_parse tlv; - int check_crypto_binding = data->state == CRYPTO_BINDING; - - if (eap_fast_parse_tlvs(in_data, &tlv) < 0) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to parse received " - "Phase 2 TLVs"); - return; - } - - if (tlv.result == EAP_TLV_RESULT_FAILURE) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Result TLV indicated " - "failure"); - eap_fast_state(data, FAILURE); - return; - } - - if (data->state == REQUEST_PAC) { - u16 type, len, res; - if (tlv.pac == NULL || tlv.pac_len < 6) { - wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC " - "Acknowledgement received"); - eap_fast_state(data, FAILURE); - return; - } - - type = WPA_GET_BE16(tlv.pac); - len = WPA_GET_BE16(tlv.pac + 2); - res = WPA_GET_BE16(tlv.pac + 4); - - if (type != PAC_TYPE_PAC_ACKNOWLEDGEMENT || len != 2 || - res != EAP_TLV_RESULT_SUCCESS) { - wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV did not " - "contain acknowledgement"); - eap_fast_state(data, FAILURE); - return; - } - - wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Acknowledgement received " - "- PAC provisioning succeeded"); - eap_fast_state(data, (data->anon_provisioning || - data->send_new_pac == 2) ? - FAILURE : SUCCESS); - return; - } - - if (check_crypto_binding) { - if (tlv.crypto_binding == NULL) { - wpa_printf(MSG_DEBUG, "EAP-FAST: No Crypto-Binding " - "TLV received"); - eap_fast_state(data, FAILURE); - return; - } - - if (data->final_result && - tlv.result != EAP_TLV_RESULT_SUCCESS) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV " - "without Success Result"); - eap_fast_state(data, FAILURE); - return; - } - - if (!data->final_result && - tlv.iresult != EAP_TLV_RESULT_SUCCESS) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV " - "without intermediate Success Result"); - eap_fast_state(data, FAILURE); - return; - } - - if (eap_fast_validate_crypto_binding(data, tlv.crypto_binding, - tlv.crypto_binding_len)) { - eap_fast_state(data, FAILURE); - return; - } - - wpa_printf(MSG_DEBUG, "EAP-FAST: Valid Crypto-Binding TLV " - "received"); - if (data->final_result) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication " - "completed successfully"); - } - - if (data->anon_provisioning && - sm->eap_fast_prov != ANON_PROV && - sm->eap_fast_prov != BOTH_PROV) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to " - "use unauthenticated provisioning which is " - "disabled"); - eap_fast_state(data, FAILURE); - return; - } - - if (sm->eap_fast_prov != AUTH_PROV && - sm->eap_fast_prov != BOTH_PROV && - tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV && - eap_fast_pac_type(tlv.pac, tlv.pac_len, - PAC_TYPE_TUNNEL_PAC)) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to " - "use authenticated provisioning which is " - "disabled"); - eap_fast_state(data, FAILURE); - return; - } - - if (data->anon_provisioning || - (tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV && - eap_fast_pac_type(tlv.pac, tlv.pac_len, - PAC_TYPE_TUNNEL_PAC))) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Requested a new " - "Tunnel PAC"); - eap_fast_state(data, REQUEST_PAC); - } else if (data->send_new_pac) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Server triggered " - "re-keying of Tunnel PAC"); - eap_fast_state(data, REQUEST_PAC); - } else if (data->final_result) - eap_fast_state(data, SUCCESS); - } - - if (tlv.eap_payload_tlv) { - eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv, - tlv.eap_payload_tlv_len); - } -} - - -static void eap_fast_process_phase2(struct eap_sm *sm, - struct eap_fast_data *data, - struct wpabuf *in_buf) -{ - struct wpabuf *in_decrypted; - - wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for" - " Phase 2", (unsigned long) wpabuf_len(in_buf)); - - if (data->pending_phase2_resp) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - " - "skip decryption and use old data"); - eap_fast_process_phase2_tlvs(sm, data, - data->pending_phase2_resp); - wpabuf_free(data->pending_phase2_resp); - data->pending_phase2_resp = NULL; - return; - } - - in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, - in_buf); - if (in_decrypted == NULL) { - wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 " - "data"); - eap_fast_state(data, FAILURE); - return; - } - - wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Decrypted Phase 2 TLVs", - in_decrypted); - - eap_fast_process_phase2_tlvs(sm, data, in_decrypted); - - if (sm->method_pending == METHOD_PENDING_WAIT) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method is in " - "pending wait state - save decrypted response"); - wpabuf_free(data->pending_phase2_resp); - data->pending_phase2_resp = in_decrypted; - return; - } - - wpabuf_free(in_decrypted); -} - - -static int eap_fast_process_version(struct eap_sm *sm, void *priv, - int peer_version) -{ - struct eap_fast_data *data = priv; - - data->peer_version = peer_version; - - if (data->force_version >= 0 && peer_version != data->force_version) { - wpa_printf(MSG_INFO, "EAP-FAST: peer did not select the forced" - " version (forced=%d peer=%d) - reject", - data->force_version, peer_version); - return -1; - } - - if (peer_version < data->fast_version) { - wpa_printf(MSG_DEBUG, "EAP-FAST: peer ver=%d, own ver=%d; " - "use version %d", - peer_version, data->fast_version, peer_version); - data->fast_version = peer_version; - } - - return 0; -} - - -static int eap_fast_process_phase1(struct eap_sm *sm, - struct eap_fast_data *data) -{ - if (eap_server_tls_phase1(sm, &data->ssl) < 0) { - wpa_printf(MSG_INFO, "EAP-FAST: TLS processing failed"); - eap_fast_state(data, FAILURE); - return -1; - } - - if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) || - wpabuf_len(data->ssl.tls_out) > 0) - return 1; - - /* - * Phase 1 was completed with the received message (e.g., when using - * abbreviated handshake), so Phase 2 can be started immediately - * without having to send through an empty message to the peer. - */ - - return eap_fast_phase1_done(sm, data); -} - - -static int eap_fast_process_phase2_start(struct eap_sm *sm, - struct eap_fast_data *data) -{ - u8 next_type; - - if (data->identity) { - os_free(sm->identity); - sm->identity = data->identity; - data->identity = NULL; - sm->identity_len = data->identity_len; - data->identity_len = 0; - sm->require_identity_match = 1; - if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: " - "Phase2 Identity not found " - "in the user database", - sm->identity, sm->identity_len); - next_type = eap_fast_req_failure(sm, data); - } else { - wpa_printf(MSG_DEBUG, "EAP-FAST: Identity already " - "known - skip Phase 2 Identity Request"); - next_type = sm->user->methods[0].method; - sm->user_eap_method_index = 1; - } - - eap_fast_state(data, PHASE2_METHOD); - } else { - eap_fast_state(data, PHASE2_ID); - next_type = EAP_TYPE_IDENTITY; - } - - return eap_fast_phase2_init(sm, data, next_type); -} - - -static void eap_fast_process_msg(struct eap_sm *sm, void *priv, - const struct wpabuf *respData) -{ - struct eap_fast_data *data = priv; - - switch (data->state) { - case PHASE1: - if (eap_fast_process_phase1(sm, data)) - break; - - /* fall through to PHASE2_START */ - case PHASE2_START: - eap_fast_process_phase2_start(sm, data); - break; - case PHASE2_ID: - case PHASE2_METHOD: - case CRYPTO_BINDING: - case REQUEST_PAC: - eap_fast_process_phase2(sm, data, data->ssl.tls_in); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected state %d in %s", - data->state, __func__); - break; - } -} - - -static void eap_fast_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_fast_data *data = priv; - if (eap_server_tls_process(sm, &data->ssl, respData, data, - EAP_TYPE_FAST, eap_fast_process_version, - eap_fast_process_msg) < 0) - eap_fast_state(data, FAILURE); -} - - -static Boolean eap_fast_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_fast_data *data = priv; - return data->state == SUCCESS || data->state == FAILURE; -} - - -static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_fast_data *data = priv; - u8 *eapKeyData; - - if (data->state != SUCCESS) - return NULL; - - eapKeyData = os_malloc(EAP_FAST_KEY_LEN); - if (eapKeyData == NULL) - return NULL; - - eap_fast_derive_eap_msk(data->simck, eapKeyData); - *len = EAP_FAST_KEY_LEN; - - return eapKeyData; -} - - -static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_fast_data *data = priv; - u8 *eapKeyData; - - if (data->state != SUCCESS) - return NULL; - - eapKeyData = os_malloc(EAP_EMSK_LEN); - if (eapKeyData == NULL) - return NULL; - - eap_fast_derive_eap_emsk(data->simck, eapKeyData); - *len = EAP_EMSK_LEN; - - return eapKeyData; -} - - -static Boolean eap_fast_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_fast_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_fast_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST"); - if (eap == NULL) - return -1; - - eap->init = eap_fast_init; - eap->reset = eap_fast_reset; - eap->buildReq = eap_fast_buildReq; - eap->check = eap_fast_check; - eap->process = eap_fast_process; - eap->isDone = eap_fast_isDone; - eap->getKey = eap_fast_getKey; - eap->get_emsk = eap_fast_get_emsk; - eap->isSuccess = eap_fast_isSuccess; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_gpsk.c b/contrib/hostapd/src/eap_server/eap_server_gpsk.c deleted file mode 100644 index 66f4271583..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_gpsk.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - * hostapd / EAP-GPSK (RFC 5433) server - * Copyright (c) 2006-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/random.h" -#include "eap_server/eap_i.h" -#include "eap_common/eap_gpsk_common.h" - - -struct eap_gpsk_data { - enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state; - u8 rand_server[EAP_GPSK_RAND_LEN]; - u8 rand_peer[EAP_GPSK_RAND_LEN]; - u8 msk[EAP_MSK_LEN]; - u8 emsk[EAP_EMSK_LEN]; - u8 sk[EAP_GPSK_MAX_SK_LEN]; - size_t sk_len; - u8 pk[EAP_GPSK_MAX_PK_LEN]; - size_t pk_len; - u8 *id_peer; - size_t id_peer_len; -#define MAX_NUM_CSUITES 2 - struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES]; - size_t csuite_count; - int vendor; /* CSuite/Vendor */ - int specifier; /* CSuite/Specifier */ -}; - - -static const char * eap_gpsk_state_txt(int state) -{ - switch (state) { - case GPSK_1: - return "GPSK-1"; - case GPSK_3: - return "GPSK-3"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "?"; - } -} - - -static void eap_gpsk_state(struct eap_gpsk_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s", - eap_gpsk_state_txt(data->state), - eap_gpsk_state_txt(state)); - data->state = state; -} - - -static void * eap_gpsk_init(struct eap_sm *sm) -{ - struct eap_gpsk_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = GPSK_1; - - data->csuite_count = 0; - if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF, - EAP_GPSK_CIPHER_AES)) { - WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor, - EAP_GPSK_VENDOR_IETF); - WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier, - EAP_GPSK_CIPHER_AES); - data->csuite_count++; - } - if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF, - EAP_GPSK_CIPHER_SHA256)) { - WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor, - EAP_GPSK_VENDOR_IETF); - WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier, - EAP_GPSK_CIPHER_SHA256); - data->csuite_count++; - } - - return data; -} - - -static void eap_gpsk_reset(struct eap_sm *sm, void *priv) -{ - struct eap_gpsk_data *data = priv; - os_free(data->id_peer); - os_free(data); -} - - -static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm, - struct eap_gpsk_data *data, u8 id) -{ - size_t len; - struct wpabuf *req; - - wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1"); - - if (random_get_bytes(data->rand_server, EAP_GPSK_RAND_LEN)) { - wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data"); - eap_gpsk_state(data, FAILURE); - return NULL; - } - wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server", - data->rand_server, EAP_GPSK_RAND_LEN); - - len = 1 + 2 + sm->server_id_len + EAP_GPSK_RAND_LEN + 2 + - data->csuite_count * sizeof(struct eap_gpsk_csuite); - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory " - "for request/GPSK-1"); - eap_gpsk_state(data, FAILURE); - return NULL; - } - - wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1); - wpabuf_put_be16(req, sm->server_id_len); - wpabuf_put_data(req, sm->server_id, sm->server_id_len); - wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN); - wpabuf_put_be16(req, - data->csuite_count * sizeof(struct eap_gpsk_csuite)); - wpabuf_put_data(req, data->csuite_list, - data->csuite_count * sizeof(struct eap_gpsk_csuite)); - - return req; -} - - -static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm, - struct eap_gpsk_data *data, u8 id) -{ - u8 *pos, *start; - size_t len, miclen; - struct eap_gpsk_csuite *csuite; - struct wpabuf *req; - - wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3"); - - miclen = eap_gpsk_mic_len(data->vendor, data->specifier); - len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->server_id_len + - sizeof(struct eap_gpsk_csuite) + 2 + miclen; - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory " - "for request/GPSK-3"); - eap_gpsk_state(data, FAILURE); - return NULL; - } - - wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_3); - start = wpabuf_put(req, 0); - - wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN); - wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN); - wpabuf_put_be16(req, sm->server_id_len); - wpabuf_put_data(req, sm->server_id, sm->server_id_len); - csuite = wpabuf_put(req, sizeof(*csuite)); - WPA_PUT_BE32(csuite->vendor, data->vendor); - WPA_PUT_BE16(csuite->specifier, data->specifier); - - /* no PD_Payload_2 */ - wpabuf_put_be16(req, 0); - - pos = wpabuf_put(req, miclen); - if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, - data->specifier, start, pos - start, pos) < 0) - { - os_free(req); - eap_gpsk_state(data, FAILURE); - return NULL; - } - - return req; -} - - -static struct wpabuf * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_gpsk_data *data = priv; - - switch (data->state) { - case GPSK_1: - return eap_gpsk_build_gpsk_1(sm, data, id); - case GPSK_3: - return eap_gpsk_build_gpsk_3(sm, data, id); - default: - wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown state %d in buildReq", - data->state); - break; - } - return NULL; -} - - -static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_gpsk_data *data = priv; - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len); - if (pos == NULL || len < 1) { - wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame"); - return TRUE; - } - - wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos); - - if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2) - return FALSE; - - if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4) - return FALSE; - - wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d", - *pos, data->state); - - return TRUE; -} - - -static void eap_gpsk_process_gpsk_2(struct eap_sm *sm, - struct eap_gpsk_data *data, - const u8 *payload, size_t payloadlen) -{ - const u8 *pos, *end; - u16 alen; - const struct eap_gpsk_csuite *csuite; - size_t i, miclen; - u8 mic[EAP_GPSK_MAX_MIC_LEN]; - - if (data->state != GPSK_1) - return; - - wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2"); - - pos = payload; - end = payload + payloadlen; - - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " - "ID_Peer length"); - eap_gpsk_state(data, FAILURE); - return; - } - alen = WPA_GET_BE16(pos); - pos += 2; - if (end - pos < alen) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " - "ID_Peer"); - eap_gpsk_state(data, FAILURE); - return; - } - os_free(data->id_peer); - data->id_peer = os_malloc(alen); - if (data->id_peer == NULL) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store " - "%d-octet ID_Peer", alen); - return; - } - os_memcpy(data->id_peer, pos, alen); - data->id_peer_len = alen; - wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer", - data->id_peer, data->id_peer_len); - pos += alen; - - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " - "ID_Server length"); - eap_gpsk_state(data, FAILURE); - return; - } - alen = WPA_GET_BE16(pos); - pos += 2; - if (end - pos < alen) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " - "ID_Server"); - eap_gpsk_state(data, FAILURE); - return; - } - if (alen != sm->server_id_len || - os_memcmp(pos, sm->server_id, alen) != 0) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and " - "GPSK-2 did not match"); - eap_gpsk_state(data, FAILURE); - return; - } - pos += alen; - - if (end - pos < EAP_GPSK_RAND_LEN) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " - "RAND_Peer"); - eap_gpsk_state(data, FAILURE); - return; - } - os_memcpy(data->rand_peer, pos, EAP_GPSK_RAND_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer", - data->rand_peer, EAP_GPSK_RAND_LEN); - pos += EAP_GPSK_RAND_LEN; - - if (end - pos < EAP_GPSK_RAND_LEN) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " - "RAND_Server"); - eap_gpsk_state(data, FAILURE); - return; - } - if (os_memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and " - "GPSK-2 did not match"); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1", - data->rand_server, EAP_GPSK_RAND_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2", - pos, EAP_GPSK_RAND_LEN); - eap_gpsk_state(data, FAILURE); - return; - } - pos += EAP_GPSK_RAND_LEN; - - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " - "CSuite_List length"); - eap_gpsk_state(data, FAILURE); - return; - } - alen = WPA_GET_BE16(pos); - pos += 2; - if (end - pos < alen) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " - "CSuite_List"); - eap_gpsk_state(data, FAILURE); - return; - } - if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) || - os_memcmp(pos, data->csuite_list, alen) != 0) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and " - "GPSK-2 did not match"); - eap_gpsk_state(data, FAILURE); - return; - } - pos += alen; - - if (end - pos < (int) sizeof(*csuite)) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " - "CSuite_Sel"); - eap_gpsk_state(data, FAILURE); - return; - } - csuite = (const struct eap_gpsk_csuite *) pos; - for (i = 0; i < data->csuite_count; i++) { - if (os_memcmp(csuite, &data->csuite_list[i], sizeof(*csuite)) - == 0) - break; - } - if (i == data->csuite_count) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported " - "ciphersuite %d:%d", - WPA_GET_BE32(csuite->vendor), - WPA_GET_BE16(csuite->specifier)); - eap_gpsk_state(data, FAILURE); - return; - } - data->vendor = WPA_GET_BE32(csuite->vendor); - data->specifier = WPA_GET_BE16(csuite->specifier); - wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d", - data->vendor, data->specifier); - pos += sizeof(*csuite); - - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " - "PD_Payload_1 length"); - eap_gpsk_state(data, FAILURE); - return; - } - alen = WPA_GET_BE16(pos); - pos += 2; - if (end - pos < alen) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " - "PD_Payload_1"); - eap_gpsk_state(data, FAILURE); - return; - } - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen); - pos += alen; - - if (sm->user == NULL || sm->user->password == NULL) { - wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured " - "for the user"); - eap_gpsk_state(data, FAILURE); - return; - } - - if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len, - data->vendor, data->specifier, - data->rand_peer, data->rand_server, - data->id_peer, data->id_peer_len, - sm->server_id, sm->server_id_len, - data->msk, data->emsk, - data->sk, &data->sk_len, - data->pk, &data->pk_len) < 0) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys"); - eap_gpsk_state(data, FAILURE); - return; - } - - miclen = eap_gpsk_mic_len(data->vendor, data->specifier); - if (end - pos < (int) miclen) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " - "(left=%lu miclen=%lu)", - (unsigned long) (end - pos), - (unsigned long) miclen); - eap_gpsk_state(data, FAILURE); - return; - } - if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, - data->specifier, payload, pos - payload, mic) - < 0) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); - eap_gpsk_state(data, FAILURE); - return; - } - if (os_memcmp(mic, pos, miclen) != 0) { - wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2"); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); - eap_gpsk_state(data, FAILURE); - return; - } - pos += miclen; - - if (pos != end) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " - "data in the end of GPSK-2", - (unsigned long) (end - pos)); - } - - eap_gpsk_state(data, GPSK_3); -} - - -static void eap_gpsk_process_gpsk_4(struct eap_sm *sm, - struct eap_gpsk_data *data, - const u8 *payload, size_t payloadlen) -{ - const u8 *pos, *end; - u16 alen; - size_t miclen; - u8 mic[EAP_GPSK_MAX_MIC_LEN]; - - if (data->state != GPSK_3) - return; - - wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4"); - - pos = payload; - end = payload + payloadlen; - - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " - "PD_Payload_1 length"); - eap_gpsk_state(data, FAILURE); - return; - } - alen = WPA_GET_BE16(pos); - pos += 2; - if (end - pos < alen) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " - "PD_Payload_1"); - eap_gpsk_state(data, FAILURE); - return; - } - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen); - pos += alen; - - miclen = eap_gpsk_mic_len(data->vendor, data->specifier); - if (end - pos < (int) miclen) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " - "(left=%lu miclen=%lu)", - (unsigned long) (end - pos), - (unsigned long) miclen); - eap_gpsk_state(data, FAILURE); - return; - } - if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, - data->specifier, payload, pos - payload, mic) - < 0) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); - eap_gpsk_state(data, FAILURE); - return; - } - if (os_memcmp(mic, pos, miclen) != 0) { - wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4"); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); - eap_gpsk_state(data, FAILURE); - return; - } - pos += miclen; - - if (pos != end) { - wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " - "data in the end of GPSK-4", - (unsigned long) (end - pos)); - } - - eap_gpsk_state(data, SUCCESS); -} - - -static void eap_gpsk_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_gpsk_data *data = priv; - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len); - if (pos == NULL || len < 1) - return; - - switch (*pos) { - case EAP_GPSK_OPCODE_GPSK_2: - eap_gpsk_process_gpsk_2(sm, data, pos + 1, len - 1); - break; - case EAP_GPSK_OPCODE_GPSK_4: - eap_gpsk_process_gpsk_4(sm, data, pos + 1, len - 1); - break; - } -} - - -static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_gpsk_data *data = priv; - return data->state == SUCCESS || data->state == FAILURE; -} - - -static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_gpsk_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->msk, EAP_MSK_LEN); - *len = EAP_MSK_LEN; - - return key; -} - - -static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_gpsk_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - *len = EAP_EMSK_LEN; - - return key; -} - - -static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_gpsk_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_gpsk_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK"); - if (eap == NULL) - return -1; - - eap->init = eap_gpsk_init; - eap->reset = eap_gpsk_reset; - eap->buildReq = eap_gpsk_buildReq; - eap->check = eap_gpsk_check; - eap->process = eap_gpsk_process; - eap->isDone = eap_gpsk_isDone; - eap->getKey = eap_gpsk_getKey; - eap->isSuccess = eap_gpsk_isSuccess; - eap->get_emsk = eap_gpsk_get_emsk; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_gtc.c b/contrib/hostapd/src/eap_server/eap_server_gtc.c deleted file mode 100644 index f423106bfc..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_gtc.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * hostapd / EAP-GTC (RFC 3748) - * Copyright (c) 2004-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" - - -struct eap_gtc_data { - enum { CONTINUE, SUCCESS, FAILURE } state; - int prefix; -}; - - -static void * eap_gtc_init(struct eap_sm *sm) -{ - struct eap_gtc_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = CONTINUE; - -#ifdef EAP_SERVER_FAST - if (sm->m && sm->m->vendor == EAP_VENDOR_IETF && - sm->m->method == EAP_TYPE_FAST) { - wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix " - "with challenge/response"); - data->prefix = 1; - } -#endif /* EAP_SERVER_FAST */ - - return data; -} - - -static void eap_gtc_reset(struct eap_sm *sm, void *priv) -{ - struct eap_gtc_data *data = priv; - os_free(data); -} - - -static struct wpabuf * eap_gtc_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_gtc_data *data = priv; - struct wpabuf *req; - char *msg; - size_t msg_len; - - msg = data->prefix ? "CHALLENGE=Password" : "Password"; - - msg_len = os_strlen(msg); - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, msg_len, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for " - "request"); - data->state = FAILURE; - return NULL; - } - - wpabuf_put_data(req, msg, msg_len); - - data->state = CONTINUE; - - return req; -} - - -static Boolean eap_gtc_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &len); - if (pos == NULL || len < 1) { - wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame"); - return TRUE; - } - - return FALSE; -} - - -static void eap_gtc_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_gtc_data *data = priv; - const u8 *pos; - size_t rlen; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &rlen); - if (pos == NULL || rlen < 1) - return; /* Should not happen - frame already validated */ - - wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen); - -#ifdef EAP_SERVER_FAST - if (data->prefix) { - const u8 *pos2, *end; - /* "RESPONSE=\0" */ - if (rlen < 10) { - wpa_printf(MSG_DEBUG, "EAP-GTC: Too short response " - "for EAP-FAST prefix"); - data->state = FAILURE; - return; - } - - end = pos + rlen; - pos += 9; - pos2 = pos; - while (pos2 < end && *pos2) - pos2++; - if (pos2 == end) { - wpa_printf(MSG_DEBUG, "EAP-GTC: No password in " - "response to EAP-FAST prefix"); - data->state = FAILURE; - return; - } - - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Response user", - pos, pos2 - pos); - if (sm->identity && sm->require_identity_match && - (pos2 - pos != (int) sm->identity_len || - os_memcmp(pos, sm->identity, sm->identity_len))) { - wpa_printf(MSG_DEBUG, "EAP-GTC: Phase 2 Identity did " - "not match with required Identity"); - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Expected " - "identity", - sm->identity, sm->identity_len); - data->state = FAILURE; - return; - } else { - os_free(sm->identity); - sm->identity_len = pos2 - pos; - sm->identity = os_malloc(sm->identity_len); - if (sm->identity == NULL) { - data->state = FAILURE; - return; - } - os_memcpy(sm->identity, pos, sm->identity_len); - } - - if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 " - "Identity not found in the user " - "database", - sm->identity, sm->identity_len); - data->state = FAILURE; - return; - } - - pos = pos2 + 1; - rlen = end - pos; - wpa_hexdump_ascii_key(MSG_MSGDUMP, - "EAP-GTC: Response password", - pos, rlen); - } -#endif /* EAP_SERVER_FAST */ - - if (sm->user == NULL || sm->user->password == NULL || - sm->user->password_hash) { - wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not " - "configured"); - data->state = FAILURE; - return; - } - - if (rlen != sm->user->password_len || - os_memcmp(pos, sm->user->password, rlen) != 0) { - wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure"); - data->state = FAILURE; - } else { - wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Success"); - data->state = SUCCESS; - } -} - - -static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_gtc_data *data = priv; - return data->state != CONTINUE; -} - - -static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_gtc_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_gtc_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC"); - if (eap == NULL) - return -1; - - eap->init = eap_gtc_init; - eap->reset = eap_gtc_reset; - eap->buildReq = eap_gtc_buildReq; - eap->check = eap_gtc_check; - eap->process = eap_gtc_process; - eap->isDone = eap_gtc_isDone; - eap->isSuccess = eap_gtc_isSuccess; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_identity.c b/contrib/hostapd/src/eap_server/eap_server_identity.c deleted file mode 100644 index 51dc4e8b4f..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_identity.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * hostapd / EAP-Identity - * Copyright (c) 2004-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" - - -struct eap_identity_data { - enum { CONTINUE, SUCCESS, FAILURE } state; - int pick_up; -}; - - -static void * eap_identity_init(struct eap_sm *sm) -{ - struct eap_identity_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = CONTINUE; - - return data; -} - - -static void * eap_identity_initPickUp(struct eap_sm *sm) -{ - struct eap_identity_data *data; - data = eap_identity_init(sm); - if (data) { - data->pick_up = 1; - } - return data; -} - - -static void eap_identity_reset(struct eap_sm *sm, void *priv) -{ - struct eap_identity_data *data = priv; - os_free(data); -} - - -static struct wpabuf * eap_identity_buildReq(struct eap_sm *sm, void *priv, - u8 id) -{ - struct eap_identity_data *data = priv; - struct wpabuf *req; - const char *req_data; - size_t req_data_len; - - if (sm->eapol_cb->get_eap_req_id_text) { - req_data = sm->eapol_cb->get_eap_req_id_text(sm->eapol_ctx, - &req_data_len); - } else { - req_data = NULL; - req_data_len = 0; - } - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req_data_len, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-Identity: Failed to allocate " - "memory for request"); - data->state = FAILURE; - return NULL; - } - - wpabuf_put_data(req, req_data, req_data_len); - - return req; -} - - -static Boolean eap_identity_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, - respData, &len); - if (pos == NULL) { - wpa_printf(MSG_INFO, "EAP-Identity: Invalid frame"); - return TRUE; - } - - return FALSE; -} - - -static void eap_identity_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_identity_data *data = priv; - const u8 *pos; - size_t len; - - if (data->pick_up) { - if (eap_identity_check(sm, data, respData)) { - wpa_printf(MSG_DEBUG, "EAP-Identity: failed to pick " - "up already started negotiation"); - data->state = FAILURE; - return; - } - data->pick_up = 0; - } - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, - respData, &len); - if (pos == NULL) - return; /* Should not happen - frame already validated */ - - wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len); - if (sm->identity) - sm->update_user = TRUE; - os_free(sm->identity); - sm->identity = os_malloc(len ? len : 1); - if (sm->identity == NULL) { - data->state = FAILURE; - } else { - os_memcpy(sm->identity, pos, len); - sm->identity_len = len; - data->state = SUCCESS; - } -} - - -static Boolean eap_identity_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_identity_data *data = priv; - return data->state != CONTINUE; -} - - -static Boolean eap_identity_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_identity_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_identity_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, - "Identity"); - if (eap == NULL) - return -1; - - eap->init = eap_identity_init; - eap->initPickUp = eap_identity_initPickUp; - eap->reset = eap_identity_reset; - eap->buildReq = eap_identity_buildReq; - eap->check = eap_identity_check; - eap->process = eap_identity_process; - eap->isDone = eap_identity_isDone; - eap->isSuccess = eap_identity_isSuccess; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_ikev2.c b/contrib/hostapd/src/eap_server/eap_server_ikev2.c deleted file mode 100644 index 1ada0c8a6d..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_ikev2.c +++ /dev/null @@ -1,536 +0,0 @@ -/* - * EAP-IKEv2 server (RFC 5106) - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" -#include "eap_common/eap_ikev2_common.h" -#include "ikev2.h" - - -struct eap_ikev2_data { - struct ikev2_initiator_data ikev2; - enum { MSG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; - struct wpabuf *in_buf; - struct wpabuf *out_buf; - size_t out_used; - size_t fragment_size; - int keys_ready; - u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN]; - int keymat_ok; -}; - - -static const u8 * eap_ikev2_get_shared_secret(void *ctx, const u8 *IDr, - size_t IDr_len, - size_t *secret_len) -{ - struct eap_sm *sm = ctx; - - if (IDr == NULL) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: No IDr received - default " - "to user identity from EAP-Identity"); - IDr = sm->identity; - IDr_len = sm->identity_len; - } - - if (eap_user_get(sm, IDr, IDr_len, 0) < 0 || sm->user == NULL || - sm->user->password == NULL) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: No user entry found"); - return NULL; - } - - *secret_len = sm->user->password_len; - return sm->user->password; -} - - -static const char * eap_ikev2_state_txt(int state) -{ - switch (state) { - case MSG: - return "MSG"; - case FRAG_ACK: - return "FRAG_ACK"; - case WAIT_FRAG_ACK: - return "WAIT_FRAG_ACK"; - case DONE: - return "DONE"; - case FAIL: - return "FAIL"; - default: - return "?"; - } -} - - -static void eap_ikev2_state(struct eap_ikev2_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s", - eap_ikev2_state_txt(data->state), - eap_ikev2_state_txt(state)); - data->state = state; -} - - -static void * eap_ikev2_init(struct eap_sm *sm) -{ - struct eap_ikev2_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = MSG; - data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size : - IKEV2_FRAGMENT_SIZE; - data->ikev2.state = SA_INIT; - data->ikev2.peer_auth = PEER_AUTH_SECRET; - data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); - if (data->ikev2.key_pad == NULL) - goto failed; - data->ikev2.key_pad_len = 21; - - /* TODO: make proposals configurable */ - data->ikev2.proposal.proposal_num = 1; - data->ikev2.proposal.integ = AUTH_HMAC_SHA1_96; - data->ikev2.proposal.prf = PRF_HMAC_SHA1; - data->ikev2.proposal.encr = ENCR_AES_CBC; - data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP; - - data->ikev2.IDi = os_malloc(sm->server_id_len); - if (data->ikev2.IDi == NULL) - goto failed; - os_memcpy(data->ikev2.IDi, sm->server_id, sm->server_id_len); - data->ikev2.IDi_len = sm->server_id_len; - - data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret; - data->ikev2.cb_ctx = sm; - - return data; - -failed: - ikev2_initiator_deinit(&data->ikev2); - os_free(data); - return NULL; -} - - -static void eap_ikev2_reset(struct eap_sm *sm, void *priv) -{ - struct eap_ikev2_data *data = priv; - wpabuf_free(data->in_buf); - wpabuf_free(data->out_buf); - ikev2_initiator_deinit(&data->ikev2); - os_free(data); -} - - -static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, u8 id) -{ - struct wpabuf *req; - u8 flags; - size_t send_len, plen, icv_len = 0; - - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Request"); - - flags = 0; - send_len = wpabuf_len(data->out_buf) - data->out_used; - if (1 + send_len > data->fragment_size) { - send_len = data->fragment_size - 1; - flags |= IKEV2_FLAGS_MORE_FRAGMENTS; - if (data->out_used == 0) { - flags |= IKEV2_FLAGS_LENGTH_INCLUDED; - send_len -= 4; - } - } - - plen = 1 + send_len; - if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) - plen += 4; - if (data->keys_ready) { - const struct ikev2_integ_alg *integ; - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum " - "Data"); - flags |= IKEV2_FLAGS_ICV_INCLUDED; - integ = ikev2_get_integ(data->ikev2.proposal.integ); - if (integ == NULL) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " - "transform / cannot generate ICV"); - return NULL; - } - icv_len = integ->hash_len; - - plen += icv_len; - } - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen, - EAP_CODE_REQUEST, id); - if (req == NULL) - return NULL; - - wpabuf_put_u8(req, flags); /* Flags */ - if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) - wpabuf_put_be32(req, wpabuf_len(data->out_buf)); - - wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, - send_len); - data->out_used += send_len; - - if (flags & IKEV2_FLAGS_ICV_INCLUDED) { - const u8 *msg = wpabuf_head(req); - size_t len = wpabuf_len(req); - ikev2_integ_hash(data->ikev2.proposal.integ, - data->ikev2.keys.SK_ai, - data->ikev2.keys.SK_integ_len, - msg, len, wpabuf_put(req, icv_len)); - } - - if (data->out_used == wpabuf_len(data->out_buf)) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " - "(message sent completely)", - (unsigned long) send_len); - wpabuf_free(data->out_buf); - data->out_buf = NULL; - data->out_used = 0; - } else { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " - "(%lu more to send)", (unsigned long) send_len, - (unsigned long) wpabuf_len(data->out_buf) - - data->out_used); - eap_ikev2_state(data, WAIT_FRAG_ACK); - } - - return req; -} - - -static struct wpabuf * eap_ikev2_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_ikev2_data *data = priv; - - switch (data->state) { - case MSG: - if (data->out_buf == NULL) { - data->out_buf = ikev2_initiator_build(&data->ikev2); - if (data->out_buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to " - "generate IKEv2 message"); - return NULL; - } - data->out_used = 0; - } - /* pass through */ - case WAIT_FRAG_ACK: - return eap_ikev2_build_msg(data, id); - case FRAG_ACK: - return eap_ikev2_build_frag_ack(id, EAP_CODE_REQUEST); - default: - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected state %d in " - "buildReq", data->state); - return NULL; - } -} - - -static Boolean eap_ikev2_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData, - &len); - if (pos == NULL) { - wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid frame"); - return TRUE; - } - - return FALSE; -} - - -static int eap_ikev2_process_icv(struct eap_ikev2_data *data, - const struct wpabuf *respData, - u8 flags, const u8 *pos, const u8 **end) -{ - if (flags & IKEV2_FLAGS_ICV_INCLUDED) { - int icv_len = eap_ikev2_validate_icv( - data->ikev2.proposal.integ, &data->ikev2.keys, 0, - respData, pos, *end); - if (icv_len < 0) - return -1; - /* Hide Integrity Checksum Data from further processing */ - *end -= icv_len; - } else if (data->keys_ready) { - wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have " - "included integrity checksum"); - return -1; - } - - return 0; -} - - -static int eap_ikev2_process_cont(struct eap_ikev2_data *data, - const u8 *buf, size_t len) -{ - /* Process continuation of a pending message */ - if (len > wpabuf_tailroom(data->in_buf)) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow"); - eap_ikev2_state(data, FAIL); - return -1; - } - - wpabuf_put_data(data->in_buf, buf, len); - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting for %lu " - "bytes more", (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); - - return 0; -} - - -static int eap_ikev2_process_fragment(struct eap_ikev2_data *data, - u8 flags, u32 message_length, - const u8 *buf, size_t len) -{ - /* Process a fragment that is not the last one of the message */ - if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in " - "a fragmented packet"); - return -1; - } - - if (data->in_buf == NULL) { - /* First fragment of the message */ - data->in_buf = wpabuf_alloc(message_length); - if (data->in_buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for " - "message"); - return -1; - } - wpabuf_put_data(data->in_buf, buf, len); - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first " - "fragment, waiting for %lu bytes more", - (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); - } - - return 0; -} - - -static int eap_ikev2_server_keymat(struct eap_ikev2_data *data) -{ - if (eap_ikev2_derive_keymat( - data->ikev2.proposal.prf, &data->ikev2.keys, - data->ikev2.i_nonce, data->ikev2.i_nonce_len, - data->ikev2.r_nonce, data->ikev2.r_nonce_len, - data->keymat) < 0) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to derive " - "key material"); - return -1; - } - data->keymat_ok = 1; - return 0; -} - - -static void eap_ikev2_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_ikev2_data *data = priv; - const u8 *start, *pos, *end; - size_t len; - u8 flags; - u32 message_length = 0; - struct wpabuf tmpbuf; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData, - &len); - if (pos == NULL) - return; /* Should not happen; message already verified */ - - start = pos; - end = start + len; - - if (len == 0) { - /* fragment ack */ - flags = 0; - } else - flags = *pos++; - - if (eap_ikev2_process_icv(data, respData, flags, pos, &end) < 0) { - eap_ikev2_state(data, FAIL); - return; - } - - if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { - if (end - pos < 4) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); - eap_ikev2_state(data, FAIL); - return; - } - message_length = WPA_GET_BE32(pos); - pos += 4; - - if (message_length < (u32) (end - pos)) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " - "Length (%d; %ld remaining in this msg)", - message_length, (long) (end - pos)); - eap_ikev2_state(data, FAIL); - return; - } - } - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " - "Message Length %u", flags, message_length); - - if (data->state == WAIT_FRAG_ACK) { - if (len != 0) { - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " - "in WAIT_FRAG_ACK state"); - eap_ikev2_state(data, FAIL); - return; - } - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); - eap_ikev2_state(data, MSG); - return; - } - - if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { - eap_ikev2_state(data, FAIL); - return; - } - - if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { - if (eap_ikev2_process_fragment(data, flags, message_length, - pos, end - pos) < 0) - eap_ikev2_state(data, FAIL); - else - eap_ikev2_state(data, FRAG_ACK); - return; - } else if (data->state == FRAG_ACK) { - wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received"); - data->state = MSG; - } - - if (data->in_buf == NULL) { - /* Wrap unfragmented messages as wpabuf without extra copy */ - wpabuf_set(&tmpbuf, pos, end - pos); - data->in_buf = &tmpbuf; - } - - if (ikev2_initiator_process(&data->ikev2, data->in_buf) < 0) { - if (data->in_buf == &tmpbuf) - data->in_buf = NULL; - eap_ikev2_state(data, FAIL); - return; - } - - switch (data->ikev2.state) { - case SA_AUTH: - /* SA_INIT was sent out, so message have to be - * integrity protected from now on. */ - data->keys_ready = 1; - break; - case IKEV2_DONE: - if (data->state == FAIL) - break; - wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication completed " - "successfully"); - if (eap_ikev2_server_keymat(data)) - break; - eap_ikev2_state(data, DONE); - break; - default: - break; - } - - if (data->in_buf != &tmpbuf) - wpabuf_free(data->in_buf); - data->in_buf = NULL; -} - - -static Boolean eap_ikev2_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_ikev2_data *data = priv; - return data->state == DONE || data->state == FAIL; -} - - -static Boolean eap_ikev2_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_ikev2_data *data = priv; - return data->state == DONE && data->ikev2.state == IKEV2_DONE && - data->keymat_ok; -} - - -static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_ikev2_data *data = priv; - u8 *key; - - if (data->state != DONE || !data->keymat_ok) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key) { - os_memcpy(key, data->keymat, EAP_MSK_LEN); - *len = EAP_MSK_LEN; - } - - return key; -} - - -static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_ikev2_data *data = priv; - u8 *key; - - if (data->state != DONE || !data->keymat_ok) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key) { - os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN); - *len = EAP_EMSK_LEN; - } - - return key; -} - - -int eap_server_ikev2_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_IKEV2, - "IKEV2"); - if (eap == NULL) - return -1; - - eap->init = eap_ikev2_init; - eap->reset = eap_ikev2_reset; - eap->buildReq = eap_ikev2_buildReq; - eap->check = eap_ikev2_check; - eap->process = eap_ikev2_process; - eap->isDone = eap_ikev2_isDone; - eap->getKey = eap_ikev2_getKey; - eap->isSuccess = eap_ikev2_isSuccess; - eap->get_emsk = eap_ikev2_get_emsk; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_md5.c b/contrib/hostapd/src/eap_server/eap_server_md5.c deleted file mode 100644 index 5a5e2907ef..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_md5.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * hostapd / EAP-MD5 server - * Copyright (c) 2004-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/random.h" -#include "eap_i.h" -#include "eap_common/chap.h" - - -#define CHALLENGE_LEN 16 - -struct eap_md5_data { - u8 challenge[CHALLENGE_LEN]; - enum { CONTINUE, SUCCESS, FAILURE } state; -}; - - -static void * eap_md5_init(struct eap_sm *sm) -{ - struct eap_md5_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = CONTINUE; - - return data; -} - - -static void eap_md5_reset(struct eap_sm *sm, void *priv) -{ - struct eap_md5_data *data = priv; - os_free(data); -} - - -static struct wpabuf * eap_md5_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_md5_data *data = priv; - struct wpabuf *req; - - if (random_get_bytes(data->challenge, CHALLENGE_LEN)) { - wpa_printf(MSG_ERROR, "EAP-MD5: Failed to get random data"); - data->state = FAILURE; - return NULL; - } - - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHALLENGE_LEN, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-MD5: Failed to allocate memory for " - "request"); - data->state = FAILURE; - return NULL; - } - - wpabuf_put_u8(req, CHALLENGE_LEN); - wpabuf_put_data(req, data->challenge, CHALLENGE_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", data->challenge, - CHALLENGE_LEN); - - data->state = CONTINUE; - - return req; -} - - -static Boolean eap_md5_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &len); - if (pos == NULL || len < 1) { - wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame"); - return TRUE; - } - if (*pos != CHAP_MD5_LEN || 1 + CHAP_MD5_LEN > len) { - wpa_printf(MSG_INFO, "EAP-MD5: Invalid response " - "(response_len=%d payload_len=%lu", - *pos, (unsigned long) len); - return TRUE; - } - - return FALSE; -} - - -static void eap_md5_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_md5_data *data = priv; - const u8 *pos; - size_t plen; - u8 hash[CHAP_MD5_LEN], id; - - if (sm->user == NULL || sm->user->password == NULL || - sm->user->password_hash) { - wpa_printf(MSG_INFO, "EAP-MD5: Plaintext password not " - "configured"); - data->state = FAILURE; - return; - } - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &plen); - if (pos == NULL || *pos != CHAP_MD5_LEN || plen < 1 + CHAP_MD5_LEN) - return; /* Should not happen - frame already validated */ - - pos++; /* Skip response len */ - wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, CHAP_MD5_LEN); - - id = eap_get_id(respData); - if (chap_md5(id, sm->user->password, sm->user->password_len, - data->challenge, CHALLENGE_LEN, hash)) { - wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed"); - data->state = FAILURE; - return; - } - - if (os_memcmp(hash, pos, CHAP_MD5_LEN) == 0) { - wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success"); - data->state = SUCCESS; - } else { - wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Failure"); - data->state = FAILURE; - } -} - - -static Boolean eap_md5_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_md5_data *data = priv; - return data->state != CONTINUE; -} - - -static Boolean eap_md5_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_md5_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_md5_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5"); - if (eap == NULL) - return -1; - - eap->init = eap_md5_init; - eap->reset = eap_md5_reset; - eap->buildReq = eap_md5_buildReq; - eap->check = eap_md5_check; - eap->process = eap_md5_process; - eap->isDone = eap_md5_isDone; - eap->isSuccess = eap_md5_isSuccess; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_methods.c b/contrib/hostapd/src/eap_server/eap_server_methods.c deleted file mode 100644 index 0209fad639..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_methods.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * EAP server method registration - * Copyright (c) 2004-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" -#include "eap_methods.h" - - -static struct eap_method *eap_methods; - - -/** - * eap_server_get_eap_method - Get EAP method based on type number - * @vendor: EAP Vendor-Id (0 = IETF) - * @method: EAP type number - * Returns: Pointer to EAP method or %NULL if not found - */ -const struct eap_method * eap_server_get_eap_method(int vendor, EapType method) -{ - struct eap_method *m; - for (m = eap_methods; m; m = m->next) { - if (m->vendor == vendor && m->method == method) - return m; - } - return NULL; -} - - -/** - * eap_server_get_type - Get EAP type for the given EAP method name - * @name: EAP method name, e.g., TLS - * @vendor: Buffer for returning EAP Vendor-Id - * Returns: EAP method type or %EAP_TYPE_NONE if not found - * - * This function maps EAP type names into EAP type numbers based on the list of - * EAP methods included in the build. - */ -EapType eap_server_get_type(const char *name, int *vendor) -{ - struct eap_method *m; - for (m = eap_methods; m; m = m->next) { - if (os_strcmp(m->name, name) == 0) { - *vendor = m->vendor; - return m->method; - } - } - *vendor = EAP_VENDOR_IETF; - return EAP_TYPE_NONE; -} - - -/** - * eap_server_method_alloc - Allocate EAP server method structure - * @version: Version of the EAP server method interface (set to - * EAP_SERVER_METHOD_INTERFACE_VERSION) - * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF) - * @method: EAP type number (EAP_TYPE_*) - * @name: Name of the method (e.g., "TLS") - * Returns: Allocated EAP method structure or %NULL on failure - * - * The returned structure should be freed with eap_server_method_free() when it - * is not needed anymore. - */ -struct eap_method * eap_server_method_alloc(int version, int vendor, - EapType method, const char *name) -{ - struct eap_method *eap; - eap = os_zalloc(sizeof(*eap)); - if (eap == NULL) - return NULL; - eap->version = version; - eap->vendor = vendor; - eap->method = method; - eap->name = name; - return eap; -} - - -/** - * eap_server_method_free - Free EAP server method structure - * @method: Method structure allocated with eap_server_method_alloc() - */ -void eap_server_method_free(struct eap_method *method) -{ - os_free(method); -} - - -/** - * eap_server_method_register - Register an EAP server method - * @method: EAP method to register - * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method - * has already been registered - * - * Each EAP server method needs to call this function to register itself as a - * supported EAP method. - */ -int eap_server_method_register(struct eap_method *method) -{ - struct eap_method *m, *last = NULL; - - if (method == NULL || method->name == NULL || - method->version != EAP_SERVER_METHOD_INTERFACE_VERSION) - return -1; - - for (m = eap_methods; m; m = m->next) { - if ((m->vendor == method->vendor && - m->method == method->method) || - os_strcmp(m->name, method->name) == 0) - return -2; - last = m; - } - - if (last) - last->next = method; - else - eap_methods = method; - - return 0; -} - - -/** - * eap_server_unregister_methods - Unregister EAP server methods - * - * This function is called at program termination to unregister all EAP server - * methods. - */ -void eap_server_unregister_methods(void) -{ - struct eap_method *m; - - while (eap_methods) { - m = eap_methods; - eap_methods = eap_methods->next; - - if (m->free) - m->free(m); - else - eap_server_method_free(m); - } -} - - -/** - * eap_server_get_name - Get EAP method name for the given EAP type - * @vendor: EAP Vendor-Id (0 = IETF) - * @type: EAP method type - * Returns: EAP method name, e.g., TLS, or %NULL if not found - * - * This function maps EAP type numbers into EAP type names based on the list of - * EAP methods included in the build. - */ -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; - } - return NULL; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_mschapv2.c b/contrib/hostapd/src/eap_server/eap_server_mschapv2.c deleted file mode 100644 index 3153d2ecfb..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_mschapv2.c +++ /dev/null @@ -1,571 +0,0 @@ -/* - * hostapd / EAP-MSCHAPv2 (draft-kamath-pppext-eap-mschapv2-00.txt) server - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/ms_funcs.h" -#include "crypto/random.h" -#include "eap_i.h" - - -struct eap_mschapv2_hdr { - u8 op_code; /* MSCHAPV2_OP_* */ - u8 mschapv2_id; /* must be changed for challenges, but not for - * success/failure */ - u8 ms_length[2]; /* Note: misaligned; length - 5 */ - /* followed by data */ -} STRUCT_PACKED; - -#define MSCHAPV2_OP_CHALLENGE 1 -#define MSCHAPV2_OP_RESPONSE 2 -#define MSCHAPV2_OP_SUCCESS 3 -#define MSCHAPV2_OP_FAILURE 4 -#define MSCHAPV2_OP_CHANGE_PASSWORD 7 - -#define MSCHAPV2_RESP_LEN 49 - -#define ERROR_RESTRICTED_LOGON_HOURS 646 -#define ERROR_ACCT_DISABLED 647 -#define ERROR_PASSWD_EXPIRED 648 -#define ERROR_NO_DIALIN_PERMISSION 649 -#define ERROR_AUTHENTICATION_FAILURE 691 -#define ERROR_CHANGING_PASSWORD 709 - -#define PASSWD_CHANGE_CHAL_LEN 16 -#define MSCHAPV2_KEY_LEN 16 - - -#define CHALLENGE_LEN 16 - -struct eap_mschapv2_data { - u8 auth_challenge[CHALLENGE_LEN]; - int auth_challenge_from_tls; - u8 *peer_challenge; - u8 auth_response[20]; - enum { CHALLENGE, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE } state; - u8 resp_mschapv2_id; - u8 master_key[16]; - int master_key_valid; -}; - - -static void * eap_mschapv2_init(struct eap_sm *sm) -{ - struct eap_mschapv2_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = CHALLENGE; - - if (sm->auth_challenge) { - os_memcpy(data->auth_challenge, sm->auth_challenge, - CHALLENGE_LEN); - data->auth_challenge_from_tls = 1; - } - - if (sm->peer_challenge) { - data->peer_challenge = os_malloc(CHALLENGE_LEN); - if (data->peer_challenge == NULL) { - os_free(data); - return NULL; - } - os_memcpy(data->peer_challenge, sm->peer_challenge, - CHALLENGE_LEN); - } - - return data; -} - - -static void eap_mschapv2_reset(struct eap_sm *sm, void *priv) -{ - struct eap_mschapv2_data *data = priv; - if (data == NULL) - return; - - os_free(data->peer_challenge); - os_free(data); -} - - -static struct wpabuf * eap_mschapv2_build_challenge( - struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id) -{ - struct wpabuf *req; - struct eap_mschapv2_hdr *ms; - size_t ms_len; - - if (!data->auth_challenge_from_tls && - random_get_bytes(data->auth_challenge, CHALLENGE_LEN)) { - wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random " - "data"); - data->state = FAILURE; - return NULL; - } - - ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->server_id_len; - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory" - " for request"); - data->state = FAILURE; - return NULL; - } - - ms = wpabuf_put(req, sizeof(*ms)); - ms->op_code = MSCHAPV2_OP_CHALLENGE; - ms->mschapv2_id = id; - WPA_PUT_BE16(ms->ms_length, ms_len); - - wpabuf_put_u8(req, CHALLENGE_LEN); - if (!data->auth_challenge_from_tls) - wpabuf_put_data(req, data->auth_challenge, CHALLENGE_LEN); - else - wpabuf_put(req, CHALLENGE_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge", - data->auth_challenge, CHALLENGE_LEN); - wpabuf_put_data(req, sm->server_id, sm->server_id_len); - - return req; -} - - -static struct wpabuf * eap_mschapv2_build_success_req( - struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id) -{ - struct wpabuf *req; - struct eap_mschapv2_hdr *ms; - u8 *msg; - char *message = "OK"; - size_t ms_len; - - ms_len = sizeof(*ms) + 2 + 2 * sizeof(data->auth_response) + 1 + 2 + - os_strlen(message); - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory" - " for request"); - data->state = FAILURE; - return NULL; - } - - ms = wpabuf_put(req, sizeof(*ms)); - ms->op_code = MSCHAPV2_OP_SUCCESS; - ms->mschapv2_id = data->resp_mschapv2_id; - WPA_PUT_BE16(ms->ms_length, ms_len); - msg = (u8 *) (ms + 1); - - wpabuf_put_u8(req, 'S'); - wpabuf_put_u8(req, '='); - wpa_snprintf_hex_uppercase( - wpabuf_put(req, sizeof(data->auth_response) * 2), - sizeof(data->auth_response) * 2 + 1, - data->auth_response, sizeof(data->auth_response)); - wpabuf_put_u8(req, ' '); - wpabuf_put_u8(req, 'M'); - wpabuf_put_u8(req, '='); - wpabuf_put_data(req, message, os_strlen(message)); - - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Success Request Message", - msg, ms_len - sizeof(*ms)); - - return req; -} - - -static struct wpabuf * eap_mschapv2_build_failure_req( - struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id) -{ - struct wpabuf *req; - struct eap_mschapv2_hdr *ms; - char *message = "E=691 R=0 C=00000000000000000000000000000000 V=3 " - "M=FAILED"; - size_t ms_len; - - ms_len = sizeof(*ms) + os_strlen(message); - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory" - " for request"); - data->state = FAILURE; - return NULL; - } - - ms = wpabuf_put(req, sizeof(*ms)); - ms->op_code = MSCHAPV2_OP_FAILURE; - ms->mschapv2_id = data->resp_mschapv2_id; - WPA_PUT_BE16(ms->ms_length, ms_len); - - wpabuf_put_data(req, message, os_strlen(message)); - - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Failure Request Message", - (u8 *) message, os_strlen(message)); - - return req; -} - - -static struct wpabuf * eap_mschapv2_buildReq(struct eap_sm *sm, void *priv, - u8 id) -{ - struct eap_mschapv2_data *data = priv; - - switch (data->state) { - case CHALLENGE: - return eap_mschapv2_build_challenge(sm, data, id); - case SUCCESS_REQ: - return eap_mschapv2_build_success_req(sm, data, id); - case FAILURE_REQ: - return eap_mschapv2_build_failure_req(sm, data, id); - default: - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in " - "buildReq", data->state); - break; - } - return NULL; -} - - -static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_mschapv2_data *data = priv; - struct eap_mschapv2_hdr *resp; - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, - &len); - if (pos == NULL || len < 1) { - wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame"); - return TRUE; - } - - resp = (struct eap_mschapv2_hdr *) pos; - if (data->state == CHALLENGE && - resp->op_code != MSCHAPV2_OP_RESPONSE) { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - " - "ignore op %d", resp->op_code); - return TRUE; - } - - if (data->state == SUCCESS_REQ && - resp->op_code != MSCHAPV2_OP_SUCCESS && - resp->op_code != MSCHAPV2_OP_FAILURE) { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Success or " - "Failure - ignore op %d", resp->op_code); - return TRUE; - } - - if (data->state == FAILURE_REQ && - resp->op_code != MSCHAPV2_OP_FAILURE) { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Failure " - "- ignore op %d", resp->op_code); - return TRUE; - } - - return FALSE; -} - - -static void eap_mschapv2_process_response(struct eap_sm *sm, - struct eap_mschapv2_data *data, - struct wpabuf *respData) -{ - struct eap_mschapv2_hdr *resp; - const u8 *pos, *end, *peer_challenge, *nt_response, *name; - u8 flags; - size_t len, name_len, i; - u8 expected[24]; - const u8 *username, *user; - size_t username_len, user_len; - int res; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, - &len); - if (pos == NULL || len < 1) - return; /* Should not happen - frame already validated */ - - end = pos + len; - resp = (struct eap_mschapv2_hdr *) pos; - pos = (u8 *) (resp + 1); - - if (len < sizeof(*resp) + 1 + 49 || - resp->op_code != MSCHAPV2_OP_RESPONSE || - pos[0] != 49) { - wpa_hexdump_buf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid response", - respData); - data->state = FAILURE; - return; - } - data->resp_mschapv2_id = resp->mschapv2_id; - pos++; - peer_challenge = pos; - pos += 16 + 8; - nt_response = pos; - pos += 24; - flags = *pos++; - name = pos; - name_len = end - name; - - if (data->peer_challenge) { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using pre-configured " - "Peer-Challenge"); - peer_challenge = data->peer_challenge; - } - wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge", - peer_challenge, 16); - wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: NT-Response", nt_response, 24); - wpa_printf(MSG_MSGDUMP, "EAP-MSCHAPV2: Flags 0x%x", flags); - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Name", name, name_len); - - /* MSCHAPv2 does not include optional domain name in the - * challenge-response calculation, so remove domain prefix - * (if present). */ - username = sm->identity; - username_len = sm->identity_len; - for (i = 0; i < username_len; i++) { - if (username[i] == '\\') { - username_len -= i + 1; - username += i + 1; - break; - } - } - - user = name; - user_len = name_len; - for (i = 0; i < user_len; i++) { - if (user[i] == '\\') { - user_len -= i + 1; - user += i + 1; - break; - } - } - - if (username_len != user_len || - os_memcmp(username, user, username_len) != 0) { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names"); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Expected user " - "name", username, username_len); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Received user " - "name", user, user_len); - data->state = FAILURE; - return; - } - - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: User name", - username, username_len); - - if (sm->user->password_hash) { - res = generate_nt_response_pwhash(data->auth_challenge, - peer_challenge, - username, username_len, - sm->user->password, - expected); - } else { - res = generate_nt_response(data->auth_challenge, - peer_challenge, - username, username_len, - sm->user->password, - sm->user->password_len, - expected); - } - if (res) { - data->state = FAILURE; - return; - } - - if (os_memcmp(nt_response, expected, 24) == 0) { - const u8 *pw_hash; - u8 pw_hash_buf[16], pw_hash_hash[16]; - - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Correct NT-Response"); - data->state = SUCCESS_REQ; - - /* Authenticator response is not really needed yet, but - * calculate it here so that peer_challenge and username need - * not be saved. */ - if (sm->user->password_hash) { - pw_hash = sm->user->password; - } else { - 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( - pw_hash, peer_challenge, data->auth_challenge, - username, username_len, nt_response, - data->auth_response); - - hash_nt_password_hash(pw_hash, pw_hash_hash); - get_master_key(pw_hash_hash, nt_response, data->master_key); - data->master_key_valid = 1; - wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key", - data->master_key, MSCHAPV2_KEY_LEN); - } else { - wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Expected NT-Response", - expected, 24); - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid NT-Response"); - data->state = FAILURE_REQ; - } -} - - -static void eap_mschapv2_process_success_resp(struct eap_sm *sm, - struct eap_mschapv2_data *data, - struct wpabuf *respData) -{ - struct eap_mschapv2_hdr *resp; - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, - &len); - if (pos == NULL || len < 1) - return; /* Should not happen - frame already validated */ - - resp = (struct eap_mschapv2_hdr *) pos; - - if (resp->op_code == MSCHAPV2_OP_SUCCESS) { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Success Response" - " - authentication completed successfully"); - data->state = SUCCESS; - } else { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Success " - "Response - peer rejected authentication"); - data->state = FAILURE; - } -} - - -static void eap_mschapv2_process_failure_resp(struct eap_sm *sm, - struct eap_mschapv2_data *data, - struct wpabuf *respData) -{ - struct eap_mschapv2_hdr *resp; - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, - &len); - if (pos == NULL || len < 1) - return; /* Should not happen - frame already validated */ - - resp = (struct eap_mschapv2_hdr *) pos; - - if (resp->op_code == MSCHAPV2_OP_FAILURE) { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Failure Response" - " - authentication failed"); - } else { - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Failure " - "Response - authentication failed"); - } - - data->state = FAILURE; -} - - -static void eap_mschapv2_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_mschapv2_data *data = priv; - - if (sm->user == NULL || sm->user->password == NULL) { - wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured"); - data->state = FAILURE; - return; - } - - switch (data->state) { - case CHALLENGE: - eap_mschapv2_process_response(sm, data, respData); - break; - case SUCCESS_REQ: - eap_mschapv2_process_success_resp(sm, data, respData); - break; - case FAILURE_REQ: - eap_mschapv2_process_failure_resp(sm, data, respData); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in " - "process", data->state); - break; - } -} - - -static Boolean eap_mschapv2_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_mschapv2_data *data = priv; - return data->state == SUCCESS || data->state == FAILURE; -} - - -static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_mschapv2_data *data = priv; - u8 *key; - - if (data->state != SUCCESS || !data->master_key_valid) - return NULL; - - *len = 2 * MSCHAPV2_KEY_LEN; - key = os_malloc(*len); - if (key == NULL) - return NULL; - /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */ - get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 1); - get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN, - MSCHAPV2_KEY_LEN, 1, 1); - wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len); - - return key; -} - - -static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_mschapv2_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_mschapv2_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, - "MSCHAPV2"); - if (eap == NULL) - return -1; - - eap->init = eap_mschapv2_init; - eap->reset = eap_mschapv2_reset; - eap->buildReq = eap_mschapv2_buildReq; - eap->check = eap_mschapv2_check; - eap->process = eap_mschapv2_process; - eap->isDone = eap_mschapv2_isDone; - eap->getKey = eap_mschapv2_getKey; - eap->isSuccess = eap_mschapv2_isSuccess; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_pax.c b/contrib/hostapd/src/eap_server/eap_server_pax.c deleted file mode 100644 index 35a42ad107..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_pax.c +++ /dev/null @@ -1,564 +0,0 @@ -/* - * hostapd / EAP-PAX (RFC 4746) server - * Copyright (c) 2005-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/random.h" -#include "eap_server/eap_i.h" -#include "eap_common/eap_pax_common.h" - -/* - * Note: only PAX_STD subprotocol is currently supported - * - * TODO: Add support with PAX_SEC with the mandatory to implement ciphersuite - * (HMAC_SHA1_128, IANA DH Group 14 (2048 bits), RSA-PKCS1-V1_5) and - * recommended ciphersuite (HMAC_SHA256_128, IANA DH Group 15 (3072 bits), - * RSAES-OAEP). - */ - -struct eap_pax_data { - enum { PAX_STD_1, PAX_STD_3, SUCCESS, FAILURE } state; - u8 mac_id; - union { - u8 e[2 * EAP_PAX_RAND_LEN]; - struct { - u8 x[EAP_PAX_RAND_LEN]; /* server rand */ - u8 y[EAP_PAX_RAND_LEN]; /* client rand */ - } r; - } rand; - u8 ak[EAP_PAX_AK_LEN]; - u8 mk[EAP_PAX_MK_LEN]; - u8 ck[EAP_PAX_CK_LEN]; - u8 ick[EAP_PAX_ICK_LEN]; - int keys_set; - char *cid; - size_t cid_len; -}; - - -static void * eap_pax_init(struct eap_sm *sm) -{ - struct eap_pax_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = PAX_STD_1; - /* - * TODO: make this configurable once EAP_PAX_HMAC_SHA256_128 is - * supported - */ - data->mac_id = EAP_PAX_MAC_HMAC_SHA1_128; - - return data; -} - - -static void eap_pax_reset(struct eap_sm *sm, void *priv) -{ - struct eap_pax_data *data = priv; - os_free(data->cid); - os_free(data); -} - - -static struct wpabuf * eap_pax_build_std_1(struct eap_sm *sm, - struct eap_pax_data *data, u8 id) -{ - struct wpabuf *req; - struct eap_pax_hdr *pax; - u8 *pos; - - wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (sending)"); - - if (random_get_bytes(data->rand.r.x, EAP_PAX_RAND_LEN)) { - wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data"); - data->state = FAILURE; - return NULL; - } - - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX, - sizeof(*pax) + 2 + EAP_PAX_RAND_LEN + - EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory " - "request"); - data->state = FAILURE; - return NULL; - } - - pax = wpabuf_put(req, sizeof(*pax)); - pax->op_code = EAP_PAX_OP_STD_1; - pax->flags = 0; - pax->mac_id = data->mac_id; - pax->dh_group_id = EAP_PAX_DH_GROUP_NONE; - pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE; - - wpabuf_put_be16(req, EAP_PAX_RAND_LEN); - wpabuf_put_data(req, data->rand.r.x, EAP_PAX_RAND_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: A = X (server rand)", - data->rand.r.x, EAP_PAX_RAND_LEN); - - pos = wpabuf_put(req, EAP_PAX_MAC_LEN); - eap_pax_mac(data->mac_id, (u8 *) "", 0, - wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN, - NULL, 0, NULL, 0, pos); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN); - - return req; -} - - -static struct wpabuf * eap_pax_build_std_3(struct eap_sm *sm, - struct eap_pax_data *data, u8 id) -{ - struct wpabuf *req; - struct eap_pax_hdr *pax; - u8 *pos; - - wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (sending)"); - - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX, - sizeof(*pax) + 2 + EAP_PAX_MAC_LEN + - EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory " - "request"); - data->state = FAILURE; - return NULL; - } - - pax = wpabuf_put(req, sizeof(*pax)); - pax->op_code = EAP_PAX_OP_STD_3; - pax->flags = 0; - pax->mac_id = data->mac_id; - pax->dh_group_id = EAP_PAX_DH_GROUP_NONE; - pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE; - - wpabuf_put_be16(req, EAP_PAX_MAC_LEN); - pos = wpabuf_put(req, EAP_PAX_MAC_LEN); - eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN, - data->rand.r.y, EAP_PAX_RAND_LEN, - (u8 *) data->cid, data->cid_len, NULL, 0, pos); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)", - pos, EAP_PAX_MAC_LEN); - pos += EAP_PAX_MAC_LEN; - - /* Optional ADE could be added here, if needed */ - - pos = wpabuf_put(req, EAP_PAX_MAC_LEN); - eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN, - wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN, - NULL, 0, NULL, 0, pos); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN); - - return req; -} - - -static struct wpabuf * eap_pax_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_pax_data *data = priv; - - switch (data->state) { - case PAX_STD_1: - return eap_pax_build_std_1(sm, data, id); - case PAX_STD_3: - return eap_pax_build_std_3(sm, data, id); - default: - wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown state %d in buildReq", - data->state); - break; - } - return NULL; -} - - -static Boolean eap_pax_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_pax_data *data = priv; - struct eap_pax_hdr *resp; - const u8 *pos; - size_t len, mlen; - u8 icvbuf[EAP_PAX_ICV_LEN], *icv; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len); - if (pos == NULL || len < sizeof(*resp)) { - wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame"); - return TRUE; - } - - mlen = sizeof(struct eap_hdr) + 1 + len; - resp = (struct eap_pax_hdr *) pos; - - wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x " - "flags 0x%x mac_id 0x%x dh_group_id 0x%x " - "public_key_id 0x%x", - resp->op_code, resp->flags, resp->mac_id, resp->dh_group_id, - resp->public_key_id); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload", - (u8 *) (resp + 1), len - sizeof(*resp) - EAP_PAX_ICV_LEN); - - if (data->state == PAX_STD_1 && - resp->op_code != EAP_PAX_OP_STD_2) { - wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX_STD-2 - " - "ignore op %d", resp->op_code); - return TRUE; - } - - if (data->state == PAX_STD_3 && - resp->op_code != EAP_PAX_OP_ACK) { - wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX-ACK - " - "ignore op %d", resp->op_code); - return TRUE; - } - - if (resp->op_code != EAP_PAX_OP_STD_2 && - resp->op_code != EAP_PAX_OP_ACK) { - wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown op_code 0x%x", - resp->op_code); - } - - if (data->mac_id != resp->mac_id) { - wpa_printf(MSG_DEBUG, "EAP-PAX: Expected MAC ID 0x%x, " - "received 0x%x", data->mac_id, resp->mac_id); - return TRUE; - } - - if (resp->dh_group_id != EAP_PAX_DH_GROUP_NONE) { - wpa_printf(MSG_INFO, "EAP-PAX: Expected DH Group ID 0x%x, " - "received 0x%x", EAP_PAX_DH_GROUP_NONE, - resp->dh_group_id); - return TRUE; - } - - if (resp->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) { - wpa_printf(MSG_INFO, "EAP-PAX: Expected Public Key ID 0x%x, " - "received 0x%x", EAP_PAX_PUBLIC_KEY_NONE, - resp->public_key_id); - return TRUE; - } - - if (resp->flags & EAP_PAX_FLAGS_MF) { - /* TODO: add support for reassembling fragments */ - wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported"); - return TRUE; - } - - if (resp->flags & EAP_PAX_FLAGS_CE) { - wpa_printf(MSG_INFO, "EAP-PAX: Unexpected CE flag"); - return TRUE; - } - - if (data->keys_set) { - if (len - sizeof(*resp) < EAP_PAX_ICV_LEN) { - wpa_printf(MSG_INFO, "EAP-PAX: No ICV in the packet"); - return TRUE; - } - icv = wpabuf_mhead_u8(respData) + mlen - EAP_PAX_ICV_LEN; - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN); - eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN, - wpabuf_mhead(respData), - wpabuf_len(respData) - EAP_PAX_ICV_LEN, - NULL, 0, NULL, 0, icvbuf); - if (os_memcmp(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) { - wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV"); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV", - icvbuf, EAP_PAX_ICV_LEN); - return TRUE; - } - } - - return FALSE; -} - - -static void eap_pax_process_std_2(struct eap_sm *sm, - struct eap_pax_data *data, - struct wpabuf *respData) -{ - struct eap_pax_hdr *resp; - u8 mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN]; - const u8 *pos; - size_t len, left; - int i; - - if (data->state != PAX_STD_1) - return; - - wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX_STD-2"); - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len); - if (pos == NULL || len < sizeof(*resp) + EAP_PAX_ICV_LEN) - return; - - resp = (struct eap_pax_hdr *) pos; - pos = (u8 *) (resp + 1); - left = len - sizeof(*resp); - - if (left < 2 + EAP_PAX_RAND_LEN || - WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) { - wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (B)"); - return; - } - pos += 2; - left -= 2; - os_memcpy(data->rand.r.y, pos, EAP_PAX_RAND_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)", - data->rand.r.y, EAP_PAX_RAND_LEN); - pos += EAP_PAX_RAND_LEN; - left -= EAP_PAX_RAND_LEN; - - if (left < 2 || (size_t) 2 + WPA_GET_BE16(pos) > left) { - wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)"); - return; - } - data->cid_len = WPA_GET_BE16(pos); - os_free(data->cid); - data->cid = os_malloc(data->cid_len); - if (data->cid == NULL) { - wpa_printf(MSG_INFO, "EAP-PAX: Failed to allocate memory for " - "CID"); - return; - } - os_memcpy(data->cid, pos + 2, data->cid_len); - pos += 2 + data->cid_len; - left -= 2 + data->cid_len; - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID", - (u8 *) data->cid, data->cid_len); - - if (left < 2 + EAP_PAX_MAC_LEN || - WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) { - wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (MAC_CK)"); - return; - } - pos += 2; - left -= 2; - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)", - pos, EAP_PAX_MAC_LEN); - - if (eap_user_get(sm, (u8 *) data->cid, data->cid_len, 0) < 0) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: unknown CID", - (u8 *) data->cid, data->cid_len); - data->state = FAILURE; - return; - } - - for (i = 0; - i < EAP_MAX_METHODS && - (sm->user->methods[i].vendor != EAP_VENDOR_IETF || - sm->user->methods[i].method != EAP_TYPE_NONE); - i++) { - if (sm->user->methods[i].vendor == EAP_VENDOR_IETF && - sm->user->methods[i].method == EAP_TYPE_PAX) - break; - } - - if (i >= EAP_MAX_METHODS || - sm->user->methods[i].vendor != EAP_VENDOR_IETF || - sm->user->methods[i].method != EAP_TYPE_PAX) { - wpa_hexdump_ascii(MSG_DEBUG, - "EAP-PAX: EAP-PAX not enabled for CID", - (u8 *) data->cid, data->cid_len); - data->state = FAILURE; - return; - } - - if (sm->user->password == NULL || - sm->user->password_len != EAP_PAX_AK_LEN) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: invalid password in " - "user database for CID", - (u8 *) data->cid, data->cid_len); - data->state = FAILURE; - return; - } - os_memcpy(data->ak, sm->user->password, EAP_PAX_AK_LEN); - - if (eap_pax_initial_key_derivation(data->mac_id, data->ak, - data->rand.e, data->mk, data->ck, - data->ick) < 0) { - wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial " - "key derivation"); - data->state = FAILURE; - return; - } - data->keys_set = 1; - - eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN, - data->rand.r.x, EAP_PAX_RAND_LEN, - data->rand.r.y, EAP_PAX_RAND_LEN, - (u8 *) data->cid, data->cid_len, mac); - if (os_memcmp(mac, pos, EAP_PAX_MAC_LEN) != 0) { - wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in " - "PAX_STD-2"); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)", - mac, EAP_PAX_MAC_LEN); - data->state = FAILURE; - return; - } - - pos += EAP_PAX_MAC_LEN; - left -= EAP_PAX_MAC_LEN; - - if (left < EAP_PAX_ICV_LEN) { - wpa_printf(MSG_INFO, "EAP-PAX: Too short ICV (%lu) in " - "PAX_STD-2", (unsigned long) left); - return; - } - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN); - eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN, - wpabuf_head(respData), - wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0, - icvbuf); - if (os_memcmp(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) { - wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2"); - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV", - icvbuf, EAP_PAX_ICV_LEN); - return; - } - pos += EAP_PAX_ICV_LEN; - left -= EAP_PAX_ICV_LEN; - - if (left > 0) { - wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload", - pos, left); - } - - data->state = PAX_STD_3; -} - - -static void eap_pax_process_ack(struct eap_sm *sm, - struct eap_pax_data *data, - struct wpabuf *respData) -{ - if (data->state != PAX_STD_3) - return; - - wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX-ACK - authentication " - "completed successfully"); - data->state = SUCCESS; -} - - -static void eap_pax_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_pax_data *data = priv; - struct eap_pax_hdr *resp; - const u8 *pos; - size_t len; - - if (sm->user == NULL || sm->user->password == NULL) { - wpa_printf(MSG_INFO, "EAP-PAX: Plaintext password not " - "configured"); - data->state = FAILURE; - return; - } - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len); - if (pos == NULL || len < sizeof(*resp)) - return; - - resp = (struct eap_pax_hdr *) pos; - - switch (resp->op_code) { - case EAP_PAX_OP_STD_2: - eap_pax_process_std_2(sm, data, respData); - break; - case EAP_PAX_OP_ACK: - eap_pax_process_ack(sm, data, respData); - break; - } -} - - -static Boolean eap_pax_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_pax_data *data = priv; - return data->state == SUCCESS || data->state == FAILURE; -} - - -static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_pax_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key == NULL) - return NULL; - - *len = EAP_MSK_LEN; - eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN, - "Master Session Key", data->rand.e, 2 * EAP_PAX_RAND_LEN, - EAP_MSK_LEN, key); - - return key; -} - - -static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_pax_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - - *len = EAP_EMSK_LEN; - eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN, - "Extended Master Session Key", - data->rand.e, 2 * EAP_PAX_RAND_LEN, - EAP_EMSK_LEN, key); - - return key; -} - - -static Boolean eap_pax_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_pax_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_pax_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX"); - if (eap == NULL) - return -1; - - eap->init = eap_pax_init; - eap->reset = eap_pax_reset; - eap->buildReq = eap_pax_buildReq; - eap->check = eap_pax_check; - eap->process = eap_pax_process; - eap->isDone = eap_pax_isDone; - eap->getKey = eap_pax_getKey; - eap->isSuccess = eap_pax_isSuccess; - eap->get_emsk = eap_pax_get_emsk; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_peap.c b/contrib/hostapd/src/eap_server/eap_server_peap.c deleted file mode 100644 index defcb3c054..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_peap.c +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt) - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha1.h" -#include "crypto/tls.h" -#include "crypto/random.h" -#include "eap_i.h" -#include "eap_tls_common.h" -#include "eap_common/eap_tlv_common.h" -#include "eap_common/eap_peap_common.h" -#include "tncs.h" - - -/* Maximum supported PEAP version - * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt - * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt - */ -#define EAP_PEAP_VERSION 1 - - -static void eap_peap_reset(struct eap_sm *sm, void *priv); - - -struct eap_peap_data { - struct eap_ssl_data ssl; - enum { - START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID, - PHASE2_METHOD, PHASE2_SOH, - PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE - } state; - - int peap_version; - int recv_version; - const struct eap_method *phase2_method; - void *phase2_priv; - int force_version; - struct wpabuf *pending_phase2_resp; - enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request; - int crypto_binding_sent; - int crypto_binding_used; - enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding; - u8 binding_nonce[32]; - u8 ipmk[40]; - u8 cmk[20]; - u8 *phase2_key; - size_t phase2_key_len; - struct wpabuf *soh_response; -}; - - -static const char * eap_peap_state_txt(int state) -{ - switch (state) { - case START: - return "START"; - case PHASE1: - return "PHASE1"; - case PHASE1_ID2: - return "PHASE1_ID2"; - case PHASE2_START: - return "PHASE2_START"; - case PHASE2_ID: - return "PHASE2_ID"; - case PHASE2_METHOD: - return "PHASE2_METHOD"; - case PHASE2_SOH: - return "PHASE2_SOH"; - case PHASE2_TLV: - return "PHASE2_TLV"; - case SUCCESS_REQ: - return "SUCCESS_REQ"; - case FAILURE_REQ: - return "FAILURE_REQ"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "Unknown?!"; - } -} - - -static void eap_peap_state(struct eap_peap_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s", - eap_peap_state_txt(data->state), - eap_peap_state_txt(state)); - data->state = state; -} - - -static void eap_peap_req_success(struct eap_sm *sm, - struct eap_peap_data *data) -{ - if (data->state == FAILURE || data->state == FAILURE_REQ) { - eap_peap_state(data, FAILURE); - return; - } - - if (data->peap_version == 0) { - data->tlv_request = TLV_REQ_SUCCESS; - eap_peap_state(data, PHASE2_TLV); - } else { - eap_peap_state(data, SUCCESS_REQ); - } -} - - -static void eap_peap_req_failure(struct eap_sm *sm, - struct eap_peap_data *data) -{ - if (data->state == FAILURE || data->state == FAILURE_REQ || - data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) { - eap_peap_state(data, FAILURE); - return; - } - - if (data->peap_version == 0) { - data->tlv_request = TLV_REQ_FAILURE; - eap_peap_state(data, PHASE2_TLV); - } else { - eap_peap_state(data, FAILURE_REQ); - } -} - - -static void * eap_peap_init(struct eap_sm *sm) -{ - struct eap_peap_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->peap_version = EAP_PEAP_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-PEAP: forcing version %d", - data->force_version); - data->peap_version = data->force_version; - } - data->state = START; - data->crypto_binding = OPTIONAL_BINDING; - - if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) { - wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL."); - eap_peap_reset(sm, data); - return NULL; - } - - return data; -} - - -static void eap_peap_reset(struct eap_sm *sm, void *priv) -{ - struct eap_peap_data *data = priv; - if (data == NULL) - return; - if (data->phase2_priv && data->phase2_method) - data->phase2_method->reset(sm, data->phase2_priv); - eap_server_tls_ssl_deinit(sm, &data->ssl); - wpabuf_free(data->pending_phase2_resp); - os_free(data->phase2_key); - wpabuf_free(data->soh_response); - os_free(data); -} - - -static struct wpabuf * eap_peap_build_start(struct eap_sm *sm, - struct eap_peap_data *data, u8 id) -{ - struct wpabuf *req; - - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for" - " request"); - eap_peap_state(data, FAILURE); - return NULL; - } - - wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version); - - eap_peap_state(data, PHASE1); - - return req; -} - - -static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm, - struct eap_peap_data *data, - u8 id) -{ - struct wpabuf *buf, *encr_req, msgbuf; - const u8 *req; - size_t req_len; - - if (data->phase2_method == NULL || data->phase2_priv == NULL) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready"); - return NULL; - } - buf = data->phase2_method->buildReq(sm, data->phase2_priv, id); - if (buf == NULL) - return NULL; - - req = wpabuf_head(buf); - req_len = wpabuf_len(buf); - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data", - req, req_len); - - if (data->peap_version == 0 && - data->phase2_method->method != EAP_TYPE_TLV) { - req += sizeof(struct eap_hdr); - req_len -= sizeof(struct eap_hdr); - } - - wpabuf_set(&msgbuf, req, req_len); - encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); - wpabuf_free(buf); - - return encr_req; -} - - -#ifdef EAP_SERVER_TNC -static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm, - struct eap_peap_data *data, - u8 id) -{ - struct wpabuf *buf1, *buf, *encr_req, msgbuf; - const u8 *req; - size_t req_len; - - buf1 = tncs_build_soh_request(); - if (buf1 == NULL) - return NULL; - - buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1), - EAP_CODE_REQUEST, id); - if (buf == NULL) { - wpabuf_free(buf1); - return NULL; - } - wpabuf_put_buf(buf, buf1); - wpabuf_free(buf1); - - req = wpabuf_head(buf); - req_len = wpabuf_len(buf); - - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data", - req, req_len); - - req += sizeof(struct eap_hdr); - req_len -= sizeof(struct eap_hdr); - wpabuf_set(&msgbuf, req, req_len); - - encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); - wpabuf_free(buf); - - return encr_req; -} -#endif /* EAP_SERVER_TNC */ - - -static void eap_peap_get_isk(struct eap_peap_data *data, - u8 *isk, size_t isk_len) -{ - size_t key_len; - - os_memset(isk, 0, isk_len); - if (data->phase2_key == NULL) - return; - - key_len = data->phase2_key_len; - if (key_len > isk_len) - key_len = isk_len; - os_memcpy(isk, data->phase2_key, key_len); -} - - -static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) -{ - u8 *tk; - u8 isk[32], imck[60]; - - /* - * Tunnel key (TK) is the first 60 octets of the key generated by - * phase 1 of PEAP (based on TLS). - */ - tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption", - EAP_TLS_KEY_LEN); - if (tk == NULL) - return -1; - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60); - - eap_peap_get_isk(data, isk, sizeof(isk)); - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk)); - - /* - * IPMK Seed = "Inner Methods Compound Keys" | ISK - * TempKey = First 40 octets of TK - * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60) - * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space - * in the end of the label just before ISK; is that just a typo?) - */ - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40); - 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)); - - os_free(tk); - - /* TODO: fast-connect: IPMK|CMK = TK */ - os_memcpy(data->ipmk, imck, 40); - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40); - os_memcpy(data->cmk, imck + 40, 20); - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20); - - return 0; -} - - -static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, - struct eap_peap_data *data, - u8 id) -{ - struct wpabuf *buf, *encr_req; - size_t mlen; - - mlen = 6; /* Result TLV */ - if (data->crypto_binding != NO_BINDING) - mlen += 60; /* Cryptobinding TLV */ -#ifdef EAP_SERVER_TNC - if (data->soh_response) - mlen += wpabuf_len(data->soh_response); -#endif /* EAP_SERVER_TNC */ - - buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen, - EAP_CODE_REQUEST, id); - if (buf == NULL) - return NULL; - - wpabuf_put_u8(buf, 0x80); /* Mandatory */ - wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV); - /* Length */ - wpabuf_put_be16(buf, 2); - /* Status */ - wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ? - EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE); - - if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS && - data->crypto_binding != NO_BINDING) { - u8 *mac; - u8 eap_type = EAP_TYPE_PEAP; - const u8 *addr[2]; - size_t len[2]; - u16 tlv_type; - -#ifdef EAP_SERVER_TNC - if (data->soh_response) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH " - "Response TLV"); - wpabuf_put_buf(buf, data->soh_response); - wpabuf_free(data->soh_response); - data->soh_response = NULL; - } -#endif /* EAP_SERVER_TNC */ - - if (eap_peap_derive_cmk(sm, data) < 0 || - random_get_bytes(data->binding_nonce, 32)) { - wpabuf_free(buf); - return NULL; - } - - /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ - addr[0] = wpabuf_put(buf, 0); - len[0] = 60; - addr[1] = &eap_type; - len[1] = 1; - - tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; - wpabuf_put_be16(buf, tlv_type); - wpabuf_put_be16(buf, 56); - - wpabuf_put_u8(buf, 0); /* Reserved */ - wpabuf_put_u8(buf, data->peap_version); /* Version */ - wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */ - wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */ - wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */ - mac = wpabuf_put(buf, 20); /* Compound_MAC */ - wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", - data->cmk, 20); - wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1", - addr[0], len[0]); - wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", - addr[1], len[1]); - hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac); - wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", - mac, SHA1_MAC_LEN); - data->crypto_binding_sent = 1; - } - - wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data", - buf); - - encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf); - wpabuf_free(buf); - - return encr_req; -} - - -static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm, - struct eap_peap_data *data, - u8 id, int success) -{ - struct wpabuf *encr_req, msgbuf; - size_t req_len; - struct eap_hdr *hdr; - - req_len = sizeof(*hdr); - hdr = os_zalloc(req_len); - if (hdr == NULL) - return NULL; - - hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE; - hdr->identifier = id; - hdr->length = host_to_be16(req_len); - - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data", - (u8 *) hdr, req_len); - - wpabuf_set(&msgbuf, hdr, req_len); - encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); - os_free(hdr); - - return encr_req; -} - - -static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_peap_data *data = priv; - - if (data->ssl.state == FRAG_ACK) { - return eap_server_tls_build_ack(id, EAP_TYPE_PEAP, - data->peap_version); - } - - if (data->ssl.state == WAIT_FRAG_ACK) { - return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP, - data->peap_version, id); - } - - switch (data->state) { - case START: - return eap_peap_build_start(sm, data, id); - case PHASE1: - case PHASE1_ID2: - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, " - "starting Phase2"); - eap_peap_state(data, PHASE2_START); - } - break; - case PHASE2_ID: - case PHASE2_METHOD: - wpabuf_free(data->ssl.tls_out); - data->ssl.tls_out_pos = 0; - data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id); - break; -#ifdef EAP_SERVER_TNC - case PHASE2_SOH: - wpabuf_free(data->ssl.tls_out); - data->ssl.tls_out_pos = 0; - data->ssl.tls_out = eap_peap_build_phase2_soh(sm, data, id); - break; -#endif /* EAP_SERVER_TNC */ - case PHASE2_TLV: - wpabuf_free(data->ssl.tls_out); - data->ssl.tls_out_pos = 0; - data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id); - break; - case SUCCESS_REQ: - wpabuf_free(data->ssl.tls_out); - data->ssl.tls_out_pos = 0; - data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id, - 1); - break; - case FAILURE_REQ: - wpabuf_free(data->ssl.tls_out); - data->ssl.tls_out_pos = 0; - data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id, - 0); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d", - __func__, data->state); - return NULL; - } - - return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP, - data->peap_version, id); -} - - -static Boolean eap_peap_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len); - if (pos == NULL || len < 1) { - wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame"); - return TRUE; - } - - return FALSE; -} - - -static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data, - EapType eap_type) -{ - if (data->phase2_priv && data->phase2_method) { - data->phase2_method->reset(sm, data->phase2_priv); - data->phase2_method = NULL; - data->phase2_priv = NULL; - } - data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF, - eap_type); - if (!data->phase2_method) - return -1; - - sm->init_phase2 = 1; - data->phase2_priv = data->phase2_method->init(sm); - sm->init_phase2 = 0; - return 0; -} - - -static int eap_tlv_validate_cryptobinding(struct eap_sm *sm, - struct eap_peap_data *data, - const u8 *crypto_tlv, - size_t crypto_tlv_len) -{ - u8 buf[61], mac[SHA1_MAC_LEN]; - const u8 *pos; - - if (crypto_tlv_len != 4 + 56) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV " - "length %d", (int) crypto_tlv_len); - return -1; - } - - pos = crypto_tlv; - pos += 4; /* TLV header */ - if (pos[1] != data->peap_version) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version " - "mismatch (was %d; expected %d)", - pos[1], data->peap_version); - return -1; - } - - if (pos[3] != 1) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV " - "SubType %d", pos[3]); - return -1; - } - pos += 4; - pos += 32; /* Nonce */ - - /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ - os_memcpy(buf, crypto_tlv, 60); - os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */ - buf[60] = EAP_TYPE_PEAP; - hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac); - - if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in " - "cryptobinding TLV"); - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20); - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data", - buf, 61); - return -1; - } - - wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received"); - - return 0; -} - - -static void eap_peap_process_phase2_tlv(struct eap_sm *sm, - struct eap_peap_data *data, - struct wpabuf *in_data) -{ - const u8 *pos; - size_t left; - const u8 *result_tlv = NULL, *crypto_tlv = NULL; - size_t result_tlv_len = 0, crypto_tlv_len = 0; - int tlv_type, mandatory, tlv_len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left); - if (pos == NULL) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header"); - return; - } - - /* Parse TLVs */ - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left); - while (left >= 4) { - mandatory = !!(pos[0] & 0x80); - tlv_type = pos[0] & 0x3f; - tlv_type = (tlv_type << 8) | pos[1]; - tlv_len = ((int) pos[2] << 8) | pos[3]; - pos += 4; - left -= 4; - if ((size_t) tlv_len > left) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun " - "(tlv_len=%d left=%lu)", tlv_len, - (unsigned long) left); - eap_peap_state(data, FAILURE); - return; - } - switch (tlv_type) { - case EAP_TLV_RESULT_TLV: - result_tlv = pos; - result_tlv_len = tlv_len; - break; - case EAP_TLV_CRYPTO_BINDING_TLV: - crypto_tlv = pos; - crypto_tlv_len = tlv_len; - break; - default: - wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type " - "%d%s", tlv_type, - mandatory ? " (mandatory)" : ""); - if (mandatory) { - eap_peap_state(data, FAILURE); - return; - } - /* Ignore this TLV, but process other TLVs */ - break; - } - - pos += tlv_len; - left -= tlv_len; - } - if (left) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in " - "Request (left=%lu)", (unsigned long) left); - eap_peap_state(data, FAILURE); - return; - } - - /* Process supported TLVs */ - if (crypto_tlv && data->crypto_binding_sent) { - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV", - crypto_tlv, crypto_tlv_len); - if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4, - crypto_tlv_len + 4) < 0) { - eap_peap_state(data, FAILURE); - return; - } - data->crypto_binding_used = 1; - } else if (!crypto_tlv && data->crypto_binding_sent && - data->crypto_binding == REQUIRE_BINDING) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV"); - eap_peap_state(data, FAILURE); - return; - } - - if (result_tlv) { - int status; - const char *requested; - - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV", - result_tlv, result_tlv_len); - if (result_tlv_len < 2) { - wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV " - "(len=%lu)", - (unsigned long) result_tlv_len); - eap_peap_state(data, FAILURE); - return; - } - requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" : - "Failure"; - status = WPA_GET_BE16(result_tlv); - if (status == EAP_TLV_RESULT_SUCCESS) { - wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success " - "- requested %s", requested); - if (data->tlv_request == TLV_REQ_SUCCESS) - eap_peap_state(data, SUCCESS); - else - eap_peap_state(data, FAILURE); - - } else if (status == EAP_TLV_RESULT_FAILURE) { - wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure " - "- requested %s", requested); - eap_peap_state(data, FAILURE); - } else { - wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result " - "Status %d", status); - eap_peap_state(data, FAILURE); - } - } -} - - -#ifdef EAP_SERVER_TNC -static void eap_peap_process_phase2_soh(struct eap_sm *sm, - struct eap_peap_data *data, - struct wpabuf *in_data) -{ - const u8 *pos, *vpos; - size_t left; - const u8 *soh_tlv = NULL; - size_t soh_tlv_len = 0; - int tlv_type, mandatory, tlv_len, vtlv_len; - u8 next_type; - u32 vendor_id; - - pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left); - if (pos == NULL) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP " - "Extensions Method header - skip TNC"); - goto auth_method; - } - - /* Parse TLVs */ - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left); - while (left >= 4) { - mandatory = !!(pos[0] & 0x80); - tlv_type = pos[0] & 0x3f; - tlv_type = (tlv_type << 8) | pos[1]; - tlv_len = ((int) pos[2] << 8) | pos[3]; - pos += 4; - left -= 4; - if ((size_t) tlv_len > left) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun " - "(tlv_len=%d left=%lu)", tlv_len, - (unsigned long) left); - eap_peap_state(data, FAILURE); - return; - } - switch (tlv_type) { - case EAP_TLV_VENDOR_SPECIFIC_TLV: - if (tlv_len < 4) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short " - "vendor specific TLV (len=%d)", - (int) tlv_len); - eap_peap_state(data, FAILURE); - return; - } - - vendor_id = WPA_GET_BE32(pos); - if (vendor_id != EAP_VENDOR_MICROSOFT) { - if (mandatory) { - eap_peap_state(data, FAILURE); - return; - } - break; - } - - vpos = pos + 4; - mandatory = !!(vpos[0] & 0x80); - tlv_type = vpos[0] & 0x3f; - tlv_type = (tlv_type << 8) | vpos[1]; - vtlv_len = ((int) vpos[2] << 8) | vpos[3]; - vpos += 4; - if (vpos + vtlv_len > pos + left) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV " - "underrun"); - eap_peap_state(data, FAILURE); - return; - } - - if (tlv_type == 1) { - soh_tlv = vpos; - soh_tlv_len = vtlv_len; - break; - } - - wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV " - "Type %d%s", tlv_type, - mandatory ? " (mandatory)" : ""); - if (mandatory) { - eap_peap_state(data, FAILURE); - return; - } - /* Ignore this TLV, but process other TLVs */ - break; - default: - wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type " - "%d%s", tlv_type, - mandatory ? " (mandatory)" : ""); - if (mandatory) { - eap_peap_state(data, FAILURE); - return; - } - /* Ignore this TLV, but process other TLVs */ - break; - } - - pos += tlv_len; - left -= tlv_len; - } - if (left) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in " - "Request (left=%lu)", (unsigned long) left); - eap_peap_state(data, FAILURE); - return; - } - - /* Process supported TLVs */ - if (soh_tlv) { - int failure = 0; - wpabuf_free(data->soh_response); - data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len, - &failure); - if (failure) { - eap_peap_state(data, FAILURE); - return; - } - } else { - wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received"); - eap_peap_state(data, FAILURE); - return; - } - -auth_method: - eap_peap_state(data, PHASE2_METHOD); - next_type = sm->user->methods[0].method; - sm->user_eap_method_index = 1; - wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); - eap_peap_phase2_init(sm, data, next_type); -} -#endif /* EAP_SERVER_TNC */ - - -static void eap_peap_process_phase2_response(struct eap_sm *sm, - struct eap_peap_data *data, - struct wpabuf *in_data) -{ - u8 next_type = EAP_TYPE_NONE; - const struct eap_hdr *hdr; - const u8 *pos; - size_t left; - - if (data->state == PHASE2_TLV) { - eap_peap_process_phase2_tlv(sm, data, in_data); - return; - } - -#ifdef EAP_SERVER_TNC - if (data->state == PHASE2_SOH) { - eap_peap_process_phase2_soh(sm, data, in_data); - return; - } -#endif /* EAP_SERVER_TNC */ - - if (data->phase2_priv == NULL) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not " - "initialized?!", __func__); - return; - } - - hdr = wpabuf_head(in_data); - pos = (const u8 *) (hdr + 1); - - if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { - left = wpabuf_len(in_data) - sizeof(*hdr); - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; " - "allowed types", pos + 1, left - 1); - eap_sm_process_nak(sm, pos + 1, left - 1); - if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && - sm->user->methods[sm->user_eap_method_index].method != - EAP_TYPE_NONE) { - next_type = sm->user->methods[ - sm->user_eap_method_index++].method; - wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", - next_type); - } else { - eap_peap_req_failure(sm, data); - next_type = EAP_TYPE_NONE; - } - eap_peap_phase2_init(sm, data, next_type); - return; - } - - if (data->phase2_method->check(sm, data->phase2_priv, in_data)) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to " - "ignore the packet"); - return; - } - - data->phase2_method->process(sm, data->phase2_priv, in_data); - - if (sm->method_pending == METHOD_PENDING_WAIT) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in " - "pending wait state - save decrypted response"); - wpabuf_free(data->pending_phase2_resp); - data->pending_phase2_resp = wpabuf_dup(in_data); - } - - if (!data->phase2_method->isDone(sm, data->phase2_priv)) - return; - - if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed"); - eap_peap_req_failure(sm, data); - next_type = EAP_TYPE_NONE; - eap_peap_phase2_init(sm, data, next_type); - return; - } - - os_free(data->phase2_key); - if (data->phase2_method->getKey) { - data->phase2_key = data->phase2_method->getKey( - sm, data->phase2_priv, &data->phase2_key_len); - if (data->phase2_key == NULL) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey " - "failed"); - eap_peap_req_failure(sm, data); - eap_peap_phase2_init(sm, data, EAP_TYPE_NONE); - return; - } - } - - switch (data->state) { - case PHASE1_ID2: - case PHASE2_ID: - case PHASE2_SOH: - if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 " - "Identity not found in the user " - "database", - sm->identity, sm->identity_len); - eap_peap_req_failure(sm, data); - next_type = EAP_TYPE_NONE; - break; - } - -#ifdef EAP_SERVER_TNC - if (data->state != PHASE2_SOH && sm->tnc && - data->peap_version == 0) { - eap_peap_state(data, PHASE2_SOH); - wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize " - "TNC (NAP SOH)"); - next_type = EAP_TYPE_NONE; - break; - } -#endif /* EAP_SERVER_TNC */ - - eap_peap_state(data, PHASE2_METHOD); - next_type = sm->user->methods[0].method; - sm->user_eap_method_index = 1; - wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); - break; - case PHASE2_METHOD: - eap_peap_req_success(sm, data); - next_type = EAP_TYPE_NONE; - break; - case FAILURE: - break; - default: - wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d", - __func__, data->state); - break; - } - - eap_peap_phase2_init(sm, data, next_type); -} - - -static void eap_peap_process_phase2(struct eap_sm *sm, - struct eap_peap_data *data, - const struct wpabuf *respData, - struct wpabuf *in_buf) -{ - struct wpabuf *in_decrypted; - const struct eap_hdr *hdr; - size_t len; - - wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" - " Phase 2", (unsigned long) wpabuf_len(in_buf)); - - if (data->pending_phase2_resp) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - " - "skip decryption and use old data"); - eap_peap_process_phase2_response(sm, data, - data->pending_phase2_resp); - wpabuf_free(data->pending_phase2_resp); - data->pending_phase2_resp = NULL; - return; - } - - in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, - in_buf); - if (in_decrypted == NULL) { - wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 " - "data"); - eap_peap_state(data, FAILURE); - return; - } - - wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", - in_decrypted); - - if (data->peap_version == 0 && data->state != PHASE2_TLV) { - const struct eap_hdr *resp; - struct eap_hdr *nhdr; - struct wpabuf *nbuf = - wpabuf_alloc(sizeof(struct eap_hdr) + - wpabuf_len(in_decrypted)); - if (nbuf == NULL) { - wpabuf_free(in_decrypted); - return; - } - - resp = wpabuf_head(respData); - nhdr = wpabuf_put(nbuf, sizeof(*nhdr)); - nhdr->code = resp->code; - nhdr->identifier = resp->identifier; - nhdr->length = host_to_be16(sizeof(struct eap_hdr) + - wpabuf_len(in_decrypted)); - wpabuf_put_buf(nbuf, in_decrypted); - wpabuf_free(in_decrypted); - - in_decrypted = nbuf; - } - - hdr = wpabuf_head(in_decrypted); - if (wpabuf_len(in_decrypted) < (int) sizeof(*hdr)) { - wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " - "EAP frame (len=%lu)", - (unsigned long) wpabuf_len(in_decrypted)); - wpabuf_free(in_decrypted); - eap_peap_req_failure(sm, data); - return; - } - len = be_to_host16(hdr->length); - if (len > wpabuf_len(in_decrypted)) { - wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in " - "Phase 2 EAP frame (len=%lu hdr->length=%lu)", - (unsigned long) wpabuf_len(in_decrypted), - (unsigned long) len); - wpabuf_free(in_decrypted); - eap_peap_req_failure(sm, data); - return; - } - wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d " - "identifier=%d length=%lu", hdr->code, hdr->identifier, - (unsigned long) len); - switch (hdr->code) { - case EAP_CODE_RESPONSE: - eap_peap_process_phase2_response(sm, data, in_decrypted); - break; - case EAP_CODE_SUCCESS: - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success"); - if (data->state == SUCCESS_REQ) { - eap_peap_state(data, SUCCESS); - } - break; - case EAP_CODE_FAILURE: - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure"); - eap_peap_state(data, FAILURE); - break; - default: - wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in " - "Phase 2 EAP header", hdr->code); - break; - } - - wpabuf_free(in_decrypted); -} - - -static int eap_peap_process_version(struct eap_sm *sm, void *priv, - int peer_version) -{ - struct eap_peap_data *data = priv; - - data->recv_version = peer_version; - if (data->force_version >= 0 && peer_version != data->force_version) { - wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced" - " version (forced=%d peer=%d) - reject", - data->force_version, peer_version); - return -1; - } - if (peer_version < data->peap_version) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; " - "use version %d", - peer_version, data->peap_version, peer_version); - data->peap_version = peer_version; - } - - return 0; -} - - -static void eap_peap_process_msg(struct eap_sm *sm, void *priv, - const struct wpabuf *respData) -{ - struct eap_peap_data *data = priv; - - switch (data->state) { - case PHASE1: - if (eap_server_tls_phase1(sm, &data->ssl) < 0) { - eap_peap_state(data, FAILURE); - break; - } - break; - case PHASE2_START: - eap_peap_state(data, PHASE2_ID); - eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY); - break; - case PHASE1_ID2: - case PHASE2_ID: - case PHASE2_METHOD: - case PHASE2_SOH: - case PHASE2_TLV: - eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in); - break; - case SUCCESS_REQ: - eap_peap_state(data, SUCCESS); - break; - case FAILURE_REQ: - eap_peap_state(data, FAILURE); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s", - data->state, __func__); - break; - } -} - - -static void eap_peap_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_peap_data *data = priv; - if (eap_server_tls_process(sm, &data->ssl, respData, data, - EAP_TYPE_PEAP, eap_peap_process_version, - eap_peap_process_msg) < 0) - eap_peap_state(data, FAILURE); -} - - -static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_peap_data *data = priv; - return data->state == SUCCESS || data->state == FAILURE; -} - - -static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_peap_data *data = priv; - u8 *eapKeyData; - - if (data->state != SUCCESS) - return NULL; - - if (data->crypto_binding_used) { - u8 csk[128]; - /* - * Note: It looks like Microsoft implementation requires null - * termination for this label while the one used for deriving - * IPMK|CMK did not use null termination. - */ - 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) { - os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN); - *len = EAP_TLS_KEY_LEN; - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", - eapKeyData, EAP_TLS_KEY_LEN); - } else { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive " - "key"); - } - - return eapKeyData; - } - - /* TODO: PEAPv1 - different label in some cases */ - eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, - "client EAP encryption", - EAP_TLS_KEY_LEN); - if (eapKeyData) { - *len = EAP_TLS_KEY_LEN; - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", - eapKeyData, EAP_TLS_KEY_LEN); - } else { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key"); - } - - return eapKeyData; -} - - -static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_peap_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_peap_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP"); - if (eap == NULL) - return -1; - - eap->init = eap_peap_init; - eap->reset = eap_peap_reset; - eap->buildReq = eap_peap_buildReq; - eap->check = eap_peap_check; - eap->process = eap_peap_process; - eap->isDone = eap_peap_isDone; - eap->getKey = eap_peap_getKey; - eap->isSuccess = eap_peap_isSuccess; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_psk.c b/contrib/hostapd/src/eap_server/eap_server_psk.c deleted file mode 100644 index 46bedd94bb..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_psk.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * hostapd / EAP-PSK (RFC 4764) server - * Copyright (c) 2005-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * Note: EAP-PSK is an EAP authentication method and as such, completely - * different from WPA-PSK. This file is not needed for WPA-PSK functionality. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/aes_wrap.h" -#include "crypto/random.h" -#include "eap_common/eap_psk_common.h" -#include "eap_server/eap_i.h" - - -struct eap_psk_data { - enum { PSK_1, PSK_3, SUCCESS, FAILURE } state; - u8 rand_s[EAP_PSK_RAND_LEN]; - u8 rand_p[EAP_PSK_RAND_LEN]; - u8 *id_p; - size_t id_p_len; - u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN]; - u8 msk[EAP_MSK_LEN]; - u8 emsk[EAP_EMSK_LEN]; -}; - - -static void * eap_psk_init(struct eap_sm *sm) -{ - struct eap_psk_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = PSK_1; - - return data; -} - - -static void eap_psk_reset(struct eap_sm *sm, void *priv) -{ - struct eap_psk_data *data = priv; - os_free(data->id_p); - os_free(data); -} - - -static struct wpabuf * eap_psk_build_1(struct eap_sm *sm, - struct eap_psk_data *data, u8 id) -{ - struct wpabuf *req; - struct eap_psk_hdr_1 *psk; - - wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-1 (sending)"); - - if (random_get_bytes(data->rand_s, EAP_PSK_RAND_LEN)) { - wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data"); - data->state = FAILURE; - return NULL; - } - wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_S (server rand)", - data->rand_s, EAP_PSK_RAND_LEN); - - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, - sizeof(*psk) + sm->server_id_len, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory " - "request"); - data->state = FAILURE; - return NULL; - } - - psk = wpabuf_put(req, sizeof(*psk)); - psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */ - os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN); - wpabuf_put_data(req, sm->server_id, sm->server_id_len); - - return req; -} - - -static struct wpabuf * eap_psk_build_3(struct eap_sm *sm, - struct eap_psk_data *data, u8 id) -{ - struct wpabuf *req; - struct eap_psk_hdr_3 *psk; - u8 *buf, *pchannel, nonce[16]; - size_t buflen; - - wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-3 (sending)"); - - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, - sizeof(*psk) + 4 + 16 + 1, EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory " - "request"); - data->state = FAILURE; - return NULL; - } - - psk = wpabuf_put(req, sizeof(*psk)); - psk->flags = EAP_PSK_FLAGS_SET_T(2); /* T=2 */ - os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN); - - /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */ - buflen = sm->server_id_len + EAP_PSK_RAND_LEN; - buf = os_malloc(buflen); - if (buf == NULL) - goto fail; - - os_memcpy(buf, sm->server_id, sm->server_id_len); - os_memcpy(buf + sm->server_id_len, data->rand_p, EAP_PSK_RAND_LEN); - if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) { - os_free(buf); - goto fail; - } - os_free(buf); - - if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk, - data->emsk)) - goto fail; - wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN); - - os_memset(nonce, 0, sizeof(nonce)); - pchannel = wpabuf_put(req, 4 + 16 + 1); - os_memcpy(pchannel, nonce + 12, 4); - os_memset(pchannel + 4, 0, 16); /* Tag */ - pchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; - wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (plaintext)", - pchannel, 4 + 16 + 1); - if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), - wpabuf_head(req), 22, - pchannel + 4 + 16, 1, pchannel + 4)) - goto fail; - wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (encrypted)", - pchannel, 4 + 16 + 1); - - return req; - -fail: - wpabuf_free(req); - data->state = FAILURE; - return NULL; -} - - -static struct wpabuf * eap_psk_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_psk_data *data = priv; - - switch (data->state) { - case PSK_1: - return eap_psk_build_1(sm, data, id); - case PSK_3: - return eap_psk_build_3(sm, data, id); - default: - wpa_printf(MSG_DEBUG, "EAP-PSK: Unknown state %d in buildReq", - data->state); - break; - } - return NULL; -} - - -static Boolean eap_psk_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_psk_data *data = priv; - size_t len; - u8 t; - const u8 *pos; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len); - if (pos == NULL || len < 1) { - wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame"); - return TRUE; - } - t = EAP_PSK_FLAGS_GET_T(*pos); - - wpa_printf(MSG_DEBUG, "EAP-PSK: received frame: T=%d", t); - - if (data->state == PSK_1 && t != 1) { - wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-2 - " - "ignore T=%d", t); - return TRUE; - } - - if (data->state == PSK_3 && t != 3) { - wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-4 - " - "ignore T=%d", t); - return TRUE; - } - - if ((t == 1 && len < sizeof(struct eap_psk_hdr_2)) || - (t == 3 && len < sizeof(struct eap_psk_hdr_4))) { - wpa_printf(MSG_DEBUG, "EAP-PSK: Too short frame"); - return TRUE; - } - - return FALSE; -} - - -static void eap_psk_process_2(struct eap_sm *sm, - struct eap_psk_data *data, - struct wpabuf *respData) -{ - const struct eap_psk_hdr_2 *resp; - u8 *pos, mac[EAP_PSK_MAC_LEN], *buf; - size_t left, buflen; - int i; - const u8 *cpos; - - if (data->state != PSK_1) - return; - - wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-2"); - - cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, - &left); - if (cpos == NULL || left < sizeof(*resp)) { - wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame"); - return; - } - resp = (const struct eap_psk_hdr_2 *) cpos; - cpos = (const u8 *) (resp + 1); - left -= sizeof(*resp); - - os_free(data->id_p); - data->id_p = os_malloc(left); - if (data->id_p == NULL) { - wpa_printf(MSG_INFO, "EAP-PSK: Failed to allocate memory for " - "ID_P"); - return; - } - os_memcpy(data->id_p, cpos, left); - data->id_p_len = left; - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PSK: ID_P", - data->id_p, data->id_p_len); - - if (eap_user_get(sm, data->id_p, data->id_p_len, 0) < 0) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: unknown ID_P", - data->id_p, data->id_p_len); - data->state = FAILURE; - return; - } - - for (i = 0; - i < EAP_MAX_METHODS && - (sm->user->methods[i].vendor != EAP_VENDOR_IETF || - sm->user->methods[i].method != EAP_TYPE_NONE); - i++) { - if (sm->user->methods[i].vendor == EAP_VENDOR_IETF && - sm->user->methods[i].method == EAP_TYPE_PSK) - break; - } - - if (i >= EAP_MAX_METHODS || - sm->user->methods[i].vendor != EAP_VENDOR_IETF || - sm->user->methods[i].method != EAP_TYPE_PSK) { - wpa_hexdump_ascii(MSG_DEBUG, - "EAP-PSK: EAP-PSK not enabled for ID_P", - data->id_p, data->id_p_len); - data->state = FAILURE; - return; - } - - if (sm->user->password == NULL || - sm->user->password_len != EAP_PSK_PSK_LEN) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: invalid password in " - "user database for ID_P", - data->id_p, data->id_p_len); - data->state = FAILURE; - return; - } - if (eap_psk_key_setup(sm->user->password, data->ak, data->kdk)) { - data->state = FAILURE; - return; - } - wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN); - - wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_P (client rand)", - resp->rand_p, EAP_PSK_RAND_LEN); - os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN); - - /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */ - buflen = data->id_p_len + sm->server_id_len + 2 * EAP_PSK_RAND_LEN; - buf = os_malloc(buflen); - if (buf == NULL) { - data->state = FAILURE; - return; - } - os_memcpy(buf, data->id_p, data->id_p_len); - pos = buf + data->id_p_len; - os_memcpy(pos, sm->server_id, sm->server_id_len); - pos += sm->server_id_len; - os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN); - pos += EAP_PSK_RAND_LEN; - os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN); - if (omac1_aes_128(data->ak, buf, buflen, mac)) { - os_free(buf); - data->state = FAILURE; - return; - } - os_free(buf); - wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", resp->mac_p, EAP_PSK_MAC_LEN); - if (os_memcmp(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) { - wpa_printf(MSG_INFO, "EAP-PSK: Invalid MAC_P"); - wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Expected MAC_P", - mac, EAP_PSK_MAC_LEN); - data->state = FAILURE; - return; - } - - data->state = PSK_3; -} - - -static void eap_psk_process_4(struct eap_sm *sm, - struct eap_psk_data *data, - struct wpabuf *respData) -{ - const struct eap_psk_hdr_4 *resp; - u8 *decrypted, nonce[16]; - size_t left; - const u8 *pos, *tag; - - if (data->state != PSK_3) - return; - - wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-4"); - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &left); - if (pos == NULL || left < sizeof(*resp)) { - wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame"); - return; - } - resp = (const struct eap_psk_hdr_4 *) pos; - pos = (const u8 *) (resp + 1); - left -= sizeof(*resp); - - wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Encrypted PCHANNEL", pos, left); - - if (left < 4 + 16 + 1) { - wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in " - "PSK-4 (len=%lu, expected 21)", - (unsigned long) left); - return; - } - - if (pos[0] == 0 && pos[1] == 0 && pos[2] == 0 && pos[3] == 0) { - wpa_printf(MSG_DEBUG, "EAP-PSK: Nonce did not increase"); - return; - } - - os_memset(nonce, 0, 12); - os_memcpy(nonce + 12, pos, 4); - pos += 4; - left -= 4; - tag = pos; - pos += 16; - left -= 16; - - decrypted = os_malloc(left); - if (decrypted == NULL) - return; - os_memcpy(decrypted, pos, left); - - if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce), - wpabuf_head(respData), 22, decrypted, left, - tag)) { - wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed"); - os_free(decrypted); - data->state = FAILURE; - return; - } - wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message", - decrypted, left); - - /* Verify R flag */ - switch (decrypted[0] >> 6) { - case EAP_PSK_R_FLAG_CONT: - wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported"); - data->state = FAILURE; - break; - case EAP_PSK_R_FLAG_DONE_SUCCESS: - wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS"); - data->state = SUCCESS; - break; - case EAP_PSK_R_FLAG_DONE_FAILURE: - wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE"); - data->state = FAILURE; - break; - } - os_free(decrypted); -} - - -static void eap_psk_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_psk_data *data = priv; - const u8 *pos; - size_t len; - - if (sm->user == NULL || sm->user->password == NULL) { - wpa_printf(MSG_INFO, "EAP-PSK: Plaintext password not " - "configured"); - data->state = FAILURE; - return; - } - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len); - if (pos == NULL || len < 1) - return; - - switch (EAP_PSK_FLAGS_GET_T(*pos)) { - case 1: - eap_psk_process_2(sm, data, respData); - break; - case 3: - eap_psk_process_4(sm, data, respData); - break; - } -} - - -static Boolean eap_psk_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_psk_data *data = priv; - return data->state == SUCCESS || data->state == FAILURE; -} - - -static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_psk_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->msk, EAP_MSK_LEN); - *len = EAP_MSK_LEN; - - return key; -} - - -static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_psk_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - *len = EAP_EMSK_LEN; - - return key; -} - - -static Boolean eap_psk_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_psk_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_psk_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK"); - if (eap == NULL) - return -1; - - eap->init = eap_psk_init; - eap->reset = eap_psk_reset; - eap->buildReq = eap_psk_buildReq; - eap->check = eap_psk_check; - eap->process = eap_psk_process; - eap->isDone = eap_psk_isDone; - eap->getKey = eap_psk_getKey; - eap->isSuccess = eap_psk_isSuccess; - eap->get_emsk = eap_psk_get_emsk; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_pwd.c b/contrib/hostapd/src/eap_server/eap_server_pwd.c deleted file mode 100644 index b61061bce7..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_pwd.c +++ /dev/null @@ -1,1045 +0,0 @@ -/* - * hostapd / EAP-pwd (RFC 5931) server - * Copyright (c) 2010, Dan Harkins - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha256.h" -#include "eap_server/eap_i.h" -#include "eap_common/eap_pwd_common.h" - - -struct eap_pwd_data { - enum { - PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE - } state; - u8 *id_peer; - size_t id_peer_len; - u8 *id_server; - size_t id_server_len; - u8 *password; - size_t password_len; - u32 token; - u16 group_num; - EAP_PWD_group *grp; - - struct wpabuf *inbuf; - size_t in_frag_pos; - struct wpabuf *outbuf; - size_t out_frag_pos; - size_t mtu; - - BIGNUM *k; - BIGNUM *private_value; - BIGNUM *peer_scalar; - BIGNUM *my_scalar; - EC_POINT *my_element; - EC_POINT *peer_element; - - u8 my_confirm[SHA256_MAC_LEN]; - - u8 msk[EAP_MSK_LEN]; - u8 emsk[EAP_EMSK_LEN]; - - BN_CTX *bnctx; -}; - - -static const char * eap_pwd_state_txt(int state) -{ - switch (state) { - case PWD_ID_Req: - return "PWD-ID-Req"; - case PWD_Commit_Req: - return "PWD-Commit-Req"; - case PWD_Confirm_Req: - return "PWD-Confirm-Req"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "PWD-Unk"; - } -} - - -static void eap_pwd_state(struct eap_pwd_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-pwd: %s -> %s", - eap_pwd_state_txt(data->state), eap_pwd_state_txt(state)); - data->state = state; -} - - -static void * eap_pwd_init(struct eap_sm *sm) -{ - struct eap_pwd_data *data; - - if (sm->user == NULL || sm->user->password == NULL || - sm->user->password_len == 0) { - wpa_printf(MSG_INFO, "EAP-PWD (server): Password is not " - "configured"); - return NULL; - } - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - - data->group_num = sm->pwd_group; - wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d", - data->group_num); - data->state = PWD_ID_Req; - - data->id_server = (u8 *) os_strdup("server"); - if (data->id_server) - data->id_server_len = os_strlen((char *) data->id_server); - - data->password = os_malloc(sm->user->password_len); - if (data->password == NULL) { - wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password " - "fail"); - os_free(data->id_server); - os_free(data); - return NULL; - } - data->password_len = sm->user->password_len; - os_memcpy(data->password, sm->user->password, data->password_len); - - data->bnctx = BN_CTX_new(); - if (data->bnctx == NULL) { - wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail"); - os_free(data->password); - os_free(data->id_server); - os_free(data); - return NULL; - } - - data->in_frag_pos = data->out_frag_pos = 0; - data->inbuf = data->outbuf = NULL; - data->mtu = 1020; /* default from RFC 5931, make it configurable! */ - - return data; -} - - -static void eap_pwd_reset(struct eap_sm *sm, void *priv) -{ - struct eap_pwd_data *data = priv; - - BN_free(data->private_value); - BN_free(data->peer_scalar); - BN_free(data->my_scalar); - BN_free(data->k); - BN_CTX_free(data->bnctx); - EC_POINT_free(data->my_element); - EC_POINT_free(data->peer_element); - os_free(data->id_peer); - os_free(data->id_server); - os_free(data->password); - if (data->grp) { - EC_GROUP_free(data->grp->group); - EC_POINT_free(data->grp->pwe); - BN_free(data->grp->order); - BN_free(data->grp->prime); - os_free(data->grp); - } - os_free(data); -} - - -static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data, - u8 id) -{ - wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request"); - /* - * if we're fragmenting then we already have an id request, just return - */ - if (data->out_frag_pos) - return; - - data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) + - data->id_server_len); - if (data->outbuf == NULL) { - eap_pwd_state(data, FAILURE); - return; - } - - /* an lfsr is good enough to generate unpredictable tokens */ - data->token = os_random(); - wpabuf_put_be16(data->outbuf, data->group_num); - wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC); - wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF); - wpabuf_put_data(data->outbuf, &data->token, sizeof(data->token)); - wpabuf_put_u8(data->outbuf, EAP_PWD_PREP_NONE); - wpabuf_put_data(data->outbuf, data->id_server, data->id_server_len); -} - - -static void eap_pwd_build_commit_req(struct eap_sm *sm, - struct eap_pwd_data *data, u8 id) -{ - BIGNUM *mask = NULL, *x = NULL, *y = NULL; - u8 *scalar = NULL, *element = NULL; - u16 offset; - - wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request"); - /* - * if we're fragmenting then we already have an commit request, just - * return - */ - if (data->out_frag_pos) - return; - - if (((data->private_value = BN_new()) == NULL) || - ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) || - ((data->my_scalar = BN_new()) == NULL) || - ((mask = BN_new()) == NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation " - "fail"); - goto fin; - } - - BN_rand_range(data->private_value, data->grp->order); - BN_rand_range(mask, data->grp->order); - BN_add(data->my_scalar, data->private_value, mask); - BN_mod(data->my_scalar, data->my_scalar, data->grp->order, - data->bnctx); - - if (!EC_POINT_mul(data->grp->group, data->my_element, NULL, - data->grp->pwe, mask, data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation " - "fail"); - eap_pwd_state(data, FAILURE); - goto fin; - } - - if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx)) - { - wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion " - "fail"); - goto fin; - } - BN_free(mask); - - if (((x = BN_new()) == NULL) || - ((y = BN_new()) == NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation " - "fail"); - goto fin; - } - if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, - data->my_element, x, y, - data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment " - "fail"); - goto fin; - } - - if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) || - ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) == - NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail"); - goto fin; - } - - /* - * bignums occupy as little memory as possible so one that is - * sufficiently smaller than the prime or order might need pre-pending - * with zeros. - */ - os_memset(scalar, 0, BN_num_bytes(data->grp->order)); - os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2); - offset = BN_num_bytes(data->grp->order) - - BN_num_bytes(data->my_scalar); - BN_bn2bin(data->my_scalar, scalar + offset); - - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); - BN_bn2bin(x, element + offset); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); - BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset); - - data->outbuf = wpabuf_alloc(2 * BN_num_bytes(data->grp->prime) + - BN_num_bytes(data->grp->order)); - if (data->outbuf == NULL) - goto fin; - - /* We send the element as (x,y) followed by the scalar */ - wpabuf_put_data(data->outbuf, element, - 2 * BN_num_bytes(data->grp->prime)); - wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order)); - -fin: - os_free(scalar); - os_free(element); - BN_free(x); - BN_free(y); - if (data->outbuf == NULL) - eap_pwd_state(data, FAILURE); -} - - -static void eap_pwd_build_confirm_req(struct eap_sm *sm, - struct eap_pwd_data *data, u8 id) -{ - BIGNUM *x = NULL, *y = NULL; - struct crypto_hash *hash; - u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr; - u16 grp; - int offset; - - wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request"); - /* - * if we're fragmenting then we already have an confirm request, just - * return - */ - if (data->out_frag_pos) - return; - - /* Each component of the cruft will be at most as big as the prime */ - if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) || - ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation " - "fail"); - goto fin; - } - - /* - * commit is H(k | server_element | server_scalar | peer_element | - * peer_scalar | ciphersuite) - */ - hash = eap_pwd_h_init(); - if (hash == NULL) - goto fin; - - /* - * Zero the memory each time because this is mod prime math and some - * value may start with a few zeros and the previous one did not. - * - * First is k - */ - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); - BN_bn2bin(data->k, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - - /* server element: x, y */ - if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, - data->my_element, x, y, - data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " - "assignment fail"); - goto fin; - } - - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); - BN_bn2bin(x, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); - BN_bn2bin(y, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - - /* server scalar */ - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->order) - - BN_num_bytes(data->my_scalar); - BN_bn2bin(data->my_scalar, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); - - /* peer element: x, y */ - if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, - data->peer_element, x, y, - data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " - "assignment fail"); - goto fin; - } - - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); - BN_bn2bin(x, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); - BN_bn2bin(y, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - - /* peer scalar */ - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->order) - - BN_num_bytes(data->peer_scalar); - BN_bn2bin(data->peer_scalar, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); - - /* ciphersuite */ - grp = htons(data->group_num); - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - ptr = cruft; - os_memcpy(ptr, &grp, sizeof(u16)); - ptr += sizeof(u16); - *ptr = EAP_PWD_DEFAULT_RAND_FUNC; - ptr += sizeof(u8); - *ptr = EAP_PWD_DEFAULT_PRF; - ptr += sizeof(u8); - eap_pwd_h_update(hash, cruft, ptr - cruft); - - /* all done with the random function */ - eap_pwd_h_final(hash, conf); - os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN); - - data->outbuf = wpabuf_alloc(SHA256_MAC_LEN); - if (data->outbuf == NULL) - goto fin; - - wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN); - -fin: - os_free(cruft); - BN_free(x); - BN_free(y); - if (data->outbuf == NULL) - eap_pwd_state(data, FAILURE); -} - - -static struct wpabuf * -eap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_pwd_data *data = priv; - struct wpabuf *req; - u8 lm_exch; - const u8 *buf; - u16 totlen = 0; - size_t len; - - /* - * if we're buffering response fragments then just ACK - */ - if (data->in_frag_pos) { - wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a fragment!!"); - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, - EAP_PWD_HDR_SIZE, EAP_CODE_REQUEST, id); - if (req == NULL) { - eap_pwd_state(data, FAILURE); - return NULL; - } - switch (data->state) { - case PWD_ID_Req: - wpabuf_put_u8(req, EAP_PWD_OPCODE_ID_EXCH); - break; - case PWD_Commit_Req: - wpabuf_put_u8(req, EAP_PWD_OPCODE_COMMIT_EXCH); - break; - case PWD_Confirm_Req: - wpabuf_put_u8(req, EAP_PWD_OPCODE_CONFIRM_EXCH); - break; - default: - eap_pwd_state(data, FAILURE); /* just to be sure */ - wpabuf_free(req); - return NULL; - } - return req; - } - - /* - * build the data portion of a request - */ - switch (data->state) { - case PWD_ID_Req: - eap_pwd_build_id_req(sm, data, id); - lm_exch = EAP_PWD_OPCODE_ID_EXCH; - break; - case PWD_Commit_Req: - eap_pwd_build_commit_req(sm, data, id); - lm_exch = EAP_PWD_OPCODE_COMMIT_EXCH; - break; - case PWD_Confirm_Req: - eap_pwd_build_confirm_req(sm, data, id); - lm_exch = EAP_PWD_OPCODE_CONFIRM_EXCH; - break; - default: - wpa_printf(MSG_INFO, "EAP-pwd: Unknown state %d in build_req", - data->state); - eap_pwd_state(data, FAILURE); - lm_exch = 0; /* hush now, sweet compiler */ - break; - } - - if (data->state == FAILURE) - return NULL; - - /* - * determine whether that data needs to be fragmented - */ - len = wpabuf_len(data->outbuf) - data->out_frag_pos; - if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { - len = data->mtu - EAP_PWD_HDR_SIZE; - EAP_PWD_SET_MORE_BIT(lm_exch); - /* - * if this is the first fragment, need to set the M bit - * and add the total length to the eap_pwd_hdr - */ - if (data->out_frag_pos == 0) { - EAP_PWD_SET_LENGTH_BIT(lm_exch); - totlen = wpabuf_len(data->outbuf) + - EAP_PWD_HDR_SIZE + sizeof(u16); - len -= sizeof(u16); - wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, " - "total length = %d", totlen); - } - wpa_printf(MSG_DEBUG, "EAP-pwd: Send a %d byte fragment", - (int) len); - } - - /* - * alloc an eap request and populate it with the data - */ - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, - EAP_PWD_HDR_SIZE + len + - (totlen ? sizeof(u16) : 0), - EAP_CODE_REQUEST, id); - if (req == NULL) { - eap_pwd_state(data, FAILURE); - return NULL; - } - - wpabuf_put_u8(req, lm_exch); - if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) - wpabuf_put_be16(req, totlen); - - buf = wpabuf_head_u8(data->outbuf); - wpabuf_put_data(req, buf + data->out_frag_pos, len); - data->out_frag_pos += len; - /* - * either not fragged or last fragment, either way free up the data - */ - if (data->out_frag_pos >= wpabuf_len(data->outbuf)) { - wpabuf_free(data->outbuf); - data->out_frag_pos = 0; - } - - return req; -} - - -static Boolean eap_pwd_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_pwd_data *data = priv; - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len); - if (pos == NULL || len < 1) { - wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame"); - return TRUE; - } - - wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: exch = %d, len = %d", - EAP_PWD_GET_EXCHANGE(*pos), (int) len); - - if (data->state == PWD_ID_Req && - ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_ID_EXCH)) - return FALSE; - - if (data->state == PWD_Commit_Req && - ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_COMMIT_EXCH)) - return FALSE; - - if (data->state == PWD_Confirm_Req && - ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_CONFIRM_EXCH)) - return FALSE; - - wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d", - *pos, data->state); - - return TRUE; -} - - -static void eap_pwd_process_id_resp(struct eap_sm *sm, - struct eap_pwd_data *data, - const u8 *payload, size_t payload_len) -{ - struct eap_pwd_id *id; - - if (payload_len < sizeof(struct eap_pwd_id)) { - wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response"); - return; - } - - id = (struct eap_pwd_id *) payload; - if ((data->group_num != be_to_host16(id->group_num)) || - (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) || - (os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) || - (id->prf != EAP_PWD_DEFAULT_PRF)) { - wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters"); - eap_pwd_state(data, FAILURE); - return; - } - data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id)); - if (data->id_peer == NULL) { - wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); - return; - } - data->id_peer_len = payload_len - sizeof(struct eap_pwd_id); - os_memcpy(data->id_peer, id->identity, data->id_peer_len); - wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of", - data->id_peer, data->id_peer_len); - - if ((data->grp = os_malloc(sizeof(EAP_PWD_group))) == NULL) { - wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for " - "group"); - return; - } - if (compute_password_element(data->grp, data->group_num, - data->password, data->password_len, - data->id_server, data->id_server_len, - data->id_peer, data->id_peer_len, - (u8 *) &data->token)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute " - "PWE"); - return; - } - wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...", - BN_num_bits(data->grp->prime)); - - eap_pwd_state(data, PWD_Commit_Req); -} - - -static void -eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, - const u8 *payload, size_t payload_len) -{ - u8 *ptr; - BIGNUM *x = NULL, *y = NULL, *cofactor = NULL; - EC_POINT *K = NULL, *point = NULL; - int res = 0; - - wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response"); - - if (((data->peer_scalar = BN_new()) == NULL) || - ((data->k = BN_new()) == NULL) || - ((cofactor = BN_new()) == NULL) || - ((x = BN_new()) == NULL) || - ((y = BN_new()) == NULL) || - ((point = EC_POINT_new(data->grp->group)) == NULL) || - ((K = EC_POINT_new(data->grp->group)) == NULL) || - ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation " - "fail"); - goto fin; - } - - if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get " - "cofactor for curve"); - goto fin; - } - - /* element, x then y, followed by scalar */ - ptr = (u8 *) payload; - BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x); - ptr += BN_num_bytes(data->grp->prime); - BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y); - ptr += BN_num_bytes(data->grp->prime); - BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar); - if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group, - data->peer_element, x, y, - data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element " - "fail"); - goto fin; - } - - /* check to ensure peer's element is not in a small sub-group */ - if (BN_cmp(cofactor, BN_value_one())) { - if (!EC_POINT_mul(data->grp->group, point, NULL, - data->peer_element, cofactor, NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): cannot " - "multiply peer element by order"); - goto fin; - } - if (EC_POINT_is_at_infinity(data->grp->group, point)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): peer element " - "is at infinity!\n"); - goto fin; - } - } - - /* compute the shared key, k */ - if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe, - data->peer_scalar, data->bnctx)) || - (!EC_POINT_add(data->grp->group, K, K, data->peer_element, - data->bnctx)) || - (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value, - data->bnctx))) { - wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key " - "fail"); - goto fin; - } - - /* ensure that the shared key isn't in a small sub-group */ - if (BN_cmp(cofactor, BN_value_one())) { - if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor, - NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): cannot " - "multiply shared key point by order!\n"); - goto fin; - } - } - - /* - * This check is strictly speaking just for the case above where - * co-factor > 1 but it was suggested that even though this is probably - * never going to happen it is a simple and safe check "just to be - * sure" so let's be safe. - */ - if (EC_POINT_is_at_infinity(data->grp->group, K)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is " - "at infinity"); - goto fin; - } - if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k, - NULL, data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract " - "shared secret from secret point"); - goto fin; - } - res = 1; - -fin: - EC_POINT_free(K); - EC_POINT_free(point); - BN_free(cofactor); - BN_free(x); - BN_free(y); - - if (res) - eap_pwd_state(data, PWD_Confirm_Req); - else - eap_pwd_state(data, FAILURE); -} - - -static void -eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data, - const u8 *payload, size_t payload_len) -{ - BIGNUM *x = NULL, *y = NULL; - struct crypto_hash *hash; - u32 cs; - u16 grp; - u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr; - int offset; - - /* build up the ciphersuite: group | random_function | prf */ - grp = htons(data->group_num); - ptr = (u8 *) &cs; - os_memcpy(ptr, &grp, sizeof(u16)); - ptr += sizeof(u16); - *ptr = EAP_PWD_DEFAULT_RAND_FUNC; - ptr += sizeof(u8); - *ptr = EAP_PWD_DEFAULT_PRF; - - /* each component of the cruft will be at most as big as the prime */ - if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) || - ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { - wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail"); - goto fin; - } - - /* - * commit is H(k | peer_element | peer_scalar | server_element | - * server_scalar | ciphersuite) - */ - hash = eap_pwd_h_init(); - if (hash == NULL) - goto fin; - - /* k */ - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k); - BN_bn2bin(data->k, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - - /* peer element: x, y */ - if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, - data->peer_element, x, y, - data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " - "assignment fail"); - goto fin; - } - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); - BN_bn2bin(x, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); - BN_bn2bin(y, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - - /* peer scalar */ - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->order) - - BN_num_bytes(data->peer_scalar); - BN_bn2bin(data->peer_scalar, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); - - /* server element: x, y */ - if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, - data->my_element, x, y, - data->bnctx)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " - "assignment fail"); - goto fin; - } - - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); - BN_bn2bin(x, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); - BN_bn2bin(y, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime)); - - /* server scalar */ - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - offset = BN_num_bytes(data->grp->order) - - BN_num_bytes(data->my_scalar); - BN_bn2bin(data->my_scalar, cruft + offset); - eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order)); - - /* ciphersuite */ - os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); - eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32)); - - /* all done */ - eap_pwd_h_final(hash, conf); - - ptr = (u8 *) payload; - if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) { - wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not " - "verify"); - goto fin; - } - - wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified"); - if (compute_keys(data->grp, data->bnctx, data->k, - data->peer_scalar, data->my_scalar, conf, - data->my_confirm, &cs, data->msk, data->emsk) < 0) - eap_pwd_state(data, FAILURE); - else - eap_pwd_state(data, SUCCESS); - -fin: - os_free(cruft); - BN_free(x); - BN_free(y); -} - - -static void eap_pwd_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_pwd_data *data = priv; - const u8 *pos; - size_t len; - u8 lm_exch; - u16 tot_len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len); - if ((pos == NULL) || (len < 1)) { - wpa_printf(MSG_INFO, "Bad EAP header! pos %s and len = %d", - (pos == NULL) ? "is NULL" : "is not NULL", - (int) len); - return; - } - - lm_exch = *pos; - pos++; /* skip over the bits and the exch */ - len--; - - /* - * if we're fragmenting then this should be an ACK with no data, - * just return and continue fragmenting in the "build" section above - */ - if (data->out_frag_pos) { - if (len > 1) - wpa_printf(MSG_INFO, "EAP-pwd: Bad response! " - "Fragmenting but not an ACK"); - else - wpa_printf(MSG_DEBUG, "EAP-pwd: received ACK from " - "peer"); - return; - } - /* - * if we're receiving fragmented packets then we need to buffer... - * - * the first fragment has a total length - */ - if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { - tot_len = WPA_GET_BE16(pos); - wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total " - "length = %d", tot_len); - data->inbuf = wpabuf_alloc(tot_len); - if (data->inbuf == NULL) { - wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to " - "buffer fragments!"); - return; - } - pos += sizeof(u16); - len -= sizeof(u16); - } - /* - * the first and all intermediate fragments have the M bit set - */ - if (EAP_PWD_GET_MORE_BIT(lm_exch)) { - if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) { - wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow " - "attack detected! (%d+%d > %d)", - (int) data->in_frag_pos, (int) len, - (int) wpabuf_size(data->inbuf)); - eap_pwd_state(data, FAILURE); - return; - } - wpabuf_put_data(data->inbuf, pos, len); - data->in_frag_pos += len; - wpa_printf(MSG_DEBUG, "EAP-pwd: Got a %d byte fragment", - (int) len); - return; - } - /* - * last fragment won't have the M bit set (but we're obviously - * buffering fragments so that's how we know it's the last) - */ - if (data->in_frag_pos) { - wpabuf_put_data(data->inbuf, pos, len); - data->in_frag_pos += len; - pos = wpabuf_head_u8(data->inbuf); - len = data->in_frag_pos; - wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes", - (int) len); - } - switch (EAP_PWD_GET_EXCHANGE(lm_exch)) { - case EAP_PWD_OPCODE_ID_EXCH: - eap_pwd_process_id_resp(sm, data, pos, len); - break; - case EAP_PWD_OPCODE_COMMIT_EXCH: - eap_pwd_process_commit_resp(sm, data, pos, len); - break; - case EAP_PWD_OPCODE_CONFIRM_EXCH: - eap_pwd_process_confirm_resp(sm, data, pos, len); - break; - } - /* - * if we had been buffering fragments, here's a great place - * to clean up - */ - if (data->in_frag_pos) { - wpabuf_free(data->inbuf); - data->in_frag_pos = 0; - } -} - - -static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_pwd_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key == NULL) - return NULL; - - os_memcpy(key, data->msk, EAP_MSK_LEN); - *len = EAP_MSK_LEN; - - return key; -} - - -static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_pwd_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - *len = EAP_EMSK_LEN; - - return key; -} - - -static Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv) -{ - struct eap_pwd_data *data = priv; - return data->state == SUCCESS; -} - - -static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv) -{ - struct eap_pwd_data *data = priv; - return (data->state == SUCCESS) || (data->state == FAILURE); -} - - -int eap_server_pwd_register(void) -{ - struct eap_method *eap; - int ret; - struct timeval tp; - struct timezone tz; - u32 sr; - - EVP_add_digest(EVP_sha256()); - - sr = 0xdeaddada; - (void) gettimeofday(&tp, &tz); - sr ^= (tp.tv_sec ^ tp.tv_usec); - srandom(sr); - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_PWD, - "PWD"); - if (eap == NULL) - return -1; - - eap->init = eap_pwd_init; - eap->reset = eap_pwd_reset; - eap->buildReq = eap_pwd_build_req; - eap->check = eap_pwd_check; - eap->process = eap_pwd_process; - eap->isDone = eap_pwd_is_done; - eap->getKey = eap_pwd_getkey; - eap->get_emsk = eap_pwd_get_emsk; - eap->isSuccess = eap_pwd_is_success; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} - diff --git a/contrib/hostapd/src/eap_server/eap_server_sake.c b/contrib/hostapd/src/eap_server/eap_server_sake.c deleted file mode 100644 index 68dd76b18e..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_sake.c +++ /dev/null @@ -1,522 +0,0 @@ -/* - * hostapd / EAP-SAKE (RFC 4763) server - * Copyright (c) 2006-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/random.h" -#include "eap_server/eap_i.h" -#include "eap_common/eap_sake_common.h" - - -struct eap_sake_data { - enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state; - u8 rand_s[EAP_SAKE_RAND_LEN]; - u8 rand_p[EAP_SAKE_RAND_LEN]; - struct { - u8 auth[EAP_SAKE_TEK_AUTH_LEN]; - u8 cipher[EAP_SAKE_TEK_CIPHER_LEN]; - } tek; - u8 msk[EAP_MSK_LEN]; - u8 emsk[EAP_EMSK_LEN]; - u8 session_id; - u8 *peerid; - size_t peerid_len; -}; - - -static const char * eap_sake_state_txt(int state) -{ - switch (state) { - case IDENTITY: - return "IDENTITY"; - case CHALLENGE: - return "CHALLENGE"; - case CONFIRM: - return "CONFIRM"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "?"; - } -} - - -static void eap_sake_state(struct eap_sake_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s", - eap_sake_state_txt(data->state), - eap_sake_state_txt(state)); - data->state = state; -} - - -static void * eap_sake_init(struct eap_sm *sm) -{ - struct eap_sake_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = CHALLENGE; - - if (os_get_random(&data->session_id, 1)) { - wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data"); - os_free(data); - return NULL; - } - wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d", - data->session_id); - - return data; -} - - -static void eap_sake_reset(struct eap_sm *sm, void *priv) -{ - struct eap_sake_data *data = priv; - os_free(data->peerid); - os_free(data); -} - - -static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data, - u8 id, size_t length, u8 subtype) -{ - struct eap_sake_hdr *sake; - struct wpabuf *msg; - size_t plen; - - plen = sizeof(struct eap_sake_hdr) + length; - - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen, - EAP_CODE_REQUEST, id); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory " - "request"); - return NULL; - } - - sake = wpabuf_put(msg, sizeof(*sake)); - sake->version = EAP_SAKE_VERSION; - sake->session_id = data->session_id; - sake->subtype = subtype; - - return msg; -} - - -static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm, - struct eap_sake_data *data, - u8 id) -{ - struct wpabuf *msg; - size_t plen; - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity"); - - plen = 4; - plen += 2 + sm->server_id_len; - msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY); - if (msg == NULL) { - data->state = FAILURE; - return NULL; - } - - wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ"); - eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2); - - wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID"); - eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID, - sm->server_id, sm->server_id_len); - - return msg; -} - - -static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm, - struct eap_sake_data *data, - u8 id) -{ - struct wpabuf *msg; - size_t plen; - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge"); - - if (random_get_bytes(data->rand_s, EAP_SAKE_RAND_LEN)) { - wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data"); - data->state = FAILURE; - return NULL; - } - wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)", - data->rand_s, EAP_SAKE_RAND_LEN); - - plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->server_id_len; - msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE); - if (msg == NULL) { - data->state = FAILURE; - return NULL; - } - - wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S"); - eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S, - data->rand_s, EAP_SAKE_RAND_LEN); - - wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID"); - eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID, - sm->server_id, sm->server_id_len); - - return msg; -} - - -static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm, - struct eap_sake_data *data, - u8 id) -{ - struct wpabuf *msg; - u8 *mic; - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm"); - - msg = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN, - EAP_SAKE_SUBTYPE_CONFIRM); - if (msg == NULL) { - data->state = FAILURE; - return NULL; - } - - wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S"); - wpabuf_put_u8(msg, EAP_SAKE_AT_MIC_S); - wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN); - mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN); - if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, - sm->server_id, sm->server_id_len, - data->peerid, data->peerid_len, 0, - wpabuf_head(msg), wpabuf_len(msg), mic, mic)) - { - wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC"); - data->state = FAILURE; - os_free(msg); - return NULL; - } - - return msg; -} - - -static struct wpabuf * eap_sake_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_sake_data *data = priv; - - switch (data->state) { - case IDENTITY: - return eap_sake_build_identity(sm, data, id); - case CHALLENGE: - return eap_sake_build_challenge(sm, data, id); - case CONFIRM: - return eap_sake_build_confirm(sm, data, id); - default: - wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq", - data->state); - break; - } - return NULL; -} - - -static Boolean eap_sake_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_sake_data *data = priv; - struct eap_sake_hdr *resp; - size_t len; - u8 version, session_id, subtype; - const u8 *pos; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len); - if (pos == NULL || len < sizeof(struct eap_sake_hdr)) { - wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame"); - return TRUE; - } - - resp = (struct eap_sake_hdr *) pos; - version = resp->version; - session_id = resp->session_id; - subtype = resp->subtype; - - if (version != EAP_SAKE_VERSION) { - wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version); - return TRUE; - } - - if (session_id != data->session_id) { - wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)", - session_id, data->session_id); - return TRUE; - } - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype); - - if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY) - return FALSE; - - if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE) - return FALSE; - - if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM) - return FALSE; - - if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT) - return FALSE; - - wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d", - subtype, data->state); - - return TRUE; -} - - -static void eap_sake_process_identity(struct eap_sm *sm, - struct eap_sake_data *data, - const struct wpabuf *respData, - const u8 *payload, size_t payloadlen) -{ - if (data->state != IDENTITY) - return; - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity"); - /* TODO: update identity and select new user data */ - eap_sake_state(data, CHALLENGE); -} - - -static void eap_sake_process_challenge(struct eap_sm *sm, - struct eap_sake_data *data, - const struct wpabuf *respData, - const u8 *payload, size_t payloadlen) -{ - struct eap_sake_parse_attr attr; - u8 mic_p[EAP_SAKE_MIC_LEN]; - - if (data->state != CHALLENGE) - return; - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge"); - - if (eap_sake_parse_attributes(payload, payloadlen, &attr)) - return; - - if (!attr.rand_p || !attr.mic_p) { - wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not " - "include AT_RAND_P or AT_MIC_P"); - return; - } - - os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN); - - os_free(data->peerid); - data->peerid = NULL; - data->peerid_len = 0; - if (attr.peerid) { - data->peerid = os_malloc(attr.peerid_len); - if (data->peerid == NULL) - return; - os_memcpy(data->peerid, attr.peerid, attr.peerid_len); - data->peerid_len = attr.peerid_len; - } - - if (sm->user == NULL || sm->user->password == NULL || - sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) { - wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with " - "%d-byte key not configured", - 2 * EAP_SAKE_ROOT_SECRET_LEN); - data->state = FAILURE; - return; - } - eap_sake_derive_keys(sm->user->password, - sm->user->password + EAP_SAKE_ROOT_SECRET_LEN, - data->rand_s, data->rand_p, - (u8 *) &data->tek, data->msk, data->emsk); - - eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, - sm->server_id, sm->server_id_len, - data->peerid, data->peerid_len, 1, - wpabuf_head(respData), wpabuf_len(respData), - attr.mic_p, mic_p); - if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) { - wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P"); - eap_sake_state(data, FAILURE); - return; - } - - eap_sake_state(data, CONFIRM); -} - - -static void eap_sake_process_confirm(struct eap_sm *sm, - struct eap_sake_data *data, - const struct wpabuf *respData, - const u8 *payload, size_t payloadlen) -{ - struct eap_sake_parse_attr attr; - u8 mic_p[EAP_SAKE_MIC_LEN]; - - if (data->state != CONFIRM) - return; - - wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm"); - - if (eap_sake_parse_attributes(payload, payloadlen, &attr)) - return; - - if (!attr.mic_p) { - wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not " - "include AT_MIC_P"); - return; - } - - eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, - sm->server_id, sm->server_id_len, - data->peerid, data->peerid_len, 1, - wpabuf_head(respData), wpabuf_len(respData), - attr.mic_p, mic_p); - if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) { - wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P"); - eap_sake_state(data, FAILURE); - } else - eap_sake_state(data, SUCCESS); -} - - -static void eap_sake_process_auth_reject(struct eap_sm *sm, - struct eap_sake_data *data, - const struct wpabuf *respData, - const u8 *payload, size_t payloadlen) -{ - wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject"); - eap_sake_state(data, FAILURE); -} - - -static void eap_sake_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_sake_data *data = priv; - struct eap_sake_hdr *resp; - u8 subtype; - size_t len; - const u8 *pos, *end; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len); - if (pos == NULL || len < sizeof(struct eap_sake_hdr)) - return; - - resp = (struct eap_sake_hdr *) pos; - end = pos + len; - subtype = resp->subtype; - pos = (u8 *) (resp + 1); - - wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes", - pos, end - pos); - - switch (subtype) { - case EAP_SAKE_SUBTYPE_IDENTITY: - eap_sake_process_identity(sm, data, respData, pos, end - pos); - break; - case EAP_SAKE_SUBTYPE_CHALLENGE: - eap_sake_process_challenge(sm, data, respData, pos, end - pos); - break; - case EAP_SAKE_SUBTYPE_CONFIRM: - eap_sake_process_confirm(sm, data, respData, pos, end - pos); - break; - case EAP_SAKE_SUBTYPE_AUTH_REJECT: - eap_sake_process_auth_reject(sm, data, respData, pos, - end - pos); - break; - } -} - - -static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_sake_data *data = priv; - return data->state == SUCCESS || data->state == FAILURE; -} - - -static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_sake_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_MSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->msk, EAP_MSK_LEN); - *len = EAP_MSK_LEN; - - return key; -} - - -static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_sake_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - *len = EAP_EMSK_LEN; - - return key; -} - - -static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_sake_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_sake_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE"); - if (eap == NULL) - return -1; - - eap->init = eap_sake_init; - eap->reset = eap_sake_reset; - eap->buildReq = eap_sake_buildReq; - eap->check = eap_sake_check; - eap->process = eap_sake_process; - eap->isDone = eap_sake_isDone; - eap->getKey = eap_sake_getKey; - eap->isSuccess = eap_sake_isSuccess; - eap->get_emsk = eap_sake_get_emsk; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_sim.c b/contrib/hostapd/src/eap_server/eap_server_sim.c deleted file mode 100644 index b531241e84..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_sim.c +++ /dev/null @@ -1,847 +0,0 @@ -/* - * hostapd / EAP-SIM (RFC 4186) - * Copyright (c) 2005-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/random.h" -#include "eap_server/eap_i.h" -#include "eap_common/eap_sim_common.h" -#include "eap_server/eap_sim_db.h" - - -struct eap_sim_data { - u8 mk[EAP_SIM_MK_LEN]; - u8 nonce_mt[EAP_SIM_NONCE_MT_LEN]; - u8 nonce_s[EAP_SIM_NONCE_S_LEN]; - u8 k_aut[EAP_SIM_K_AUT_LEN]; - u8 k_encr[EAP_SIM_K_ENCR_LEN]; - u8 msk[EAP_SIM_KEYING_DATA_LEN]; - u8 emsk[EAP_EMSK_LEN]; - u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN]; - u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN]; - u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN]; - int num_chal; - enum { - START, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE - } state; - char *next_pseudonym; - char *next_reauth_id; - u16 counter; - struct eap_sim_reauth *reauth; - u16 notification; - int use_result_ind; - int start_round; - char permanent[20]; /* Permanent username */ -}; - - -static const char * eap_sim_state_txt(int state) -{ - switch (state) { - case START: - return "START"; - case CHALLENGE: - return "CHALLENGE"; - case REAUTH: - return "REAUTH"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - case NOTIFICATION: - return "NOTIFICATION"; - default: - return "Unknown?!"; - } -} - - -static void eap_sim_state(struct eap_sim_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s", - eap_sim_state_txt(data->state), - eap_sim_state_txt(state)); - data->state = state; -} - - -static void * eap_sim_init(struct eap_sm *sm) -{ - struct eap_sim_data *data; - - if (sm->eap_sim_db_priv == NULL) { - wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured"); - return NULL; - } - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = START; - - return data; -} - - -static void eap_sim_reset(struct eap_sm *sm, void *priv) -{ - struct eap_sim_data *data = priv; - os_free(data->next_pseudonym); - os_free(data->next_reauth_id); - os_free(data); -} - - -static struct wpabuf * eap_sim_build_start(struct eap_sm *sm, - struct eap_sim_data *data, u8 id) -{ - struct eap_sim_msg *msg; - u8 ver[2]; - - wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start"); - msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, - EAP_SIM_SUBTYPE_START); - data->start_round++; - if (data->start_round == 1) { - /* - * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is - * ignored and the SIM/Start is used to request the identity. - */ - wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ"); - eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0); - } else if (data->start_round > 3) { - /* Cannot use more than three rounds of Start messages */ - eap_sim_msg_free(msg); - return NULL; - } else if (data->start_round == 0) { - /* - * This is a special case that is used to recover from - * AT_COUNTER_TOO_SMALL during re-authentication. Since we - * already know the identity of the peer, there is no need to - * request any identity in this case. - */ - } else if (sm->identity && sm->identity_len > 0 && - sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) { - /* Reauth id may have expired - try fullauth */ - wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ"); - eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0); - } else { - wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); - eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); - } - wpa_printf(MSG_DEBUG, " AT_VERSION_LIST"); - ver[0] = 0; - ver[1] = EAP_SIM_VERSION; - eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver), - ver, sizeof(ver)); - return eap_sim_msg_finish(msg, NULL, NULL, 0); -} - - -static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data, - struct eap_sim_msg *msg, u16 counter, - const u8 *nonce_s) -{ - os_free(data->next_pseudonym); - if (nonce_s == NULL) { - data->next_pseudonym = - eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, - EAP_SIM_DB_SIM); - } else { - /* Do not update pseudonym during re-authentication */ - data->next_pseudonym = NULL; - } - os_free(data->next_reauth_id); - if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) { - data->next_reauth_id = - eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, - EAP_SIM_DB_SIM); - } else { - wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication " - "count exceeded - force full authentication"); - data->next_reauth_id = NULL; - } - - if (data->next_pseudonym == NULL && data->next_reauth_id == NULL && - counter == 0 && nonce_s == NULL) - return 0; - - wpa_printf(MSG_DEBUG, " AT_IV"); - wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); - eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); - - if (counter > 0) { - wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter); - eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); - } - - if (nonce_s) { - wpa_printf(MSG_DEBUG, " *AT_NONCE_S"); - eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s, - EAP_SIM_NONCE_S_LEN); - } - - if (data->next_pseudonym) { - wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)", - data->next_pseudonym); - eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM, - os_strlen(data->next_pseudonym), - (u8 *) data->next_pseudonym, - os_strlen(data->next_pseudonym)); - } - - if (data->next_reauth_id) { - wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)", - data->next_reauth_id); - eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID, - os_strlen(data->next_reauth_id), - (u8 *) data->next_reauth_id, - os_strlen(data->next_reauth_id)); - } - - if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { - wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt " - "AT_ENCR_DATA"); - return -1; - } - - return 0; -} - - -static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm, - struct eap_sim_data *data, - u8 id) -{ - struct eap_sim_msg *msg; - - wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge"); - msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, - EAP_SIM_SUBTYPE_CHALLENGE); - wpa_printf(MSG_DEBUG, " AT_RAND"); - eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand, - data->num_chal * GSM_RAND_LEN); - - if (eap_sim_build_encr(sm, data, msg, 0, NULL)) { - eap_sim_msg_free(msg); - return NULL; - } - - if (sm->eap_sim_aka_result_ind) { - wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); - eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); - } - - wpa_printf(MSG_DEBUG, " AT_MAC"); - eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, data->nonce_mt, - EAP_SIM_NONCE_MT_LEN); -} - - -static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm, - struct eap_sim_data *data, u8 id) -{ - struct eap_sim_msg *msg; - - wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication"); - - if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN)) - return NULL; - wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S", - data->nonce_s, EAP_SIM_NONCE_S_LEN); - - eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, - data->emsk); - eap_sim_derive_keys_reauth(data->counter, sm->identity, - sm->identity_len, data->nonce_s, data->mk, - data->msk, data->emsk); - - msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, - EAP_SIM_SUBTYPE_REAUTHENTICATION); - - if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) { - eap_sim_msg_free(msg); - return NULL; - } - - if (sm->eap_sim_aka_result_ind) { - wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); - eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); - } - - wpa_printf(MSG_DEBUG, " AT_MAC"); - eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); -} - - -static struct wpabuf * eap_sim_build_notification(struct eap_sm *sm, - struct eap_sim_data *data, - u8 id) -{ - struct eap_sim_msg *msg; - - wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Notification"); - msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, - EAP_SIM_SUBTYPE_NOTIFICATION); - wpa_printf(MSG_DEBUG, " AT_NOTIFICATION (%d)", data->notification); - eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification, - NULL, 0); - if (data->use_result_ind) { - if (data->reauth) { - wpa_printf(MSG_DEBUG, " AT_IV"); - wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); - eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, - EAP_SIM_AT_ENCR_DATA); - wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", - data->counter); - eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, - NULL, 0); - - if (eap_sim_msg_add_encr_end(msg, data->k_encr, - EAP_SIM_AT_PADDING)) { - wpa_printf(MSG_WARNING, "EAP-SIM: Failed to " - "encrypt AT_ENCR_DATA"); - eap_sim_msg_free(msg); - return NULL; - } - } - - wpa_printf(MSG_DEBUG, " AT_MAC"); - eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - } - return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); -} - - -static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_sim_data *data = priv; - - switch (data->state) { - case START: - return eap_sim_build_start(sm, data, id); - case CHALLENGE: - return eap_sim_build_challenge(sm, data, id); - case REAUTH: - return eap_sim_build_reauth(sm, data, id); - case NOTIFICATION: - return eap_sim_build_notification(sm, data, id); - default: - wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in " - "buildReq", data->state); - break; - } - return NULL; -} - - -static Boolean eap_sim_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len); - if (pos == NULL || len < 3) { - wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame"); - return TRUE; - } - - return FALSE; -} - - -static Boolean eap_sim_unexpected_subtype(struct eap_sim_data *data, - u8 subtype) -{ - if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) - return FALSE; - - switch (data->state) { - case START: - if (subtype != EAP_SIM_SUBTYPE_START) { - wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " - "subtype %d", subtype); - return TRUE; - } - break; - case CHALLENGE: - if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) { - wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " - "subtype %d", subtype); - return TRUE; - } - break; - case REAUTH: - if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) { - wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " - "subtype %d", subtype); - return TRUE; - } - break; - case NOTIFICATION: - if (subtype != EAP_SIM_SUBTYPE_NOTIFICATION) { - wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " - "subtype %d", subtype); - return TRUE; - } - break; - default: - wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for " - "processing a response", data->state); - return TRUE; - } - - return FALSE; -} - - -static int eap_sim_supported_ver(struct eap_sim_data *data, int version) -{ - return version == EAP_SIM_VERSION; -} - - -static void eap_sim_process_start(struct eap_sm *sm, - struct eap_sim_data *data, - struct wpabuf *respData, - struct eap_sim_attrs *attr) -{ - size_t identity_len; - u8 ver_list[2]; - u8 *new_identity; - char *username; - - wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response"); - - if (data->start_round == 0) { - /* - * Special case for AT_COUNTER_TOO_SMALL recovery - no identity - * was requested since we already know it. - */ - goto skip_id_update; - } - - /* - * We always request identity in SIM/Start, so the peer is required to - * have replied with one. - */ - if (!attr->identity || attr->identity_len == 0) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any " - "identity"); - goto failed; - } - - new_identity = os_malloc(attr->identity_len); - if (new_identity == NULL) - goto failed; - os_free(sm->identity); - sm->identity = new_identity; - os_memcpy(sm->identity, attr->identity, attr->identity_len); - sm->identity_len = attr->identity_len; - - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", - sm->identity, sm->identity_len); - username = sim_get_username(sm->identity, sm->identity_len); - if (username == NULL) - goto failed; - - if (username[0] == EAP_SIM_REAUTH_ID_PREFIX) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'", - username); - data->reauth = eap_sim_db_get_reauth_entry( - sm->eap_sim_db_priv, username); - os_free(username); - if (data->reauth == NULL) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth " - "identity - request full auth identity"); - /* Remain in START state for another round */ - return; - } - wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast re-authentication"); - os_strlcpy(data->permanent, data->reauth->permanent, - sizeof(data->permanent)); - data->counter = data->reauth->counter; - os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN); - eap_sim_state(data, REAUTH); - return; - } - - if (username[0] == EAP_SIM_PSEUDONYM_PREFIX) { - const char *permanent; - wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'", - username); - permanent = eap_sim_db_get_permanent( - sm->eap_sim_db_priv, username); - os_free(username); - if (permanent == NULL) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym " - "identity - request permanent identity"); - /* Remain in START state for another round */ - return; - } - os_strlcpy(data->permanent, permanent, - sizeof(data->permanent)); - } else if (username[0] == EAP_SIM_PERMANENT_PREFIX) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Permanent username '%s'", - username); - os_strlcpy(data->permanent, username, sizeof(data->permanent)); - os_free(username); - } else { - wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'", - username); - os_free(username); - goto failed; - } - -skip_id_update: - /* Full authentication */ - - if (attr->nonce_mt == NULL || attr->selected_version < 0) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing " - "required attributes"); - goto failed; - } - - if (!eap_sim_supported_ver(data, attr->selected_version)) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported " - "version %d", attr->selected_version); - goto failed; - } - - data->counter = 0; /* reset re-auth counter since this is full auth */ - data->reauth = NULL; - - data->num_chal = eap_sim_db_get_gsm_triplets( - sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL, - (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm); - if (data->num_chal == EAP_SIM_DB_PENDING) { - wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets " - "not yet available - pending request"); - sm->method_pending = METHOD_PENDING_WAIT; - return; - } - if (data->num_chal < 2) { - wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM " - "authentication triplets for the peer"); - goto failed; - } - - identity_len = sm->identity_len; - while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { - wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null " - "character from identity"); - identity_len--; - } - wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation", - sm->identity, identity_len); - - os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN); - WPA_PUT_BE16(ver_list, EAP_SIM_VERSION); - eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt, - attr->selected_version, ver_list, sizeof(ver_list), - data->num_chal, (const u8 *) data->kc, data->mk); - eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, - data->emsk); - - eap_sim_state(data, CHALLENGE); - return; - -failed: - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_sim_state(data, NOTIFICATION); -} - - -static void eap_sim_process_challenge(struct eap_sm *sm, - struct eap_sim_data *data, - struct wpabuf *respData, - struct eap_sim_attrs *attr) -{ - if (attr->mac == NULL || - eap_sim_verify_mac(data->k_aut, respData, attr->mac, - (u8 *) data->sres, - data->num_chal * EAP_SIM_SRES_LEN)) { - wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " - "did not include valid AT_MAC"); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_sim_state(data, NOTIFICATION); - return; - } - - wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the " - "correct AT_MAC"); - if (sm->eap_sim_aka_result_ind && attr->result_ind) { - data->use_result_ind = 1; - data->notification = EAP_SIM_SUCCESS; - eap_sim_state(data, NOTIFICATION); - } else - eap_sim_state(data, SUCCESS); - - if (data->next_pseudonym) { - eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent, - data->next_pseudonym); - data->next_pseudonym = NULL; - } - if (data->next_reauth_id) { - eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent, - data->next_reauth_id, data->counter + 1, - data->mk); - data->next_reauth_id = NULL; - } -} - - -static void eap_sim_process_reauth(struct eap_sm *sm, - struct eap_sim_data *data, - struct wpabuf *respData, - struct eap_sim_attrs *attr) -{ - struct eap_sim_attrs eattr; - u8 *decrypted = NULL; - - if (attr->mac == NULL || - eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s, - EAP_SIM_NONCE_S_LEN)) { - wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " - "did not include valid AT_MAC"); - goto fail; - } - - if (attr->encr_data == NULL || attr->iv == NULL) { - wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " - "message did not include encrypted data"); - goto fail; - } - - decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, - attr->encr_data_len, attr->iv, &eattr, - 0); - if (decrypted == NULL) { - wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " - "data from reauthentication message"); - goto fail; - } - - if (eattr.counter != data->counter) { - wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " - "used incorrect counter %u, expected %u", - eattr.counter, data->counter); - goto fail; - } - os_free(decrypted); - decrypted = NULL; - - wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes " - "the correct AT_MAC"); - - if (eattr.counter_too_small) { - wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response " - "included AT_COUNTER_TOO_SMALL - starting full " - "authentication"); - data->start_round = -1; - eap_sim_state(data, START); - return; - } - - if (sm->eap_sim_aka_result_ind && attr->result_ind) { - data->use_result_ind = 1; - data->notification = EAP_SIM_SUCCESS; - eap_sim_state(data, NOTIFICATION); - } else - eap_sim_state(data, SUCCESS); - - if (data->next_reauth_id) { - eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent, - data->next_reauth_id, - data->counter + 1, data->mk); - data->next_reauth_id = NULL; - } else { - eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); - data->reauth = NULL; - } - - return; - -fail: - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_sim_state(data, NOTIFICATION); - eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); - data->reauth = NULL; - os_free(decrypted); -} - - -static void eap_sim_process_client_error(struct eap_sm *sm, - struct eap_sim_data *data, - struct wpabuf *respData, - struct eap_sim_attrs *attr) -{ - wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d", - attr->client_error_code); - if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) - eap_sim_state(data, SUCCESS); - else - eap_sim_state(data, FAILURE); -} - - -static void eap_sim_process_notification(struct eap_sm *sm, - struct eap_sim_data *data, - struct wpabuf *respData, - struct eap_sim_attrs *attr) -{ - wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification"); - if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) - eap_sim_state(data, SUCCESS); - else - eap_sim_state(data, FAILURE); -} - - -static void eap_sim_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_sim_data *data = priv; - const u8 *pos, *end; - u8 subtype; - size_t len; - struct eap_sim_attrs attr; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len); - if (pos == NULL || len < 3) - return; - - end = pos + len; - subtype = *pos; - pos += 3; - - if (eap_sim_unexpected_subtype(data, subtype)) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized or unexpected " - "EAP-SIM Subtype in EAP Response"); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_sim_state(data, NOTIFICATION); - return; - } - - if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) { - wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes"); - if (subtype != EAP_SIM_SUBTYPE_CLIENT_ERROR && - (data->state == START || data->state == CHALLENGE || - data->state == REAUTH)) { - data->notification = - EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_sim_state(data, NOTIFICATION); - return; - } - eap_sim_state(data, FAILURE); - return; - } - - if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) { - eap_sim_process_client_error(sm, data, respData, &attr); - return; - } - - switch (data->state) { - case START: - eap_sim_process_start(sm, data, respData, &attr); - break; - case CHALLENGE: - eap_sim_process_challenge(sm, data, respData, &attr); - break; - case REAUTH: - eap_sim_process_reauth(sm, data, respData, &attr); - break; - case NOTIFICATION: - eap_sim_process_notification(sm, data, respData, &attr); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in " - "process", data->state); - break; - } -} - - -static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_sim_data *data = priv; - return data->state == SUCCESS || data->state == FAILURE; -} - - -static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_sim_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_SIM_KEYING_DATA_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); - *len = EAP_SIM_KEYING_DATA_LEN; - return key; -} - - -static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_sim_data *data = priv; - u8 *key; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - os_memcpy(key, data->emsk, EAP_EMSK_LEN); - *len = EAP_EMSK_LEN; - return key; -} - - -static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_sim_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_sim_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM"); - if (eap == NULL) - return -1; - - eap->init = eap_sim_init; - eap->reset = eap_sim_reset; - eap->buildReq = eap_sim_buildReq; - eap->check = eap_sim_check; - eap->process = eap_sim_process; - eap->isDone = eap_sim_isDone; - eap->getKey = eap_sim_getKey; - eap->isSuccess = eap_sim_isSuccess; - eap->get_emsk = eap_sim_get_emsk; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_tls.c b/contrib/hostapd/src/eap_server/eap_server_tls.c deleted file mode 100644 index 447f47cfa0..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_tls.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * hostapd / EAP-TLS (RFC 2716) - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" -#include "eap_tls_common.h" -#include "crypto/tls.h" - - -static void eap_tls_reset(struct eap_sm *sm, void *priv); - - -struct eap_tls_data { - struct eap_ssl_data ssl; - enum { START, CONTINUE, SUCCESS, FAILURE } state; - int established; - u8 eap_type; -}; - - -static const char * eap_tls_state_txt(int state) -{ - switch (state) { - case START: - return "START"; - case CONTINUE: - return "CONTINUE"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "Unknown?!"; - } -} - - -static void eap_tls_state(struct eap_tls_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s", - eap_tls_state_txt(data->state), - eap_tls_state_txt(state)); - data->state = state; -} - - -static void * eap_tls_init(struct eap_sm *sm) -{ - struct eap_tls_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = START; - - if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) { - wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); - eap_tls_reset(sm, data); - return NULL; - } - - data->eap_type = EAP_TYPE_TLS; - - return data; -} - - -#ifdef EAP_SERVER_UNAUTH_TLS -static void * eap_unauth_tls_init(struct eap_sm *sm) -{ - struct eap_tls_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = START; - - if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) { - wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); - eap_tls_reset(sm, data); - return NULL; - } - - data->eap_type = EAP_UNAUTH_TLS_TYPE; - return data; -} -#endif /* EAP_SERVER_UNAUTH_TLS */ - - -static void eap_tls_reset(struct eap_sm *sm, void *priv) -{ - struct eap_tls_data *data = priv; - if (data == NULL) - return; - eap_server_tls_ssl_deinit(sm, &data->ssl); - os_free(data); -} - - -static struct wpabuf * eap_tls_build_start(struct eap_sm *sm, - struct eap_tls_data *data, u8 id) -{ - struct wpabuf *req; - - req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for " - "request"); - eap_tls_state(data, FAILURE); - return NULL; - } - - wpabuf_put_u8(req, EAP_TLS_FLAGS_START); - - eap_tls_state(data, CONTINUE); - - return req; -} - - -static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_tls_data *data = priv; - struct wpabuf *res; - - if (data->ssl.state == FRAG_ACK) { - return eap_server_tls_build_ack(id, data->eap_type, 0); - } - - if (data->ssl.state == WAIT_FRAG_ACK) { - res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, - id); - goto check_established; - } - - switch (data->state) { - case START: - return eap_tls_build_start(sm, data, id); - case CONTINUE: - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) - data->established = 1; - break; - default: - wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d", - __func__, data->state); - return NULL; - } - - res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id); - -check_established: - if (data->established && data->ssl.state != WAIT_FRAG_ACK) { - /* TLS handshake has been completed and there are no more - * fragments waiting to be sent out. */ - wpa_printf(MSG_DEBUG, "EAP-TLS: Done"); - eap_tls_state(data, SUCCESS); - } - - return res; -} - - -static Boolean eap_tls_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_tls_data *data = priv; - const u8 *pos; - size_t len; - - if (data->eap_type == EAP_UNAUTH_TLS_TYPE) - pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, - EAP_VENDOR_TYPE_UNAUTH_TLS, respData, - &len); - else - pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type, - respData, &len); - if (pos == NULL || len < 1) { - wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame"); - return TRUE; - } - - return FALSE; -} - - -static void eap_tls_process_msg(struct eap_sm *sm, void *priv, - const struct wpabuf *respData) -{ - struct eap_tls_data *data = priv; - if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) { - wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS " - "handshake message"); - return; - } - if (eap_server_tls_phase1(sm, &data->ssl) < 0) - eap_tls_state(data, FAILURE); -} - - -static void eap_tls_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_tls_data *data = priv; - if (eap_server_tls_process(sm, &data->ssl, respData, data, - data->eap_type, NULL, eap_tls_process_msg) < - 0) - eap_tls_state(data, FAILURE); -} - - -static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_tls_data *data = priv; - return data->state == SUCCESS || data->state == FAILURE; -} - - -static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_tls_data *data = priv; - u8 *eapKeyData; - - if (data->state != SUCCESS) - return NULL; - - eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, - "client EAP encryption", - EAP_TLS_KEY_LEN); - if (eapKeyData) { - *len = EAP_TLS_KEY_LEN; - wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key", - eapKeyData, EAP_TLS_KEY_LEN); - } else { - wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key"); - } - - return eapKeyData; -} - - -static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_tls_data *data = priv; - u8 *eapKeyData, *emsk; - - if (data->state != SUCCESS) - return NULL; - - eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, - "client EAP encryption", - EAP_TLS_KEY_LEN + EAP_EMSK_LEN); - if (eapKeyData) { - emsk = os_malloc(EAP_EMSK_LEN); - if (emsk) - os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN, - EAP_EMSK_LEN); - os_free(eapKeyData); - } else - emsk = NULL; - - if (emsk) { - *len = EAP_EMSK_LEN; - wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK", - emsk, EAP_EMSK_LEN); - } else { - wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK"); - } - - return emsk; -} - - -static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_tls_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_tls_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); - if (eap == NULL) - return -1; - - eap->init = eap_tls_init; - eap->reset = eap_tls_reset; - eap->buildReq = eap_tls_buildReq; - eap->check = eap_tls_check; - eap->process = eap_tls_process; - eap->isDone = eap_tls_isDone; - eap->getKey = eap_tls_getKey; - eap->isSuccess = eap_tls_isSuccess; - eap->get_emsk = eap_tls_get_emsk; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} - - -#ifdef EAP_SERVER_UNAUTH_TLS -int eap_server_unauth_tls_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_UNAUTH_TLS, - EAP_VENDOR_TYPE_UNAUTH_TLS, - "UNAUTH-TLS"); - if (eap == NULL) - return -1; - - eap->init = eap_unauth_tls_init; - eap->reset = eap_tls_reset; - eap->buildReq = eap_tls_buildReq; - eap->check = eap_tls_check; - eap->process = eap_tls_process; - eap->isDone = eap_tls_isDone; - eap->getKey = eap_tls_getKey; - eap->isSuccess = eap_tls_isSuccess; - eap->get_emsk = eap_tls_get_emsk; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} -#endif /* EAP_SERVER_UNAUTH_TLS */ diff --git a/contrib/hostapd/src/eap_server/eap_server_tls_common.c b/contrib/hostapd/src/eap_server/eap_server_tls_common.c deleted file mode 100644 index 526e1bcc9c..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_tls_common.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * EAP-TLS/PEAP/TTLS/FAST server common functions - * Copyright (c) 2004-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha1.h" -#include "crypto/tls.h" -#include "eap_i.h" -#include "eap_tls_common.h" - - -static void eap_server_tls_free_in_buf(struct eap_ssl_data *data); - - -struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len, - u8 code, u8 identifier) -{ - if (type == EAP_UNAUTH_TLS_TYPE) - return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS, - EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len, - code, identifier); - return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code, - identifier); -} - - -int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, - int verify_peer) -{ - if (sm->ssl_ctx == NULL) { - wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method"); - return -1; - } - - data->eap = sm; - data->phase2 = sm->init_phase2; - - data->conn = tls_connection_init(sm->ssl_ctx); - if (data->conn == NULL) { - wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " - "connection"); - return -1; - } - - if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) { - wpa_printf(MSG_INFO, "SSL: Failed to configure verification " - "of TLS peer certificate"); - tls_connection_deinit(sm->ssl_ctx, data->conn); - data->conn = NULL; - return -1; - } - - data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398; - if (data->phase2) { - /* Limit the fragment size in the inner TLS authentication - * since the outer authentication with EAP-PEAP does not yet - * support fragmentation */ - if (data->tls_out_limit > 100) - data->tls_out_limit -= 100; - } - return 0; -} - - -void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) -{ - tls_connection_deinit(sm->ssl_ctx, data->conn); - eap_server_tls_free_in_buf(data); - wpabuf_free(data->tls_out); - data->tls_out = NULL; -} - - -u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, - char *label, size_t len) -{ - struct tls_keys keys; - u8 *rnd = NULL, *out; - - out = os_malloc(len); - if (out == NULL) - return NULL; - - if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) == - 0) - return out; - - if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) - goto fail; - - if (keys.client_random == NULL || keys.server_random == NULL || - keys.master_key == NULL) - goto fail; - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - if (rnd == NULL) - goto fail; - 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_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); - return out; - -fail: - os_free(out); - os_free(rnd); - return NULL; -} - - -struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data, - int eap_type, int version, u8 id) -{ - struct wpabuf *req; - u8 flags; - size_t send_len, plen; - - wpa_printf(MSG_DEBUG, "SSL: Generating Request"); - if (data->tls_out == NULL) { - wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__); - return NULL; - } - - flags = version; - send_len = wpabuf_len(data->tls_out) - data->tls_out_pos; - if (1 + send_len > data->tls_out_limit) { - send_len = data->tls_out_limit - 1; - flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; - if (data->tls_out_pos == 0) { - flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; - send_len -= 4; - } - } - - plen = 1 + send_len; - if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) - plen += 4; - - req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id); - if (req == NULL) - return NULL; - - wpabuf_put_u8(req, flags); /* Flags */ - if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) - wpabuf_put_be32(req, wpabuf_len(data->tls_out)); - - wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos, - send_len); - data->tls_out_pos += send_len; - - if (data->tls_out_pos == wpabuf_len(data->tls_out)) { - wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " - "(message sent completely)", - (unsigned long) send_len); - wpabuf_free(data->tls_out); - data->tls_out = NULL; - data->tls_out_pos = 0; - data->state = MSG; - } else { - wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " - "(%lu more to send)", (unsigned long) send_len, - (unsigned long) wpabuf_len(data->tls_out) - - data->tls_out_pos); - data->state = WAIT_FRAG_ACK; - } - - return req; -} - - -struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version) -{ - struct wpabuf *req; - - req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id); - if (req == NULL) - return NULL; - wpa_printf(MSG_DEBUG, "SSL: Building ACK"); - wpabuf_put_u8(req, version); /* Flags */ - return req; -} - - -static int eap_server_tls_process_cont(struct eap_ssl_data *data, - const u8 *buf, size_t len) -{ - /* Process continuation of a pending message */ - if (len > wpabuf_tailroom(data->tls_in)) { - wpa_printf(MSG_DEBUG, "SSL: Fragment overflow"); - return -1; - } - - wpabuf_put_data(data->tls_in, buf, len); - wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu " - "bytes more", (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->tls_in)); - - return 0; -} - - -static int eap_server_tls_process_fragment(struct eap_ssl_data *data, - u8 flags, u32 message_length, - const u8 *buf, size_t len) -{ - /* Process a fragment that is not the last one of the message */ - if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) { - wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a " - "fragmented packet"); - return -1; - } - - if (data->tls_in == NULL) { - /* First fragment of the message */ - - /* Limit length to avoid rogue peers from causing large - * memory allocations. */ - if (message_length > 65536) { - wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size" - " over 64 kB)"); - return -1; - } - - if (len > message_length) { - wpa_printf(MSG_INFO, "SSL: Too much data (%d bytes) in " - "first fragment of frame (TLS Message " - "Length %d bytes)", - (int) len, (int) message_length); - return -1; - } - - data->tls_in = wpabuf_alloc(message_length); - if (data->tls_in == NULL) { - wpa_printf(MSG_DEBUG, "SSL: No memory for message"); - return -1; - } - wpabuf_put_data(data->tls_in, buf, len); - wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first " - "fragment, waiting for %lu bytes more", - (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->tls_in)); - } - - return 0; -} - - -int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data) -{ - if (data->tls_out) { - /* This should not happen.. */ - wpa_printf(MSG_INFO, "SSL: pending tls_out data when " - "processing new message"); - wpabuf_free(data->tls_out); - WPA_ASSERT(data->tls_out == NULL); - } - - data->tls_out = tls_connection_server_handshake(sm->ssl_ctx, - data->conn, - data->tls_in, NULL); - if (data->tls_out == NULL) { - wpa_printf(MSG_INFO, "SSL: TLS processing failed"); - return -1; - } - if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) { - /* TLS processing has failed - return error */ - wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " - "report error"); - return -1; - } - - return 0; -} - - -static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags, - const u8 **pos, size_t *left) -{ - unsigned int tls_msg_len = 0; - const u8 *end = *pos + *left; - - if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { - if (*left < 4) { - wpa_printf(MSG_INFO, "SSL: Short frame with TLS " - "length"); - return -1; - } - tls_msg_len = WPA_GET_BE32(*pos); - wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", - tls_msg_len); - *pos += 4; - *left -= 4; - - if (*left > tls_msg_len) { - wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d " - "bytes) smaller than this fragment (%d " - "bytes)", (int) tls_msg_len, (int) *left); - return -1; - } - } - - wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x " - "Message Length %u", flags, tls_msg_len); - - if (data->state == WAIT_FRAG_ACK) { - if (*left != 0) { - wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in " - "WAIT_FRAG_ACK state"); - return -1; - } - wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged"); - return 1; - } - - if (data->tls_in && - eap_server_tls_process_cont(data, *pos, end - *pos) < 0) - return -1; - - if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) { - if (eap_server_tls_process_fragment(data, flags, tls_msg_len, - *pos, end - *pos) < 0) - return -1; - - data->state = FRAG_ACK; - return 1; - } - - if (data->state == FRAG_ACK) { - wpa_printf(MSG_DEBUG, "SSL: All fragments received"); - data->state = MSG; - } - - if (data->tls_in == NULL) { - /* Wrap unfragmented messages as wpabuf without extra copy */ - wpabuf_set(&data->tmpbuf, *pos, end - *pos); - data->tls_in = &data->tmpbuf; - } - - return 0; -} - - -static void eap_server_tls_free_in_buf(struct eap_ssl_data *data) -{ - if (data->tls_in != &data->tmpbuf) - wpabuf_free(data->tls_in); - data->tls_in = NULL; -} - - -struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm, - struct eap_ssl_data *data, - const struct wpabuf *plain) -{ - struct wpabuf *buf; - - buf = tls_connection_encrypt(sm->ssl_ctx, data->conn, - plain); - if (buf == NULL) { - wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data"); - return NULL; - } - - return buf; -} - - -int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data, - struct wpabuf *respData, void *priv, int eap_type, - int (*proc_version)(struct eap_sm *sm, void *priv, - int peer_version), - void (*proc_msg)(struct eap_sm *sm, void *priv, - const struct wpabuf *respData)) -{ - const u8 *pos; - u8 flags; - size_t left; - int ret, res = 0; - - if (eap_type == EAP_UNAUTH_TLS_TYPE) - pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, - EAP_VENDOR_TYPE_UNAUTH_TLS, respData, - &left); - else - pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, - &left); - if (pos == NULL || left < 1) - return 0; /* Should not happen - frame already validated */ - flags = *pos++; - left--; - wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x", - (unsigned long) wpabuf_len(respData), flags); - - if (proc_version && - proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0) - return -1; - - ret = eap_server_tls_reassemble(data, flags, &pos, &left); - if (ret < 0) { - res = -1; - goto done; - } else if (ret == 1) - return 0; - - if (proc_msg) - proc_msg(sm, priv, respData); - - if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) { - wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in " - "TLS processing"); - res = -1; - } - -done: - eap_server_tls_free_in_buf(data); - - return res; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_tnc.c b/contrib/hostapd/src/eap_server/eap_server_tnc.c deleted file mode 100644 index 67a3dfa306..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_tnc.c +++ /dev/null @@ -1,575 +0,0 @@ -/* - * EAP server method: EAP-TNC (Trusted Network Connect) - * Copyright (c) 2007-2010, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" -#include "tncs.h" - - -struct eap_tnc_data { - enum eap_tnc_state { - START, CONTINUE, RECOMMENDATION, FRAG_ACK, WAIT_FRAG_ACK, DONE, - FAIL - } state; - enum { ALLOW, ISOLATE, NO_ACCESS, NO_RECOMMENDATION } recommendation; - struct tncs_data *tncs; - struct wpabuf *in_buf; - struct wpabuf *out_buf; - size_t out_used; - size_t fragment_size; - unsigned int was_done:1; - unsigned int was_fail:1; -}; - - -/* EAP-TNC Flags */ -#define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80 -#define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40 -#define EAP_TNC_FLAGS_START 0x20 -#define EAP_TNC_VERSION_MASK 0x07 - -#define EAP_TNC_VERSION 1 - - -static const char * eap_tnc_state_txt(enum eap_tnc_state state) -{ - switch (state) { - case START: - return "START"; - case CONTINUE: - return "CONTINUE"; - case RECOMMENDATION: - return "RECOMMENDATION"; - case FRAG_ACK: - return "FRAG_ACK"; - case WAIT_FRAG_ACK: - return "WAIT_FRAG_ACK"; - case DONE: - return "DONE"; - case FAIL: - return "FAIL"; - } - return "??"; -} - - -static void eap_tnc_set_state(struct eap_tnc_data *data, - enum eap_tnc_state new_state) -{ - wpa_printf(MSG_DEBUG, "EAP-TNC: %s -> %s", - eap_tnc_state_txt(data->state), - eap_tnc_state_txt(new_state)); - data->state = new_state; -} - - -static void * eap_tnc_init(struct eap_sm *sm) -{ - struct eap_tnc_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - eap_tnc_set_state(data, START); - data->tncs = tncs_init(); - if (data->tncs == NULL) { - os_free(data); - return NULL; - } - - data->fragment_size = sm->fragment_size > 100 ? - sm->fragment_size - 98 : 1300; - - return data; -} - - -static void eap_tnc_reset(struct eap_sm *sm, void *priv) -{ - struct eap_tnc_data *data = priv; - wpabuf_free(data->in_buf); - wpabuf_free(data->out_buf); - tncs_deinit(data->tncs); - os_free(data); -} - - -static struct wpabuf * eap_tnc_build_start(struct eap_sm *sm, - struct eap_tnc_data *data, u8 id) -{ - struct wpabuf *req; - - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, EAP_CODE_REQUEST, - id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory for " - "request"); - eap_tnc_set_state(data, FAIL); - return NULL; - } - - wpabuf_put_u8(req, EAP_TNC_FLAGS_START | EAP_TNC_VERSION); - - eap_tnc_set_state(data, CONTINUE); - - return req; -} - - -static struct wpabuf * eap_tnc_build(struct eap_sm *sm, - struct eap_tnc_data *data) -{ - struct wpabuf *req; - u8 *rpos, *rpos1; - size_t rlen; - char *start_buf, *end_buf; - size_t start_len, end_len; - size_t imv_len; - - imv_len = tncs_total_send_len(data->tncs); - - start_buf = tncs_if_tnccs_start(data->tncs); - if (start_buf == NULL) - return NULL; - start_len = os_strlen(start_buf); - end_buf = tncs_if_tnccs_end(); - if (end_buf == NULL) { - os_free(start_buf); - return NULL; - } - end_len = os_strlen(end_buf); - - rlen = start_len + imv_len + end_len; - req = wpabuf_alloc(rlen); - if (req == NULL) { - os_free(start_buf); - os_free(end_buf); - return NULL; - } - - wpabuf_put_data(req, start_buf, start_len); - os_free(start_buf); - - rpos1 = wpabuf_put(req, 0); - rpos = tncs_copy_send_buf(data->tncs, rpos1); - wpabuf_put(req, rpos - rpos1); - - wpabuf_put_data(req, end_buf, end_len); - os_free(end_buf); - - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Request", - wpabuf_head(req), wpabuf_len(req)); - - return req; -} - - -static struct wpabuf * eap_tnc_build_recommendation(struct eap_sm *sm, - struct eap_tnc_data *data) -{ - switch (data->recommendation) { - case ALLOW: - eap_tnc_set_state(data, DONE); - break; - case ISOLATE: - eap_tnc_set_state(data, FAIL); - /* TODO: support assignment to a different VLAN */ - break; - case NO_ACCESS: - eap_tnc_set_state(data, FAIL); - break; - case NO_RECOMMENDATION: - eap_tnc_set_state(data, DONE); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-TNC: Unknown recommendation"); - return NULL; - } - - return eap_tnc_build(sm, data); -} - - -static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code) -{ - struct wpabuf *msg; - - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory " - "for fragment ack"); - return NULL; - } - wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */ - - wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack"); - - return msg; -} - - -static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data, u8 id) -{ - struct wpabuf *req; - u8 flags; - size_t send_len, plen; - - wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Request"); - - flags = EAP_TNC_VERSION; - send_len = wpabuf_len(data->out_buf) - data->out_used; - if (1 + send_len > data->fragment_size) { - send_len = data->fragment_size - 1; - flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS; - if (data->out_used == 0) { - flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED; - send_len -= 4; - } - } - - plen = 1 + send_len; - if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) - plen += 4; - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen, - EAP_CODE_REQUEST, id); - if (req == NULL) - return NULL; - - wpabuf_put_u8(req, flags); /* Flags */ - if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) - wpabuf_put_be32(req, wpabuf_len(data->out_buf)); - - wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, - send_len); - data->out_used += send_len; - - if (data->out_used == wpabuf_len(data->out_buf)) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " - "(message sent completely)", - (unsigned long) send_len); - wpabuf_free(data->out_buf); - data->out_buf = NULL; - data->out_used = 0; - if (data->was_fail) - eap_tnc_set_state(data, FAIL); - else if (data->was_done) - eap_tnc_set_state(data, DONE); - } else { - wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " - "(%lu more to send)", (unsigned long) send_len, - (unsigned long) wpabuf_len(data->out_buf) - - data->out_used); - if (data->state == FAIL) - data->was_fail = 1; - else if (data->state == DONE) - data->was_done = 1; - eap_tnc_set_state(data, WAIT_FRAG_ACK); - } - - return req; -} - - -static struct wpabuf * eap_tnc_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_tnc_data *data = priv; - - switch (data->state) { - case START: - tncs_init_connection(data->tncs); - return eap_tnc_build_start(sm, data, id); - case CONTINUE: - if (data->out_buf == NULL) { - data->out_buf = eap_tnc_build(sm, data); - if (data->out_buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to " - "generate message"); - return NULL; - } - data->out_used = 0; - } - return eap_tnc_build_msg(data, id); - case RECOMMENDATION: - if (data->out_buf == NULL) { - data->out_buf = eap_tnc_build_recommendation(sm, data); - if (data->out_buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to " - "generate recommendation message"); - return NULL; - } - data->out_used = 0; - } - return eap_tnc_build_msg(data, id); - case WAIT_FRAG_ACK: - return eap_tnc_build_msg(data, id); - case FRAG_ACK: - return eap_tnc_build_frag_ack(id, EAP_CODE_REQUEST); - case DONE: - case FAIL: - return NULL; - } - - return NULL; -} - - -static Boolean eap_tnc_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_tnc_data *data = priv; - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, - &len); - if (pos == NULL) { - wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame"); - return TRUE; - } - - if (len == 0 && data->state != WAIT_FRAG_ACK) { - wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (empty)"); - return TRUE; - } - - if (len == 0) - return FALSE; /* Fragment ACK does not include flags */ - - if ((*pos & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d", - *pos & EAP_TNC_VERSION_MASK); - return TRUE; - } - - if (*pos & EAP_TNC_FLAGS_START) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Peer used Start flag"); - return TRUE; - } - - return FALSE; -} - - -static void tncs_process(struct eap_tnc_data *data, struct wpabuf *inbuf) -{ - enum tncs_process_res res; - - res = tncs_process_if_tnccs(data->tncs, wpabuf_head(inbuf), - wpabuf_len(inbuf)); - switch (res) { - case TNCCS_RECOMMENDATION_ALLOW: - wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS allowed access"); - eap_tnc_set_state(data, RECOMMENDATION); - data->recommendation = ALLOW; - break; - case TNCCS_RECOMMENDATION_NO_RECOMMENDATION: - wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS has no recommendation"); - eap_tnc_set_state(data, RECOMMENDATION); - data->recommendation = NO_RECOMMENDATION; - break; - case TNCCS_RECOMMENDATION_ISOLATE: - wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS requested isolation"); - eap_tnc_set_state(data, RECOMMENDATION); - data->recommendation = ISOLATE; - break; - case TNCCS_RECOMMENDATION_NO_ACCESS: - wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS rejected access"); - eap_tnc_set_state(data, RECOMMENDATION); - data->recommendation = NO_ACCESS; - break; - case TNCCS_PROCESS_ERROR: - wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS processing error"); - eap_tnc_set_state(data, FAIL); - break; - default: - break; - } -} - - -static int eap_tnc_process_cont(struct eap_tnc_data *data, - const u8 *buf, size_t len) -{ - /* Process continuation of a pending message */ - if (len > wpabuf_tailroom(data->in_buf)) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow"); - eap_tnc_set_state(data, FAIL); - return -1; - } - - wpabuf_put_data(data->in_buf, buf, len); - wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for %lu " - "bytes more", (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); - - return 0; -} - - -static int eap_tnc_process_fragment(struct eap_tnc_data *data, - u8 flags, u32 message_length, - const u8 *buf, size_t len) -{ - /* Process a fragment that is not the last one of the message */ - if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) { - wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a " - "fragmented packet"); - return -1; - } - - if (data->in_buf == NULL) { - /* First fragment of the message */ - data->in_buf = wpabuf_alloc(message_length); - if (data->in_buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for " - "message"); - return -1; - } - wpabuf_put_data(data->in_buf, buf, len); - wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first " - "fragment, waiting for %lu bytes more", - (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); - } - - return 0; -} - - -static void eap_tnc_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_tnc_data *data = priv; - const u8 *pos, *end; - size_t len; - u8 flags; - u32 message_length = 0; - struct wpabuf tmpbuf; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, &len); - if (pos == NULL) - return; /* Should not happen; message already verified */ - - end = pos + len; - - if (len == 1 && (data->state == DONE || data->state == FAIL)) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Peer acknowledged the last " - "message"); - return; - } - - if (len == 0) { - /* fragment ack */ - flags = 0; - } else - flags = *pos++; - - if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) { - if (end - pos < 4) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow"); - eap_tnc_set_state(data, FAIL); - return; - } - message_length = WPA_GET_BE32(pos); - pos += 4; - - if (message_length < (u32) (end - pos)) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message " - "Length (%d; %ld remaining in this msg)", - message_length, (long) (end - pos)); - eap_tnc_set_state(data, FAIL); - return; - } - } - wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x " - "Message Length %u", flags, message_length); - - if (data->state == WAIT_FRAG_ACK) { - if (len > 1) { - wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload " - "in WAIT_FRAG_ACK state"); - eap_tnc_set_state(data, FAIL); - return; - } - wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged"); - eap_tnc_set_state(data, CONTINUE); - return; - } - - if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) { - eap_tnc_set_state(data, FAIL); - return; - } - - if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) { - if (eap_tnc_process_fragment(data, flags, message_length, - pos, end - pos) < 0) - eap_tnc_set_state(data, FAIL); - else - eap_tnc_set_state(data, FRAG_ACK); - return; - } else if (data->state == FRAG_ACK) { - wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received"); - eap_tnc_set_state(data, CONTINUE); - } - - if (data->in_buf == NULL) { - /* Wrap unfragmented messages as wpabuf without extra copy */ - wpabuf_set(&tmpbuf, pos, end - pos); - data->in_buf = &tmpbuf; - } - - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload", - wpabuf_head(data->in_buf), wpabuf_len(data->in_buf)); - tncs_process(data, data->in_buf); - - if (data->in_buf != &tmpbuf) - wpabuf_free(data->in_buf); - data->in_buf = NULL; -} - - -static Boolean eap_tnc_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_tnc_data *data = priv; - return data->state == DONE || data->state == FAIL; -} - - -static Boolean eap_tnc_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_tnc_data *data = priv; - return data->state == DONE; -} - - -int eap_server_tnc_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC"); - if (eap == NULL) - return -1; - - eap->init = eap_tnc_init; - eap->reset = eap_tnc_reset; - eap->buildReq = eap_tnc_buildReq; - eap->check = eap_tnc_check; - eap->process = eap_tnc_process; - eap->isDone = eap_tnc_isDone; - eap->isSuccess = eap_tnc_isSuccess; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_ttls.c b/contrib/hostapd/src/eap_server/eap_server_ttls.c deleted file mode 100644 index 647bd2fad9..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_ttls.c +++ /dev/null @@ -1,1193 +0,0 @@ -/* - * hostapd / EAP-TTLS (RFC 5281) - * Copyright (c) 2004-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/ms_funcs.h" -#include "crypto/sha1.h" -#include "crypto/tls.h" -#include "eap_server/eap_i.h" -#include "eap_server/eap_tls_common.h" -#include "eap_common/chap.h" -#include "eap_common/eap_ttls.h" - - -#define EAP_TTLS_VERSION 0 - - -static void eap_ttls_reset(struct eap_sm *sm, void *priv); - - -struct eap_ttls_data { - struct eap_ssl_data ssl; - enum { - START, PHASE1, PHASE2_START, PHASE2_METHOD, - PHASE2_MSCHAPV2_RESP, SUCCESS, FAILURE - } state; - - int ttls_version; - const struct eap_method *phase2_method; - void *phase2_priv; - int mschapv2_resp_ok; - u8 mschapv2_auth_response[20]; - u8 mschapv2_ident; - struct wpabuf *pending_phase2_eap_resp; - int tnc_started; -}; - - -static const char * eap_ttls_state_txt(int state) -{ - switch (state) { - case START: - return "START"; - case PHASE1: - return "PHASE1"; - case PHASE2_START: - return "PHASE2_START"; - case PHASE2_METHOD: - return "PHASE2_METHOD"; - case PHASE2_MSCHAPV2_RESP: - return "PHASE2_MSCHAPV2_RESP"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "Unknown?!"; - } -} - - -static void eap_ttls_state(struct eap_ttls_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-TTLS: %s -> %s", - eap_ttls_state_txt(data->state), - eap_ttls_state_txt(state)); - data->state = state; -} - - -static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, - int mandatory, size_t len) -{ - struct ttls_avp_vendor *avp; - u8 flags; - size_t hdrlen; - - avp = (struct ttls_avp_vendor *) avphdr; - flags = mandatory ? AVP_FLAGS_MANDATORY : 0; - if (vendor_id) { - flags |= AVP_FLAGS_VENDOR; - hdrlen = sizeof(*avp); - avp->vendor_id = host_to_be32(vendor_id); - } else { - hdrlen = sizeof(struct ttls_avp); - } - - avp->avp_code = host_to_be32(avp_code); - avp->avp_length = host_to_be32(((u32) flags << 24) | - ((u32) (hdrlen + len))); - - return avphdr + hdrlen; -} - - -static struct wpabuf * eap_ttls_avp_encapsulate(struct wpabuf *resp, - u32 avp_code, int mandatory) -{ - struct wpabuf *avp; - u8 *pos; - - avp = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(resp) + 4); - if (avp == NULL) { - wpabuf_free(resp); - return NULL; - } - - pos = eap_ttls_avp_hdr(wpabuf_mhead(avp), avp_code, 0, mandatory, - wpabuf_len(resp)); - os_memcpy(pos, wpabuf_head(resp), wpabuf_len(resp)); - pos += wpabuf_len(resp); - AVP_PAD((const u8 *) wpabuf_head(avp), pos); - wpabuf_free(resp); - wpabuf_put(avp, pos - (u8 *) wpabuf_head(avp)); - return avp; -} - - -struct eap_ttls_avp { - /* Note: eap is allocated memory; caller is responsible for freeing - * it. All the other pointers are pointing to the packet data, i.e., - * they must not be freed separately. */ - u8 *eap; - size_t eap_len; - u8 *user_name; - size_t user_name_len; - u8 *user_password; - size_t user_password_len; - u8 *chap_challenge; - size_t chap_challenge_len; - u8 *chap_password; - size_t chap_password_len; - u8 *mschap_challenge; - size_t mschap_challenge_len; - u8 *mschap_response; - size_t mschap_response_len; - u8 *mschap2_response; - size_t mschap2_response_len; -}; - - -static int eap_ttls_avp_parse(struct wpabuf *buf, struct eap_ttls_avp *parse) -{ - struct ttls_avp *avp; - u8 *pos; - int left; - - pos = wpabuf_mhead(buf); - left = wpabuf_len(buf); - os_memset(parse, 0, sizeof(*parse)); - - while (left > 0) { - u32 avp_code, avp_length, vendor_id = 0; - u8 avp_flags, *dpos; - size_t pad, dlen; - avp = (struct ttls_avp *) pos; - avp_code = be_to_host32(avp->avp_code); - avp_length = be_to_host32(avp->avp_length); - avp_flags = (avp_length >> 24) & 0xff; - avp_length &= 0xffffff; - wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x " - "length=%d", (int) avp_code, avp_flags, - (int) avp_length); - if ((int) avp_length > left) { - wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow " - "(len=%d, left=%d) - dropped", - (int) avp_length, left); - goto fail; - } - if (avp_length < sizeof(*avp)) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length " - "%d", avp_length); - goto fail; - } - dpos = (u8 *) (avp + 1); - dlen = avp_length - sizeof(*avp); - if (avp_flags & AVP_FLAGS_VENDOR) { - if (dlen < 4) { - wpa_printf(MSG_WARNING, "EAP-TTLS: vendor AVP " - "underflow"); - goto fail; - } - vendor_id = be_to_host32(* (be32 *) dpos); - wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d", - (int) vendor_id); - dpos += 4; - dlen -= 4; - } - - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen); - - if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message"); - if (parse->eap == NULL) { - parse->eap = os_malloc(dlen); - if (parse->eap == NULL) { - wpa_printf(MSG_WARNING, "EAP-TTLS: " - "failed to allocate memory " - "for Phase 2 EAP data"); - goto fail; - } - os_memcpy(parse->eap, dpos, dlen); - parse->eap_len = dlen; - } else { - u8 *neweap = os_realloc(parse->eap, - parse->eap_len + dlen); - if (neweap == NULL) { - wpa_printf(MSG_WARNING, "EAP-TTLS: " - "failed to allocate memory " - "for Phase 2 EAP data"); - goto fail; - } - os_memcpy(neweap + parse->eap_len, dpos, dlen); - parse->eap = neweap; - parse->eap_len += dlen; - } - } else if (vendor_id == 0 && - avp_code == RADIUS_ATTR_USER_NAME) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: User-Name", - dpos, dlen); - parse->user_name = dpos; - parse->user_name_len = dlen; - } else if (vendor_id == 0 && - avp_code == RADIUS_ATTR_USER_PASSWORD) { - u8 *password = dpos; - size_t password_len = dlen; - while (password_len > 0 && - password[password_len - 1] == '\0') { - password_len--; - } - wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: " - "User-Password (PAP)", - password, password_len); - parse->user_password = password; - parse->user_password_len = password_len; - } else if (vendor_id == 0 && - avp_code == RADIUS_ATTR_CHAP_CHALLENGE) { - wpa_hexdump(MSG_DEBUG, - "EAP-TTLS: CHAP-Challenge (CHAP)", - dpos, dlen); - parse->chap_challenge = dpos; - parse->chap_challenge_len = dlen; - } else if (vendor_id == 0 && - avp_code == RADIUS_ATTR_CHAP_PASSWORD) { - wpa_hexdump(MSG_DEBUG, - "EAP-TTLS: CHAP-Password (CHAP)", - dpos, dlen); - parse->chap_password = dpos; - parse->chap_password_len = dlen; - } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && - avp_code == RADIUS_ATTR_MS_CHAP_CHALLENGE) { - wpa_hexdump(MSG_DEBUG, - "EAP-TTLS: MS-CHAP-Challenge", - dpos, dlen); - parse->mschap_challenge = dpos; - parse->mschap_challenge_len = dlen; - } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && - avp_code == RADIUS_ATTR_MS_CHAP_RESPONSE) { - wpa_hexdump(MSG_DEBUG, - "EAP-TTLS: MS-CHAP-Response (MSCHAP)", - dpos, dlen); - parse->mschap_response = dpos; - parse->mschap_response_len = dlen; - } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && - avp_code == RADIUS_ATTR_MS_CHAP2_RESPONSE) { - wpa_hexdump(MSG_DEBUG, - "EAP-TTLS: MS-CHAP2-Response (MSCHAPV2)", - dpos, dlen); - parse->mschap2_response = dpos; - parse->mschap2_response_len = dlen; - } else if (avp_flags & AVP_FLAGS_MANDATORY) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported " - "mandatory AVP code %d vendor_id %d - " - "dropped", (int) avp_code, (int) vendor_id); - goto fail; - } else { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported " - "AVP code %d vendor_id %d", - (int) avp_code, (int) vendor_id); - } - - pad = (4 - (avp_length & 3)) & 3; - pos += avp_length + pad; - left -= avp_length + pad; - } - - return 0; - -fail: - os_free(parse->eap); - parse->eap = NULL; - return -1; -} - - -static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, - struct eap_ttls_data *data, size_t len) -{ - return eap_server_tls_derive_key(sm, &data->ssl, "ttls challenge", - len); -} - - -static void * eap_ttls_init(struct eap_sm *sm) -{ - struct eap_ttls_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->ttls_version = EAP_TTLS_VERSION; - data->state = START; - - 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); - return NULL; - } - - return data; -} - - -static void eap_ttls_reset(struct eap_sm *sm, void *priv) -{ - struct eap_ttls_data *data = priv; - if (data == NULL) - return; - if (data->phase2_priv && data->phase2_method) - data->phase2_method->reset(sm, data->phase2_priv); - eap_server_tls_ssl_deinit(sm, &data->ssl); - wpabuf_free(data->pending_phase2_eap_resp); - os_free(data); -} - - -static struct wpabuf * eap_ttls_build_start(struct eap_sm *sm, - struct eap_ttls_data *data, u8 id) -{ - struct wpabuf *req; - - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, 1, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to allocate memory for" - " request"); - eap_ttls_state(data, FAILURE); - return NULL; - } - - wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->ttls_version); - - eap_ttls_state(data, PHASE1); - - return req; -} - - -static struct wpabuf * eap_ttls_build_phase2_eap_req( - struct eap_sm *sm, struct eap_ttls_data *data, u8 id) -{ - struct wpabuf *buf, *encr_req; - - - buf = data->phase2_method->buildReq(sm, data->phase2_priv, id); - if (buf == NULL) - return NULL; - - wpa_hexdump_buf_key(MSG_DEBUG, - "EAP-TTLS/EAP: Encapsulate Phase 2 data", buf); - - buf = eap_ttls_avp_encapsulate(buf, RADIUS_ATTR_EAP_MESSAGE, 1); - if (buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Failed to encapsulate " - "packet"); - return NULL; - } - - wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/EAP: Encrypt encapsulated " - "Phase 2 data", buf); - - encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf); - wpabuf_free(buf); - - return encr_req; -} - - -static struct wpabuf * eap_ttls_build_phase2_mschapv2( - struct eap_sm *sm, struct eap_ttls_data *data) -{ - struct wpabuf *encr_req, msgbuf; - u8 *req, *pos, *end; - int ret; - - pos = req = os_malloc(100); - if (req == NULL) - return NULL; - end = req + 100; - - if (data->mschapv2_resp_ok) { - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_SUCCESS, - RADIUS_VENDOR_ID_MICROSOFT, 1, 43); - *pos++ = data->mschapv2_ident; - ret = os_snprintf((char *) pos, end - pos, "S="); - if (ret >= 0 && ret < end - pos) - pos += ret; - pos += wpa_snprintf_hex_uppercase( - (char *) pos, end - pos, data->mschapv2_auth_response, - sizeof(data->mschapv2_auth_response)); - } else { - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_ERROR, - RADIUS_VENDOR_ID_MICROSOFT, 1, 6); - os_memcpy(pos, "Failed", 6); - pos += 6; - AVP_PAD(req, pos); - } - - wpabuf_set(&msgbuf, req, pos - req); - wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 " - "data", &msgbuf); - - encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); - os_free(req); - - return encr_req; -} - - -static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_ttls_data *data = priv; - - if (data->ssl.state == FRAG_ACK) { - return eap_server_tls_build_ack(id, EAP_TYPE_TTLS, - data->ttls_version); - } - - if (data->ssl.state == WAIT_FRAG_ACK) { - return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS, - data->ttls_version, id); - } - - switch (data->state) { - case START: - return eap_ttls_build_start(sm, data, id); - case PHASE1: - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, " - "starting Phase2"); - eap_ttls_state(data, PHASE2_START); - } - break; - case PHASE2_METHOD: - wpabuf_free(data->ssl.tls_out); - data->ssl.tls_out_pos = 0; - data->ssl.tls_out = eap_ttls_build_phase2_eap_req(sm, data, - id); - break; - case PHASE2_MSCHAPV2_RESP: - wpabuf_free(data->ssl.tls_out); - data->ssl.tls_out_pos = 0; - data->ssl.tls_out = eap_ttls_build_phase2_mschapv2(sm, data); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d", - __func__, data->state); - return NULL; - } - - return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS, - data->ttls_version, id); -} - - -static Boolean eap_ttls_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TTLS, respData, &len); - if (pos == NULL || len < 1) { - wpa_printf(MSG_INFO, "EAP-TTLS: Invalid frame"); - return TRUE; - } - - return FALSE; -} - - -static void eap_ttls_process_phase2_pap(struct eap_sm *sm, - struct eap_ttls_data *data, - const u8 *user_password, - size_t user_password_len) -{ - if (!sm->user || !sm->user->password || sm->user->password_hash || - !(sm->user->ttls_auth & EAP_TTLS_AUTH_PAP)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: No plaintext user " - "password configured"); - eap_ttls_state(data, FAILURE); - return; - } - - if (sm->user->password_len != user_password_len || - os_memcmp(sm->user->password, user_password, user_password_len) != - 0) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Invalid user password"); - eap_ttls_state(data, FAILURE); - return; - } - - wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password"); - eap_ttls_state(data, SUCCESS); -} - - -static void eap_ttls_process_phase2_chap(struct eap_sm *sm, - struct eap_ttls_data *data, - const u8 *challenge, - size_t challenge_len, - const u8 *password, - size_t password_len) -{ - u8 *chal, hash[CHAP_MD5_LEN]; - - if (challenge == NULL || password == NULL || - challenge_len != EAP_TTLS_CHAP_CHALLENGE_LEN || - password_len != 1 + EAP_TTLS_CHAP_PASSWORD_LEN) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid CHAP attributes " - "(challenge len %lu password len %lu)", - (unsigned long) challenge_len, - (unsigned long) password_len); - eap_ttls_state(data, FAILURE); - return; - } - - if (!sm->user || !sm->user->password || sm->user->password_hash || - !(sm->user->ttls_auth & EAP_TTLS_AUTH_CHAP)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: No plaintext user " - "password configured"); - eap_ttls_state(data, FAILURE); - return; - } - - chal = eap_ttls_implicit_challenge(sm, data, - EAP_TTLS_CHAP_CHALLENGE_LEN + 1); - if (chal == NULL) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Failed to generate " - "challenge from TLS data"); - eap_ttls_state(data, FAILURE); - return; - } - - if (os_memcmp(challenge, chal, EAP_TTLS_CHAP_CHALLENGE_LEN) != 0 || - password[0] != chal[EAP_TTLS_CHAP_CHALLENGE_LEN]) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Challenge mismatch"); - os_free(chal); - eap_ttls_state(data, FAILURE); - return; - } - os_free(chal); - - /* MD5(Ident + Password + Challenge) */ - chap_md5(password[0], sm->user->password, sm->user->password_len, - challenge, challenge_len, hash); - - 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, SUCCESS); - } else { - wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password"); - eap_ttls_state(data, FAILURE); - } -} - - -static void eap_ttls_process_phase2_mschap(struct eap_sm *sm, - struct eap_ttls_data *data, - u8 *challenge, size_t challenge_len, - u8 *response, size_t response_len) -{ - u8 *chal, nt_response[24]; - - if (challenge == NULL || response == NULL || - challenge_len != EAP_TTLS_MSCHAP_CHALLENGE_LEN || - response_len != EAP_TTLS_MSCHAP_RESPONSE_LEN) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid MS-CHAP " - "attributes (challenge len %lu response len %lu)", - (unsigned long) challenge_len, - (unsigned long) response_len); - eap_ttls_state(data, FAILURE); - return; - } - - if (!sm->user || !sm->user->password || - !(sm->user->ttls_auth & EAP_TTLS_AUTH_MSCHAP)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: No user password " - "configured"); - eap_ttls_state(data, FAILURE); - return; - } - - chal = eap_ttls_implicit_challenge(sm, data, - EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); - if (chal == NULL) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Failed to generate " - "challenge from TLS data"); - eap_ttls_state(data, FAILURE); - return; - } - - if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN) != 0 || - response[0] != chal[EAP_TTLS_MSCHAP_CHALLENGE_LEN]) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Challenge mismatch"); - os_free(chal); - eap_ttls_state(data, FAILURE); - return; - } - os_free(chal); - - if (sm->user->password_hash) - challenge_response(challenge, sm->user->password, nt_response); - else - nt_challenge_response(challenge, sm->user->password, - sm->user->password_len, nt_response); - - if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response"); - eap_ttls_state(data, SUCCESS); - } else { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response"); - wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received", - response + 2 + 24, 24); - wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Expected", - nt_response, 24); - eap_ttls_state(data, FAILURE); - } -} - - -static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, - struct eap_ttls_data *data, - u8 *challenge, - size_t challenge_len, - u8 *response, size_t response_len) -{ - u8 *chal, *username, nt_response[24], *rx_resp, *peer_challenge, - *auth_challenge; - size_t username_len, i; - - if (challenge == NULL || response == NULL || - challenge_len != EAP_TTLS_MSCHAPV2_CHALLENGE_LEN || - response_len != EAP_TTLS_MSCHAPV2_RESPONSE_LEN) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid MS-CHAP2 " - "attributes (challenge len %lu response len %lu)", - (unsigned long) challenge_len, - (unsigned long) response_len); - eap_ttls_state(data, FAILURE); - return; - } - - if (!sm->user || !sm->user->password || - !(sm->user->ttls_auth & EAP_TTLS_AUTH_MSCHAPV2)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: No user password " - "configured"); - eap_ttls_state(data, FAILURE); - return; - } - - if (sm->identity == NULL) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: No user identity " - "known"); - eap_ttls_state(data, FAILURE); - return; - } - - /* MSCHAPv2 does not include optional domain name in the - * challenge-response calculation, so remove domain prefix - * (if present). */ - username = sm->identity; - username_len = sm->identity_len; - for (i = 0; i < username_len; i++) { - if (username[i] == '\\') { - username_len -= i + 1; - username += i + 1; - break; - } - } - - chal = eap_ttls_implicit_challenge( - sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1); - if (chal == NULL) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Failed to generate " - "challenge from TLS data"); - eap_ttls_state(data, FAILURE); - return; - } - - if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) != 0 || - response[0] != chal[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Challenge mismatch"); - os_free(chal); - eap_ttls_state(data, FAILURE); - return; - } - os_free(chal); - - auth_challenge = challenge; - peer_challenge = response + 2; - - wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: User", - username, username_len); - wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: auth_challenge", - auth_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); - wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: peer_challenge", - peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); - - if (sm->user->password_hash) { - generate_nt_response_pwhash(auth_challenge, peer_challenge, - username, username_len, - sm->user->password, - nt_response); - } else { - generate_nt_response(auth_challenge, peer_challenge, - username, username_len, - sm->user->password, - sm->user->password_len, - nt_response); - } - - rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8; - if (os_memcmp(nt_response, rx_resp, 24) == 0) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct " - "NT-Response"); - data->mschapv2_resp_ok = 1; - - if (sm->user->password_hash) { - generate_authenticator_response_pwhash( - sm->user->password, - peer_challenge, auth_challenge, - username, username_len, nt_response, - data->mschapv2_auth_response); - } else { - generate_authenticator_response( - sm->user->password, sm->user->password_len, - peer_challenge, auth_challenge, - username, username_len, nt_response, - data->mschapv2_auth_response); - } - } else { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid " - "NT-Response"); - wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Received", - rx_resp, 24); - wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Expected", - nt_response, 24); - data->mschapv2_resp_ok = 0; - } - eap_ttls_state(data, PHASE2_MSCHAPV2_RESP); - data->mschapv2_ident = response[0]; -} - - -static int eap_ttls_phase2_eap_init(struct eap_sm *sm, - struct eap_ttls_data *data, - EapType eap_type) -{ - if (data->phase2_priv && data->phase2_method) { - data->phase2_method->reset(sm, data->phase2_priv); - data->phase2_method = NULL; - data->phase2_priv = NULL; - } - data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF, - eap_type); - if (!data->phase2_method) - return -1; - - sm->init_phase2 = 1; - data->phase2_priv = data->phase2_method->init(sm); - sm->init_phase2 = 0; - return data->phase2_priv == NULL ? -1 : 0; -} - - -static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm, - struct eap_ttls_data *data, - u8 *in_data, size_t in_len) -{ - u8 next_type = EAP_TYPE_NONE; - struct eap_hdr *hdr; - u8 *pos; - size_t left; - struct wpabuf buf; - const struct eap_method *m = data->phase2_method; - void *priv = data->phase2_priv; - - if (priv == NULL) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: %s - Phase2 not " - "initialized?!", __func__); - return; - } - - hdr = (struct eap_hdr *) in_data; - pos = (u8 *) (hdr + 1); - - if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { - left = in_len - sizeof(*hdr); - wpa_hexdump(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 type Nak'ed; " - "allowed types", pos + 1, left - 1); - eap_sm_process_nak(sm, pos + 1, left - 1); - if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && - sm->user->methods[sm->user_eap_method_index].method != - EAP_TYPE_NONE) { - next_type = sm->user->methods[ - sm->user_eap_method_index++].method; - wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", - next_type); - if (eap_ttls_phase2_eap_init(sm, data, next_type)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to " - "initialize EAP type %d", - next_type); - eap_ttls_state(data, FAILURE); - return; - } - } else { - eap_ttls_state(data, FAILURE); - } - return; - } - - wpabuf_set(&buf, in_data, in_len); - - if (m->check(sm, priv, &buf)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 check() asked to " - "ignore the packet"); - return; - } - - m->process(sm, priv, &buf); - - if (sm->method_pending == METHOD_PENDING_WAIT) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method is in " - "pending wait state - save decrypted response"); - wpabuf_free(data->pending_phase2_eap_resp); - data->pending_phase2_eap_resp = wpabuf_dup(&buf); - } - - if (!m->isDone(sm, priv)) - return; - - if (!m->isSuccess(sm, priv)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method failed"); - eap_ttls_state(data, FAILURE); - return; - } - - switch (data->state) { - case PHASE2_START: - if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP_TTLS: Phase2 " - "Identity not found in the user " - "database", - sm->identity, sm->identity_len); - eap_ttls_state(data, FAILURE); - break; - } - - eap_ttls_state(data, PHASE2_METHOD); - next_type = sm->user->methods[0].method; - sm->user_eap_method_index = 1; - wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type); - if (eap_ttls_phase2_eap_init(sm, data, next_type)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize " - "EAP type %d", next_type); - eap_ttls_state(data, FAILURE); - } - break; - case PHASE2_METHOD: - eap_ttls_state(data, SUCCESS); - break; - case FAILURE: - break; - default: - wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d", - __func__, data->state); - break; - } -} - - -static void eap_ttls_process_phase2_eap(struct eap_sm *sm, - struct eap_ttls_data *data, - const u8 *eap, size_t eap_len) -{ - struct eap_hdr *hdr; - size_t len; - - if (data->state == PHASE2_START) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: initializing Phase 2"); - if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_IDENTITY) < 0) - { - wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: failed to " - "initialize EAP-Identity"); - return; - } - } - - if (eap_len < sizeof(*hdr)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: too short Phase 2 EAP " - "packet (len=%lu)", (unsigned long) eap_len); - return; - } - - hdr = (struct eap_hdr *) eap; - len = be_to_host16(hdr->length); - wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: received Phase 2 EAP: code=%d " - "identifier=%d length=%lu", hdr->code, hdr->identifier, - (unsigned long) len); - if (len > eap_len) { - wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Length mismatch in Phase 2" - " EAP frame (hdr len=%lu, data len in AVP=%lu)", - (unsigned long) len, (unsigned long) eap_len); - return; - } - - switch (hdr->code) { - case EAP_CODE_RESPONSE: - eap_ttls_process_phase2_eap_response(sm, data, (u8 *) hdr, - len); - break; - default: - wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Unexpected code=%d in " - "Phase 2 EAP header", hdr->code); - break; - } -} - - -static void eap_ttls_process_phase2(struct eap_sm *sm, - struct eap_ttls_data *data, - struct wpabuf *in_buf) -{ - struct wpabuf *in_decrypted; - struct eap_ttls_avp parse; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" - " Phase 2", (unsigned long) wpabuf_len(in_buf)); - - if (data->pending_phase2_eap_resp) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 EAP response " - "- skip decryption and use old data"); - eap_ttls_process_phase2_eap( - sm, data, wpabuf_head(data->pending_phase2_eap_resp), - wpabuf_len(data->pending_phase2_eap_resp)); - wpabuf_free(data->pending_phase2_eap_resp); - data->pending_phase2_eap_resp = NULL; - return; - } - - in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, - in_buf); - if (in_decrypted == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 " - "data"); - eap_ttls_state(data, FAILURE); - return; - } - - wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP", - in_decrypted); - - if (eap_ttls_avp_parse(in_decrypted, &parse) < 0) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to parse AVPs"); - wpabuf_free(in_decrypted); - eap_ttls_state(data, FAILURE); - return; - } - - if (parse.user_name) { - os_free(sm->identity); - sm->identity = os_malloc(parse.user_name_len); - if (sm->identity == NULL) { - eap_ttls_state(data, FAILURE); - goto done; - } - os_memcpy(sm->identity, parse.user_name, parse.user_name_len); - sm->identity_len = parse.user_name_len; - if (eap_user_get(sm, parse.user_name, parse.user_name_len, 1) - != 0) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 Identity not " - "found in the user database"); - eap_ttls_state(data, FAILURE); - goto done; - } - } - -#ifdef EAP_SERVER_TNC - if (data->tnc_started && parse.eap == NULL) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: TNC started but no EAP " - "response from peer"); - eap_ttls_state(data, FAILURE); - goto done; - } -#endif /* EAP_SERVER_TNC */ - - if (parse.eap) { - eap_ttls_process_phase2_eap(sm, data, parse.eap, - parse.eap_len); - } else if (parse.user_password) { - eap_ttls_process_phase2_pap(sm, data, parse.user_password, - parse.user_password_len); - } else if (parse.chap_password) { - eap_ttls_process_phase2_chap(sm, data, - parse.chap_challenge, - parse.chap_challenge_len, - parse.chap_password, - parse.chap_password_len); - } else if (parse.mschap_response) { - eap_ttls_process_phase2_mschap(sm, data, - parse.mschap_challenge, - parse.mschap_challenge_len, - parse.mschap_response, - parse.mschap_response_len); - } else if (parse.mschap2_response) { - eap_ttls_process_phase2_mschapv2(sm, data, - parse.mschap_challenge, - parse.mschap_challenge_len, - parse.mschap2_response, - parse.mschap2_response_len); - } - -done: - wpabuf_free(in_decrypted); - os_free(parse.eap); -} - - -static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data) -{ -#ifdef EAP_SERVER_TNC - if (!sm->tnc || data->state != SUCCESS || data->tnc_started) - return; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Initialize TNC"); - if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_TNC)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize TNC"); - eap_ttls_state(data, FAILURE); - return; - } - - data->tnc_started = 1; - eap_ttls_state(data, PHASE2_METHOD); -#endif /* EAP_SERVER_TNC */ -} - - -static int eap_ttls_process_version(struct eap_sm *sm, void *priv, - int peer_version) -{ - struct eap_ttls_data *data = priv; - if (peer_version < data->ttls_version) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: peer ver=%d, own ver=%d; " - "use version %d", - peer_version, data->ttls_version, peer_version); - data->ttls_version = peer_version; - } - - return 0; -} - - -static void eap_ttls_process_msg(struct eap_sm *sm, void *priv, - const struct wpabuf *respData) -{ - struct eap_ttls_data *data = priv; - - switch (data->state) { - case PHASE1: - if (eap_server_tls_phase1(sm, &data->ssl) < 0) - eap_ttls_state(data, FAILURE); - break; - case PHASE2_START: - case PHASE2_METHOD: - eap_ttls_process_phase2(sm, data, data->ssl.tls_in); - eap_ttls_start_tnc(sm, data); - break; - case PHASE2_MSCHAPV2_RESP: - if (data->mschapv2_resp_ok && wpabuf_len(data->ssl.tls_in) == - 0) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer " - "acknowledged response"); - eap_ttls_state(data, SUCCESS); - } else if (!data->mschapv2_resp_ok) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer " - "acknowledged error"); - eap_ttls_state(data, FAILURE); - } else { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Unexpected " - "frame from peer (payload len %lu, " - "expected empty frame)", - (unsigned long) - wpabuf_len(data->ssl.tls_in)); - eap_ttls_state(data, FAILURE); - } - eap_ttls_start_tnc(sm, data); - break; - default: - wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected state %d in %s", - data->state, __func__); - break; - } -} - - -static void eap_ttls_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_ttls_data *data = priv; - if (eap_server_tls_process(sm, &data->ssl, respData, data, - EAP_TYPE_TTLS, eap_ttls_process_version, - eap_ttls_process_msg) < 0) - eap_ttls_state(data, FAILURE); -} - - -static Boolean eap_ttls_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_ttls_data *data = priv; - return data->state == SUCCESS || data->state == FAILURE; -} - - -static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_ttls_data *data = priv; - u8 *eapKeyData; - - if (data->state != SUCCESS) - return NULL; - - 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", - eapKeyData, EAP_TLS_KEY_LEN); - } else { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); - } - - return eapKeyData; -} - - -static Boolean eap_ttls_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_ttls_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_ttls_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); - if (eap == NULL) - return -1; - - eap->init = eap_ttls_init; - eap->reset = eap_ttls_reset; - eap->buildReq = eap_ttls_buildReq; - eap->check = eap_ttls_check; - eap->process = eap_ttls_process; - eap->isDone = eap_ttls_isDone; - eap->getKey = eap_ttls_getKey; - eap->isSuccess = eap_ttls_isSuccess; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_vendor_test.c b/contrib/hostapd/src/eap_server/eap_server_vendor_test.c deleted file mode 100644 index 30f600d3ba..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_vendor_test.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * hostapd / Test method for vendor specific (expanded) EAP type - * Copyright (c) 2005-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" - - -#define EAP_VENDOR_ID EAP_VENDOR_HOSTAP -#define EAP_VENDOR_TYPE 0xfcfbfaf9 - - -struct eap_vendor_test_data { - enum { INIT, CONFIRM, SUCCESS, FAILURE } state; -}; - - -static const char * eap_vendor_test_state_txt(int state) -{ - switch (state) { - case INIT: - return "INIT"; - case CONFIRM: - return "CONFIRM"; - case SUCCESS: - return "SUCCESS"; - case FAILURE: - return "FAILURE"; - default: - return "?"; - } -} - - -static void eap_vendor_test_state(struct eap_vendor_test_data *data, - int state) -{ - wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: %s -> %s", - eap_vendor_test_state_txt(data->state), - eap_vendor_test_state_txt(state)); - data->state = state; -} - - -static void * eap_vendor_test_init(struct eap_sm *sm) -{ - struct eap_vendor_test_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = INIT; - - return data; -} - - -static void eap_vendor_test_reset(struct eap_sm *sm, void *priv) -{ - struct eap_vendor_test_data *data = priv; - os_free(data); -} - - -static struct wpabuf * eap_vendor_test_buildReq(struct eap_sm *sm, void *priv, - u8 id) -{ - struct eap_vendor_test_data *data = priv; - struct wpabuf *req; - - req = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, 1, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-VENDOR-TEST: Failed to allocate " - "memory for request"); - return NULL; - } - - wpabuf_put_u8(req, data->state == INIT ? 1 : 3); - - return req; -} - - -static Boolean eap_vendor_test_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, respData, &len); - if (pos == NULL || len < 1) { - wpa_printf(MSG_INFO, "EAP-VENDOR-TEST: Invalid frame"); - return TRUE; - } - - return FALSE; -} - - -static void eap_vendor_test_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_vendor_test_data *data = priv; - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, respData, &len); - if (pos == NULL || len < 1) - return; - - if (data->state == INIT) { - if (*pos == 2) - eap_vendor_test_state(data, CONFIRM); - else - eap_vendor_test_state(data, FAILURE); - } else if (data->state == CONFIRM) { - if (*pos == 4) - eap_vendor_test_state(data, SUCCESS); - else - eap_vendor_test_state(data, FAILURE); - } else - eap_vendor_test_state(data, FAILURE); -} - - -static Boolean eap_vendor_test_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_vendor_test_data *data = priv; - return data->state == SUCCESS; -} - - -static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_vendor_test_data *data = priv; - u8 *key; - const int key_len = 64; - - if (data->state != SUCCESS) - return NULL; - - key = os_malloc(key_len); - if (key == NULL) - return NULL; - - os_memset(key, 0x11, key_len / 2); - os_memset(key + key_len / 2, 0x22, key_len / 2); - *len = key_len; - - return key; -} - - -static Boolean eap_vendor_test_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_vendor_test_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_vendor_test_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_ID, EAP_VENDOR_TYPE, - "VENDOR-TEST"); - if (eap == NULL) - return -1; - - eap->init = eap_vendor_test_init; - eap->reset = eap_vendor_test_reset; - eap->buildReq = eap_vendor_test_buildReq; - eap->check = eap_vendor_test_check; - eap->process = eap_vendor_test_process; - eap->isDone = eap_vendor_test_isDone; - eap->getKey = eap_vendor_test_getKey; - eap->isSuccess = eap_vendor_test_isSuccess; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_server_wsc.c b/contrib/hostapd/src/eap_server/eap_server_wsc.c deleted file mode 100644 index 97ec0c0eaa..0000000000 --- a/contrib/hostapd/src/eap_server/eap_server_wsc.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * EAP-WSC server for Wi-Fi Protected Setup - * Copyright (c) 2007-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eloop.h" -#include "eap_i.h" -#include "eap_common/eap_wsc_common.h" -#include "p2p/p2p.h" -#include "wps/wps.h" - - -struct eap_wsc_data { - enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; - int registrar; - struct wpabuf *in_buf; - struct wpabuf *out_buf; - enum wsc_op_code in_op_code, out_op_code; - size_t out_used; - size_t fragment_size; - struct wps_data *wps; - int ext_reg_timeout; -}; - - -#ifndef CONFIG_NO_STDOUT_DEBUG -static const char * eap_wsc_state_txt(int state) -{ - switch (state) { - case START: - return "START"; - case MESG: - return "MESG"; - case FRAG_ACK: - return "FRAG_ACK"; - case WAIT_FRAG_ACK: - return "WAIT_FRAG_ACK"; - case DONE: - return "DONE"; - case FAIL: - return "FAIL"; - default: - return "?"; - } -} -#endif /* CONFIG_NO_STDOUT_DEBUG */ - - -static void eap_wsc_state(struct eap_wsc_data *data, int state) -{ - wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s", - eap_wsc_state_txt(data->state), - eap_wsc_state_txt(state)); - data->state = state; -} - - -static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct eap_sm *sm = eloop_ctx; - struct eap_wsc_data *data = timeout_ctx; - - if (sm->method_pending != METHOD_PENDING_WAIT) - return; - - wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External " - "Registrar"); - data->ext_reg_timeout = 1; - eap_sm_pending_cb(sm); -} - - -static void * eap_wsc_init(struct eap_sm *sm) -{ - struct eap_wsc_data *data; - int registrar; - struct wps_config cfg; - - if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN && - os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == - 0) - registrar = 0; /* Supplicant is Registrar */ - else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN && - os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) - == 0) - registrar = 1; /* Supplicant is Enrollee */ - else { - wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity", - sm->identity, sm->identity_len); - return NULL; - } - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = registrar ? START : MESG; - data->registrar = registrar; - - os_memset(&cfg, 0, sizeof(cfg)); - cfg.wps = sm->wps; - cfg.registrar = registrar; - if (registrar) { - if (sm->wps == NULL || sm->wps->registrar == NULL) { - wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not " - "initialized"); - os_free(data); - return NULL; - } - } else { - if (sm->user == NULL || sm->user->password == NULL) { - /* - * In theory, this should not really be needed, but - * Windows 7 uses Registrar mode to probe AP's WPS - * capabilities before trying to use Enrollee and fails - * if the AP does not allow that probing to happen.. - */ - wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) " - "configured for Enrollee functionality - " - "allow for probing capabilities (M1)"); - } else { - cfg.pin = sm->user->password; - cfg.pin_len = sm->user->password_len; - } - } - cfg.assoc_wps_ie = sm->assoc_wps_ie; - cfg.peer_addr = sm->peer_addr; -#ifdef CONFIG_P2P - if (sm->assoc_p2p_ie) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P " - "client"); - cfg.use_psk_key = 1; - cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie); - } -#endif /* CONFIG_P2P */ - cfg.pbc_in_m1 = sm->pbc_in_m1; - data->wps = wps_init(&cfg); - if (data->wps == NULL) { - os_free(data); - return NULL; - } - data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size : - WSC_FRAGMENT_SIZE; - - return data; -} - - -static void eap_wsc_reset(struct eap_sm *sm, void *priv) -{ - struct eap_wsc_data *data = priv; - eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); - wpabuf_free(data->in_buf); - wpabuf_free(data->out_buf); - wps_deinit(data->wps); - os_free(data); -} - - -static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm, - struct eap_wsc_data *data, u8 id) -{ - struct wpabuf *req; - - req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for " - "request"); - return NULL; - } - - wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start"); - wpabuf_put_u8(req, WSC_Start); /* Op-Code */ - wpabuf_put_u8(req, 0); /* Flags */ - - return req; -} - - -static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id) -{ - struct wpabuf *req; - u8 flags; - size_t send_len, plen; - - flags = 0; - send_len = wpabuf_len(data->out_buf) - data->out_used; - if (2 + send_len > data->fragment_size) { - send_len = data->fragment_size - 2; - flags |= WSC_FLAGS_MF; - if (data->out_used == 0) { - flags |= WSC_FLAGS_LF; - send_len -= 2; - } - } - plen = 2 + send_len; - if (flags & WSC_FLAGS_LF) - plen += 2; - req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen, - EAP_CODE_REQUEST, id); - if (req == NULL) { - wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for " - "request"); - return NULL; - } - - wpabuf_put_u8(req, data->out_op_code); /* Op-Code */ - wpabuf_put_u8(req, flags); /* Flags */ - if (flags & WSC_FLAGS_LF) - wpabuf_put_be16(req, wpabuf_len(data->out_buf)); - - wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, - send_len); - data->out_used += send_len; - - if (data->out_used == wpabuf_len(data->out_buf)) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " - "(message sent completely)", - (unsigned long) send_len); - wpabuf_free(data->out_buf); - data->out_buf = NULL; - data->out_used = 0; - eap_wsc_state(data, MESG); - } else { - wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " - "(%lu more to send)", (unsigned long) send_len, - (unsigned long) wpabuf_len(data->out_buf) - - data->out_used); - eap_wsc_state(data, WAIT_FRAG_ACK); - } - - return req; -} - - -static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct eap_wsc_data *data = priv; - - switch (data->state) { - case START: - return eap_wsc_build_start(sm, data, id); - case MESG: - if (data->out_buf == NULL) { - data->out_buf = wps_get_msg(data->wps, - &data->out_op_code); - if (data->out_buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to " - "receive message from WPS"); - return NULL; - } - data->out_used = 0; - } - /* pass through */ - case WAIT_FRAG_ACK: - return eap_wsc_build_msg(data, id); - case FRAG_ACK: - return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST); - default: - wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in " - "buildReq", data->state); - return NULL; - } -} - - -static Boolean eap_wsc_check(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - const u8 *pos; - size_t len; - - pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, - respData, &len); - if (pos == NULL || len < 2) { - wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame"); - return TRUE; - } - - return FALSE; -} - - -static int eap_wsc_process_cont(struct eap_wsc_data *data, - const u8 *buf, size_t len, u8 op_code) -{ - /* Process continuation of a pending message */ - if (op_code != data->in_op_code) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " - "fragment (expected %d)", - op_code, data->in_op_code); - eap_wsc_state(data, FAIL); - return -1; - } - - if (len > wpabuf_tailroom(data->in_buf)) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); - eap_wsc_state(data, FAIL); - return -1; - } - - wpabuf_put_data(data->in_buf, buf, len); - wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu " - "bytes more", (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); - - return 0; -} - - -static int eap_wsc_process_fragment(struct eap_wsc_data *data, - u8 flags, u8 op_code, u16 message_length, - const u8 *buf, size_t len) -{ - /* Process a fragment that is not the last one of the message */ - if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { - wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length " - "field in a fragmented packet"); - return -1; - } - - if (data->in_buf == NULL) { - /* First fragment of the message */ - data->in_buf = wpabuf_alloc(message_length); - if (data->in_buf == NULL) { - wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for " - "message"); - return -1; - } - data->in_op_code = op_code; - wpabuf_put_data(data->in_buf, buf, len); - wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in " - "first fragment, waiting for %lu bytes more", - (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); - } - - return 0; -} - - -static void eap_wsc_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_wsc_data *data = priv; - const u8 *start, *pos, *end; - size_t len; - u8 op_code, flags; - u16 message_length = 0; - enum wps_process_res res; - struct wpabuf tmpbuf; - - eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); - if (data->ext_reg_timeout) { - eap_wsc_state(data, FAIL); - return; - } - - pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, - respData, &len); - if (pos == NULL || len < 2) - return; /* Should not happen; message already verified */ - - start = pos; - end = start + len; - - op_code = *pos++; - flags = *pos++; - if (flags & WSC_FLAGS_LF) { - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); - return; - } - message_length = WPA_GET_BE16(pos); - pos += 2; - - if (message_length < end - pos) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " - "Length"); - return; - } - } - - wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " - "Flags 0x%x Message Length %d", - op_code, flags, message_length); - - if (data->state == WAIT_FRAG_ACK) { - if (op_code != WSC_FRAG_ACK) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " - "in WAIT_FRAG_ACK state", op_code); - eap_wsc_state(data, FAIL); - return; - } - wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); - eap_wsc_state(data, MESG); - return; - } - - if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && - op_code != WSC_Done) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", - op_code); - eap_wsc_state(data, FAIL); - return; - } - - if (data->in_buf && - eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { - eap_wsc_state(data, FAIL); - return; - } - - if (flags & WSC_FLAGS_MF) { - if (eap_wsc_process_fragment(data, flags, op_code, - message_length, pos, end - pos) < - 0) - eap_wsc_state(data, FAIL); - else - eap_wsc_state(data, FRAG_ACK); - return; - } - - if (data->in_buf == NULL) { - /* Wrap unfragmented messages as wpabuf without extra copy */ - wpabuf_set(&tmpbuf, pos, end - pos); - data->in_buf = &tmpbuf; - } - - res = wps_process_msg(data->wps, op_code, data->in_buf); - switch (res) { - case WPS_DONE: - wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " - "successfully - report EAP failure"); - eap_wsc_state(data, FAIL); - break; - case WPS_CONTINUE: - eap_wsc_state(data, MESG); - break; - case WPS_FAILURE: - wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); - eap_wsc_state(data, FAIL); - break; - case WPS_PENDING: - eap_wsc_state(data, MESG); - sm->method_pending = METHOD_PENDING_WAIT; - eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); - eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout, - sm, data); - break; - } - - if (data->in_buf != &tmpbuf) - wpabuf_free(data->in_buf); - data->in_buf = NULL; -} - - -static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_wsc_data *data = priv; - return data->state == FAIL; -} - - -static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv) -{ - /* EAP-WSC will always result in EAP-Failure */ - return FALSE; -} - - -static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv) -{ - /* Recommended retransmit times: retransmit timeout 5 seconds, - * per-message timeout 15 seconds, i.e., 3 tries. */ - sm->MaxRetrans = 2; /* total 3 attempts */ - return 5; -} - - -int eap_server_wsc_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, - "WSC"); - if (eap == NULL) - return -1; - - eap->init = eap_wsc_init; - eap->reset = eap_wsc_reset; - eap->buildReq = eap_wsc_buildReq; - eap->check = eap_wsc_check; - eap->process = eap_wsc_process; - eap->isDone = eap_wsc_isDone; - eap->isSuccess = eap_wsc_isSuccess; - eap->getTimeout = eap_wsc_getTimeout; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -} diff --git a/contrib/hostapd/src/eap_server/eap_sim_db.c b/contrib/hostapd/src/eap_server/eap_sim_db.c deleted file mode 100644 index 45660ed7d2..0000000000 --- a/contrib/hostapd/src/eap_server/eap_sim_db.c +++ /dev/null @@ -1,1494 +0,0 @@ -/* - * hostapd / EAP-SIM database/authenticator gateway - * Copyright (c) 2005-2010, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This is an example implementation of the EAP-SIM/AKA database/authentication - * gateway interface that is using an external program as an SS7 gateway to - * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example - * implementation of such a gateway program. This eap_sim_db.c takes care of - * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different - * gateway implementations for HLR/AuC access. Alternatively, it can also be - * completely replaced if the in-memory database of pseudonyms/re-auth - * identities is not suitable for some cases. - */ - -#include "includes.h" -#include -#ifdef CONFIG_SQLITE -#include -#endif /* CONFIG_SQLITE */ - -#include "common.h" -#include "crypto/random.h" -#include "eap_common/eap_sim_common.h" -#include "eap_server/eap_sim_db.h" -#include "eloop.h" - -struct eap_sim_pseudonym { - struct eap_sim_pseudonym *next; - char *permanent; /* permanent username */ - char *pseudonym; /* pseudonym username */ -}; - -struct eap_sim_db_pending { - struct eap_sim_db_pending *next; - char imsi[20]; - enum { PENDING, SUCCESS, FAILURE } state; - void *cb_session_ctx; - int aka; - union { - struct { - u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN]; - u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN]; - u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN]; - int num_chal; - } sim; - struct { - u8 rand[EAP_AKA_RAND_LEN]; - u8 autn[EAP_AKA_AUTN_LEN]; - u8 ik[EAP_AKA_IK_LEN]; - u8 ck[EAP_AKA_CK_LEN]; - u8 res[EAP_AKA_RES_MAX_LEN]; - size_t res_len; - } aka; - } u; -}; - -struct eap_sim_db_data { - int sock; - char *fname; - char *local_sock; - void (*get_complete_cb)(void *ctx, void *session_ctx); - void *ctx; - struct eap_sim_pseudonym *pseudonyms; - struct eap_sim_reauth *reauths; - struct eap_sim_db_pending *pending; -#ifdef CONFIG_SQLITE - sqlite3 *sqlite_db; - char db_tmp_identity[100]; - char db_tmp_pseudonym_str[100]; - struct eap_sim_pseudonym db_tmp_pseudonym; - struct eap_sim_reauth db_tmp_reauth; -#endif /* CONFIG_SQLITE */ -}; - - -#ifdef CONFIG_SQLITE - -static int db_table_exists(sqlite3 *db, const char *name) -{ - char cmd[128]; - os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name); - return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK; -} - - -static int db_table_create_pseudonym(sqlite3 *db) -{ - char *err = NULL; - const char *sql = - "CREATE TABLE pseudonyms(" - " permanent CHAR(21) PRIMARY KEY," - " pseudonym CHAR(21) NOT NULL" - ");"; - - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for " - "pseudonym information"); - if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) { - wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err); - sqlite3_free(err); - return -1; - } - - return 0; -} - - -static int db_table_create_reauth(sqlite3 *db) -{ - char *err = NULL; - const char *sql = - "CREATE TABLE reauth(" - " permanent CHAR(21) PRIMARY KEY," - " reauth_id CHAR(21) NOT NULL," - " counter INTEGER," - " mk CHAR(40)," - " k_encr CHAR(32)," - " k_aut CHAR(64)," - " k_re CHAR(64)" - ");"; - - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for " - "reauth information"); - if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) { - wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err); - sqlite3_free(err); - return -1; - } - - return 0; -} - - -static sqlite3 * db_open(const char *db_file) -{ - sqlite3 *db; - - if (sqlite3_open(db_file, &db)) { - wpa_printf(MSG_ERROR, "EAP-SIM DB: Failed to open database " - "%s: %s", db_file, sqlite3_errmsg(db)); - sqlite3_close(db); - return NULL; - } - - if (!db_table_exists(db, "pseudonyms") && - db_table_create_pseudonym(db) < 0) { - sqlite3_close(db); - return NULL; - } - - if (!db_table_exists(db, "reauth") && - db_table_create_reauth(db) < 0) { - sqlite3_close(db); - return NULL; - } - - return db; -} - - -static int valid_db_string(const char *str) -{ - const char *pos = str; - while (*pos) { - if ((*pos < '0' || *pos > '9') && - (*pos < 'a' || *pos > 'f')) - return 0; - pos++; - } - return 1; -} - - -static int db_add_pseudonym(struct eap_sim_db_data *data, - const char *permanent, char *pseudonym) -{ - char cmd[128]; - char *err = NULL; - - if (!valid_db_string(permanent) || !valid_db_string(pseudonym)) { - os_free(pseudonym); - return -1; - } - - os_snprintf(cmd, sizeof(cmd), "INSERT OR REPLACE INTO pseudonyms " - "(permanent, pseudonym) VALUES ('%s', '%s');", - permanent, pseudonym); - os_free(pseudonym); - if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK) - { - wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err); - sqlite3_free(err); - return -1; - } - - return 0; -} - - -static int get_pseudonym_cb(void *ctx, int argc, char *argv[], char *col[]) -{ - struct eap_sim_db_data *data = ctx; - int i; - - for (i = 0; i < argc; i++) { - if (os_strcmp(col[i], "permanent") == 0 && argv[i]) { - os_strlcpy(data->db_tmp_identity, argv[i], - sizeof(data->db_tmp_identity)); - } - } - - return 0; -} - - -static char * -db_get_pseudonym(struct eap_sim_db_data *data, const char *pseudonym) -{ - char cmd[128]; - - if (!valid_db_string(pseudonym)) - return NULL; - os_memset(&data->db_tmp_identity, 0, sizeof(data->db_tmp_identity)); - os_snprintf(cmd, sizeof(cmd), - "SELECT permanent FROM pseudonyms WHERE pseudonym='%s';", - pseudonym); - if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) != - SQLITE_OK) - return NULL; - if (data->db_tmp_identity[0] == '\0') - return NULL; - return data->db_tmp_identity; -} - - -static int db_add_reauth(struct eap_sim_db_data *data, const char *permanent, - char *reauth_id, u16 counter, const u8 *mk, - const u8 *k_encr, const u8 *k_aut, const u8 *k_re) -{ - char cmd[2000], *pos, *end; - char *err = NULL; - - if (!valid_db_string(permanent) || !valid_db_string(reauth_id)) { - os_free(reauth_id); - return -1; - } - - pos = cmd; - end = pos + sizeof(cmd); - pos += os_snprintf(pos, end - pos, "INSERT OR REPLACE INTO reauth " - "(permanent, reauth_id, counter%s%s%s%s) " - "VALUES ('%s', '%s', %u", - mk ? ", mk" : "", - k_encr ? ", k_encr" : "", - k_aut ? ", k_aut" : "", - k_re ? ", k_re" : "", - permanent, reauth_id, counter); - os_free(reauth_id); - - if (mk) { - pos += os_snprintf(pos, end - pos, ", '"); - pos += wpa_snprintf_hex(pos, end - pos, mk, EAP_SIM_MK_LEN); - pos += os_snprintf(pos, end - pos, "'"); - } - - if (k_encr) { - pos += os_snprintf(pos, end - pos, ", '"); - pos += wpa_snprintf_hex(pos, end - pos, k_encr, - EAP_SIM_K_ENCR_LEN); - pos += os_snprintf(pos, end - pos, "'"); - } - - if (k_aut) { - pos += os_snprintf(pos, end - pos, ", '"); - pos += wpa_snprintf_hex(pos, end - pos, k_aut, - EAP_AKA_PRIME_K_AUT_LEN); - pos += os_snprintf(pos, end - pos, "'"); - } - - if (k_re) { - pos += os_snprintf(pos, end - pos, ", '"); - pos += wpa_snprintf_hex(pos, end - pos, k_re, - EAP_AKA_PRIME_K_RE_LEN); - pos += os_snprintf(pos, end - pos, "'"); - } - - os_snprintf(pos, end - pos, ");"); - - if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK) - { - wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err); - sqlite3_free(err); - return -1; - } - - return 0; -} - - -static int get_reauth_cb(void *ctx, int argc, char *argv[], char *col[]) -{ - struct eap_sim_db_data *data = ctx; - int i; - struct eap_sim_reauth *reauth = &data->db_tmp_reauth; - - for (i = 0; i < argc; i++) { - if (os_strcmp(col[i], "permanent") == 0 && argv[i]) { - os_strlcpy(data->db_tmp_identity, argv[i], - sizeof(data->db_tmp_identity)); - reauth->permanent = data->db_tmp_identity; - } else if (os_strcmp(col[i], "counter") == 0 && argv[i]) { - reauth->counter = atoi(argv[i]); - } else if (os_strcmp(col[i], "mk") == 0 && argv[i]) { - hexstr2bin(argv[i], reauth->mk, sizeof(reauth->mk)); - } else if (os_strcmp(col[i], "k_encr") == 0 && argv[i]) { - hexstr2bin(argv[i], reauth->k_encr, - sizeof(reauth->k_encr)); - } else if (os_strcmp(col[i], "k_aut") == 0 && argv[i]) { - hexstr2bin(argv[i], reauth->k_aut, - sizeof(reauth->k_aut)); - } else if (os_strcmp(col[i], "k_re") == 0 && argv[i]) { - hexstr2bin(argv[i], reauth->k_re, - sizeof(reauth->k_re)); - } - } - - return 0; -} - - -static struct eap_sim_reauth * -db_get_reauth(struct eap_sim_db_data *data, const char *reauth_id) -{ - char cmd[256]; - - if (!valid_db_string(reauth_id)) - return NULL; - os_memset(&data->db_tmp_reauth, 0, sizeof(data->db_tmp_reauth)); - os_strlcpy(data->db_tmp_pseudonym_str, reauth_id, - sizeof(data->db_tmp_pseudonym_str)); - data->db_tmp_reauth.reauth_id = data->db_tmp_pseudonym_str; - os_snprintf(cmd, sizeof(cmd), - "SELECT * FROM reauth WHERE reauth_id='%s';", reauth_id); - if (sqlite3_exec(data->sqlite_db, cmd, get_reauth_cb, data, NULL) != - SQLITE_OK) - return NULL; - if (data->db_tmp_reauth.permanent == NULL) - return NULL; - return &data->db_tmp_reauth; -} - - -static void db_remove_reauth(struct eap_sim_db_data *data, - struct eap_sim_reauth *reauth) -{ - char cmd[256]; - - if (!valid_db_string(reauth->permanent)) - return; - os_snprintf(cmd, sizeof(cmd), - "DELETE FROM reauth WHERE permanent='%s';", - reauth->permanent); - sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, NULL); -} - -#endif /* CONFIG_SQLITE */ - - -static struct eap_sim_db_pending * -eap_sim_db_get_pending(struct eap_sim_db_data *data, const char *imsi, int aka) -{ - struct eap_sim_db_pending *entry, *prev = NULL; - - entry = data->pending; - while (entry) { - if (entry->aka == aka && os_strcmp(entry->imsi, imsi) == 0) { - if (prev) - prev->next = entry->next; - else - data->pending = entry->next; - break; - } - prev = entry; - entry = entry->next; - } - return entry; -} - - -static void eap_sim_db_add_pending(struct eap_sim_db_data *data, - struct eap_sim_db_pending *entry) -{ - entry->next = data->pending; - data->pending = entry; -} - - -static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data, - const char *imsi, char *buf) -{ - char *start, *end, *pos; - struct eap_sim_db_pending *entry; - int num_chal; - - /* - * SIM-RESP-AUTH Kc(i):SRES(i):RAND(i) ... - * SIM-RESP-AUTH FAILURE - * (IMSI = ASCII string, Kc/SRES/RAND = hex string) - */ - - entry = eap_sim_db_get_pending(data, imsi, 0); - if (entry == NULL) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the " - "received message found"); - return; - } - - start = buf; - if (os_strncmp(start, "FAILURE", 7) == 0) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported " - "failure"); - entry->state = FAILURE; - eap_sim_db_add_pending(data, entry); - data->get_complete_cb(data->ctx, entry->cb_session_ctx); - return; - } - - num_chal = 0; - while (num_chal < EAP_SIM_MAX_CHAL) { - end = os_strchr(start, ' '); - if (end) - *end = '\0'; - - pos = os_strchr(start, ':'); - if (pos == NULL) - goto parse_fail; - *pos = '\0'; - if (hexstr2bin(start, entry->u.sim.kc[num_chal], - EAP_SIM_KC_LEN)) - goto parse_fail; - - start = pos + 1; - pos = os_strchr(start, ':'); - if (pos == NULL) - goto parse_fail; - *pos = '\0'; - if (hexstr2bin(start, entry->u.sim.sres[num_chal], - EAP_SIM_SRES_LEN)) - goto parse_fail; - - start = pos + 1; - if (hexstr2bin(start, entry->u.sim.rand[num_chal], - GSM_RAND_LEN)) - goto parse_fail; - - num_chal++; - if (end == NULL) - break; - else - start = end + 1; - } - entry->u.sim.num_chal = num_chal; - - entry->state = SUCCESS; - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed " - "successfully - callback"); - eap_sim_db_add_pending(data, entry); - data->get_complete_cb(data->ctx, entry->cb_session_ctx); - return; - -parse_fail: - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string"); - os_free(entry); -} - - -static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data, - const char *imsi, char *buf) -{ - char *start, *end; - struct eap_sim_db_pending *entry; - - /* - * AKA-RESP-AUTH - * AKA-RESP-AUTH FAILURE - * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string) - */ - - entry = eap_sim_db_get_pending(data, imsi, 1); - if (entry == NULL) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the " - "received message found"); - return; - } - - start = buf; - if (os_strncmp(start, "FAILURE", 7) == 0) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported " - "failure"); - entry->state = FAILURE; - eap_sim_db_add_pending(data, entry); - data->get_complete_cb(data->ctx, entry->cb_session_ctx); - return; - } - - end = os_strchr(start, ' '); - if (end == NULL) - goto parse_fail; - *end = '\0'; - if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN)) - goto parse_fail; - - start = end + 1; - end = os_strchr(start, ' '); - if (end == NULL) - goto parse_fail; - *end = '\0'; - if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN)) - goto parse_fail; - - start = end + 1; - end = os_strchr(start, ' '); - if (end == NULL) - goto parse_fail; - *end = '\0'; - if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN)) - goto parse_fail; - - start = end + 1; - end = os_strchr(start, ' '); - if (end == NULL) - goto parse_fail; - *end = '\0'; - if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN)) - goto parse_fail; - - start = end + 1; - end = os_strchr(start, ' '); - if (end) - *end = '\0'; - else { - end = start; - while (*end) - end++; - } - entry->u.aka.res_len = (end - start) / 2; - if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES"); - entry->u.aka.res_len = 0; - goto parse_fail; - } - if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len)) - goto parse_fail; - - entry->state = SUCCESS; - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed " - "successfully - callback"); - eap_sim_db_add_pending(data, entry); - data->get_complete_cb(data->ctx, entry->cb_session_ctx); - return; - -parse_fail: - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string"); - os_free(entry); -} - - -static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct eap_sim_db_data *data = eloop_ctx; - char buf[1000], *pos, *cmd, *imsi; - int res; - - res = recv(sock, buf, sizeof(buf), 0); - if (res < 0) - return; - wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an " - "external source", (u8 *) buf, res); - if (res == 0) - return; - if (res >= (int) sizeof(buf)) - res = sizeof(buf) - 1; - buf[res] = '\0'; - - if (data->get_complete_cb == NULL) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb " - "registered"); - return; - } - - /* ... */ - - cmd = buf; - pos = os_strchr(cmd, ' '); - if (pos == NULL) - goto parse_fail; - *pos = '\0'; - imsi = pos + 1; - pos = os_strchr(imsi, ' '); - if (pos == NULL) - goto parse_fail; - *pos = '\0'; - wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s", - cmd, imsi); - - if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0) - eap_sim_db_sim_resp_auth(data, imsi, pos + 1); - else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0) - eap_sim_db_aka_resp_auth(data, imsi, pos + 1); - else - wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response " - "'%s'", cmd); - return; - -parse_fail: - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string"); -} - - -static int eap_sim_db_open_socket(struct eap_sim_db_data *data) -{ - struct sockaddr_un addr; - static int counter = 0; - - if (os_strncmp(data->fname, "unix:", 5) != 0) - return -1; - - data->sock = socket(PF_UNIX, SOCK_DGRAM, 0); - if (data->sock < 0) { - wpa_printf(MSG_INFO, "socket(eap_sim_db): %s", strerror(errno)); - return -1; - } - - os_memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - os_snprintf(addr.sun_path, sizeof(addr.sun_path), - "/tmp/eap_sim_db_%d-%d", getpid(), counter++); - os_free(data->local_sock); - data->local_sock = os_strdup(addr.sun_path); - if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - wpa_printf(MSG_INFO, "bind(eap_sim_db): %s", strerror(errno)); - close(data->sock); - data->sock = -1; - return -1; - } - - os_memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path)); - if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - wpa_printf(MSG_INFO, "connect(eap_sim_db): %s", - strerror(errno)); - wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket", - (u8 *) addr.sun_path, - os_strlen(addr.sun_path)); - close(data->sock); - data->sock = -1; - return -1; - } - - eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL); - - return 0; -} - - -static void eap_sim_db_close_socket(struct eap_sim_db_data *data) -{ - if (data->sock >= 0) { - eloop_unregister_read_sock(data->sock); - close(data->sock); - data->sock = -1; - } - if (data->local_sock) { - unlink(data->local_sock); - os_free(data->local_sock); - data->local_sock = NULL; - } -} - - -/** - * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface - * @config: Configuration data (e.g., file name) - * @get_complete_cb: Callback function for reporting availability of triplets - * @ctx: Context pointer for get_complete_cb - * Returns: Pointer to a private data structure or %NULL on failure - */ -struct eap_sim_db_data * -eap_sim_db_init(const char *config, - void (*get_complete_cb)(void *ctx, void *session_ctx), - void *ctx) -{ - struct eap_sim_db_data *data; - char *pos; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - - data->sock = -1; - data->get_complete_cb = get_complete_cb; - data->ctx = ctx; - data->fname = os_strdup(config); - if (data->fname == NULL) - goto fail; - pos = os_strstr(data->fname, " db="); - if (pos) { - *pos = '\0'; -#ifdef CONFIG_SQLITE - pos += 4; - data->sqlite_db = db_open(pos); - if (data->sqlite_db == NULL) - goto fail; -#endif /* CONFIG_SQLITE */ - } - - if (os_strncmp(data->fname, "unix:", 5) == 0) { - if (eap_sim_db_open_socket(data)) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database " - "connection not available - will retry " - "later"); - } - } - - return data; - -fail: - eap_sim_db_close_socket(data); - os_free(data->fname); - os_free(data); - return NULL; -} - - -static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p) -{ - os_free(p->permanent); - os_free(p->pseudonym); - os_free(p); -} - - -static void eap_sim_db_free_reauth(struct eap_sim_reauth *r) -{ - os_free(r->permanent); - os_free(r->reauth_id); - os_free(r); -} - - -/** - * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface - * @priv: Private data pointer from eap_sim_db_init() - */ -void eap_sim_db_deinit(void *priv) -{ - struct eap_sim_db_data *data = priv; - struct eap_sim_pseudonym *p, *prev; - struct eap_sim_reauth *r, *prevr; - struct eap_sim_db_pending *pending, *prev_pending; - -#ifdef CONFIG_SQLITE - if (data->sqlite_db) { - sqlite3_close(data->sqlite_db); - data->sqlite_db = NULL; - } -#endif /* CONFIG_SQLITE */ - - eap_sim_db_close_socket(data); - os_free(data->fname); - - p = data->pseudonyms; - while (p) { - prev = p; - p = p->next; - eap_sim_db_free_pseudonym(prev); - } - - r = data->reauths; - while (r) { - prevr = r; - r = r->next; - eap_sim_db_free_reauth(prevr); - } - - pending = data->pending; - while (pending) { - prev_pending = pending; - pending = pending->next; - os_free(prev_pending); - } - - os_free(data); -} - - -static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg, - size_t len) -{ - int _errno = 0; - - if (send(data->sock, msg, len, 0) < 0) { - _errno = errno; - wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s", - strerror(errno)); - } - - if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL || - _errno == ECONNREFUSED) { - /* Try to reconnect */ - eap_sim_db_close_socket(data); - if (eap_sim_db_open_socket(data) < 0) - return -1; - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the " - "external server"); - if (send(data->sock, msg, len, 0) < 0) { - wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s", - strerror(errno)); - return -1; - } - } - - return 0; -} - - -static void eap_sim_db_expire_pending(struct eap_sim_db_data *data) -{ - /* TODO: add limit for maximum length for pending list; remove latest - * (i.e., last) entry from the list if the limit is reached; could also - * use timeout to expire pending entries */ -} - - -/** - * eap_sim_db_get_gsm_triplets - Get GSM triplets - * @data: Private data pointer from eap_sim_db_init() - * @username: Permanent username (prefix | IMSI) - * @max_chal: Maximum number of triplets - * @_rand: Buffer for RAND values - * @kc: Buffer for Kc values - * @sres: Buffer for SRES values - * @cb_session_ctx: Session callback context for get_complete_cb() - * Returns: Number of triplets received (has to be less than or equal to - * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or - * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the - * callback function registered with eap_sim_db_init() will be called once the - * results become available. - * - * When using an external server for GSM triplets, this function can always - * start a request and return EAP_SIM_DB_PENDING immediately if authentication - * triplets are not available. Once the triplets are received, callback - * function registered with eap_sim_db_init() is called to notify EAP state - * machine to reprocess the message. This eap_sim_db_get_gsm_triplets() - * function will then be called again and the newly received triplets will then - * be given to the caller. - */ -int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data, - const char *username, int max_chal, - u8 *_rand, u8 *kc, u8 *sres, - void *cb_session_ctx) -{ - struct eap_sim_db_pending *entry; - int len, ret; - char msg[40]; - const char *imsi; - size_t imsi_len; - - if (username == NULL || username[0] != EAP_SIM_PERMANENT_PREFIX || - username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'", - username); - return EAP_SIM_DB_FAILURE; - } - imsi = username + 1; - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'", - imsi); - - entry = eap_sim_db_get_pending(data, imsi, 0); - if (entry) { - int num_chal; - if (entry->state == FAILURE) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " - "failure"); - os_free(entry); - return EAP_SIM_DB_FAILURE; - } - - if (entry->state == PENDING) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " - "still pending"); - eap_sim_db_add_pending(data, entry); - return EAP_SIM_DB_PENDING; - } - - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " - "%d challenges", entry->u.sim.num_chal); - num_chal = entry->u.sim.num_chal; - if (num_chal > max_chal) - num_chal = max_chal; - os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN); - os_memcpy(sres, entry->u.sim.sres, - num_chal * EAP_SIM_SRES_LEN); - os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN); - os_free(entry); - return num_chal; - } - - if (data->sock < 0) { - if (eap_sim_db_open_socket(data) < 0) - return EAP_SIM_DB_FAILURE; - } - - imsi_len = os_strlen(imsi); - len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH "); - if (len < 0 || len + imsi_len >= sizeof(msg)) - return EAP_SIM_DB_FAILURE; - os_memcpy(msg + len, imsi, imsi_len); - len += imsi_len; - ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal); - if (ret < 0 || (size_t) ret >= sizeof(msg) - len) - return EAP_SIM_DB_FAILURE; - len += ret; - - wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication " - "data for IMSI '%s'", imsi); - if (eap_sim_db_send(data, msg, len) < 0) - return EAP_SIM_DB_FAILURE; - - entry = os_zalloc(sizeof(*entry)); - if (entry == NULL) - return EAP_SIM_DB_FAILURE; - - os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi)); - entry->cb_session_ctx = cb_session_ctx; - entry->state = PENDING; - eap_sim_db_add_pending(data, entry); - eap_sim_db_expire_pending(data); - - return EAP_SIM_DB_PENDING; -} - - -static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix) -{ - char *id, *pos, *end; - u8 buf[10]; - - if (random_get_bytes(buf, sizeof(buf))) - return NULL; - id = os_malloc(sizeof(buf) * 2 + 2); - if (id == NULL) - return NULL; - - pos = id; - end = id + sizeof(buf) * 2 + 2; - *pos++ = prefix; - pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf)); - - return id; -} - - -/** - * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym - * @data: Private data pointer from eap_sim_db_init() - * @method: EAP method (SIM/AKA/AKA') - * Returns: Next pseudonym (allocated string) or %NULL on failure - * - * This function is used to generate a pseudonym for EAP-SIM. The returned - * pseudonym is not added to database at this point; it will need to be added - * with eap_sim_db_add_pseudonym() once the authentication has been completed - * successfully. Caller is responsible for freeing the returned buffer. - */ -char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data, - enum eap_sim_db_method method) -{ - char prefix = EAP_SIM_REAUTH_ID_PREFIX; - - switch (method) { - case EAP_SIM_DB_SIM: - prefix = EAP_SIM_PSEUDONYM_PREFIX; - break; - case EAP_SIM_DB_AKA: - prefix = EAP_AKA_PSEUDONYM_PREFIX; - break; - case EAP_SIM_DB_AKA_PRIME: - prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX; - break; - } - - return eap_sim_db_get_next(data, prefix); -} - - -/** - * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id - * @data: Private data pointer from eap_sim_db_init() - * @method: EAP method (SIM/AKA/AKA') - * Returns: Next reauth_id (allocated string) or %NULL on failure - * - * This function is used to generate a fast re-authentication identity for - * EAP-SIM. The returned reauth_id is not added to database at this point; it - * will need to be added with eap_sim_db_add_reauth() once the authentication - * has been completed successfully. Caller is responsible for freeing the - * returned buffer. - */ -char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data, - enum eap_sim_db_method method) -{ - char prefix = EAP_SIM_REAUTH_ID_PREFIX; - - switch (method) { - case EAP_SIM_DB_SIM: - prefix = EAP_SIM_REAUTH_ID_PREFIX; - break; - case EAP_SIM_DB_AKA: - prefix = EAP_AKA_REAUTH_ID_PREFIX; - break; - case EAP_SIM_DB_AKA_PRIME: - prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX; - break; - } - - return eap_sim_db_get_next(data, prefix); -} - - -/** - * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym - * @data: Private data pointer from eap_sim_db_init() - * @permanent: Permanent username - * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer, - * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not - * free it. - * Returns: 0 on success, -1 on failure - * - * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is - * responsible of freeing pseudonym buffer once it is not needed anymore. - */ -int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data, - const char *permanent, char *pseudonym) -{ - struct eap_sim_pseudonym *p; - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add pseudonym '%s' for permanent " - "username '%s'", pseudonym, permanent); - - /* TODO: could store last two pseudonyms */ -#ifdef CONFIG_SQLITE - if (data->sqlite_db) - return db_add_pseudonym(data, permanent, pseudonym); -#endif /* CONFIG_SQLITE */ - for (p = data->pseudonyms; p; p = p->next) { - if (os_strcmp(permanent, p->permanent) == 0) - break; - } - if (p) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous " - "pseudonym: %s", p->pseudonym); - os_free(p->pseudonym); - p->pseudonym = pseudonym; - return 0; - } - - p = os_zalloc(sizeof(*p)); - if (p == NULL) { - os_free(pseudonym); - return -1; - } - - p->next = data->pseudonyms; - p->permanent = os_strdup(permanent); - if (p->permanent == NULL) { - os_free(p); - os_free(pseudonym); - return -1; - } - p->pseudonym = pseudonym; - data->pseudonyms = p; - - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry"); - return 0; -} - - -static struct eap_sim_reauth * -eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, - const char *permanent, - char *reauth_id, u16 counter) -{ - struct eap_sim_reauth *r; - - for (r = data->reauths; r; r = r->next) { - if (os_strcmp(r->permanent, permanent) == 0) - break; - } - - if (r) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous " - "reauth_id: %s", r->reauth_id); - os_free(r->reauth_id); - r->reauth_id = reauth_id; - } else { - r = os_zalloc(sizeof(*r)); - if (r == NULL) { - os_free(reauth_id); - return NULL; - } - - r->next = data->reauths; - r->permanent = os_strdup(permanent); - if (r->permanent == NULL) { - os_free(r); - os_free(reauth_id); - return NULL; - } - r->reauth_id = reauth_id; - data->reauths = r; - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry"); - } - - r->counter = counter; - - return r; -} - - -/** - * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry - * @priv: Private data pointer from eap_sim_db_init() - * @permanent: Permanent username - * @identity_len: Length of identity - * @reauth_id: reauth_id for this user. This needs to be an allocated buffer, - * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not - * free it. - * @counter: AT_COUNTER value for fast re-authentication - * @mk: 16-byte MK from the previous full authentication or %NULL - * Returns: 0 on success, -1 on failure - * - * This function adds a new re-authentication entry for an EAP-SIM user. - * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed - * anymore. - */ -int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent, - char *reauth_id, u16 counter, const u8 *mk) -{ - struct eap_sim_reauth *r; - - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent " - "identity '%s'", reauth_id, permanent); - -#ifdef CONFIG_SQLITE - if (data->sqlite_db) - return db_add_reauth(data, permanent, reauth_id, counter, mk, - NULL, NULL, NULL); -#endif /* CONFIG_SQLITE */ - r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter); - if (r == NULL) - return -1; - - os_memcpy(r->mk, mk, EAP_SIM_MK_LEN); - - return 0; -} - - -#ifdef EAP_SERVER_AKA_PRIME -/** - * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry - * @data: Private data pointer from eap_sim_db_init() - * @permanent: Permanent username - * @reauth_id: reauth_id for this user. This needs to be an allocated buffer, - * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not - * free it. - * @counter: AT_COUNTER value for fast re-authentication - * @k_encr: K_encr from the previous full authentication - * @k_aut: K_aut from the previous full authentication - * @k_re: 32-byte K_re from the previous full authentication - * Returns: 0 on success, -1 on failure - * - * This function adds a new re-authentication entry for an EAP-AKA' user. - * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed - * anymore. - */ -int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data, - const char *permanent, char *reauth_id, - u16 counter, const u8 *k_encr, - const u8 *k_aut, const u8 *k_re) -{ - struct eap_sim_reauth *r; - - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent " - "identity '%s'", reauth_id, permanent); - -#ifdef CONFIG_SQLITE - if (data->sqlite_db) - return db_add_reauth(data, permanent, reauth_id, counter, NULL, - k_encr, k_aut, k_re); -#endif /* CONFIG_SQLITE */ - r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter); - if (r == NULL) - return -1; - - os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN); - os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN); - os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN); - - return 0; -} -#endif /* EAP_SERVER_AKA_PRIME */ - - -/** - * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity - * @data: Private data pointer from eap_sim_db_init() - * @pseudonym: Pseudonym username - * Returns: Pointer to permanent username or %NULL if not found - */ -const char * -eap_sim_db_get_permanent(struct eap_sim_db_data *data, const char *pseudonym) -{ - struct eap_sim_pseudonym *p; - -#ifdef CONFIG_SQLITE - if (data->sqlite_db) - return db_get_pseudonym(data, pseudonym); -#endif /* CONFIG_SQLITE */ - - p = data->pseudonyms; - while (p) { - if (os_strcmp(p->pseudonym, pseudonym) == 0) - return p->permanent; - p = p->next; - } - - return NULL; -} - - -/** - * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry - * @data: Private data pointer from eap_sim_db_init() - * @reauth_id: Fast re-authentication username - * Returns: Pointer to the re-auth entry, or %NULL if not found - */ -struct eap_sim_reauth * -eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data, - const char *reauth_id) -{ - struct eap_sim_reauth *r; - -#ifdef CONFIG_SQLITE - if (data->sqlite_db) - return db_get_reauth(data, reauth_id); -#endif /* CONFIG_SQLITE */ - - r = data->reauths; - while (r) { - if (os_strcmp(r->reauth_id, reauth_id) == 0) - break; - r = r->next; - } - - return r; -} - - -/** - * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry - * @data: Private data pointer from eap_sim_db_init() - * @reauth: Pointer to re-authentication entry from - * eap_sim_db_get_reauth_entry() - */ -void eap_sim_db_remove_reauth(struct eap_sim_db_data *data, - struct eap_sim_reauth *reauth) -{ - struct eap_sim_reauth *r, *prev = NULL; -#ifdef CONFIG_SQLITE - if (data->sqlite_db) { - db_remove_reauth(data, reauth); - return; - } -#endif /* CONFIG_SQLITE */ - r = data->reauths; - while (r) { - if (r == reauth) { - if (prev) - prev->next = r->next; - else - data->reauths = r->next; - eap_sim_db_free_reauth(r); - return; - } - prev = r; - r = r->next; - } -} - - -/** - * eap_sim_db_get_aka_auth - Get AKA authentication values - * @data: Private data pointer from eap_sim_db_init() - * @username: Permanent username (prefix | IMSI) - * @_rand: Buffer for RAND value - * @autn: Buffer for AUTN value - * @ik: Buffer for IK value - * @ck: Buffer for CK value - * @res: Buffer for RES value - * @res_len: Buffer for RES length - * @cb_session_ctx: Session callback context for get_complete_cb() - * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not - * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this - * case, the callback function registered with eap_sim_db_init() will be - * called once the results become available. - * - * When using an external server for AKA authentication, this function can - * always start a request and return EAP_SIM_DB_PENDING immediately if - * authentication triplets are not available. Once the authentication data are - * received, callback function registered with eap_sim_db_init() is called to - * notify EAP state machine to reprocess the message. This - * eap_sim_db_get_aka_auth() function will then be called again and the newly - * received triplets will then be given to the caller. - */ -int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username, - u8 *_rand, u8 *autn, u8 *ik, u8 *ck, - u8 *res, size_t *res_len, void *cb_session_ctx) -{ - struct eap_sim_db_pending *entry; - int len; - char msg[40]; - const char *imsi; - size_t imsi_len; - - if (username == NULL || - (username[0] != EAP_AKA_PERMANENT_PREFIX && - username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) || - username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'", - username); - return EAP_SIM_DB_FAILURE; - } - imsi = username + 1; - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'", - imsi); - - entry = eap_sim_db_get_pending(data, imsi, 1); - if (entry) { - if (entry->state == FAILURE) { - os_free(entry); - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure"); - return EAP_SIM_DB_FAILURE; - } - - if (entry->state == PENDING) { - eap_sim_db_add_pending(data, entry); - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending"); - return EAP_SIM_DB_PENDING; - } - - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully " - "received authentication data"); - os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN); - os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN); - os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN); - os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN); - os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN); - *res_len = entry->u.aka.res_len; - os_free(entry); - return 0; - } - - if (data->sock < 0) { - if (eap_sim_db_open_socket(data) < 0) - return EAP_SIM_DB_FAILURE; - } - - imsi_len = os_strlen(imsi); - len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH "); - if (len < 0 || len + imsi_len >= sizeof(msg)) - return EAP_SIM_DB_FAILURE; - os_memcpy(msg + len, imsi, imsi_len); - len += imsi_len; - - wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication " - "data for IMSI '%s'", imsi); - if (eap_sim_db_send(data, msg, len) < 0) - return EAP_SIM_DB_FAILURE; - - entry = os_zalloc(sizeof(*entry)); - if (entry == NULL) - return EAP_SIM_DB_FAILURE; - - entry->aka = 1; - os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi)); - entry->cb_session_ctx = cb_session_ctx; - entry->state = PENDING; - eap_sim_db_add_pending(data, entry); - eap_sim_db_expire_pending(data); - - return EAP_SIM_DB_PENDING; -} - - -/** - * eap_sim_db_resynchronize - Resynchronize AKA AUTN - * @data: Private data pointer from eap_sim_db_init() - * @username: Permanent username - * @auts: AUTS value from the peer - * @_rand: RAND value used in the rejected message - * Returns: 0 on success, -1 on failure - * - * This function is called when the peer reports synchronization failure in the - * AUTN value by sending AUTS. The AUTS and RAND values should be sent to - * HLR/AuC to allow it to resynchronize with the peer. After this, - * eap_sim_db_get_aka_auth() will be called again to to fetch updated - * RAND/AUTN values for the next challenge. - */ -int eap_sim_db_resynchronize(struct eap_sim_db_data *data, - const char *username, - const u8 *auts, const u8 *_rand) -{ - const char *imsi; - size_t imsi_len; - - if (username == NULL || - (username[0] != EAP_AKA_PERMANENT_PREFIX && - username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) || - username[1] == '\0' || os_strlen(username) > 20) { - wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'", - username); - return -1; - } - imsi = username + 1; - wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'", - imsi); - - if (data->sock >= 0) { - char msg[100]; - int len, ret; - - imsi_len = os_strlen(imsi); - len = os_snprintf(msg, sizeof(msg), "AKA-AUTS "); - if (len < 0 || len + imsi_len >= sizeof(msg)) - return -1; - os_memcpy(msg + len, imsi, imsi_len); - len += imsi_len; - - ret = os_snprintf(msg + len, sizeof(msg) - len, " "); - if (ret < 0 || (size_t) ret >= sizeof(msg) - len) - return -1; - len += ret; - len += wpa_snprintf_hex(msg + len, sizeof(msg) - len, - auts, EAP_AKA_AUTS_LEN); - ret = os_snprintf(msg + len, sizeof(msg) - len, " "); - if (ret < 0 || (size_t) ret >= sizeof(msg) - len) - return -1; - len += ret; - len += wpa_snprintf_hex(msg + len, sizeof(msg) - len, - _rand, EAP_AKA_RAND_LEN); - wpa_printf(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for " - "IMSI '%s'", imsi); - if (eap_sim_db_send(data, msg, len) < 0) - return -1; - } - - return 0; -} - - -/** - * sim_get_username - Extract username from SIM identity - * @identity: Identity - * @identity_len: Identity length - * Returns: Allocated buffer with the username part of the identity - * - * Caller is responsible for freeing the returned buffer with os_free(). - */ -char * sim_get_username(const u8 *identity, size_t identity_len) -{ - size_t pos; - - if (identity == NULL) - return NULL; - - for (pos = 0; pos < identity_len; pos++) { - if (identity[pos] == '@' || identity[pos] == '\0') - break; - } - - return dup_binstr(identity, pos); -} diff --git a/contrib/hostapd/src/eap_server/eap_sim_db.h b/contrib/hostapd/src/eap_server/eap_sim_db.h deleted file mode 100644 index 53a1a7c3b4..0000000000 --- a/contrib/hostapd/src/eap_server/eap_sim_db.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * hostapd / EAP-SIM database/authenticator gateway - * Copyright (c) 2005-2008, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_SIM_DB_H -#define EAP_SIM_DB_H - -#include "eap_common/eap_sim_common.h" - -/* Identity prefixes */ -#define EAP_SIM_PERMANENT_PREFIX '1' -#define EAP_SIM_PSEUDONYM_PREFIX '3' -#define EAP_SIM_REAUTH_ID_PREFIX '5' -#define EAP_AKA_PERMANENT_PREFIX '0' -#define EAP_AKA_PSEUDONYM_PREFIX '2' -#define EAP_AKA_REAUTH_ID_PREFIX '4' -#define EAP_AKA_PRIME_PERMANENT_PREFIX '6' -#define EAP_AKA_PRIME_PSEUDONYM_PREFIX '7' -#define EAP_AKA_PRIME_REAUTH_ID_PREFIX '8' - -enum eap_sim_db_method { - EAP_SIM_DB_SIM, - EAP_SIM_DB_AKA, - EAP_SIM_DB_AKA_PRIME -}; - -struct eap_sim_db_data; - -struct eap_sim_db_data * -eap_sim_db_init(const char *config, - void (*get_complete_cb)(void *ctx, void *session_ctx), - void *ctx); - -void eap_sim_db_deinit(void *priv); - -int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data, - const char *username, int max_chal, - u8 *_rand, u8 *kc, u8 *sres, - void *cb_session_ctx); - -#define EAP_SIM_DB_FAILURE -1 -#define EAP_SIM_DB_PENDING -2 - -char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data, - enum eap_sim_db_method method); - -char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data, - enum eap_sim_db_method method); - -int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data, - const char *permanent, char *pseudonym); - -int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent, - char *reauth_id, u16 counter, const u8 *mk); -int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data, - const char *permanent, - char *reauth_id, u16 counter, const u8 *k_encr, - const u8 *k_aut, const u8 *k_re); - -const char * eap_sim_db_get_permanent(struct eap_sim_db_data *data, - const char *pseudonym); - -struct eap_sim_reauth { - struct eap_sim_reauth *next; - char *permanent; /* Permanent username */ - char *reauth_id; /* Fast re-authentication username */ - u16 counter; - u8 mk[EAP_SIM_MK_LEN]; - u8 k_encr[EAP_SIM_K_ENCR_LEN]; - u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN]; - u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; -}; - -struct eap_sim_reauth * -eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data, - const char *reauth_id); - -void eap_sim_db_remove_reauth(struct eap_sim_db_data *data, - struct eap_sim_reauth *reauth); - -int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username, - u8 *_rand, u8 *autn, u8 *ik, u8 *ck, - u8 *res, size_t *res_len, void *cb_session_ctx); - -int eap_sim_db_resynchronize(struct eap_sim_db_data *data, - const char *username, const u8 *auts, - const u8 *_rand); - -char * sim_get_username(const u8 *identity, size_t identity_len); - -#endif /* EAP_SIM_DB_H */ diff --git a/contrib/hostapd/src/eap_server/eap_tls_common.h b/contrib/hostapd/src/eap_server/eap_tls_common.h deleted file mode 100644 index 11f5827513..0000000000 --- a/contrib/hostapd/src/eap_server/eap_tls_common.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * EAP-TLS/PEAP/TTLS/FAST server common functions - * Copyright (c) 2004-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_TLS_COMMON_H -#define EAP_TLS_COMMON_H - -/** - * struct eap_ssl_data - TLS data for EAP methods - */ -struct eap_ssl_data { - /** - * conn - TLS connection context data from tls_connection_init() - */ - struct tls_connection *conn; - - /** - * tls_out - TLS message to be sent out in fragments - */ - struct wpabuf *tls_out; - - /** - * tls_out_pos - The current position in the outgoing TLS message - */ - size_t tls_out_pos; - - /** - * tls_out_limit - Maximum fragment size for outgoing TLS messages - */ - size_t tls_out_limit; - - /** - * tls_in - Received TLS message buffer for re-assembly - */ - struct wpabuf *tls_in; - - /** - * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel) - */ - int phase2; - - /** - * eap - EAP state machine allocated with eap_server_sm_init() - */ - struct eap_sm *eap; - - enum { MSG, FRAG_ACK, WAIT_FRAG_ACK } state; - struct wpabuf tmpbuf; -}; - - -/* EAP TLS Flags */ -#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80 -#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40 -#define EAP_TLS_FLAGS_START 0x20 -#define EAP_TLS_VERSION_MASK 0x07 - - /* could be up to 128 bytes, but only the first 64 bytes are used */ -#define EAP_TLS_KEY_LEN 64 - -/* dummy type used as a flag for UNAUTH-TLS */ -#define EAP_UNAUTH_TLS_TYPE 255 - - -struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len, - u8 code, u8 identifier); -int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, - int verify_peer); -void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); -u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, - char *label, size_t len); -struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data, - int eap_type, int version, u8 id); -struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version); -int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data); -struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm, - struct eap_ssl_data *data, - const struct wpabuf *plain); -int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data, - struct wpabuf *respData, void *priv, int eap_type, - int (*proc_version)(struct eap_sm *sm, void *priv, - int peer_version), - void (*proc_msg)(struct eap_sm *sm, void *priv, - const struct wpabuf *respData)); - -#endif /* EAP_TLS_COMMON_H */ diff --git a/contrib/hostapd/src/eap_server/ikev2.c b/contrib/hostapd/src/eap_server/ikev2.c deleted file mode 100644 index 512ba30747..0000000000 --- a/contrib/hostapd/src/eap_server/ikev2.c +++ /dev/null @@ -1,1200 +0,0 @@ -/* - * IKEv2 initiator (RFC 4306) for EAP-IKEV2 - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/dh_groups.h" -#include "crypto/random.h" -#include "ikev2.h" - - -static int ikev2_process_idr(struct ikev2_initiator_data *data, - const u8 *idr, size_t idr_len); - - -void ikev2_initiator_deinit(struct ikev2_initiator_data *data) -{ - ikev2_free_keys(&data->keys); - wpabuf_free(data->r_dh_public); - wpabuf_free(data->i_dh_private); - os_free(data->IDi); - os_free(data->IDr); - os_free(data->shared_secret); - wpabuf_free(data->i_sign_msg); - wpabuf_free(data->r_sign_msg); - os_free(data->key_pad); -} - - -static int ikev2_derive_keys(struct ikev2_initiator_data *data) -{ - u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN]; - size_t buf_len, pad_len; - struct wpabuf *shared; - const struct ikev2_integ_alg *integ; - const struct ikev2_prf_alg *prf; - const struct ikev2_encr_alg *encr; - int ret; - const u8 *addr[2]; - size_t len[2]; - - /* RFC 4306, Sect. 2.14 */ - - integ = ikev2_get_integ(data->proposal.integ); - prf = ikev2_get_prf(data->proposal.prf); - encr = ikev2_get_encr(data->proposal.encr); - if (integ == NULL || prf == NULL || encr == NULL) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal"); - return -1; - } - - shared = dh_derive_shared(data->r_dh_public, data->i_dh_private, - data->dh); - if (shared == NULL) - return -1; - - /* Construct Ni | Nr | SPIi | SPIr */ - - buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN; - buf = os_malloc(buf_len); - if (buf == NULL) { - wpabuf_free(shared); - return -1; - } - - pos = buf; - os_memcpy(pos, data->i_nonce, data->i_nonce_len); - pos += data->i_nonce_len; - os_memcpy(pos, data->r_nonce, data->r_nonce_len); - pos += data->r_nonce_len; - os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN); - pos += IKEV2_SPI_LEN; - os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN); - - /* SKEYSEED = prf(Ni | Nr, g^ir) */ - - /* Use zero-padding per RFC 4306, Sect. 2.14 */ - pad_len = data->dh->prime_len - wpabuf_len(shared); - pad = os_zalloc(pad_len ? pad_len : 1); - if (pad == NULL) { - wpabuf_free(shared); - os_free(buf); - return -1; - } - addr[0] = pad; - len[0] = pad_len; - addr[1] = wpabuf_head(shared); - len[1] = wpabuf_len(shared); - if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len, - 2, addr, len, skeyseed) < 0) { - wpabuf_free(shared); - os_free(buf); - os_free(pad); - return -1; - } - os_free(pad); - wpabuf_free(shared); - - /* DH parameters are not needed anymore, so free them */ - wpabuf_free(data->r_dh_public); - data->r_dh_public = NULL; - wpabuf_free(data->i_dh_private); - data->i_dh_private = NULL; - - wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED", - skeyseed, prf->hash_len); - - ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len, - &data->keys); - os_free(buf); - return ret; -} - - -static int ikev2_parse_transform(struct ikev2_initiator_data *data, - struct ikev2_proposal_data *prop, - const u8 *pos, const u8 *end) -{ - int transform_len; - const struct ikev2_transform *t; - u16 transform_id; - const u8 *tend; - - if (end - pos < (int) sizeof(*t)) { - wpa_printf(MSG_INFO, "IKEV2: Too short transform"); - return -1; - } - - t = (const struct ikev2_transform *) pos; - transform_len = WPA_GET_BE16(t->transform_length); - if (transform_len < (int) sizeof(*t) || pos + transform_len > end) { - wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d", - transform_len); - return -1; - } - tend = pos + transform_len; - - transform_id = WPA_GET_BE16(t->transform_id); - - wpa_printf(MSG_DEBUG, "IKEV2: Transform:"); - wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Transform Length: %d " - "Transform Type: %d Transform ID: %d", - t->type, transform_len, t->transform_type, transform_id); - - if (t->type != 0 && t->type != 3) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type"); - return -1; - } - - pos = (const u8 *) (t + 1); - if (pos < tend) { - wpa_hexdump(MSG_DEBUG, "IKEV2: Transform Attributes", - pos, tend - pos); - } - - switch (t->transform_type) { - case IKEV2_TRANSFORM_ENCR: - if (ikev2_get_encr(transform_id) && - transform_id == data->proposal.encr) { - if (transform_id == ENCR_AES_CBC) { - if (tend - pos != 4) { - wpa_printf(MSG_DEBUG, "IKEV2: No " - "Transform Attr for AES"); - break; - } - if (WPA_GET_BE16(pos) != 0x800e) { - wpa_printf(MSG_DEBUG, "IKEV2: Not a " - "Key Size attribute for " - "AES"); - break; - } - if (WPA_GET_BE16(pos + 2) != 128) { - wpa_printf(MSG_DEBUG, "IKEV2: " - "Unsupported AES key size " - "%d bits", - WPA_GET_BE16(pos + 2)); - break; - } - } - prop->encr = transform_id; - } - break; - case IKEV2_TRANSFORM_PRF: - if (ikev2_get_prf(transform_id) && - transform_id == data->proposal.prf) - prop->prf = transform_id; - break; - case IKEV2_TRANSFORM_INTEG: - if (ikev2_get_integ(transform_id) && - transform_id == data->proposal.integ) - prop->integ = transform_id; - break; - case IKEV2_TRANSFORM_DH: - if (dh_groups_get(transform_id) && - transform_id == data->proposal.dh) - prop->dh = transform_id; - break; - } - - return transform_len; -} - - -static int ikev2_parse_proposal(struct ikev2_initiator_data *data, - struct ikev2_proposal_data *prop, - const u8 *pos, const u8 *end) -{ - const u8 *pend, *ppos; - int proposal_len, i; - const struct ikev2_proposal *p; - - if (end - pos < (int) sizeof(*p)) { - wpa_printf(MSG_INFO, "IKEV2: Too short proposal"); - return -1; - } - - p = (const struct ikev2_proposal *) pos; - proposal_len = WPA_GET_BE16(p->proposal_length); - if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) { - wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d", - proposal_len); - return -1; - } - wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d", - p->proposal_num); - wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Proposal Length: %d " - " Protocol ID: %d", - p->type, proposal_len, p->protocol_id); - wpa_printf(MSG_DEBUG, "IKEV2: SPI Size: %d Transforms: %d", - p->spi_size, p->num_transforms); - - if (p->type != 0 && p->type != 2) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type"); - return -1; - } - - if (p->protocol_id != IKEV2_PROTOCOL_IKE) { - wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID " - "(only IKE allowed for EAP-IKEv2)"); - return -1; - } - - if (p->proposal_num != prop->proposal_num) { - if (p->proposal_num == prop->proposal_num + 1) - prop->proposal_num = p->proposal_num; - else { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #"); - return -1; - } - } - - ppos = (const u8 *) (p + 1); - pend = pos + proposal_len; - if (ppos + p->spi_size > pend) { - wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI " - "in proposal"); - return -1; - } - if (p->spi_size) { - wpa_hexdump(MSG_DEBUG, "IKEV2: SPI", - ppos, p->spi_size); - ppos += p->spi_size; - } - - /* - * For initial IKE_SA negotiation, SPI Size MUST be zero; for - * subsequent negotiations, it must be 8 for IKE. We only support - * initial case for now. - */ - if (p->spi_size != 0) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size"); - return -1; - } - - if (p->num_transforms == 0) { - wpa_printf(MSG_INFO, "IKEV2: At least one transform required"); - return -1; - } - - for (i = 0; i < (int) p->num_transforms; i++) { - int tlen = ikev2_parse_transform(data, prop, ppos, pend); - if (tlen < 0) - return -1; - ppos += tlen; - } - - if (ppos != pend) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected data after " - "transforms"); - return -1; - } - - return proposal_len; -} - - -static int ikev2_process_sar1(struct ikev2_initiator_data *data, - const u8 *sar1, size_t sar1_len) -{ - struct ikev2_proposal_data prop; - const u8 *pos, *end; - int found = 0; - - /* Security Association Payloads: */ - - if (sar1 == NULL) { - wpa_printf(MSG_INFO, "IKEV2: SAr1 not received"); - return -1; - } - - os_memset(&prop, 0, sizeof(prop)); - prop.proposal_num = 1; - - pos = sar1; - end = sar1 + sar1_len; - - while (pos < end) { - int plen; - - prop.integ = -1; - prop.prf = -1; - prop.encr = -1; - prop.dh = -1; - plen = ikev2_parse_proposal(data, &prop, pos, end); - if (plen < 0) - return -1; - - if (!found && prop.integ != -1 && prop.prf != -1 && - prop.encr != -1 && prop.dh != -1) { - found = 1; - } - - pos += plen; - - /* Only one proposal expected in SAr */ - break; - } - - if (pos != end) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposal"); - return -1; - } - - if (!found) { - wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found"); - return -1; - } - - wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d " - "INTEG:%d D-H:%d", data->proposal.proposal_num, - data->proposal.encr, data->proposal.prf, - data->proposal.integ, data->proposal.dh); - - return 0; -} - - -static int ikev2_process_ker(struct ikev2_initiator_data *data, - const u8 *ker, size_t ker_len) -{ - u16 group; - - /* - * Key Exchange Payload: - * DH Group # (16 bits) - * RESERVED (16 bits) - * Key Exchange Data (Diffie-Hellman public value) - */ - - if (ker == NULL) { - wpa_printf(MSG_INFO, "IKEV2: KEr not received"); - return -1; - } - - if (ker_len < 4 + 96) { - wpa_printf(MSG_INFO, "IKEV2: Too show Key Exchange Payload"); - return -1; - } - - group = WPA_GET_BE16(ker); - wpa_printf(MSG_DEBUG, "IKEV2: KEr DH Group #%u", group); - - if (group != data->proposal.dh) { - wpa_printf(MSG_DEBUG, "IKEV2: KEr DH Group #%u does not match " - "with the selected proposal (%u)", - group, data->proposal.dh); - return -1; - } - - if (data->dh == NULL) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group"); - return -1; - } - - /* RFC 4306, Section 3.4: - * The length of DH public value MUST be equal to the length of the - * prime modulus. - */ - if (ker_len - 4 != data->dh->prime_len) { - wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length " - "%ld (expected %ld)", - (long) (ker_len - 4), (long) data->dh->prime_len); - return -1; - } - - wpabuf_free(data->r_dh_public); - data->r_dh_public = wpabuf_alloc_copy(ker + 4, ker_len - 4); - if (data->r_dh_public == NULL) - return -1; - - wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEr Diffie-Hellman Public Value", - data->r_dh_public); - - return 0; -} - - -static int ikev2_process_nr(struct ikev2_initiator_data *data, - const u8 *nr, size_t nr_len) -{ - if (nr == NULL) { - wpa_printf(MSG_INFO, "IKEV2: Nr not received"); - return -1; - } - - if (nr_len < IKEV2_NONCE_MIN_LEN || nr_len > IKEV2_NONCE_MAX_LEN) { - wpa_printf(MSG_INFO, "IKEV2: Invalid Nr length %ld", - (long) nr_len); - return -1; - } - - data->r_nonce_len = nr_len; - os_memcpy(data->r_nonce, nr, nr_len); - wpa_hexdump(MSG_MSGDUMP, "IKEV2: Nr", - data->r_nonce, data->r_nonce_len); - - return 0; -} - - -static int ikev2_process_sa_init_encr(struct ikev2_initiator_data *data, - const struct ikev2_hdr *hdr, - const u8 *encrypted, - size_t encrypted_len, u8 next_payload) -{ - u8 *decrypted; - size_t decrypted_len; - struct ikev2_payloads pl; - int ret = 0; - - decrypted = ikev2_decrypt_payload(data->proposal.encr, - data->proposal.integ, &data->keys, 0, - hdr, encrypted, encrypted_len, - &decrypted_len); - if (decrypted == NULL) - return -1; - - wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads"); - - if (ikev2_parse_payloads(&pl, next_payload, decrypted, - decrypted + decrypted_len) < 0) { - wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted " - "payloads"); - return -1; - } - - if (pl.idr) - ret = ikev2_process_idr(data, pl.idr, pl.idr_len); - - os_free(decrypted); - - return ret; -} - - -static int ikev2_process_sa_init(struct ikev2_initiator_data *data, - const struct ikev2_hdr *hdr, - struct ikev2_payloads *pl) -{ - if (ikev2_process_sar1(data, pl->sa, pl->sa_len) < 0 || - ikev2_process_ker(data, pl->ke, pl->ke_len) < 0 || - ikev2_process_nr(data, pl->nonce, pl->nonce_len) < 0) - return -1; - - os_memcpy(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN); - - if (ikev2_derive_keys(data) < 0) - return -1; - - if (pl->encrypted) { - wpa_printf(MSG_DEBUG, "IKEV2: Encrypted payload in SA_INIT - " - "try to get IDr from it"); - if (ikev2_process_sa_init_encr(data, hdr, pl->encrypted, - pl->encrypted_len, - pl->encr_next_payload) < 0) { - wpa_printf(MSG_INFO, "IKEV2: Failed to process " - "encrypted payload"); - return -1; - } - } - - data->state = SA_AUTH; - - return 0; -} - - -static int ikev2_process_idr(struct ikev2_initiator_data *data, - const u8 *idr, size_t idr_len) -{ - u8 id_type; - - if (idr == NULL) { - wpa_printf(MSG_INFO, "IKEV2: No IDr received"); - return -1; - } - - if (idr_len < 4) { - wpa_printf(MSG_INFO, "IKEV2: Too short IDr payload"); - return -1; - } - - id_type = idr[0]; - idr += 4; - idr_len -= 4; - - wpa_printf(MSG_DEBUG, "IKEV2: IDr ID Type %d", id_type); - wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDr", idr, idr_len); - if (data->IDr) { - if (id_type != data->IDr_type || idr_len != data->IDr_len || - os_memcmp(idr, data->IDr, idr_len) != 0) { - wpa_printf(MSG_INFO, "IKEV2: IDr differs from the one " - "received earlier"); - wpa_printf(MSG_DEBUG, "IKEV2: Previous IDr ID Type %d", - id_type); - wpa_hexdump_ascii(MSG_DEBUG, "Previous IKEV2: IDr", - data->IDr, data->IDr_len); - return -1; - } - os_free(data->IDr); - } - data->IDr = os_malloc(idr_len); - if (data->IDr == NULL) - return -1; - os_memcpy(data->IDr, idr, idr_len); - data->IDr_len = idr_len; - data->IDr_type = id_type; - - return 0; -} - - -static int ikev2_process_cert(struct ikev2_initiator_data *data, - const u8 *cert, size_t cert_len) -{ - u8 cert_encoding; - - if (cert == NULL) { - if (data->peer_auth == PEER_AUTH_CERT) { - wpa_printf(MSG_INFO, "IKEV2: No Certificate received"); - return -1; - } - return 0; - } - - if (cert_len < 1) { - wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field"); - return -1; - } - - cert_encoding = cert[0]; - cert++; - cert_len--; - - wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding); - wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len); - - /* TODO: validate certificate */ - - return 0; -} - - -static int ikev2_process_auth_cert(struct ikev2_initiator_data *data, - u8 method, const u8 *auth, size_t auth_len) -{ - if (method != AUTH_RSA_SIGN) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " - "method %d", method); - return -1; - } - - /* TODO: validate AUTH */ - return 0; -} - - -static int ikev2_process_auth_secret(struct ikev2_initiator_data *data, - u8 method, const u8 *auth, - size_t auth_len) -{ - u8 auth_data[IKEV2_MAX_HASH_LEN]; - const struct ikev2_prf_alg *prf; - - if (method != AUTH_SHARED_KEY_MIC) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " - "method %d", method); - return -1; - } - - /* msg | Ni | prf(SK_pr,IDr') */ - if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg, - data->IDr, data->IDr_len, data->IDr_type, - &data->keys, 0, data->shared_secret, - data->shared_secret_len, - data->i_nonce, data->i_nonce_len, - data->key_pad, data->key_pad_len, - auth_data) < 0) { - wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); - return -1; - } - - wpabuf_free(data->r_sign_msg); - data->r_sign_msg = NULL; - - prf = ikev2_get_prf(data->proposal.prf); - if (prf == NULL) - return -1; - - if (auth_len != prf->hash_len || - os_memcmp(auth, auth_data, auth_len) != 0) { - wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data"); - wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data", - auth, auth_len); - wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data", - auth_data, prf->hash_len); - return -1; - } - - wpa_printf(MSG_DEBUG, "IKEV2: Peer authenticated successfully " - "using shared keys"); - - return 0; -} - - -static int ikev2_process_auth(struct ikev2_initiator_data *data, - const u8 *auth, size_t auth_len) -{ - u8 auth_method; - - if (auth == NULL) { - wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload"); - return -1; - } - - if (auth_len < 4) { - wpa_printf(MSG_INFO, "IKEV2: Too short Authentication " - "Payload"); - return -1; - } - - auth_method = auth[0]; - auth += 4; - auth_len -= 4; - - wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method); - wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len); - - switch (data->peer_auth) { - case PEER_AUTH_CERT: - return ikev2_process_auth_cert(data, auth_method, auth, - auth_len); - case PEER_AUTH_SECRET: - return ikev2_process_auth_secret(data, auth_method, auth, - auth_len); - } - - return -1; -} - - -static int ikev2_process_sa_auth_decrypted(struct ikev2_initiator_data *data, - u8 next_payload, - u8 *payload, size_t payload_len) -{ - struct ikev2_payloads pl; - - wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads"); - - if (ikev2_parse_payloads(&pl, next_payload, payload, payload + - payload_len) < 0) { - wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted " - "payloads"); - return -1; - } - - if (ikev2_process_idr(data, pl.idr, pl.idr_len) < 0 || - ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 || - ikev2_process_auth(data, pl.auth, pl.auth_len) < 0) - return -1; - - return 0; -} - - -static int ikev2_process_sa_auth(struct ikev2_initiator_data *data, - const struct ikev2_hdr *hdr, - struct ikev2_payloads *pl) -{ - u8 *decrypted; - size_t decrypted_len; - int ret; - - decrypted = ikev2_decrypt_payload(data->proposal.encr, - data->proposal.integ, - &data->keys, 0, hdr, pl->encrypted, - pl->encrypted_len, &decrypted_len); - if (decrypted == NULL) - return -1; - - ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload, - decrypted, decrypted_len); - os_free(decrypted); - - if (ret == 0 && !data->unknown_user) { - wpa_printf(MSG_DEBUG, "IKEV2: Authentication completed"); - data->state = IKEV2_DONE; - } - - return ret; -} - - -static int ikev2_validate_rx_state(struct ikev2_initiator_data *data, - u8 exchange_type, u32 message_id) -{ - switch (data->state) { - case SA_INIT: - /* Expect to receive IKE_SA_INIT: HDR, SAr, KEr, Nr, [CERTREQ], - * [SK{IDr}] */ - if (exchange_type != IKE_SA_INIT) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " - "%u in SA_INIT state", exchange_type); - return -1; - } - if (message_id != 0) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " - "in SA_INIT state", message_id); - return -1; - } - break; - case SA_AUTH: - /* Expect to receive IKE_SA_AUTH: - * HDR, SK {IDr, [CERT,] [CERTREQ,] [NFID,] AUTH} - */ - if (exchange_type != IKE_SA_AUTH) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " - "%u in SA_AUTH state", exchange_type); - return -1; - } - if (message_id != 1) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " - "in SA_AUTH state", message_id); - return -1; - } - break; - case CHILD_SA: - if (exchange_type != CREATE_CHILD_SA) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " - "%u in CHILD_SA state", exchange_type); - return -1; - } - if (message_id != 2) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " - "in CHILD_SA state", message_id); - return -1; - } - break; - case IKEV2_DONE: - return -1; - } - - return 0; -} - - -int ikev2_initiator_process(struct ikev2_initiator_data *data, - const struct wpabuf *buf) -{ - const struct ikev2_hdr *hdr; - u32 length, message_id; - const u8 *pos, *end; - struct ikev2_payloads pl; - - wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)", - (unsigned long) wpabuf_len(buf)); - - if (wpabuf_len(buf) < sizeof(*hdr)) { - wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR"); - return -1; - } - - hdr = (const struct ikev2_hdr *) wpabuf_head(buf); - end = wpabuf_head_u8(buf) + wpabuf_len(buf); - message_id = WPA_GET_BE32(hdr->message_id); - length = WPA_GET_BE32(hdr->length); - - wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", - hdr->i_spi, IKEV2_SPI_LEN); - wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", - hdr->r_spi, IKEV2_SPI_LEN); - wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Version: 0x%x " - "Exchange Type: %u", - hdr->next_payload, hdr->version, hdr->exchange_type); - wpa_printf(MSG_DEBUG, "IKEV2: Message ID: %u Length: %u", - message_id, length); - - if (hdr->version != IKEV2_VERSION) { - wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x " - "(expected 0x%x)", hdr->version, IKEV2_VERSION); - return -1; - } - - if (length != wpabuf_len(buf)) { - wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != " - "RX: %lu)", (unsigned long) length, - (unsigned long) wpabuf_len(buf)); - return -1; - } - - if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0) - return -1; - - if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) != - IKEV2_HDR_RESPONSE) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x", - hdr->flags); - return -1; - } - - if (data->state != SA_INIT) { - if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " - "Initiator's SPI"); - return -1; - } - if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) { - wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " - "Responder's SPI"); - return -1; - } - } - - pos = (const u8 *) (hdr + 1); - if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0) - return -1; - - switch (data->state) { - case SA_INIT: - if (ikev2_process_sa_init(data, hdr, &pl) < 0) - return -1; - wpabuf_free(data->r_sign_msg); - data->r_sign_msg = wpabuf_dup(buf); - break; - case SA_AUTH: - if (ikev2_process_sa_auth(data, hdr, &pl) < 0) - return -1; - break; - case CHILD_SA: - case IKEV2_DONE: - break; - } - - return 0; -} - - -static void ikev2_build_hdr(struct ikev2_initiator_data *data, - struct wpabuf *msg, u8 exchange_type, - u8 next_payload, u32 message_id) -{ - struct ikev2_hdr *hdr; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR"); - - /* HDR - RFC 4306, Sect. 3.1 */ - hdr = wpabuf_put(msg, sizeof(*hdr)); - os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN); - os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN); - hdr->next_payload = next_payload; - hdr->version = IKEV2_VERSION; - hdr->exchange_type = exchange_type; - hdr->flags = IKEV2_HDR_INITIATOR; - WPA_PUT_BE32(hdr->message_id, message_id); -} - - -static int ikev2_build_sai(struct ikev2_initiator_data *data, - struct wpabuf *msg, u8 next_payload) -{ - struct ikev2_payload_hdr *phdr; - size_t plen; - struct ikev2_proposal *p; - struct ikev2_transform *t; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding SAi payload"); - - /* SAi1 - RFC 4306, Sect. 2.7 and 3.3 */ - phdr = wpabuf_put(msg, sizeof(*phdr)); - phdr->next_payload = next_payload; - phdr->flags = 0; - - /* TODO: support for multiple proposals */ - p = wpabuf_put(msg, sizeof(*p)); - p->proposal_num = data->proposal.proposal_num; - p->protocol_id = IKEV2_PROTOCOL_IKE; - p->num_transforms = 4; - - t = wpabuf_put(msg, sizeof(*t)); - t->type = 3; - t->transform_type = IKEV2_TRANSFORM_ENCR; - WPA_PUT_BE16(t->transform_id, data->proposal.encr); - if (data->proposal.encr == ENCR_AES_CBC) { - /* Transform Attribute: Key Len = 128 bits */ - wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */ - wpabuf_put_be16(msg, 128); /* 128-bit key */ - } - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t; - WPA_PUT_BE16(t->transform_length, plen); - - t = wpabuf_put(msg, sizeof(*t)); - t->type = 3; - WPA_PUT_BE16(t->transform_length, sizeof(*t)); - t->transform_type = IKEV2_TRANSFORM_PRF; - WPA_PUT_BE16(t->transform_id, data->proposal.prf); - - t = wpabuf_put(msg, sizeof(*t)); - t->type = 3; - WPA_PUT_BE16(t->transform_length, sizeof(*t)); - t->transform_type = IKEV2_TRANSFORM_INTEG; - WPA_PUT_BE16(t->transform_id, data->proposal.integ); - - t = wpabuf_put(msg, sizeof(*t)); - WPA_PUT_BE16(t->transform_length, sizeof(*t)); - t->transform_type = IKEV2_TRANSFORM_DH; - WPA_PUT_BE16(t->transform_id, data->proposal.dh); - - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p; - WPA_PUT_BE16(p->proposal_length, plen); - - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; - WPA_PUT_BE16(phdr->payload_length, plen); - - return 0; -} - - -static int ikev2_build_kei(struct ikev2_initiator_data *data, - struct wpabuf *msg, u8 next_payload) -{ - struct ikev2_payload_hdr *phdr; - size_t plen; - struct wpabuf *pv; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding KEi payload"); - - data->dh = dh_groups_get(data->proposal.dh); - pv = dh_init(data->dh, &data->i_dh_private); - if (pv == NULL) { - wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH"); - return -1; - } - - /* KEi - RFC 4306, Sect. 3.4 */ - phdr = wpabuf_put(msg, sizeof(*phdr)); - phdr->next_payload = next_payload; - phdr->flags = 0; - - wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */ - wpabuf_put(msg, 2); /* RESERVED */ - /* - * RFC 4306, Sect. 3.4: possible zero padding for public value to - * match the length of the prime. - */ - wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv)); - wpabuf_put_buf(msg, pv); - wpabuf_free(pv); - - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; - WPA_PUT_BE16(phdr->payload_length, plen); - return 0; -} - - -static int ikev2_build_ni(struct ikev2_initiator_data *data, - struct wpabuf *msg, u8 next_payload) -{ - struct ikev2_payload_hdr *phdr; - size_t plen; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding Ni payload"); - - /* Ni - RFC 4306, Sect. 3.9 */ - phdr = wpabuf_put(msg, sizeof(*phdr)); - phdr->next_payload = next_payload; - phdr->flags = 0; - wpabuf_put_data(msg, data->i_nonce, data->i_nonce_len); - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; - WPA_PUT_BE16(phdr->payload_length, plen); - return 0; -} - - -static int ikev2_build_idi(struct ikev2_initiator_data *data, - struct wpabuf *msg, u8 next_payload) -{ - struct ikev2_payload_hdr *phdr; - size_t plen; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding IDi payload"); - - if (data->IDi == NULL) { - wpa_printf(MSG_INFO, "IKEV2: No IDi available"); - return -1; - } - - /* IDi - RFC 4306, Sect. 3.5 */ - phdr = wpabuf_put(msg, sizeof(*phdr)); - phdr->next_payload = next_payload; - phdr->flags = 0; - wpabuf_put_u8(msg, ID_KEY_ID); - wpabuf_put(msg, 3); /* RESERVED */ - wpabuf_put_data(msg, data->IDi, data->IDi_len); - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; - WPA_PUT_BE16(phdr->payload_length, plen); - return 0; -} - - -static int ikev2_build_auth(struct ikev2_initiator_data *data, - struct wpabuf *msg, u8 next_payload) -{ - struct ikev2_payload_hdr *phdr; - size_t plen; - const struct ikev2_prf_alg *prf; - - wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload"); - - prf = ikev2_get_prf(data->proposal.prf); - if (prf == NULL) - return -1; - - /* Authentication - RFC 4306, Sect. 3.8 */ - phdr = wpabuf_put(msg, sizeof(*phdr)); - phdr->next_payload = next_payload; - phdr->flags = 0; - wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC); - wpabuf_put(msg, 3); /* RESERVED */ - - /* msg | Nr | prf(SK_pi,IDi') */ - if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg, - data->IDi, data->IDi_len, ID_KEY_ID, - &data->keys, 1, data->shared_secret, - data->shared_secret_len, - data->r_nonce, data->r_nonce_len, - data->key_pad, data->key_pad_len, - wpabuf_put(msg, prf->hash_len)) < 0) { - wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); - return -1; - } - wpabuf_free(data->i_sign_msg); - data->i_sign_msg = NULL; - - plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; - WPA_PUT_BE16(phdr->payload_length, plen); - return 0; -} - - -static struct wpabuf * ikev2_build_sa_init(struct ikev2_initiator_data *data) -{ - struct wpabuf *msg; - - /* build IKE_SA_INIT: HDR, SAi, KEi, Ni */ - - if (os_get_random(data->i_spi, IKEV2_SPI_LEN)) - return NULL; - wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", - data->i_spi, IKEV2_SPI_LEN); - - data->i_nonce_len = IKEV2_NONCE_MIN_LEN; - if (random_get_bytes(data->i_nonce, data->i_nonce_len)) - return NULL; - wpa_hexdump(MSG_DEBUG, "IKEV2: Ni", data->i_nonce, data->i_nonce_len); - - msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000); - if (msg == NULL) - return NULL; - - ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0); - if (ikev2_build_sai(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) || - ikev2_build_kei(data, msg, IKEV2_PAYLOAD_NONCE) || - ikev2_build_ni(data, msg, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { - wpabuf_free(msg); - return NULL; - } - - ikev2_update_hdr(msg); - - wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg); - - wpabuf_free(data->i_sign_msg); - data->i_sign_msg = wpabuf_dup(msg); - - return msg; -} - - -static struct wpabuf * ikev2_build_sa_auth(struct ikev2_initiator_data *data) -{ - struct wpabuf *msg, *plain; - const u8 *secret; - size_t secret_len; - - secret = data->get_shared_secret(data->cb_ctx, data->IDr, - data->IDr_len, &secret_len); - if (secret == NULL) { - wpa_printf(MSG_INFO, "IKEV2: Could not get shared secret - " - "use fake value"); - /* RFC 5106, Sect. 7: - * Use a random key to fake AUTH generation in order to prevent - * probing of user identities. - */ - data->unknown_user = 1; - os_free(data->shared_secret); - data->shared_secret = os_malloc(16); - if (data->shared_secret == NULL) - return NULL; - data->shared_secret_len = 16; - if (random_get_bytes(data->shared_secret, 16)) - return NULL; - } else { - os_free(data->shared_secret); - data->shared_secret = os_malloc(secret_len); - if (data->shared_secret == NULL) - return NULL; - os_memcpy(data->shared_secret, secret, secret_len); - data->shared_secret_len = secret_len; - } - - /* build IKE_SA_AUTH: HDR, SK {IDi, [CERT,] [CERTREQ,] AUTH} */ - - msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000); - if (msg == NULL) - return NULL; - ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1); - - plain = wpabuf_alloc(data->IDr_len + 1000); - if (plain == NULL) { - wpabuf_free(msg); - return NULL; - } - - if (ikev2_build_idi(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) || - ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || - ikev2_build_encrypted(data->proposal.encr, data->proposal.integ, - &data->keys, 1, msg, plain, - IKEV2_PAYLOAD_IDi)) { - wpabuf_free(plain); - wpabuf_free(msg); - return NULL; - } - wpabuf_free(plain); - - wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg); - - return msg; -} - - -struct wpabuf * ikev2_initiator_build(struct ikev2_initiator_data *data) -{ - switch (data->state) { - case SA_INIT: - return ikev2_build_sa_init(data); - case SA_AUTH: - return ikev2_build_sa_auth(data); - case CHILD_SA: - return NULL; - case IKEV2_DONE: - return NULL; - } - return NULL; -} diff --git a/contrib/hostapd/src/eap_server/ikev2.h b/contrib/hostapd/src/eap_server/ikev2.h deleted file mode 100644 index 051a93869c..0000000000 --- a/contrib/hostapd/src/eap_server/ikev2.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * IKEv2 initiator (RFC 4306) for EAP-IKEV2 - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef IKEV2_H -#define IKEV2_H - -#include "eap_common/ikev2_common.h" - -struct ikev2_proposal_data { - u8 proposal_num; - int integ; - int prf; - int encr; - int dh; -}; - - -struct ikev2_initiator_data { - enum { SA_INIT, SA_AUTH, CHILD_SA, IKEV2_DONE } state; - u8 i_spi[IKEV2_SPI_LEN]; - u8 r_spi[IKEV2_SPI_LEN]; - u8 i_nonce[IKEV2_NONCE_MAX_LEN]; - size_t i_nonce_len; - u8 r_nonce[IKEV2_NONCE_MAX_LEN]; - size_t r_nonce_len; - struct wpabuf *r_dh_public; - struct wpabuf *i_dh_private; - struct ikev2_proposal_data proposal; - const struct dh_group *dh; - struct ikev2_keys keys; - u8 *IDi; - size_t IDi_len; - u8 *IDr; - size_t IDr_len; - u8 IDr_type; - struct wpabuf *r_sign_msg; - struct wpabuf *i_sign_msg; - u8 *shared_secret; - size_t shared_secret_len; - enum { PEER_AUTH_CERT, PEER_AUTH_SECRET } peer_auth; - u8 *key_pad; - size_t key_pad_len; - - const u8 * (*get_shared_secret)(void *ctx, const u8 *IDr, - size_t IDr_len, size_t *secret_len); - void *cb_ctx; - int unknown_user; -}; - - -void ikev2_initiator_deinit(struct ikev2_initiator_data *data); -int ikev2_initiator_process(struct ikev2_initiator_data *data, - const struct wpabuf *buf); -struct wpabuf * ikev2_initiator_build(struct ikev2_initiator_data *data); - -#endif /* IKEV2_H */ diff --git a/contrib/hostapd/src/eap_server/tncs.c b/contrib/hostapd/src/eap_server/tncs.c deleted file mode 100644 index e429f1e67f..0000000000 --- a/contrib/hostapd/src/eap_server/tncs.c +++ /dev/null @@ -1,1265 +0,0 @@ -/* - * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH) - * Copyright (c) 2007-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "base64.h" -#include "tncs.h" -#include "eap_common/eap_tlv_common.h" -#include "eap_common/eap_defs.h" - - -/* TODO: TNCS must be thread-safe; review the code and add locking etc. if - * needed.. */ - -#define TNC_CONFIG_FILE "/etc/tnc_config" -#define IF_TNCCS_START \ -"\n" \ -"\n" -#define IF_TNCCS_END "\n" - -/* TNC IF-IMV */ - -typedef unsigned long TNC_UInt32; -typedef unsigned char *TNC_BufferReference; - -typedef TNC_UInt32 TNC_IMVID; -typedef TNC_UInt32 TNC_ConnectionID; -typedef TNC_UInt32 TNC_ConnectionState; -typedef TNC_UInt32 TNC_RetryReason; -typedef TNC_UInt32 TNC_IMV_Action_Recommendation; -typedef TNC_UInt32 TNC_IMV_Evaluation_Result; -typedef TNC_UInt32 TNC_MessageType; -typedef TNC_MessageType *TNC_MessageTypeList; -typedef TNC_UInt32 TNC_VendorID; -typedef TNC_UInt32 TNC_Subtype; -typedef TNC_UInt32 TNC_Version; -typedef TNC_UInt32 TNC_Result; -typedef TNC_UInt32 TNC_AttributeID; - -typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)( - TNC_IMVID imvID, - char *functionName, - void **pOutfunctionPointer); - -#define TNC_RESULT_SUCCESS 0 -#define TNC_RESULT_NOT_INITIALIZED 1 -#define TNC_RESULT_ALREADY_INITIALIZED 2 -#define TNC_RESULT_NO_COMMON_VERSION 3 -#define TNC_RESULT_CANT_RETRY 4 -#define TNC_RESULT_WONT_RETRY 5 -#define TNC_RESULT_INVALID_PARAMETER 6 -#define TNC_RESULT_CANT_RESPOND 7 -#define TNC_RESULT_ILLEGAL_OPERATION 8 -#define TNC_RESULT_OTHER 9 -#define TNC_RESULT_FATAL 10 - -#define TNC_CONNECTION_STATE_CREATE 0 -#define TNC_CONNECTION_STATE_HANDSHAKE 1 -#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2 -#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3 -#define TNC_CONNECTION_STATE_ACCESS_NONE 4 -#define TNC_CONNECTION_STATE_DELETE 5 - -#define TNC_IFIMV_VERSION_1 1 - -#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff) -#define TNC_SUBTYPE_ANY ((TNC_Subtype) 0xff) - -/* TNCC-TNCS Message Types */ -#define TNC_TNCCS_RECOMMENDATION 0x00000001 -#define TNC_TNCCS_ERROR 0x00000002 -#define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003 -#define TNC_TNCCS_REASONSTRINGS 0x00000004 - -/* Possible TNC_IMV_Action_Recommendation values: */ -enum IMV_Action_Recommendation { - TNC_IMV_ACTION_RECOMMENDATION_ALLOW, - TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS, - TNC_IMV_ACTION_RECOMMENDATION_ISOLATE, - TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION -}; - -/* Possible TNC_IMV_Evaluation_Result values: */ -enum IMV_Evaluation_Result { - TNC_IMV_EVALUATION_RESULT_COMPLIANT, - TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR, - TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR, - TNC_IMV_EVALUATION_RESULT_ERROR, - TNC_IMV_EVALUATION_RESULT_DONT_KNOW -}; - -struct tnc_if_imv { - struct tnc_if_imv *next; - char *name; - char *path; - void *dlhandle; /* from dlopen() */ - TNC_IMVID imvID; - TNC_MessageTypeList supported_types; - size_t num_supported_types; - - /* Functions implemented by IMVs (with TNC_IMV_ prefix) */ - TNC_Result (*Initialize)( - TNC_IMVID imvID, - TNC_Version minVersion, - TNC_Version maxVersion, - TNC_Version *pOutActualVersion); - TNC_Result (*NotifyConnectionChange)( - TNC_IMVID imvID, - TNC_ConnectionID connectionID, - TNC_ConnectionState newState); - TNC_Result (*ReceiveMessage)( - TNC_IMVID imvID, - TNC_ConnectionID connectionID, - TNC_BufferReference message, - TNC_UInt32 messageLength, - TNC_MessageType messageType); - TNC_Result (*SolicitRecommendation)( - TNC_IMVID imvID, - TNC_ConnectionID connectionID); - TNC_Result (*BatchEnding)( - TNC_IMVID imvID, - TNC_ConnectionID connectionID); - TNC_Result (*Terminate)(TNC_IMVID imvID); - TNC_Result (*ProvideBindFunction)( - TNC_IMVID imvID, - TNC_TNCS_BindFunctionPointer bindFunction); -}; - - -#define TNC_MAX_IMV_ID 10 - -struct tncs_data { - struct tncs_data *next; - struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */ - TNC_ConnectionID connectionID; - unsigned int last_batchid; - enum IMV_Action_Recommendation recommendation; - int done; - - struct conn_imv { - u8 *imv_send; - size_t imv_send_len; - enum IMV_Action_Recommendation recommendation; - int recommendation_set; - } imv_data[TNC_MAX_IMV_ID]; - - char *tncs_message; -}; - - -struct tncs_global { - struct tnc_if_imv *imv; - TNC_ConnectionID next_conn_id; - struct tncs_data *connections; -}; - -static struct tncs_global *tncs_global_data = NULL; - - -static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID) -{ - struct tnc_if_imv *imv; - - if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL) - return NULL; - imv = tncs_global_data->imv; - while (imv) { - if (imv->imvID == imvID) - return imv; - imv = imv->next; - } - return NULL; -} - - -static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID) -{ - struct tncs_data *tncs; - - if (tncs_global_data == NULL) - return NULL; - - tncs = tncs_global_data->connections; - while (tncs) { - if (tncs->connectionID == connectionID) - return tncs; - tncs = tncs->next; - } - - wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found", - (unsigned long) connectionID); - - return NULL; -} - - -/* TNCS functions that IMVs can call */ -TNC_Result TNC_TNCS_ReportMessageTypes( - TNC_IMVID imvID, - TNC_MessageTypeList supportedTypes, - TNC_UInt32 typeCount) -{ - TNC_UInt32 i; - struct tnc_if_imv *imv; - - wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu " - "typeCount=%lu)", - (unsigned long) imvID, (unsigned long) typeCount); - - for (i = 0; i < typeCount; i++) { - wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu", - i, supportedTypes[i]); - } - - imv = tncs_get_imv(imvID); - if (imv == NULL) - return TNC_RESULT_INVALID_PARAMETER; - os_free(imv->supported_types); - imv->supported_types = - os_malloc(typeCount * sizeof(TNC_MessageType)); - if (imv->supported_types == NULL) - return TNC_RESULT_FATAL; - os_memcpy(imv->supported_types, supportedTypes, - typeCount * sizeof(TNC_MessageType)); - imv->num_supported_types = typeCount; - - return TNC_RESULT_SUCCESS; -} - - -TNC_Result TNC_TNCS_SendMessage( - TNC_IMVID imvID, - TNC_ConnectionID connectionID, - TNC_BufferReference message, - TNC_UInt32 messageLength, - TNC_MessageType messageType) -{ - struct tncs_data *tncs; - unsigned char *b64; - size_t b64len; - - wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu " - "connectionID=%lu messageType=%lu)", - imvID, connectionID, messageType); - wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage", - message, messageLength); - - if (tncs_get_imv(imvID) == NULL) - return TNC_RESULT_INVALID_PARAMETER; - - tncs = tncs_get_conn(connectionID); - if (tncs == NULL) - return TNC_RESULT_INVALID_PARAMETER; - - b64 = base64_encode(message, messageLength, &b64len); - if (b64 == NULL) - return TNC_RESULT_FATAL; - - os_free(tncs->imv_data[imvID].imv_send); - tncs->imv_data[imvID].imv_send_len = 0; - tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100); - if (tncs->imv_data[imvID].imv_send == NULL) { - os_free(b64); - return TNC_RESULT_OTHER; - } - - tncs->imv_data[imvID].imv_send_len = - os_snprintf((char *) tncs->imv_data[imvID].imv_send, - b64len + 100, - "%08X" - "%s", - (unsigned int) messageType, b64); - - os_free(b64); - - return TNC_RESULT_SUCCESS; -} - - -TNC_Result TNC_TNCS_RequestHandshakeRetry( - TNC_IMVID imvID, - TNC_ConnectionID connectionID, - TNC_RetryReason reason) -{ - wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry"); - /* TODO */ - return TNC_RESULT_SUCCESS; -} - - -TNC_Result TNC_TNCS_ProvideRecommendation( - TNC_IMVID imvID, - TNC_ConnectionID connectionID, - TNC_IMV_Action_Recommendation recommendation, - TNC_IMV_Evaluation_Result evaluation) -{ - struct tncs_data *tncs; - - wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu " - "connectionID=%lu recommendation=%lu evaluation=%lu)", - (unsigned long) imvID, (unsigned long) connectionID, - (unsigned long) recommendation, (unsigned long) evaluation); - - if (tncs_get_imv(imvID) == NULL) - return TNC_RESULT_INVALID_PARAMETER; - - tncs = tncs_get_conn(connectionID); - if (tncs == NULL) - return TNC_RESULT_INVALID_PARAMETER; - - tncs->imv_data[imvID].recommendation = recommendation; - tncs->imv_data[imvID].recommendation_set = 1; - - return TNC_RESULT_SUCCESS; -} - - -TNC_Result TNC_TNCS_GetAttribute( - TNC_IMVID imvID, - TNC_ConnectionID connectionID, - TNC_AttributeID attribureID, - TNC_UInt32 bufferLength, - TNC_BufferReference buffer, - TNC_UInt32 *pOutValueLength) -{ - wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute"); - /* TODO */ - return TNC_RESULT_SUCCESS; -} - - -TNC_Result TNC_TNCS_SetAttribute( - TNC_IMVID imvID, - TNC_ConnectionID connectionID, - TNC_AttributeID attribureID, - TNC_UInt32 bufferLength, - TNC_BufferReference buffer) -{ - wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute"); - /* TODO */ - return TNC_RESULT_SUCCESS; -} - - -TNC_Result TNC_TNCS_BindFunction( - TNC_IMVID imvID, - char *functionName, - void **pOutFunctionPointer) -{ - wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, " - "functionName='%s')", (unsigned long) imvID, functionName); - - if (tncs_get_imv(imvID) == NULL) - return TNC_RESULT_INVALID_PARAMETER; - - if (pOutFunctionPointer == NULL) - return TNC_RESULT_INVALID_PARAMETER; - - if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0) - *pOutFunctionPointer = TNC_TNCS_ReportMessageTypes; - else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0) - *pOutFunctionPointer = TNC_TNCS_SendMessage; - else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") == - 0) - *pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry; - else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") == - 0) - *pOutFunctionPointer = TNC_TNCS_ProvideRecommendation; - else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0) - *pOutFunctionPointer = TNC_TNCS_GetAttribute; - else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0) - *pOutFunctionPointer = TNC_TNCS_SetAttribute; - else - *pOutFunctionPointer = NULL; - - return TNC_RESULT_SUCCESS; -} - - -static void * tncs_get_sym(void *handle, char *func) -{ - void *fptr; - - fptr = dlsym(handle, func); - - return fptr; -} - - -static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv) -{ - void *handle = imv->dlhandle; - - /* Mandatory IMV functions */ - imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize"); - if (imv->Initialize == NULL) { - wpa_printf(MSG_ERROR, "TNC: IMV does not export " - "TNC_IMV_Initialize"); - return -1; - } - - imv->SolicitRecommendation = tncs_get_sym( - handle, "TNC_IMV_SolicitRecommendation"); - if (imv->SolicitRecommendation == NULL) { - wpa_printf(MSG_ERROR, "TNC: IMV does not export " - "TNC_IMV_SolicitRecommendation"); - return -1; - } - - imv->ProvideBindFunction = - tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction"); - if (imv->ProvideBindFunction == NULL) { - wpa_printf(MSG_ERROR, "TNC: IMV does not export " - "TNC_IMV_ProvideBindFunction"); - return -1; - } - - /* Optional IMV functions */ - imv->NotifyConnectionChange = - tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange"); - imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage"); - imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding"); - imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate"); - - return 0; -} - - -static int tncs_imv_initialize(struct tnc_if_imv *imv) -{ - TNC_Result res; - TNC_Version imv_ver; - - wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'", - imv->name); - res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1, - TNC_IFIMV_VERSION_1, &imv_ver); - wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu", - (unsigned long) res, (unsigned long) imv_ver); - - return res == TNC_RESULT_SUCCESS ? 0 : -1; -} - - -static int tncs_imv_terminate(struct tnc_if_imv *imv) -{ - TNC_Result res; - - if (imv->Terminate == NULL) - return 0; - - wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'", - imv->name); - res = imv->Terminate(imv->imvID); - wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu", - (unsigned long) res); - - return res == TNC_RESULT_SUCCESS ? 0 : -1; -} - - -static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv) -{ - TNC_Result res; - - wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for " - "IMV '%s'", imv->name); - res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction); - wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu", - (unsigned long) res); - - return res == TNC_RESULT_SUCCESS ? 0 : -1; -} - - -static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv, - TNC_ConnectionID conn, - TNC_ConnectionState state) -{ - TNC_Result res; - - if (imv->NotifyConnectionChange == NULL) - return 0; - - wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)" - " for IMV '%s'", (int) state, imv->name); - res = imv->NotifyConnectionChange(imv->imvID, conn, state); - wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu", - (unsigned long) res); - - return res == TNC_RESULT_SUCCESS ? 0 : -1; -} - - -static int tncs_load_imv(struct tnc_if_imv *imv) -{ - if (imv->path == NULL) { - wpa_printf(MSG_DEBUG, "TNC: No IMV configured"); - return -1; - } - - wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)", - imv->name, imv->path); - imv->dlhandle = dlopen(imv->path, RTLD_LAZY); - if (imv->dlhandle == NULL) { - wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s", - imv->name, imv->path, dlerror()); - return -1; - } - - if (tncs_imv_resolve_funcs(imv) < 0) { - wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions"); - return -1; - } - - if (tncs_imv_initialize(imv) < 0 || - tncs_imv_provide_bind_function(imv) < 0) { - wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV"); - return -1; - } - - return 0; -} - - -static void tncs_free_imv(struct tnc_if_imv *imv) -{ - os_free(imv->name); - os_free(imv->path); - os_free(imv->supported_types); -} - -static void tncs_unload_imv(struct tnc_if_imv *imv) -{ - tncs_imv_terminate(imv); - - if (imv->dlhandle) - dlclose(imv->dlhandle); - - tncs_free_imv(imv); -} - - -static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type) -{ - size_t i; - unsigned int vendor, subtype; - - if (imv == NULL || imv->supported_types == NULL) - return 0; - - vendor = type >> 8; - subtype = type & 0xff; - - for (i = 0; i < imv->num_supported_types; i++) { - unsigned int svendor, ssubtype; - svendor = imv->supported_types[i] >> 8; - ssubtype = imv->supported_types[i] & 0xff; - if ((vendor == svendor || svendor == TNC_VENDORID_ANY) && - (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY)) - return 1; - } - - return 0; -} - - -static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type, - const u8 *msg, size_t len) -{ - struct tnc_if_imv *imv; - TNC_Result res; - - wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len); - - for (imv = tncs->imv; imv; imv = imv->next) { - if (imv->ReceiveMessage == NULL || - !tncs_supported_type(imv, type)) - continue; - - wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'", - imv->name); - res = imv->ReceiveMessage(imv->imvID, tncs->connectionID, - (TNC_BufferReference) msg, len, - type); - wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu", - (unsigned long) res); - } -} - - -static void tncs_batch_ending(struct tncs_data *tncs) -{ - struct tnc_if_imv *imv; - TNC_Result res; - - for (imv = tncs->imv; imv; imv = imv->next) { - if (imv->BatchEnding == NULL) - continue; - - wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'", - imv->name); - res = imv->BatchEnding(imv->imvID, tncs->connectionID); - wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu", - (unsigned long) res); - } -} - - -static void tncs_solicit_recommendation(struct tncs_data *tncs) -{ - struct tnc_if_imv *imv; - TNC_Result res; - - for (imv = tncs->imv; imv; imv = imv->next) { - if (tncs->imv_data[imv->imvID].recommendation_set) - continue; - - wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for " - "IMV '%s'", imv->name); - res = imv->SolicitRecommendation(imv->imvID, - tncs->connectionID); - wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu", - (unsigned long) res); - } -} - - -void tncs_init_connection(struct tncs_data *tncs) -{ - struct tnc_if_imv *imv; - int i; - - for (imv = tncs->imv; imv; imv = imv->next) { - tncs_imv_notify_connection_change( - imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE); - tncs_imv_notify_connection_change( - imv, tncs->connectionID, - TNC_CONNECTION_STATE_HANDSHAKE); - } - - for (i = 0; i < TNC_MAX_IMV_ID; i++) { - os_free(tncs->imv_data[i].imv_send); - tncs->imv_data[i].imv_send = NULL; - tncs->imv_data[i].imv_send_len = 0; - } -} - - -size_t tncs_total_send_len(struct tncs_data *tncs) -{ - int i; - size_t len = 0; - - for (i = 0; i < TNC_MAX_IMV_ID; i++) - len += tncs->imv_data[i].imv_send_len; - if (tncs->tncs_message) - len += os_strlen(tncs->tncs_message); - return len; -} - - -u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos) -{ - int i; - - for (i = 0; i < TNC_MAX_IMV_ID; i++) { - if (tncs->imv_data[i].imv_send == NULL) - continue; - - os_memcpy(pos, tncs->imv_data[i].imv_send, - tncs->imv_data[i].imv_send_len); - pos += tncs->imv_data[i].imv_send_len; - os_free(tncs->imv_data[i].imv_send); - tncs->imv_data[i].imv_send = NULL; - tncs->imv_data[i].imv_send_len = 0; - } - - if (tncs->tncs_message) { - size_t len = os_strlen(tncs->tncs_message); - os_memcpy(pos, tncs->tncs_message, len); - pos += len; - os_free(tncs->tncs_message); - tncs->tncs_message = NULL; - } - - return pos; -} - - -char * tncs_if_tnccs_start(struct tncs_data *tncs) -{ - char *buf = os_malloc(1000); - if (buf == NULL) - return NULL; - tncs->last_batchid++; - os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid); - return buf; -} - - -char * tncs_if_tnccs_end(void) -{ - char *buf = os_malloc(100); - if (buf == NULL) - return NULL; - os_snprintf(buf, 100, IF_TNCCS_END); - return buf; -} - - -static int tncs_get_type(char *start, unsigned int *type) -{ - char *pos = os_strstr(start, ""); - if (pos == NULL) - return -1; - pos += 6; - *type = strtoul(pos, NULL, 16); - return 0; -} - - -static unsigned char * tncs_get_base64(char *start, size_t *decoded_len) -{ - char *pos, *pos2; - unsigned char *decoded; - - pos = os_strstr(start, ""); - if (pos == NULL) - return NULL; - - pos += 8; - pos2 = os_strstr(pos, ""); - if (pos2 == NULL) - return NULL; - *pos2 = '\0'; - - decoded = base64_decode((unsigned char *) pos, os_strlen(pos), - decoded_len); - *pos2 = '<'; - if (decoded == NULL) { - wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data"); - } - - return decoded; -} - - -static enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs) -{ - enum IMV_Action_Recommendation rec; - struct tnc_if_imv *imv; - TNC_ConnectionState state; - char *txt; - - wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs"); - - if (tncs->done) - return TNCCS_PROCESS_OK_NO_RECOMMENDATION; - - tncs_solicit_recommendation(tncs); - - /* Select the most restrictive recommendation */ - rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; - for (imv = tncs->imv; imv; imv = imv->next) { - TNC_IMV_Action_Recommendation irec; - irec = tncs->imv_data[imv->imvID].recommendation; - if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS) - rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS; - if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE && - rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS) - rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE; - if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW && - rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION) - rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW; - } - - wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec); - tncs->recommendation = rec; - tncs->done = 1; - - txt = NULL; - switch (rec) { - case TNC_IMV_ACTION_RECOMMENDATION_ALLOW: - case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION: - txt = "allow"; - state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; - break; - case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE: - txt = "isolate"; - state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; - break; - case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS: - txt = "none"; - state = TNC_CONNECTION_STATE_ACCESS_NONE; - break; - default: - state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; - break; - } - - if (txt) { - os_free(tncs->tncs_message); - tncs->tncs_message = os_zalloc(200); - if (tncs->tncs_message) { - os_snprintf(tncs->tncs_message, 199, - "%08X" - "" - "" - "", - TNC_TNCCS_RECOMMENDATION, txt); - } - } - - for (imv = tncs->imv; imv; imv = imv->next) { - tncs_imv_notify_connection_change(imv, tncs->connectionID, - state); - } - - switch (rec) { - case TNC_IMV_ACTION_RECOMMENDATION_ALLOW: - return TNCCS_RECOMMENDATION_ALLOW; - case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS: - return TNCCS_RECOMMENDATION_NO_ACCESS; - case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE: - return TNCCS_RECOMMENDATION_ISOLATE; - case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION: - return TNCCS_RECOMMENDATION_NO_RECOMMENDATION; - default: - return TNCCS_PROCESS_ERROR; - } -} - - -enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs, - const u8 *msg, size_t len) -{ - char *buf, *start, *end, *pos, *pos2, *payload; - unsigned int batch_id; - unsigned char *decoded; - size_t decoded_len; - - buf = dup_binstr(msg, len); - if (buf == NULL) - return TNCCS_PROCESS_ERROR; - - start = os_strstr(buf, ""); - if (start == NULL || end == NULL || start > end) { - os_free(buf); - return TNCCS_PROCESS_ERROR; - } - - start += 13; - while (*start == ' ') - start++; - *end = '\0'; - - pos = os_strstr(start, "BatchId="); - if (pos == NULL) { - os_free(buf); - return TNCCS_PROCESS_ERROR; - } - - pos += 8; - if (*pos == '"') - pos++; - batch_id = atoi(pos); - wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u", - batch_id); - if (batch_id != tncs->last_batchid + 1) { - wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId " - "%u (expected %u)", - batch_id, tncs->last_batchid + 1); - os_free(buf); - return TNCCS_PROCESS_ERROR; - } - tncs->last_batchid = batch_id; - - while (*pos != '\0' && *pos != '>') - pos++; - if (*pos == '\0') { - os_free(buf); - return TNCCS_PROCESS_ERROR; - } - pos++; - payload = start; - - /* - * - * 01234567 - * foo== - * - */ - - while (*start) { - char *endpos; - unsigned int type; - - pos = os_strstr(start, ""); - if (pos == NULL) - break; - start = pos + 17; - end = os_strstr(start, ""); - if (end == NULL) - break; - *end = '\0'; - endpos = end; - end += 18; - - if (tncs_get_type(start, &type) < 0) { - *endpos = '<'; - start = end; - continue; - } - wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type); - - decoded = tncs_get_base64(start, &decoded_len); - if (decoded == NULL) { - *endpos = '<'; - start = end; - continue; - } - - tncs_send_to_imvs(tncs, type, decoded, decoded_len); - - os_free(decoded); - - start = end; - } - - /* - * - * 01234567 - * - * foo== - * - */ - - start = payload; - while (*start) { - unsigned int type; - char *xml, *xmlend, *endpos; - - pos = os_strstr(start, ""); - if (pos == NULL) - break; - start = pos + 19; - end = os_strstr(start, ""); - if (end == NULL) - break; - *end = '\0'; - endpos = end; - end += 20; - - if (tncs_get_type(start, &type) < 0) { - *endpos = '<'; - start = end; - continue; - } - wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x", - type); - - /* Base64 OR XML */ - decoded = NULL; - xml = NULL; - xmlend = NULL; - pos = os_strstr(start, ""); - if (pos) { - pos += 5; - pos2 = os_strstr(pos, ""); - if (pos2 == NULL) { - *endpos = '<'; - start = end; - continue; - } - xmlend = pos2; - xml = pos; - } else { - decoded = tncs_get_base64(start, &decoded_len); - if (decoded == NULL) { - *endpos = '<'; - start = end; - continue; - } - } - - if (decoded) { - wpa_hexdump_ascii(MSG_MSGDUMP, - "TNC: TNCC-TNCS-Message Base64", - decoded, decoded_len); - os_free(decoded); - } - - if (xml) { - wpa_hexdump_ascii(MSG_MSGDUMP, - "TNC: TNCC-TNCS-Message XML", - (unsigned char *) xml, - xmlend - xml); - } - - start = end; - } - - os_free(buf); - - tncs_batch_ending(tncs); - - if (tncs_total_send_len(tncs) == 0) - return tncs_derive_recommendation(tncs); - - return TNCCS_PROCESS_OK_NO_RECOMMENDATION; -} - - -static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end, - int *error) -{ - struct tnc_if_imv *imv; - char *pos, *pos2; - - if (id >= TNC_MAX_IMV_ID) { - wpa_printf(MSG_DEBUG, "TNC: Too many IMVs"); - return NULL; - } - - imv = os_zalloc(sizeof(*imv)); - if (imv == NULL) { - *error = 1; - return NULL; - } - - imv->imvID = id; - - pos = start; - wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos); - if (pos + 1 >= end || *pos != '"') { - wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' " - "(no starting quotation mark)", start); - os_free(imv); - return NULL; - } - - pos++; - pos2 = pos; - while (pos2 < end && *pos2 != '"') - pos2++; - if (pos2 >= end) { - wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' " - "(no ending quotation mark)", start); - os_free(imv); - return NULL; - } - *pos2 = '\0'; - wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos); - imv->name = os_strdup(pos); - - pos = pos2 + 1; - if (pos >= end || *pos != ' ') { - wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' " - "(no space after name)", start); - os_free(imv); - return NULL; - } - - pos++; - wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos); - imv->path = os_strdup(pos); - - return imv; -} - - -static int tncs_read_config(struct tncs_global *global) -{ - char *config, *end, *pos, *line_end; - size_t config_len; - struct tnc_if_imv *imv, *last; - int id = 0; - - last = NULL; - - config = os_readfile(TNC_CONFIG_FILE, &config_len); - if (config == NULL) { - wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration " - "file '%s'", TNC_CONFIG_FILE); - return -1; - } - - end = config + config_len; - for (pos = config; pos < end; pos = line_end + 1) { - line_end = pos; - while (*line_end != '\n' && *line_end != '\r' && - line_end < end) - line_end++; - *line_end = '\0'; - - if (os_strncmp(pos, "IMV ", 4) == 0) { - int error = 0; - - imv = tncs_parse_imv(id++, pos + 4, line_end, &error); - if (error) - return -1; - if (imv) { - if (last == NULL) - global->imv = imv; - else - last->next = imv; - last = imv; - } - } - } - - os_free(config); - - return 0; -} - - -struct tncs_data * tncs_init(void) -{ - struct tncs_data *tncs; - - if (tncs_global_data == NULL) - return NULL; - - tncs = os_zalloc(sizeof(*tncs)); - if (tncs == NULL) - return NULL; - tncs->imv = tncs_global_data->imv; - tncs->connectionID = tncs_global_data->next_conn_id++; - tncs->next = tncs_global_data->connections; - tncs_global_data->connections = tncs; - - return tncs; -} - - -void tncs_deinit(struct tncs_data *tncs) -{ - int i; - struct tncs_data *prev, *conn; - - if (tncs == NULL) - return; - - for (i = 0; i < TNC_MAX_IMV_ID; i++) - os_free(tncs->imv_data[i].imv_send); - - prev = NULL; - conn = tncs_global_data->connections; - while (conn) { - if (conn == tncs) { - if (prev) - prev->next = tncs->next; - else - tncs_global_data->connections = tncs->next; - break; - } - prev = conn; - conn = conn->next; - } - - os_free(tncs->tncs_message); - os_free(tncs); -} - - -int tncs_global_init(void) -{ - struct tnc_if_imv *imv; - - tncs_global_data = os_zalloc(sizeof(*tncs_global_data)); - if (tncs_global_data == NULL) - return -1; - - if (tncs_read_config(tncs_global_data) < 0) { - wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration"); - goto failed; - } - - for (imv = tncs_global_data->imv; imv; imv = imv->next) { - if (tncs_load_imv(imv)) { - wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'", - imv->name); - goto failed; - } - } - - return 0; - -failed: - tncs_global_deinit(); - return -1; -} - - -void tncs_global_deinit(void) -{ - struct tnc_if_imv *imv, *prev; - - if (tncs_global_data == NULL) - return; - - imv = tncs_global_data->imv; - while (imv) { - tncs_unload_imv(imv); - - prev = imv; - imv = imv->next; - os_free(prev); - } - - os_free(tncs_global_data); - tncs_global_data = NULL; -} - - -struct wpabuf * tncs_build_soh_request(void) -{ - struct wpabuf *buf; - - /* - * Build a SoH Request TLV (to be used inside SoH EAP Extensions - * Method) - */ - - buf = wpabuf_alloc(8 + 4); - if (buf == NULL) - return NULL; - - /* Vendor-Specific TLV (Microsoft) - SoH Request */ - wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */ - wpabuf_put_be16(buf, 8); /* Length */ - - wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */ - - wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */ - wpabuf_put_be16(buf, 0); /* Length */ - - return buf; -} - - -struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len, - int *failure) -{ - wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len); - *failure = 0; - - /* TODO: return MS-SoH Response TLV */ - - return NULL; -} diff --git a/contrib/hostapd/src/eap_server/tncs.h b/contrib/hostapd/src/eap_server/tncs.h deleted file mode 100644 index ac7251bf8c..0000000000 --- a/contrib/hostapd/src/eap_server/tncs.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH) - * Copyright (c) 2007-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef TNCS_H -#define TNCS_H - -struct tncs_data; - -struct tncs_data * tncs_init(void); -void tncs_deinit(struct tncs_data *tncs); -void tncs_init_connection(struct tncs_data *tncs); -size_t tncs_total_send_len(struct tncs_data *tncs); -u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos); -char * tncs_if_tnccs_start(struct tncs_data *tncs); -char * tncs_if_tnccs_end(void); - -enum tncs_process_res { - TNCCS_PROCESS_ERROR = -1, - TNCCS_PROCESS_OK_NO_RECOMMENDATION = 0, - TNCCS_RECOMMENDATION_ERROR, - TNCCS_RECOMMENDATION_ALLOW, - TNCCS_RECOMMENDATION_NONE, - TNCCS_RECOMMENDATION_ISOLATE, - TNCCS_RECOMMENDATION_NO_ACCESS, - TNCCS_RECOMMENDATION_NO_RECOMMENDATION -}; - -enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs, - const u8 *msg, size_t len); - -int tncs_global_init(void); -void tncs_global_deinit(void); - -struct wpabuf * tncs_build_soh_request(void); -struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len, - int *failure); - -#endif /* TNCS_H */ diff --git a/contrib/hostapd/src/eapol_auth/eapol_auth_dump.c b/contrib/hostapd/src/eapol_auth/eapol_auth_dump.c deleted file mode 100644 index 6c6969b5c9..0000000000 --- a/contrib/hostapd/src/eapol_auth/eapol_auth_dump.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * IEEE 802.1X-2004 Authenticator - State dump - * Copyright (c) 2002-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_server/eap.h" -#include "eapol_auth_sm.h" -#include "eapol_auth_sm_i.h" - -static inline const char * port_type_txt(PortTypes pt) -{ - switch (pt) { - case ForceUnauthorized: return "ForceUnauthorized"; - case ForceAuthorized: return "ForceAuthorized"; - case Auto: return "Auto"; - default: return "Unknown"; - } -} - - -static inline const char * port_state_txt(PortState ps) -{ - switch (ps) { - case Unauthorized: return "Unauthorized"; - case Authorized: return "Authorized"; - default: return "Unknown"; - } -} - - -static inline const char * ctrl_dir_txt(ControlledDirection dir) -{ - switch (dir) { - case Both: return "Both"; - case In: return "In"; - default: return "Unknown"; - } -} - - -static inline const char * auth_pae_state_txt(int s) -{ - switch (s) { - case AUTH_PAE_INITIALIZE: return "INITIALIZE"; - case AUTH_PAE_DISCONNECTED: return "DISCONNECTED"; - case AUTH_PAE_CONNECTING: return "CONNECTING"; - case AUTH_PAE_AUTHENTICATING: return "AUTHENTICATING"; - case AUTH_PAE_AUTHENTICATED: return "AUTHENTICATED"; - case AUTH_PAE_ABORTING: return "ABORTING"; - case AUTH_PAE_HELD: return "HELD"; - case AUTH_PAE_FORCE_AUTH: return "FORCE_AUTH"; - case AUTH_PAE_FORCE_UNAUTH: return "FORCE_UNAUTH"; - case AUTH_PAE_RESTART: return "RESTART"; - default: return "Unknown"; - } -} - - -static inline const char * be_auth_state_txt(int s) -{ - switch (s) { - case BE_AUTH_REQUEST: return "REQUEST"; - case BE_AUTH_RESPONSE: return "RESPONSE"; - case BE_AUTH_SUCCESS: return "SUCCESS"; - case BE_AUTH_FAIL: return "FAIL"; - case BE_AUTH_TIMEOUT: return "TIMEOUT"; - case BE_AUTH_IDLE: return "IDLE"; - case BE_AUTH_INITIALIZE: return "INITIALIZE"; - case BE_AUTH_IGNORE: return "IGNORE"; - default: return "Unknown"; - } -} - - -static inline const char * reauth_timer_state_txt(int s) -{ - switch (s) { - case REAUTH_TIMER_INITIALIZE: return "INITIALIZE"; - case REAUTH_TIMER_REAUTHENTICATE: return "REAUTHENTICATE"; - default: return "Unknown"; - } -} - - -static inline const char * auth_key_tx_state_txt(int s) -{ - switch (s) { - case AUTH_KEY_TX_NO_KEY_TRANSMIT: return "NO_KEY_TRANSMIT"; - case AUTH_KEY_TX_KEY_TRANSMIT: return "KEY_TRANSMIT"; - default: return "Unknown"; - } -} - - -static inline const char * key_rx_state_txt(int s) -{ - switch (s) { - case KEY_RX_NO_KEY_RECEIVE: return "NO_KEY_RECEIVE"; - case KEY_RX_KEY_RECEIVE: return "KEY_RECEIVE"; - default: return "Unknown"; - } -} - - -static inline const char * ctrl_dir_state_txt(int s) -{ - switch (s) { - case CTRL_DIR_FORCE_BOTH: return "FORCE_BOTH"; - case CTRL_DIR_IN_OR_BOTH: return "IN_OR_BOTH"; - default: return "Unknown"; - } -} - - -int eapol_auth_dump_state(struct eapol_state_machine *sm, char *buf, - size_t buflen) -{ - char *pos, *end; - int ret; - - pos = buf; - end = pos + buflen; - - ret = os_snprintf(pos, end - pos, "aWhile=%d\nquietWhile=%d\n" - "reAuthWhen=%d\n", - sm->aWhile, sm->quietWhile, sm->reAuthWhen); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - -#define _SB(b) ((b) ? "TRUE" : "FALSE") - ret = os_snprintf(pos, end - pos, - "authAbort=%s\n" - "authFail=%s\n" - "authPortStatus=%s\n" - "authStart=%s\n" - "authTimeout=%s\n" - "authSuccess=%s\n" - "eapFail=%s\n" - "eapolEap=%s\n" - "eapSuccess=%s\n" - "eapTimeout=%s\n" - "initialize=%s\n" - "keyAvailable=%s\n" - "keyDone=%s\n" - "keyRun=%s\n" - "keyTxEnabled=%s\n" - "portControl=%s\n" - "portEnabled=%s\n" - "portValid=%s\n" - "reAuthenticate=%s\n", - _SB(sm->authAbort), - _SB(sm->authFail), - port_state_txt(sm->authPortStatus), - _SB(sm->authStart), - _SB(sm->authTimeout), - _SB(sm->authSuccess), - _SB(sm->eap_if->eapFail), - _SB(sm->eapolEap), - _SB(sm->eap_if->eapSuccess), - _SB(sm->eap_if->eapTimeout), - _SB(sm->initialize), - _SB(sm->eap_if->eapKeyAvailable), - _SB(sm->keyDone), _SB(sm->keyRun), - _SB(sm->keyTxEnabled), - port_type_txt(sm->portControl), - _SB(sm->eap_if->portEnabled), - _SB(sm->portValid), - _SB(sm->reAuthenticate)); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - ret = os_snprintf(pos, end - pos, - "auth_pae_state=%s\n" - "eapolLogoff=%s\n" - "eapolStart=%s\n" - "eapRestart=%s\n" - "portMode=%s\n" - "reAuthCount=%d\n" - "quietPeriod=%d\n" - "reAuthMax=%d\n" - "authEntersConnecting=%d\n" - "authEapLogoffsWhileConnecting=%d\n" - "authEntersAuthenticating=%d\n" - "authAuthSuccessesWhileAuthenticating=%d\n" - "authAuthTimeoutsWhileAuthenticating=%d\n" - "authAuthFailWhileAuthenticating=%d\n" - "authAuthEapStartsWhileAuthenticating=%d\n" - "authAuthEapLogoffWhileAuthenticating=%d\n" - "authAuthReauthsWhileAuthenticated=%d\n" - "authAuthEapStartsWhileAuthenticated=%d\n" - "authAuthEapLogoffWhileAuthenticated=%d\n", - auth_pae_state_txt(sm->auth_pae_state), - _SB(sm->eapolLogoff), - _SB(sm->eapolStart), - _SB(sm->eap_if->eapRestart), - port_type_txt(sm->portMode), - sm->reAuthCount, - sm->quietPeriod, sm->reAuthMax, - sm->authEntersConnecting, - sm->authEapLogoffsWhileConnecting, - sm->authEntersAuthenticating, - sm->authAuthSuccessesWhileAuthenticating, - sm->authAuthTimeoutsWhileAuthenticating, - sm->authAuthFailWhileAuthenticating, - sm->authAuthEapStartsWhileAuthenticating, - sm->authAuthEapLogoffWhileAuthenticating, - sm->authAuthReauthsWhileAuthenticated, - sm->authAuthEapStartsWhileAuthenticated, - sm->authAuthEapLogoffWhileAuthenticated); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - ret = os_snprintf(pos, end - pos, - "be_auth_state=%s\n" - "eapNoReq=%s\n" - "eapReq=%s\n" - "eapResp=%s\n" - "serverTimeout=%d\n" - "backendResponses=%d\n" - "backendAccessChallenges=%d\n" - "backendOtherRequestsToSupplicant=%d\n" - "backendAuthSuccesses=%d\n" - "backendAuthFails=%d\n", - be_auth_state_txt(sm->be_auth_state), - _SB(sm->eap_if->eapNoReq), - _SB(sm->eap_if->eapReq), - _SB(sm->eap_if->eapResp), - sm->serverTimeout, - sm->backendResponses, - sm->backendAccessChallenges, - sm->backendOtherRequestsToSupplicant, - sm->backendAuthSuccesses, - sm->backendAuthFails); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - ret = os_snprintf(pos, end - pos, - "reauth_timer_state=%s\n" - "reAuthPeriod=%d\n" - "reAuthEnabled=%s\n", - reauth_timer_state_txt(sm->reauth_timer_state), - sm->reAuthPeriod, - _SB(sm->reAuthEnabled)); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - ret = os_snprintf(pos, end - pos, - "auth_key_tx_state=%s\n", - auth_key_tx_state_txt(sm->auth_key_tx_state)); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - ret = os_snprintf(pos, end - pos, - "key_rx_state=%s\n" - "rxKey=%s\n", - key_rx_state_txt(sm->key_rx_state), - _SB(sm->rxKey)); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - ret = os_snprintf(pos, end - pos, - "ctrl_dir_state=%s\n" - "adminControlledDirections=%s\n" - "operControlledDirections=%s\n" - "operEdge=%s\n", - ctrl_dir_state_txt(sm->ctrl_dir_state), - ctrl_dir_txt(sm->adminControlledDirections), - ctrl_dir_txt(sm->operControlledDirections), - _SB(sm->operEdge)); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; -#undef _SB - - return pos - buf; -} diff --git a/contrib/hostapd/src/eapol_auth/eapol_auth_sm.c b/contrib/hostapd/src/eapol_auth/eapol_auth_sm.c deleted file mode 100644 index a2577814ec..0000000000 --- a/contrib/hostapd/src/eapol_auth/eapol_auth_sm.c +++ /dev/null @@ -1,1161 +0,0 @@ -/* - * IEEE 802.1X-2004 Authenticator - EAPOL state machine - * Copyright (c) 2002-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eloop.h" -#include "state_machine.h" -#include "common/eapol_common.h" -#include "eap_common/eap_defs.h" -#include "eap_common/eap_common.h" -#include "eap_server/eap.h" -#include "eapol_auth_sm.h" -#include "eapol_auth_sm_i.h" - -#define STATE_MACHINE_DATA struct eapol_state_machine -#define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X" -#define STATE_MACHINE_ADDR sm->addr - -static struct eapol_callbacks eapol_cb; - -/* EAPOL state machines are described in IEEE Std 802.1X-2004, Chap. 8.2 */ - -#define setPortAuthorized() \ -sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 1) -#define setPortUnauthorized() \ -sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 0) - -/* procedures */ -#define txCannedFail() eapol_auth_tx_canned_eap(sm, 0) -#define txCannedSuccess() eapol_auth_tx_canned_eap(sm, 1) -#define txReq() eapol_auth_tx_req(sm) -#define abortAuth() sm->eapol->cb.abort_auth(sm->eapol->conf.ctx, sm->sta) -#define txKey() sm->eapol->cb.tx_key(sm->eapol->conf.ctx, sm->sta) -#define processKey() do { } while (0) - - -static void eapol_sm_step_run(struct eapol_state_machine *sm); -static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx); -static void eapol_auth_initialize(struct eapol_state_machine *sm); - - -static void eapol_auth_logger(struct eapol_authenticator *eapol, - const u8 *addr, eapol_logger_level level, - const char *txt) -{ - if (eapol->cb.logger == NULL) - return; - eapol->cb.logger(eapol->conf.ctx, addr, level, txt); -} - - -static void eapol_auth_vlogger(struct eapol_authenticator *eapol, - const u8 *addr, eapol_logger_level level, - const char *fmt, ...) -{ - char *format; - int maxlen; - va_list ap; - - if (eapol->cb.logger == NULL) - return; - - maxlen = os_strlen(fmt) + 100; - format = os_malloc(maxlen); - if (!format) - return; - - va_start(ap, fmt); - vsnprintf(format, maxlen, fmt, ap); - va_end(ap); - - eapol_auth_logger(eapol, addr, level, format); - - os_free(format); -} - - -static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm, - int success) -{ - struct eap_hdr eap; - - os_memset(&eap, 0, sizeof(eap)); - - eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE; - eap.identifier = ++sm->last_eap_id; - eap.length = host_to_be16(sizeof(eap)); - - eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG, - "Sending canned EAP packet %s (identifier %d)", - success ? "SUCCESS" : "FAILURE", eap.identifier); - sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta, - IEEE802_1X_TYPE_EAP_PACKET, - (u8 *) &eap, sizeof(eap)); - sm->dot1xAuthEapolFramesTx++; -} - - -static void eapol_auth_tx_req(struct eapol_state_machine *sm) -{ - if (sm->eap_if->eapReqData == NULL || - wpabuf_len(sm->eap_if->eapReqData) < sizeof(struct eap_hdr)) { - eapol_auth_logger(sm->eapol, sm->addr, - EAPOL_LOGGER_DEBUG, - "TxReq called, but there is no EAP request " - "from authentication server"); - return; - } - - if (sm->flags & EAPOL_SM_WAIT_START) { - wpa_printf(MSG_DEBUG, "EAPOL: Drop EAPOL TX to " MACSTR - " while waiting for EAPOL-Start", - MAC2STR(sm->addr)); - return; - } - - sm->last_eap_id = eap_get_id(sm->eap_if->eapReqData); - eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG, - "Sending EAP Packet (identifier %d)", - sm->last_eap_id); - sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta, - IEEE802_1X_TYPE_EAP_PACKET, - wpabuf_head(sm->eap_if->eapReqData), - wpabuf_len(sm->eap_if->eapReqData)); - sm->dot1xAuthEapolFramesTx++; - if (eap_get_type(sm->eap_if->eapReqData) == EAP_TYPE_IDENTITY) - sm->dot1xAuthEapolReqIdFramesTx++; - else - sm->dot1xAuthEapolReqFramesTx++; -} - - -/** - * eapol_port_timers_tick - Port Timers state machine - * @eloop_ctx: struct eapol_state_machine * - * @timeout_ctx: Not used - * - * This statemachine is implemented as a function that will be called - * once a second as a registered event loop timeout. - */ -static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx) -{ - struct eapol_state_machine *state = timeout_ctx; - - if (state->aWhile > 0) { - state->aWhile--; - if (state->aWhile == 0) { - wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR - " - aWhile --> 0", - MAC2STR(state->addr)); - } - } - - if (state->quietWhile > 0) { - state->quietWhile--; - if (state->quietWhile == 0) { - wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR - " - quietWhile --> 0", - MAC2STR(state->addr)); - } - } - - if (state->reAuthWhen > 0) { - state->reAuthWhen--; - if (state->reAuthWhen == 0) { - wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR - " - reAuthWhen --> 0", - MAC2STR(state->addr)); - } - } - - if (state->eap_if->retransWhile > 0) { - state->eap_if->retransWhile--; - if (state->eap_if->retransWhile == 0) { - wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR - " - (EAP) retransWhile --> 0", - MAC2STR(state->addr)); - } - } - - eapol_sm_step_run(state); - - eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state); -} - - - -/* Authenticator PAE state machine */ - -SM_STATE(AUTH_PAE, INITIALIZE) -{ - SM_ENTRY_MA(AUTH_PAE, INITIALIZE, auth_pae); - sm->portMode = Auto; -} - - -SM_STATE(AUTH_PAE, DISCONNECTED) -{ - int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE; - - if (sm->eapolLogoff) { - if (sm->auth_pae_state == AUTH_PAE_CONNECTING) - sm->authEapLogoffsWhileConnecting++; - else if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) - sm->authAuthEapLogoffWhileAuthenticated++; - } - - SM_ENTRY_MA(AUTH_PAE, DISCONNECTED, auth_pae); - - sm->authPortStatus = Unauthorized; - setPortUnauthorized(); - sm->reAuthCount = 0; - sm->eapolLogoff = FALSE; - if (!from_initialize) { - sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0, - sm->flags & EAPOL_SM_PREAUTH); - } -} - - -SM_STATE(AUTH_PAE, RESTART) -{ - if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) { - if (sm->reAuthenticate) - sm->authAuthReauthsWhileAuthenticated++; - if (sm->eapolStart) - sm->authAuthEapStartsWhileAuthenticated++; - if (sm->eapolLogoff) - sm->authAuthEapLogoffWhileAuthenticated++; - } - - SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae); - - sm->eap_if->eapRestart = TRUE; -} - - -SM_STATE(AUTH_PAE, CONNECTING) -{ - if (sm->auth_pae_state != AUTH_PAE_CONNECTING) - sm->authEntersConnecting++; - - SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae); - - sm->reAuthenticate = FALSE; - sm->reAuthCount++; -} - - -SM_STATE(AUTH_PAE, HELD) -{ - if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authFail) - sm->authAuthFailWhileAuthenticating++; - - SM_ENTRY_MA(AUTH_PAE, HELD, auth_pae); - - sm->authPortStatus = Unauthorized; - setPortUnauthorized(); - sm->quietWhile = sm->quietPeriod; - sm->eapolLogoff = FALSE; - - eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING, - "authentication failed - EAP type: %d (%s)", - sm->eap_type_authsrv, - eap_server_get_name(0, sm->eap_type_authsrv)); - if (sm->eap_type_authsrv != sm->eap_type_supp) { - eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO, - "Supplicant used different EAP type: " - "%d (%s)", sm->eap_type_supp, - eap_server_get_name(0, sm->eap_type_supp)); - } - sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0, - sm->flags & EAPOL_SM_PREAUTH); -} - - -SM_STATE(AUTH_PAE, AUTHENTICATED) -{ - char *extra = ""; - - if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess) - sm->authAuthSuccessesWhileAuthenticating++; - - SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae); - - sm->authPortStatus = Authorized; - setPortAuthorized(); - sm->reAuthCount = 0; - if (sm->flags & EAPOL_SM_PREAUTH) - extra = " (pre-authentication)"; - else if (sm->flags & EAPOL_SM_FROM_PMKSA_CACHE) - extra = " (PMKSA cache)"; - eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO, - "authenticated - EAP type: %d (%s)%s", - sm->eap_type_authsrv, - eap_server_get_name(0, sm->eap_type_authsrv), - extra); - sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1, - sm->flags & EAPOL_SM_PREAUTH); -} - - -SM_STATE(AUTH_PAE, AUTHENTICATING) -{ - SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae); - - sm->eapolStart = FALSE; - sm->authSuccess = FALSE; - sm->authFail = FALSE; - sm->authTimeout = FALSE; - sm->authStart = TRUE; - sm->keyRun = FALSE; - sm->keyDone = FALSE; -} - - -SM_STATE(AUTH_PAE, ABORTING) -{ - if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING) { - if (sm->authTimeout) - sm->authAuthTimeoutsWhileAuthenticating++; - if (sm->eapolStart) - sm->authAuthEapStartsWhileAuthenticating++; - if (sm->eapolLogoff) - sm->authAuthEapLogoffWhileAuthenticating++; - } - - SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae); - - sm->authAbort = TRUE; - sm->keyRun = FALSE; - sm->keyDone = FALSE; -} - - -SM_STATE(AUTH_PAE, FORCE_AUTH) -{ - SM_ENTRY_MA(AUTH_PAE, FORCE_AUTH, auth_pae); - - sm->authPortStatus = Authorized; - setPortAuthorized(); - sm->portMode = ForceAuthorized; - sm->eapolStart = FALSE; - txCannedSuccess(); -} - - -SM_STATE(AUTH_PAE, FORCE_UNAUTH) -{ - SM_ENTRY_MA(AUTH_PAE, FORCE_UNAUTH, auth_pae); - - sm->authPortStatus = Unauthorized; - setPortUnauthorized(); - sm->portMode = ForceUnauthorized; - sm->eapolStart = FALSE; - txCannedFail(); -} - - -SM_STEP(AUTH_PAE) -{ - if ((sm->portControl == Auto && sm->portMode != sm->portControl) || - sm->initialize || !sm->eap_if->portEnabled) - SM_ENTER_GLOBAL(AUTH_PAE, INITIALIZE); - else if (sm->portControl == ForceAuthorized && - sm->portMode != sm->portControl && - !(sm->initialize || !sm->eap_if->portEnabled)) - SM_ENTER_GLOBAL(AUTH_PAE, FORCE_AUTH); - else if (sm->portControl == ForceUnauthorized && - sm->portMode != sm->portControl && - !(sm->initialize || !sm->eap_if->portEnabled)) - SM_ENTER_GLOBAL(AUTH_PAE, FORCE_UNAUTH); - else { - switch (sm->auth_pae_state) { - case AUTH_PAE_INITIALIZE: - SM_ENTER(AUTH_PAE, DISCONNECTED); - break; - case AUTH_PAE_DISCONNECTED: - SM_ENTER(AUTH_PAE, RESTART); - break; - case AUTH_PAE_RESTART: - if (!sm->eap_if->eapRestart) - SM_ENTER(AUTH_PAE, CONNECTING); - break; - case AUTH_PAE_HELD: - if (sm->quietWhile == 0) - SM_ENTER(AUTH_PAE, RESTART); - break; - case AUTH_PAE_CONNECTING: - if (sm->eapolLogoff || sm->reAuthCount > sm->reAuthMax) - SM_ENTER(AUTH_PAE, DISCONNECTED); - else if ((sm->eap_if->eapReq && - sm->reAuthCount <= sm->reAuthMax) || - sm->eap_if->eapSuccess || sm->eap_if->eapFail) - SM_ENTER(AUTH_PAE, AUTHENTICATING); - break; - case AUTH_PAE_AUTHENTICATED: - if (sm->eapolStart || sm->reAuthenticate) - SM_ENTER(AUTH_PAE, RESTART); - else if (sm->eapolLogoff || !sm->portValid) - SM_ENTER(AUTH_PAE, DISCONNECTED); - break; - case AUTH_PAE_AUTHENTICATING: - if (sm->authSuccess && sm->portValid) - SM_ENTER(AUTH_PAE, AUTHENTICATED); - else if (sm->authFail || - (sm->keyDone && !sm->portValid)) - SM_ENTER(AUTH_PAE, HELD); - else if (sm->eapolStart || sm->eapolLogoff || - sm->authTimeout) - SM_ENTER(AUTH_PAE, ABORTING); - break; - case AUTH_PAE_ABORTING: - if (sm->eapolLogoff && !sm->authAbort) - SM_ENTER(AUTH_PAE, DISCONNECTED); - else if (!sm->eapolLogoff && !sm->authAbort) - SM_ENTER(AUTH_PAE, RESTART); - break; - case AUTH_PAE_FORCE_AUTH: - if (sm->eapolStart) - SM_ENTER(AUTH_PAE, FORCE_AUTH); - break; - case AUTH_PAE_FORCE_UNAUTH: - if (sm->eapolStart) - SM_ENTER(AUTH_PAE, FORCE_UNAUTH); - break; - } - } -} - - - -/* Backend Authentication state machine */ - -SM_STATE(BE_AUTH, INITIALIZE) -{ - SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth); - - abortAuth(); - sm->eap_if->eapNoReq = FALSE; - sm->authAbort = FALSE; -} - - -SM_STATE(BE_AUTH, REQUEST) -{ - SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth); - - txReq(); - sm->eap_if->eapReq = FALSE; - sm->backendOtherRequestsToSupplicant++; - - /* - * Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but - * it looks like this would be logical thing to do there since the old - * EAP response would not be valid anymore after the new EAP request - * was sent out. - * - * A race condition has been reported, in which hostapd ended up - * sending out EAP-Response/Identity as a response to the first - * EAP-Request from the main EAP method. This can be avoided by - * clearing eapolEap here. - */ - sm->eapolEap = FALSE; -} - - -SM_STATE(BE_AUTH, RESPONSE) -{ - SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth); - - sm->authTimeout = FALSE; - sm->eapolEap = FALSE; - sm->eap_if->eapNoReq = FALSE; - sm->aWhile = sm->serverTimeout; - sm->eap_if->eapResp = TRUE; - /* sendRespToServer(); */ - sm->backendResponses++; -} - - -SM_STATE(BE_AUTH, SUCCESS) -{ - SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth); - - txReq(); - sm->authSuccess = TRUE; - sm->keyRun = TRUE; -} - - -SM_STATE(BE_AUTH, FAIL) -{ - SM_ENTRY_MA(BE_AUTH, FAIL, be_auth); - - txReq(); - sm->authFail = TRUE; -} - - -SM_STATE(BE_AUTH, TIMEOUT) -{ - SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth); - - sm->authTimeout = TRUE; -} - - -SM_STATE(BE_AUTH, IDLE) -{ - SM_ENTRY_MA(BE_AUTH, IDLE, be_auth); - - sm->authStart = FALSE; -} - - -SM_STATE(BE_AUTH, IGNORE) -{ - SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth); - - sm->eap_if->eapNoReq = FALSE; -} - - -SM_STEP(BE_AUTH) -{ - if (sm->portControl != Auto || sm->initialize || sm->authAbort) { - SM_ENTER_GLOBAL(BE_AUTH, INITIALIZE); - return; - } - - switch (sm->be_auth_state) { - case BE_AUTH_INITIALIZE: - SM_ENTER(BE_AUTH, IDLE); - break; - case BE_AUTH_REQUEST: - if (sm->eapolEap) - SM_ENTER(BE_AUTH, RESPONSE); - else if (sm->eap_if->eapReq) - SM_ENTER(BE_AUTH, REQUEST); - else if (sm->eap_if->eapTimeout) - SM_ENTER(BE_AUTH, TIMEOUT); - break; - case BE_AUTH_RESPONSE: - if (sm->eap_if->eapNoReq) - SM_ENTER(BE_AUTH, IGNORE); - if (sm->eap_if->eapReq) { - sm->backendAccessChallenges++; - SM_ENTER(BE_AUTH, REQUEST); - } else if (sm->aWhile == 0) - SM_ENTER(BE_AUTH, TIMEOUT); - else if (sm->eap_if->eapFail) { - sm->backendAuthFails++; - SM_ENTER(BE_AUTH, FAIL); - } else if (sm->eap_if->eapSuccess) { - sm->backendAuthSuccesses++; - SM_ENTER(BE_AUTH, SUCCESS); - } - break; - case BE_AUTH_SUCCESS: - SM_ENTER(BE_AUTH, IDLE); - break; - case BE_AUTH_FAIL: - SM_ENTER(BE_AUTH, IDLE); - break; - case BE_AUTH_TIMEOUT: - SM_ENTER(BE_AUTH, IDLE); - break; - case BE_AUTH_IDLE: - if (sm->eap_if->eapFail && sm->authStart) - SM_ENTER(BE_AUTH, FAIL); - else if (sm->eap_if->eapReq && sm->authStart) - SM_ENTER(BE_AUTH, REQUEST); - else if (sm->eap_if->eapSuccess && sm->authStart) - SM_ENTER(BE_AUTH, SUCCESS); - break; - case BE_AUTH_IGNORE: - if (sm->eapolEap) - SM_ENTER(BE_AUTH, RESPONSE); - else if (sm->eap_if->eapReq) - SM_ENTER(BE_AUTH, REQUEST); - else if (sm->eap_if->eapTimeout) - SM_ENTER(BE_AUTH, TIMEOUT); - break; - } -} - - - -/* Reauthentication Timer state machine */ - -SM_STATE(REAUTH_TIMER, INITIALIZE) -{ - SM_ENTRY_MA(REAUTH_TIMER, INITIALIZE, reauth_timer); - - sm->reAuthWhen = sm->reAuthPeriod; -} - - -SM_STATE(REAUTH_TIMER, REAUTHENTICATE) -{ - SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer); - - sm->reAuthenticate = TRUE; - sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta, - EAPOL_AUTH_REAUTHENTICATE); -} - - -SM_STEP(REAUTH_TIMER) -{ - if (sm->portControl != Auto || sm->initialize || - sm->authPortStatus == Unauthorized || !sm->reAuthEnabled) { - SM_ENTER_GLOBAL(REAUTH_TIMER, INITIALIZE); - return; - } - - switch (sm->reauth_timer_state) { - case REAUTH_TIMER_INITIALIZE: - if (sm->reAuthWhen == 0) - SM_ENTER(REAUTH_TIMER, REAUTHENTICATE); - break; - case REAUTH_TIMER_REAUTHENTICATE: - SM_ENTER(REAUTH_TIMER, INITIALIZE); - break; - } -} - - - -/* Authenticator Key Transmit state machine */ - -SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT) -{ - SM_ENTRY_MA(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx); -} - - -SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT) -{ - SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx); - - txKey(); - sm->eap_if->eapKeyAvailable = FALSE; - sm->keyDone = TRUE; -} - - -SM_STEP(AUTH_KEY_TX) -{ - if (sm->initialize || sm->portControl != Auto) { - SM_ENTER_GLOBAL(AUTH_KEY_TX, NO_KEY_TRANSMIT); - return; - } - - switch (sm->auth_key_tx_state) { - case AUTH_KEY_TX_NO_KEY_TRANSMIT: - if (sm->keyTxEnabled && sm->eap_if->eapKeyAvailable && - sm->keyRun && !(sm->flags & EAPOL_SM_USES_WPA)) - SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT); - break; - case AUTH_KEY_TX_KEY_TRANSMIT: - if (!sm->keyTxEnabled || !sm->keyRun) - SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT); - else if (sm->eap_if->eapKeyAvailable) - SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT); - break; - } -} - - - -/* Key Receive state machine */ - -SM_STATE(KEY_RX, NO_KEY_RECEIVE) -{ - SM_ENTRY_MA(KEY_RX, NO_KEY_RECEIVE, key_rx); -} - - -SM_STATE(KEY_RX, KEY_RECEIVE) -{ - SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx); - - processKey(); - sm->rxKey = FALSE; -} - - -SM_STEP(KEY_RX) -{ - if (sm->initialize || !sm->eap_if->portEnabled) { - SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE); - return; - } - - switch (sm->key_rx_state) { - case KEY_RX_NO_KEY_RECEIVE: - if (sm->rxKey) - SM_ENTER(KEY_RX, KEY_RECEIVE); - break; - case KEY_RX_KEY_RECEIVE: - if (sm->rxKey) - SM_ENTER(KEY_RX, KEY_RECEIVE); - break; - } -} - - - -/* Controlled Directions state machine */ - -SM_STATE(CTRL_DIR, FORCE_BOTH) -{ - SM_ENTRY_MA(CTRL_DIR, FORCE_BOTH, ctrl_dir); - sm->operControlledDirections = Both; -} - - -SM_STATE(CTRL_DIR, IN_OR_BOTH) -{ - SM_ENTRY_MA(CTRL_DIR, IN_OR_BOTH, ctrl_dir); - sm->operControlledDirections = sm->adminControlledDirections; -} - - -SM_STEP(CTRL_DIR) -{ - if (sm->initialize) { - SM_ENTER_GLOBAL(CTRL_DIR, IN_OR_BOTH); - return; - } - - switch (sm->ctrl_dir_state) { - case CTRL_DIR_FORCE_BOTH: - if (sm->eap_if->portEnabled && sm->operEdge) - SM_ENTER(CTRL_DIR, IN_OR_BOTH); - break; - case CTRL_DIR_IN_OR_BOTH: - if (sm->operControlledDirections != - sm->adminControlledDirections) - SM_ENTER(CTRL_DIR, IN_OR_BOTH); - if (!sm->eap_if->portEnabled || !sm->operEdge) - SM_ENTER(CTRL_DIR, FORCE_BOTH); - break; - } -} - - - -struct eapol_state_machine * -eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, - int flags, const struct wpabuf *assoc_wps_ie, - const struct wpabuf *assoc_p2p_ie, void *sta_ctx, - const char *identity, const char *radius_cui) -{ - struct eapol_state_machine *sm; - struct eap_config eap_conf; - - if (eapol == NULL) - return NULL; - - sm = os_zalloc(sizeof(*sm)); - if (sm == NULL) { - wpa_printf(MSG_DEBUG, "IEEE 802.1X state machine allocation " - "failed"); - return NULL; - } - sm->radius_identifier = -1; - os_memcpy(sm->addr, addr, ETH_ALEN); - sm->flags = flags; - - sm->eapol = eapol; - sm->sta = sta_ctx; - - /* Set default values for state machine constants */ - sm->auth_pae_state = AUTH_PAE_INITIALIZE; - sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod; - sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax; - - sm->be_auth_state = BE_AUTH_INITIALIZE; - sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout; - - sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE; - sm->reAuthPeriod = eapol->conf.eap_reauth_period; - sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE; - - sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT; - - sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE; - - sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH; - - sm->portControl = Auto; - - if (!eapol->conf.wpa && - (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0)) - sm->keyTxEnabled = TRUE; - else - sm->keyTxEnabled = FALSE; - if (eapol->conf.wpa) - sm->portValid = FALSE; - else - sm->portValid = TRUE; - - os_memset(&eap_conf, 0, sizeof(eap_conf)); - eap_conf.eap_server = eapol->conf.eap_server; - eap_conf.ssl_ctx = eapol->conf.ssl_ctx; - eap_conf.msg_ctx = eapol->conf.msg_ctx; - eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv; - eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key; - eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id; - eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len; - eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info; - eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov; - eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime; - eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time; - eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind; - eap_conf.tnc = eapol->conf.tnc; - eap_conf.wps = eapol->conf.wps; - eap_conf.assoc_wps_ie = assoc_wps_ie; - eap_conf.assoc_p2p_ie = assoc_p2p_ie; - eap_conf.peer_addr = addr; - eap_conf.fragment_size = eapol->conf.fragment_size; - eap_conf.pwd_group = eapol->conf.pwd_group; - eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1; - eap_conf.server_id = eapol->conf.server_id; - eap_conf.server_id_len = eapol->conf.server_id_len; - sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf); - if (sm->eap == NULL) { - eapol_auth_free(sm); - return NULL; - } - sm->eap_if = eap_get_interface(sm->eap); - - eapol_auth_initialize(sm); - - if (identity) { - sm->identity = (u8 *) os_strdup(identity); - if (sm->identity) - sm->identity_len = os_strlen(identity); - } - if (radius_cui) - sm->radius_cui = wpabuf_alloc_copy(radius_cui, - os_strlen(radius_cui)); - - return sm; -} - - -void eapol_auth_free(struct eapol_state_machine *sm) -{ - if (sm == NULL) - return; - - eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm); - eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL); - if (sm->eap) - eap_server_sm_deinit(sm->eap); - os_free(sm); -} - - -static int eapol_sm_sta_entry_alive(struct eapol_authenticator *eapol, - const u8 *addr) -{ - return eapol->cb.sta_entry_alive(eapol->conf.ctx, addr); -} - - -static void eapol_sm_step_run(struct eapol_state_machine *sm) -{ - struct eapol_authenticator *eapol = sm->eapol; - u8 addr[ETH_ALEN]; - unsigned int prev_auth_pae, prev_be_auth, prev_reauth_timer, - prev_auth_key_tx, prev_key_rx, prev_ctrl_dir; - int max_steps = 100; - - os_memcpy(addr, sm->addr, ETH_ALEN); - - /* - * Allow EAPOL state machines to run as long as there are state - * changes, but exit and return here through event loop if more than - * 100 steps is needed as a precaution against infinite loops inside - * eloop callback. - */ -restart: - prev_auth_pae = sm->auth_pae_state; - prev_be_auth = sm->be_auth_state; - prev_reauth_timer = sm->reauth_timer_state; - prev_auth_key_tx = sm->auth_key_tx_state; - prev_key_rx = sm->key_rx_state; - prev_ctrl_dir = sm->ctrl_dir_state; - - SM_STEP_RUN(AUTH_PAE); - if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) - SM_STEP_RUN(BE_AUTH); - if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) - SM_STEP_RUN(REAUTH_TIMER); - if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) - SM_STEP_RUN(AUTH_KEY_TX); - if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) - SM_STEP_RUN(KEY_RX); - if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) - SM_STEP_RUN(CTRL_DIR); - - if (prev_auth_pae != sm->auth_pae_state || - prev_be_auth != sm->be_auth_state || - prev_reauth_timer != sm->reauth_timer_state || - prev_auth_key_tx != sm->auth_key_tx_state || - prev_key_rx != sm->key_rx_state || - prev_ctrl_dir != sm->ctrl_dir_state) { - if (--max_steps > 0) - goto restart; - /* Re-run from eloop timeout */ - eapol_auth_step(sm); - return; - } - - if (eapol_sm_sta_entry_alive(eapol, addr) && sm->eap) { - if (eap_server_sm_step(sm->eap)) { - if (--max_steps > 0) - goto restart; - /* Re-run from eloop timeout */ - eapol_auth_step(sm); - return; - } - - /* TODO: find a better location for this */ - if (sm->eap_if->aaaEapResp) { - sm->eap_if->aaaEapResp = FALSE; - if (sm->eap_if->aaaEapRespData == NULL) { - wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, " - "but no aaaEapRespData available"); - return; - } - sm->eapol->cb.aaa_send( - sm->eapol->conf.ctx, sm->sta, - wpabuf_head(sm->eap_if->aaaEapRespData), - wpabuf_len(sm->eap_if->aaaEapRespData)); - } - } - - if (eapol_sm_sta_entry_alive(eapol, addr)) - sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta, - EAPOL_AUTH_SM_CHANGE); -} - - -static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx) -{ - struct eapol_state_machine *sm = eloop_ctx; - eapol_sm_step_run(sm); -} - - -/** - * eapol_auth_step - Advance EAPOL state machines - * @sm: EAPOL state machine - * - * This function is called to advance EAPOL state machines after any change - * that could affect their state. - */ -void eapol_auth_step(struct eapol_state_machine *sm) -{ - /* - * Run eapol_sm_step_run from a registered timeout to make sure that - * other possible timeouts/events are processed and to avoid long - * function call chains. - */ - - eloop_register_timeout(0, 0, eapol_sm_step_cb, sm, NULL); -} - - -static void eapol_auth_initialize(struct eapol_state_machine *sm) -{ - sm->initializing = TRUE; - /* Initialize the state machines by asserting initialize and then - * deasserting it after one step */ - sm->initialize = TRUE; - eapol_sm_step_run(sm); - sm->initialize = FALSE; - eapol_sm_step_run(sm); - sm->initializing = FALSE; - - /* Start one second tick for port timers state machine */ - eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm); - eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm); -} - - -static int eapol_sm_get_eap_user(void *ctx, const u8 *identity, - size_t identity_len, int phase2, - struct eap_user *user) -{ - struct eapol_state_machine *sm = ctx; - return sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity, - identity_len, phase2, user); -} - - -static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len) -{ - struct eapol_state_machine *sm = ctx; - *len = sm->eapol->conf.eap_req_id_text_len; - return sm->eapol->conf.eap_req_id_text; -} - - -static struct eapol_callbacks eapol_cb = -{ - eapol_sm_get_eap_user, - eapol_sm_get_eap_req_id_text -}; - - -int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx) -{ - if (sm == NULL || ctx == NULL || ctx != sm->eap) - return -1; - - eap_sm_pending_cb(sm->eap); - eapol_auth_step(sm); - - return 0; -} - - -static int eapol_auth_conf_clone(struct eapol_auth_config *dst, - struct eapol_auth_config *src) -{ - dst->ctx = src->ctx; - dst->eap_reauth_period = src->eap_reauth_period; - dst->wpa = src->wpa; - dst->individual_wep_key_len = src->individual_wep_key_len; - dst->eap_server = src->eap_server; - dst->ssl_ctx = src->ssl_ctx; - dst->msg_ctx = src->msg_ctx; - dst->eap_sim_db_priv = src->eap_sim_db_priv; - os_free(dst->eap_req_id_text); - dst->pwd_group = src->pwd_group; - dst->pbc_in_m1 = src->pbc_in_m1; - dst->server_id = src->server_id; - dst->server_id_len = src->server_id_len; - if (src->eap_req_id_text) { - dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len); - if (dst->eap_req_id_text == NULL) - return -1; - os_memcpy(dst->eap_req_id_text, src->eap_req_id_text, - src->eap_req_id_text_len); - dst->eap_req_id_text_len = src->eap_req_id_text_len; - } else { - dst->eap_req_id_text = NULL; - dst->eap_req_id_text_len = 0; - } - if (src->pac_opaque_encr_key) { - dst->pac_opaque_encr_key = os_malloc(16); - if (dst->pac_opaque_encr_key == NULL) { - os_free(dst->eap_req_id_text); - return -1; - } - os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key, - 16); - } else - dst->pac_opaque_encr_key = NULL; - if (src->eap_fast_a_id) { - dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len); - if (dst->eap_fast_a_id == NULL) { - os_free(dst->eap_req_id_text); - os_free(dst->pac_opaque_encr_key); - return -1; - } - os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id, - src->eap_fast_a_id_len); - dst->eap_fast_a_id_len = src->eap_fast_a_id_len; - } else - dst->eap_fast_a_id = NULL; - if (src->eap_fast_a_id_info) { - dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info); - if (dst->eap_fast_a_id_info == NULL) { - os_free(dst->eap_req_id_text); - os_free(dst->pac_opaque_encr_key); - os_free(dst->eap_fast_a_id); - return -1; - } - } else - dst->eap_fast_a_id_info = NULL; - dst->eap_fast_prov = src->eap_fast_prov; - dst->pac_key_lifetime = src->pac_key_lifetime; - dst->pac_key_refresh_time = src->pac_key_refresh_time; - dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind; - dst->tnc = src->tnc; - dst->wps = src->wps; - dst->fragment_size = src->fragment_size; - return 0; -} - - -static void eapol_auth_conf_free(struct eapol_auth_config *conf) -{ - os_free(conf->eap_req_id_text); - conf->eap_req_id_text = NULL; - os_free(conf->pac_opaque_encr_key); - conf->pac_opaque_encr_key = NULL; - os_free(conf->eap_fast_a_id); - conf->eap_fast_a_id = NULL; - os_free(conf->eap_fast_a_id_info); - conf->eap_fast_a_id_info = NULL; -} - - -struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf, - struct eapol_auth_cb *cb) -{ - struct eapol_authenticator *eapol; - - eapol = os_zalloc(sizeof(*eapol)); - if (eapol == NULL) - return NULL; - - if (eapol_auth_conf_clone(&eapol->conf, conf) < 0) { - os_free(eapol); - return NULL; - } - - if (conf->individual_wep_key_len > 0) { - /* use key0 in individual key and key1 in broadcast key */ - eapol->default_wep_key_idx = 1; - } - - eapol->cb.eapol_send = cb->eapol_send; - eapol->cb.aaa_send = cb->aaa_send; - eapol->cb.finished = cb->finished; - eapol->cb.get_eap_user = cb->get_eap_user; - eapol->cb.sta_entry_alive = cb->sta_entry_alive; - eapol->cb.logger = cb->logger; - eapol->cb.set_port_authorized = cb->set_port_authorized; - eapol->cb.abort_auth = cb->abort_auth; - eapol->cb.tx_key = cb->tx_key; - eapol->cb.eapol_event = cb->eapol_event; - - return eapol; -} - - -void eapol_auth_deinit(struct eapol_authenticator *eapol) -{ - if (eapol == NULL) - return; - - eapol_auth_conf_free(&eapol->conf); - os_free(eapol->default_wep_key); - os_free(eapol); -} diff --git a/contrib/hostapd/src/eapol_auth/eapol_auth_sm.h b/contrib/hostapd/src/eapol_auth/eapol_auth_sm.h deleted file mode 100644 index f0ff4644f5..0000000000 --- a/contrib/hostapd/src/eapol_auth/eapol_auth_sm.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * IEEE 802.1X-2004 Authenticator - EAPOL state machine - * Copyright (c) 2002-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAPOL_AUTH_SM_H -#define EAPOL_AUTH_SM_H - -#define EAPOL_SM_PREAUTH BIT(0) -#define EAPOL_SM_WAIT_START BIT(1) -#define EAPOL_SM_USES_WPA BIT(2) -#define EAPOL_SM_FROM_PMKSA_CACHE BIT(3) - -struct eapol_auth_config { - int eap_reauth_period; - int wpa; - int individual_wep_key_len; - int eap_server; - void *ssl_ctx; - void *msg_ctx; - void *eap_sim_db_priv; - char *eap_req_id_text; /* a copy of this will be allocated */ - size_t eap_req_id_text_len; - u8 *pac_opaque_encr_key; - u8 *eap_fast_a_id; - size_t eap_fast_a_id_len; - char *eap_fast_a_id_info; - int eap_fast_prov; - int pac_key_lifetime; - int pac_key_refresh_time; - int eap_sim_aka_result_ind; - int tnc; - struct wps_context *wps; - int fragment_size; - u16 pwd_group; - int pbc_in_m1; - const u8 *server_id; - size_t server_id_len; - - /* Opaque context pointer to owner data for callback functions */ - void *ctx; -}; - -struct eap_user; - -typedef enum { - EAPOL_LOGGER_DEBUG, EAPOL_LOGGER_INFO, EAPOL_LOGGER_WARNING -} eapol_logger_level; - -enum eapol_event { - EAPOL_AUTH_SM_CHANGE, - EAPOL_AUTH_REAUTHENTICATE -}; - -struct eapol_auth_cb { - void (*eapol_send)(void *ctx, void *sta_ctx, u8 type, const u8 *data, - size_t datalen); - void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data, - size_t datalen); - void (*finished)(void *ctx, void *sta_ctx, int success, int preauth); - int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, - int phase2, struct eap_user *user); - int (*sta_entry_alive)(void *ctx, const u8 *addr); - void (*logger)(void *ctx, const u8 *addr, eapol_logger_level level, - const char *txt); - void (*set_port_authorized)(void *ctx, void *sta_ctx, int authorized); - void (*abort_auth)(void *ctx, void *sta_ctx); - void (*tx_key)(void *ctx, void *sta_ctx); - void (*eapol_event)(void *ctx, void *sta_ctx, enum eapol_event type); -}; - - -struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf, - struct eapol_auth_cb *cb); -void eapol_auth_deinit(struct eapol_authenticator *eapol); -struct eapol_state_machine * -eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, - int flags, const struct wpabuf *assoc_wps_ie, - const struct wpabuf *assoc_p2p_ie, void *sta_ctx, - const char *identity, const char *radius_cui); -void eapol_auth_free(struct eapol_state_machine *sm); -void eapol_auth_step(struct eapol_state_machine *sm); -int eapol_auth_dump_state(struct eapol_state_machine *sm, char *buf, - size_t buflen); -int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx); - -#endif /* EAPOL_AUTH_SM_H */ diff --git a/contrib/hostapd/src/eapol_auth/eapol_auth_sm_i.h b/contrib/hostapd/src/eapol_auth/eapol_auth_sm_i.h deleted file mode 100644 index d7f893a1d6..0000000000 --- a/contrib/hostapd/src/eapol_auth/eapol_auth_sm_i.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * IEEE 802.1X-2004 Authenticator - EAPOL state machine (internal definitions) - * Copyright (c) 2002-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAPOL_AUTH_SM_I_H -#define EAPOL_AUTH_SM_I_H - -#include "common/defs.h" -#include "radius/radius.h" - -/* IEEE Std 802.1X-2004, Ch. 8.2 */ - -typedef enum { ForceUnauthorized = 1, ForceAuthorized = 3, Auto = 2 } - PortTypes; -typedef enum { Unauthorized = 2, Authorized = 1 } PortState; -typedef enum { Both = 0, In = 1 } ControlledDirection; -typedef unsigned int Counter; - - -/** - * struct eapol_authenticator - Global EAPOL authenticator data - */ -struct eapol_authenticator { - struct eapol_auth_config conf; - struct eapol_auth_cb cb; - - u8 *default_wep_key; - u8 default_wep_key_idx; -}; - - -/** - * struct eapol_state_machine - Per-Supplicant Authenticator state machines - */ -struct eapol_state_machine { - /* timers */ - int aWhile; - int quietWhile; - int reAuthWhen; - - /* global variables */ - Boolean authAbort; - Boolean authFail; - PortState authPortStatus; - Boolean authStart; - Boolean authTimeout; - Boolean authSuccess; - Boolean eapolEap; - Boolean initialize; - Boolean keyDone; - Boolean keyRun; - Boolean keyTxEnabled; - PortTypes portControl; - Boolean portValid; - Boolean reAuthenticate; - - /* Port Timers state machine */ - /* 'Boolean tick' implicitly handled as registered timeout */ - - /* Authenticator PAE state machine */ - enum { AUTH_PAE_INITIALIZE, AUTH_PAE_DISCONNECTED, AUTH_PAE_CONNECTING, - AUTH_PAE_AUTHENTICATING, AUTH_PAE_AUTHENTICATED, - AUTH_PAE_ABORTING, AUTH_PAE_HELD, AUTH_PAE_FORCE_AUTH, - AUTH_PAE_FORCE_UNAUTH, AUTH_PAE_RESTART } auth_pae_state; - /* variables */ - Boolean eapolLogoff; - Boolean eapolStart; - PortTypes portMode; - unsigned int reAuthCount; - /* constants */ - unsigned int quietPeriod; /* default 60; 0..65535 */ -#define AUTH_PAE_DEFAULT_quietPeriod 60 - unsigned int reAuthMax; /* default 2 */ -#define AUTH_PAE_DEFAULT_reAuthMax 2 - /* counters */ - Counter authEntersConnecting; - Counter authEapLogoffsWhileConnecting; - Counter authEntersAuthenticating; - Counter authAuthSuccessesWhileAuthenticating; - Counter authAuthTimeoutsWhileAuthenticating; - Counter authAuthFailWhileAuthenticating; - Counter authAuthEapStartsWhileAuthenticating; - Counter authAuthEapLogoffWhileAuthenticating; - Counter authAuthReauthsWhileAuthenticated; - Counter authAuthEapStartsWhileAuthenticated; - Counter authAuthEapLogoffWhileAuthenticated; - - /* Backend Authentication state machine */ - enum { BE_AUTH_REQUEST, BE_AUTH_RESPONSE, BE_AUTH_SUCCESS, - BE_AUTH_FAIL, BE_AUTH_TIMEOUT, BE_AUTH_IDLE, BE_AUTH_INITIALIZE, - BE_AUTH_IGNORE - } be_auth_state; - /* constants */ - unsigned int serverTimeout; /* default 30; 1..X */ -#define BE_AUTH_DEFAULT_serverTimeout 30 - /* counters */ - Counter backendResponses; - Counter backendAccessChallenges; - Counter backendOtherRequestsToSupplicant; - Counter backendAuthSuccesses; - Counter backendAuthFails; - - /* Reauthentication Timer state machine */ - enum { REAUTH_TIMER_INITIALIZE, REAUTH_TIMER_REAUTHENTICATE - } reauth_timer_state; - /* constants */ - unsigned int reAuthPeriod; /* default 3600 s */ - Boolean reAuthEnabled; - - /* Authenticator Key Transmit state machine */ - enum { AUTH_KEY_TX_NO_KEY_TRANSMIT, AUTH_KEY_TX_KEY_TRANSMIT - } auth_key_tx_state; - - /* Key Receive state machine */ - enum { KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE } key_rx_state; - /* variables */ - Boolean rxKey; - - /* Controlled Directions state machine */ - enum { CTRL_DIR_FORCE_BOTH, CTRL_DIR_IN_OR_BOTH } ctrl_dir_state; - /* variables */ - ControlledDirection adminControlledDirections; - ControlledDirection operControlledDirections; - Boolean operEdge; - - /* Authenticator Statistics Table */ - Counter dot1xAuthEapolFramesRx; - Counter dot1xAuthEapolFramesTx; - Counter dot1xAuthEapolStartFramesRx; - Counter dot1xAuthEapolLogoffFramesRx; - Counter dot1xAuthEapolRespIdFramesRx; - Counter dot1xAuthEapolRespFramesRx; - Counter dot1xAuthEapolReqIdFramesTx; - Counter dot1xAuthEapolReqFramesTx; - Counter dot1xAuthInvalidEapolFramesRx; - Counter dot1xAuthEapLengthErrorFramesRx; - Counter dot1xAuthLastEapolFrameVersion; - - /* Other variables - not defined in IEEE 802.1X */ - u8 addr[ETH_ALEN]; /* Supplicant address */ - int flags; /* EAPOL_SM_* */ - - /* EAPOL/AAA <-> EAP full authenticator interface */ - struct eap_eapol_interface *eap_if; - - int radius_identifier; - /* TODO: check when the last messages can be released */ - struct radius_msg *last_recv_radius; - u8 last_eap_id; /* last used EAP Identifier */ - u8 *identity; - size_t identity_len; - u8 eap_type_authsrv; /* EAP type of the last EAP packet from - * Authentication server */ - u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */ - struct radius_class_data radius_class; - struct wpabuf *radius_cui; /* Chargeable-User-Identity */ - - /* Keys for encrypting and signing EAPOL-Key frames */ - u8 *eapol_key_sign; - size_t eapol_key_sign_len; - u8 *eapol_key_crypt; - size_t eapol_key_crypt_len; - - struct eap_sm *eap; - - Boolean initializing; /* in process of initializing state machines */ - Boolean changed; - - struct eapol_authenticator *eapol; - - void *sta; /* station context pointer to use in callbacks */ -}; - -#endif /* EAPOL_AUTH_SM_I_H */ diff --git a/contrib/hostapd/src/eapol_supp/eapol_supp_sm.c b/contrib/hostapd/src/eapol_supp/eapol_supp_sm.c deleted file mode 100644 index cbcde7ec95..0000000000 --- a/contrib/hostapd/src/eapol_supp/eapol_supp_sm.c +++ /dev/null @@ -1,2080 +0,0 @@ -/* - * EAPOL supplicant state machines - * Copyright (c) 2004-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "state_machine.h" -#include "wpabuf.h" -#include "eloop.h" -#include "crypto/crypto.h" -#include "crypto/md5.h" -#include "common/eapol_common.h" -#include "eap_peer/eap.h" -#include "eap_peer/eap_proxy.h" -#include "eapol_supp_sm.h" - -#define STATE_MACHINE_DATA struct eapol_sm -#define STATE_MACHINE_DEBUG_PREFIX "EAPOL" - - -/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */ - -/** - * struct eapol_sm - Internal data for EAPOL state machines - */ -struct eapol_sm { - /* Timers */ - unsigned int authWhile; - unsigned int heldWhile; - unsigned int startWhen; - unsigned int idleWhile; /* for EAP state machine */ - int timer_tick_enabled; - - /* Global variables */ - Boolean eapFail; - Boolean eapolEap; - Boolean eapSuccess; - Boolean initialize; - Boolean keyDone; - Boolean keyRun; - PortControl portControl; - Boolean portEnabled; - PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */ - Boolean portValid; - Boolean suppAbort; - Boolean suppFail; - Boolean suppStart; - Boolean suppSuccess; - Boolean suppTimeout; - - /* Supplicant PAE state machine */ - enum { - SUPP_PAE_UNKNOWN = 0, - SUPP_PAE_DISCONNECTED = 1, - SUPP_PAE_LOGOFF = 2, - SUPP_PAE_CONNECTING = 3, - SUPP_PAE_AUTHENTICATING = 4, - SUPP_PAE_AUTHENTICATED = 5, - /* unused(6) */ - SUPP_PAE_HELD = 7, - SUPP_PAE_RESTART = 8, - SUPP_PAE_S_FORCE_AUTH = 9, - SUPP_PAE_S_FORCE_UNAUTH = 10 - } SUPP_PAE_state; /* dot1xSuppPaeState */ - /* Variables */ - Boolean userLogoff; - Boolean logoffSent; - unsigned int startCount; - Boolean eapRestart; - PortControl sPortMode; - /* Constants */ - unsigned int heldPeriod; /* dot1xSuppHeldPeriod */ - unsigned int startPeriod; /* dot1xSuppStartPeriod */ - unsigned int maxStart; /* dot1xSuppMaxStart */ - - /* Key Receive state machine */ - enum { - KEY_RX_UNKNOWN = 0, - KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE - } KEY_RX_state; - /* Variables */ - Boolean rxKey; - - /* Supplicant Backend state machine */ - enum { - SUPP_BE_UNKNOWN = 0, - SUPP_BE_INITIALIZE = 1, - SUPP_BE_IDLE = 2, - SUPP_BE_REQUEST = 3, - SUPP_BE_RECEIVE = 4, - SUPP_BE_RESPONSE = 5, - SUPP_BE_FAIL = 6, - SUPP_BE_TIMEOUT = 7, - SUPP_BE_SUCCESS = 8 - } SUPP_BE_state; /* dot1xSuppBackendPaeState */ - /* Variables */ - Boolean eapNoResp; - Boolean eapReq; - Boolean eapResp; - /* Constants */ - unsigned int authPeriod; /* dot1xSuppAuthPeriod */ - - /* Statistics */ - unsigned int dot1xSuppEapolFramesRx; - unsigned int dot1xSuppEapolFramesTx; - unsigned int dot1xSuppEapolStartFramesTx; - unsigned int dot1xSuppEapolLogoffFramesTx; - unsigned int dot1xSuppEapolRespFramesTx; - unsigned int dot1xSuppEapolReqIdFramesRx; - unsigned int dot1xSuppEapolReqFramesRx; - unsigned int dot1xSuppInvalidEapolFramesRx; - unsigned int dot1xSuppEapLengthErrorFramesRx; - unsigned int dot1xSuppLastEapolFrameVersion; - unsigned char dot1xSuppLastEapolFrameSource[6]; - - /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */ - Boolean changed; - struct eap_sm *eap; - struct eap_peer_config *config; - Boolean initial_req; - u8 *last_rx_key; - size_t last_rx_key_len; - struct wpabuf *eapReqData; /* for EAP */ - Boolean altAccept; /* for EAP */ - Boolean altReject; /* for EAP */ - Boolean replay_counter_valid; - u8 last_replay_counter[16]; - struct eapol_config conf; - struct eapol_ctx *ctx; - enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE } - cb_status; - Boolean cached_pmk; - - Boolean unicast_key_received, broadcast_key_received; - - Boolean force_authorized_update; - -#ifdef CONFIG_EAP_PROXY - Boolean use_eap_proxy; - struct eap_proxy_sm *eap_proxy; -#endif /* CONFIG_EAP_PROXY */ -}; - - -static void eapol_sm_txLogoff(struct eapol_sm *sm); -static void eapol_sm_txStart(struct eapol_sm *sm); -static void eapol_sm_processKey(struct eapol_sm *sm); -static void eapol_sm_getSuppRsp(struct eapol_sm *sm); -static void eapol_sm_txSuppRsp(struct eapol_sm *sm); -static void eapol_sm_abortSupp(struct eapol_sm *sm); -static void eapol_sm_abort_cached(struct eapol_sm *sm); -static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx); -static void eapol_sm_set_port_authorized(struct eapol_sm *sm); -static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm); - - -/* Port Timers state machine - implemented as a function that will be called - * once a second as a registered event loop timeout */ -static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx) -{ - struct eapol_sm *sm = timeout_ctx; - - if (sm->authWhile > 0) { - sm->authWhile--; - if (sm->authWhile == 0) - wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0"); - } - if (sm->heldWhile > 0) { - sm->heldWhile--; - if (sm->heldWhile == 0) - wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0"); - } - if (sm->startWhen > 0) { - sm->startWhen--; - if (sm->startWhen == 0) - wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0"); - } - if (sm->idleWhile > 0) { - sm->idleWhile--; - if (sm->idleWhile == 0) - wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0"); - } - - if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) { - eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, - sm); - } else { - wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick"); - sm->timer_tick_enabled = 0; - } - eapol_sm_step(sm); -} - - -static void eapol_enable_timer_tick(struct eapol_sm *sm) -{ - if (sm->timer_tick_enabled) - return; - wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick"); - sm->timer_tick_enabled = 1; - eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm); - eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm); -} - - -SM_STATE(SUPP_PAE, LOGOFF) -{ - SM_ENTRY(SUPP_PAE, LOGOFF); - eapol_sm_txLogoff(sm); - sm->logoffSent = TRUE; - eapol_sm_set_port_unauthorized(sm); -} - - -SM_STATE(SUPP_PAE, DISCONNECTED) -{ - SM_ENTRY(SUPP_PAE, DISCONNECTED); - sm->sPortMode = Auto; - sm->startCount = 0; - sm->logoffSent = FALSE; - eapol_sm_set_port_unauthorized(sm); - sm->suppAbort = TRUE; - - sm->unicast_key_received = FALSE; - sm->broadcast_key_received = FALSE; - - /* - * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so - * allows the timer tick to be stopped more quickly when the port is - * not enabled. Since this variable is used only within HELD state, - * clearing it on initialization does not change actual state machine - * behavior. - */ - sm->heldWhile = 0; -} - - -SM_STATE(SUPP_PAE, CONNECTING) -{ - int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING; - SM_ENTRY(SUPP_PAE, CONNECTING); - if (send_start) { - sm->startWhen = sm->startPeriod; - sm->startCount++; - } else { - /* - * Do not send EAPOL-Start immediately since in most cases, - * Authenticator is going to start authentication immediately - * after association and an extra EAPOL-Start is just going to - * delay authentication. Use a short timeout to send the first - * EAPOL-Start if Authenticator does not start authentication. - */ -#ifdef CONFIG_WPS - /* Reduce latency on starting WPS negotiation. */ - sm->startWhen = 1; -#else /* CONFIG_WPS */ - sm->startWhen = 3; -#endif /* CONFIG_WPS */ - } - eapol_enable_timer_tick(sm); - sm->eapolEap = FALSE; - if (send_start) - eapol_sm_txStart(sm); -} - - -SM_STATE(SUPP_PAE, AUTHENTICATING) -{ - SM_ENTRY(SUPP_PAE, AUTHENTICATING); - sm->startCount = 0; - sm->suppSuccess = FALSE; - sm->suppFail = FALSE; - sm->suppTimeout = FALSE; - sm->keyRun = FALSE; - sm->keyDone = FALSE; - sm->suppStart = TRUE; -} - - -SM_STATE(SUPP_PAE, HELD) -{ - SM_ENTRY(SUPP_PAE, HELD); - sm->heldWhile = sm->heldPeriod; - eapol_enable_timer_tick(sm); - eapol_sm_set_port_unauthorized(sm); - sm->cb_status = EAPOL_CB_FAILURE; -} - - -SM_STATE(SUPP_PAE, AUTHENTICATED) -{ - SM_ENTRY(SUPP_PAE, AUTHENTICATED); - eapol_sm_set_port_authorized(sm); - sm->cb_status = EAPOL_CB_SUCCESS; -} - - -SM_STATE(SUPP_PAE, RESTART) -{ - SM_ENTRY(SUPP_PAE, RESTART); - sm->eapRestart = TRUE; -} - - -SM_STATE(SUPP_PAE, S_FORCE_AUTH) -{ - SM_ENTRY(SUPP_PAE, S_FORCE_AUTH); - eapol_sm_set_port_authorized(sm); - sm->sPortMode = ForceAuthorized; -} - - -SM_STATE(SUPP_PAE, S_FORCE_UNAUTH) -{ - SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH); - eapol_sm_set_port_unauthorized(sm); - sm->sPortMode = ForceUnauthorized; - eapol_sm_txLogoff(sm); -} - - -SM_STEP(SUPP_PAE) -{ - if ((sm->userLogoff && !sm->logoffSent) && - !(sm->initialize || !sm->portEnabled)) - SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF); - else if (((sm->portControl == Auto) && - (sm->sPortMode != sm->portControl)) || - sm->initialize || !sm->portEnabled) - SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED); - else if ((sm->portControl == ForceAuthorized) && - (sm->sPortMode != sm->portControl) && - !(sm->initialize || !sm->portEnabled)) - SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH); - else if ((sm->portControl == ForceUnauthorized) && - (sm->sPortMode != sm->portControl) && - !(sm->initialize || !sm->portEnabled)) - SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH); - else switch (sm->SUPP_PAE_state) { - case SUPP_PAE_UNKNOWN: - break; - case SUPP_PAE_LOGOFF: - if (!sm->userLogoff) - SM_ENTER(SUPP_PAE, DISCONNECTED); - break; - case SUPP_PAE_DISCONNECTED: - SM_ENTER(SUPP_PAE, CONNECTING); - break; - case SUPP_PAE_CONNECTING: - if (sm->startWhen == 0 && sm->startCount < sm->maxStart) - SM_ENTER(SUPP_PAE, CONNECTING); - else if (sm->startWhen == 0 && - sm->startCount >= sm->maxStart && - sm->portValid) - SM_ENTER(SUPP_PAE, AUTHENTICATED); - else if (sm->eapSuccess || sm->eapFail) - SM_ENTER(SUPP_PAE, AUTHENTICATING); - else if (sm->eapolEap) - SM_ENTER(SUPP_PAE, RESTART); - else if (sm->startWhen == 0 && - sm->startCount >= sm->maxStart && - !sm->portValid) - SM_ENTER(SUPP_PAE, HELD); - break; - case SUPP_PAE_AUTHENTICATING: - if (sm->eapSuccess && !sm->portValid && - sm->conf.accept_802_1x_keys && - sm->conf.required_keys == 0) { - wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for " - "plaintext connection; no EAPOL-Key frames " - "required"); - sm->portValid = TRUE; - if (sm->ctx->eapol_done_cb) - sm->ctx->eapol_done_cb(sm->ctx->ctx); - } - if (sm->eapSuccess && sm->portValid) - SM_ENTER(SUPP_PAE, AUTHENTICATED); - else if (sm->eapFail || (sm->keyDone && !sm->portValid)) - SM_ENTER(SUPP_PAE, HELD); - else if (sm->suppTimeout) - SM_ENTER(SUPP_PAE, CONNECTING); - break; - case SUPP_PAE_HELD: - if (sm->heldWhile == 0) - SM_ENTER(SUPP_PAE, CONNECTING); - else if (sm->eapolEap) - SM_ENTER(SUPP_PAE, RESTART); - break; - case SUPP_PAE_AUTHENTICATED: - if (sm->eapolEap && sm->portValid) - SM_ENTER(SUPP_PAE, RESTART); - else if (!sm->portValid) - SM_ENTER(SUPP_PAE, DISCONNECTED); - break; - case SUPP_PAE_RESTART: - if (!sm->eapRestart) - SM_ENTER(SUPP_PAE, AUTHENTICATING); - break; - case SUPP_PAE_S_FORCE_AUTH: - break; - case SUPP_PAE_S_FORCE_UNAUTH: - break; - } -} - - -SM_STATE(KEY_RX, NO_KEY_RECEIVE) -{ - SM_ENTRY(KEY_RX, NO_KEY_RECEIVE); -} - - -SM_STATE(KEY_RX, KEY_RECEIVE) -{ - SM_ENTRY(KEY_RX, KEY_RECEIVE); - eapol_sm_processKey(sm); - sm->rxKey = FALSE; -} - - -SM_STEP(KEY_RX) -{ - if (sm->initialize || !sm->portEnabled) - SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE); - switch (sm->KEY_RX_state) { - case KEY_RX_UNKNOWN: - break; - case KEY_RX_NO_KEY_RECEIVE: - if (sm->rxKey) - SM_ENTER(KEY_RX, KEY_RECEIVE); - break; - case KEY_RX_KEY_RECEIVE: - if (sm->rxKey) - SM_ENTER(KEY_RX, KEY_RECEIVE); - break; - } -} - - -SM_STATE(SUPP_BE, REQUEST) -{ - SM_ENTRY(SUPP_BE, REQUEST); - sm->authWhile = 0; - sm->eapReq = TRUE; - eapol_sm_getSuppRsp(sm); -} - - -SM_STATE(SUPP_BE, RESPONSE) -{ - SM_ENTRY(SUPP_BE, RESPONSE); - eapol_sm_txSuppRsp(sm); - sm->eapResp = FALSE; -} - - -SM_STATE(SUPP_BE, SUCCESS) -{ - SM_ENTRY(SUPP_BE, SUCCESS); - sm->keyRun = TRUE; - sm->suppSuccess = TRUE; - -#ifdef CONFIG_EAP_PROXY - if (sm->use_eap_proxy) { - if (eap_proxy_key_available(sm->eap_proxy)) { - /* New key received - clear IEEE 802.1X EAPOL-Key replay - * counter */ - sm->replay_counter_valid = FALSE; - } - return; - } -#endif /* CONFIG_EAP_PROXY */ - - if (eap_key_available(sm->eap)) { - /* New key received - clear IEEE 802.1X EAPOL-Key replay - * counter */ - sm->replay_counter_valid = FALSE; - } -} - - -SM_STATE(SUPP_BE, FAIL) -{ - SM_ENTRY(SUPP_BE, FAIL); - sm->suppFail = TRUE; -} - - -SM_STATE(SUPP_BE, TIMEOUT) -{ - SM_ENTRY(SUPP_BE, TIMEOUT); - sm->suppTimeout = TRUE; -} - - -SM_STATE(SUPP_BE, IDLE) -{ - SM_ENTRY(SUPP_BE, IDLE); - sm->suppStart = FALSE; - sm->initial_req = TRUE; -} - - -SM_STATE(SUPP_BE, INITIALIZE) -{ - SM_ENTRY(SUPP_BE, INITIALIZE); - eapol_sm_abortSupp(sm); - sm->suppAbort = FALSE; - - /* - * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so - * allows the timer tick to be stopped more quickly when the port is - * not enabled. Since this variable is used only within RECEIVE state, - * clearing it on initialization does not change actual state machine - * behavior. - */ - sm->authWhile = 0; -} - - -SM_STATE(SUPP_BE, RECEIVE) -{ - SM_ENTRY(SUPP_BE, RECEIVE); - sm->authWhile = sm->authPeriod; - eapol_enable_timer_tick(sm); - sm->eapolEap = FALSE; - sm->eapNoResp = FALSE; - sm->initial_req = FALSE; -} - - -SM_STEP(SUPP_BE) -{ - if (sm->initialize || sm->suppAbort) - SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE); - else switch (sm->SUPP_BE_state) { - case SUPP_BE_UNKNOWN: - break; - case SUPP_BE_REQUEST: - /* - * 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 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 - * cause problems and the direct transitions to do not seem - * correct. Because of this, the conditions for these - * transitions are verified only after eapNoResp. They are - * unlikely to be used since eapNoResp should always be set if - * either of eapSuccess or eapFail is set. - */ - if (sm->eapResp && sm->eapNoResp) { - wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both " - "eapResp and eapNoResp set?!"); - } - if (sm->eapResp) - SM_ENTER(SUPP_BE, RESPONSE); - else if (sm->eapNoResp) - SM_ENTER(SUPP_BE, RECEIVE); - else if (sm->eapFail) - SM_ENTER(SUPP_BE, FAIL); - else if (sm->eapSuccess) - SM_ENTER(SUPP_BE, SUCCESS); - break; - case SUPP_BE_RESPONSE: - SM_ENTER(SUPP_BE, RECEIVE); - break; - case SUPP_BE_SUCCESS: - SM_ENTER(SUPP_BE, IDLE); - break; - case SUPP_BE_FAIL: - SM_ENTER(SUPP_BE, IDLE); - break; - case SUPP_BE_TIMEOUT: - SM_ENTER(SUPP_BE, IDLE); - break; - case SUPP_BE_IDLE: - if (sm->eapFail && sm->suppStart) - SM_ENTER(SUPP_BE, FAIL); - else if (sm->eapolEap && sm->suppStart) - SM_ENTER(SUPP_BE, REQUEST); - else if (sm->eapSuccess && sm->suppStart) - SM_ENTER(SUPP_BE, SUCCESS); - break; - case SUPP_BE_INITIALIZE: - SM_ENTER(SUPP_BE, IDLE); - break; - case SUPP_BE_RECEIVE: - if (sm->eapolEap) - SM_ENTER(SUPP_BE, REQUEST); - else if (sm->eapFail) - SM_ENTER(SUPP_BE, FAIL); - else if (sm->authWhile == 0) - SM_ENTER(SUPP_BE, TIMEOUT); - else if (sm->eapSuccess) - SM_ENTER(SUPP_BE, SUCCESS); - break; - } -} - - -static void eapol_sm_txLogoff(struct eapol_sm *sm) -{ - wpa_printf(MSG_DEBUG, "EAPOL: txLogoff"); - sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, - IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0); - sm->dot1xSuppEapolLogoffFramesTx++; - sm->dot1xSuppEapolFramesTx++; -} - - -static void eapol_sm_txStart(struct eapol_sm *sm) -{ - wpa_printf(MSG_DEBUG, "EAPOL: txStart"); - sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, - IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0); - sm->dot1xSuppEapolStartFramesTx++; - sm->dot1xSuppEapolFramesTx++; -} - - -#define IEEE8021X_ENCR_KEY_LEN 32 -#define IEEE8021X_SIGN_KEY_LEN 32 - -struct eap_key_data { - u8 encr_key[IEEE8021X_ENCR_KEY_LEN]; - u8 sign_key[IEEE8021X_SIGN_KEY_LEN]; -}; - - -static void eapol_sm_processKey(struct eapol_sm *sm) -{ -#ifndef CONFIG_FIPS - struct ieee802_1x_hdr *hdr; - struct ieee802_1x_eapol_key *key; - struct eap_key_data keydata; - u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32]; - u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN]; - int key_len, res, sign_key_len, encr_key_len; - u16 rx_key_length; - size_t plen; - - wpa_printf(MSG_DEBUG, "EAPOL: processKey"); - if (sm->last_rx_key == NULL) - return; - - if (!sm->conf.accept_802_1x_keys) { - wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key" - " even though this was not accepted - " - "ignoring this packet"); - return; - } - - if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key)) - return; - hdr = (struct ieee802_1x_hdr *) sm->last_rx_key; - key = (struct ieee802_1x_eapol_key *) (hdr + 1); - plen = be_to_host16(hdr->length); - if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) { - wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame"); - return; - } - rx_key_length = WPA_GET_BE16(key->key_length); - wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d " - "EAPOL-Key: type=%d key_length=%d key_index=0x%x", - hdr->version, hdr->type, be_to_host16(hdr->length), - key->type, rx_key_length, key->key_index); - - eapol_sm_notify_lower_layer_success(sm, 1); - sign_key_len = IEEE8021X_SIGN_KEY_LEN; - encr_key_len = IEEE8021X_ENCR_KEY_LEN; - res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata)); - if (res < 0) { - wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for " - "decrypting EAPOL-Key keys"); - return; - } - if (res == 16) { - /* LEAP derives only 16 bytes of keying material. */ - res = eapol_sm_get_key(sm, (u8 *) &keydata, 16); - if (res) { - wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP " - "master key for decrypting EAPOL-Key keys"); - return; - } - sign_key_len = 16; - encr_key_len = 16; - os_memcpy(keydata.sign_key, keydata.encr_key, 16); - } else if (res) { - wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key " - "data for decrypting EAPOL-Key keys (res=%d)", res); - return; - } - - /* The key replay_counter must increase when same master key */ - if (sm->replay_counter_valid && - os_memcmp(sm->last_replay_counter, key->replay_counter, - IEEE8021X_REPLAY_COUNTER_LEN) >= 0) { - wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did " - "not increase - ignoring key"); - wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter", - sm->last_replay_counter, - IEEE8021X_REPLAY_COUNTER_LEN); - wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter", - key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN); - return; - } - - /* Verify key signature (HMAC-MD5) */ - os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN); - os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN); - hmac_md5(keydata.sign_key, sign_key_len, - sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length), - key->key_signature); - if (os_memcmp(orig_key_sign, key->key_signature, - IEEE8021X_KEY_SIGN_LEN) != 0) { - wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in " - "EAPOL-Key packet"); - os_memcpy(key->key_signature, orig_key_sign, - IEEE8021X_KEY_SIGN_LEN); - return; - } - wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified"); - - key_len = plen - sizeof(*key); - if (key_len > 32 || rx_key_length > 32) { - wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d", - key_len ? key_len : rx_key_length); - return; - } - if (key_len == rx_key_length) { - os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN); - os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key, - encr_key_len); - os_memcpy(datakey, key + 1, key_len); - rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0, - datakey, key_len); - wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key", - datakey, key_len); - } else if (key_len == 0) { - /* - * IEEE 802.1X-2004 specifies that least significant Key Length - * octets from MS-MPPE-Send-Key are used as the key if the key - * data is not present. This seems to be meaning the beginning - * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in - * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator. - * Anyway, taking the beginning of the keying material from EAP - * seems to interoperate with Authenticators. - */ - key_len = rx_key_length; - os_memcpy(datakey, keydata.encr_key, key_len); - wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying " - "material data encryption key", - datakey, key_len); - } else { - wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d " - "(key_length=%d)", key_len, rx_key_length); - return; - } - - sm->replay_counter_valid = TRUE; - os_memcpy(sm->last_replay_counter, key->replay_counter, - IEEE8021X_REPLAY_COUNTER_LEN); - - wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d " - "len %d", - key->key_index & IEEE8021X_KEY_INDEX_FLAG ? - "unicast" : "broadcast", - key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len); - - if (sm->ctx->set_wep_key && - sm->ctx->set_wep_key(sm->ctx->ctx, - key->key_index & IEEE8021X_KEY_INDEX_FLAG, - key->key_index & IEEE8021X_KEY_INDEX_MASK, - datakey, key_len) < 0) { - wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the " - " driver."); - } else { - if (key->key_index & IEEE8021X_KEY_INDEX_FLAG) - sm->unicast_key_received = TRUE; - else - sm->broadcast_key_received = TRUE; - - if ((sm->unicast_key_received || - !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) && - (sm->broadcast_key_received || - !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST))) - { - wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key " - "frames received"); - sm->portValid = TRUE; - if (sm->ctx->eapol_done_cb) - sm->ctx->eapol_done_cb(sm->ctx->ctx); - } - } -#endif /* CONFIG_FIPS */ -} - - -static void eapol_sm_getSuppRsp(struct eapol_sm *sm) -{ - wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp"); - /* EAP layer processing; no special code is needed, since Supplicant - * Backend state machine is waiting for eapNoResp or eapResp to be set - * and these are only set in the EAP state machine when the processing - * has finished. */ -} - - -static void eapol_sm_txSuppRsp(struct eapol_sm *sm) -{ - struct wpabuf *resp; - - wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp"); - -#ifdef CONFIG_EAP_PROXY - if (sm->use_eap_proxy) { - /* Get EAP Response from EAP Proxy */ - resp = eap_proxy_get_eapRespData(sm->eap_proxy); - if (resp == NULL) { - wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP Proxy " - "response data not available"); - return; - } - } else -#endif /* CONFIG_EAP_PROXY */ - - resp = eap_get_eapRespData(sm->eap); - if (resp == NULL) { - wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data " - "not available"); - return; - } - - /* Send EAP-Packet from the EAP layer to the Authenticator */ - sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, - IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp), - wpabuf_len(resp)); - - /* eapRespData is not used anymore, so free it here */ - wpabuf_free(resp); - - if (sm->initial_req) - sm->dot1xSuppEapolReqIdFramesRx++; - else - sm->dot1xSuppEapolReqFramesRx++; - sm->dot1xSuppEapolRespFramesTx++; - sm->dot1xSuppEapolFramesTx++; -} - - -static void eapol_sm_abortSupp(struct eapol_sm *sm) -{ - /* release system resources that may have been allocated for the - * authentication session */ - os_free(sm->last_rx_key); - sm->last_rx_key = NULL; - wpabuf_free(sm->eapReqData); - sm->eapReqData = NULL; - eap_sm_abort(sm->eap); -} - - -static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx) -{ - eapol_sm_step(timeout_ctx); -} - - -static void eapol_sm_set_port_authorized(struct eapol_sm *sm) -{ - int cb; - - cb = sm->suppPortStatus != Authorized || sm->force_authorized_update; - sm->force_authorized_update = FALSE; - sm->suppPortStatus = Authorized; - if (cb && sm->ctx->port_cb) - sm->ctx->port_cb(sm->ctx->ctx, 1); -} - - -static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm) -{ - int cb; - - cb = sm->suppPortStatus != Unauthorized || sm->force_authorized_update; - sm->force_authorized_update = FALSE; - sm->suppPortStatus = Unauthorized; - if (cb && sm->ctx->port_cb) - sm->ctx->port_cb(sm->ctx->ctx, 0); -} - - -/** - * eapol_sm_step - EAPOL state machine step function - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * - * This function is called to notify the state machine about changed external - * variables. It will step through the EAPOL state machines in loop to process - * all triggered state changes. - */ -void eapol_sm_step(struct eapol_sm *sm) -{ - int i; - - /* In theory, it should be ok to run this in loop until !changed. - * However, it is better to use a limit on number of iterations to - * allow events (e.g., SIGTERM) to stop the program cleanly if the - * state machine were to generate a busy loop. */ - for (i = 0; i < 100; i++) { - sm->changed = FALSE; - SM_STEP_RUN(SUPP_PAE); - SM_STEP_RUN(KEY_RX); - SM_STEP_RUN(SUPP_BE); -#ifdef CONFIG_EAP_PROXY - if (sm->use_eap_proxy) { - /* Drive the EAP proxy state machine */ - if (eap_proxy_sm_step(sm->eap_proxy, sm->eap)) - sm->changed = TRUE; - } else -#endif /* CONFIG_EAP_PROXY */ - if (eap_peer_sm_step(sm->eap)) - sm->changed = TRUE; - if (!sm->changed) - break; - } - - if (sm->changed) { - /* restart EAPOL state machine step from timeout call in order - * to allow other events to be processed. */ - eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm); - eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm); - } - - if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) { - enum eapol_supp_result result; - if (sm->cb_status == EAPOL_CB_SUCCESS) - result = EAPOL_SUPP_RESULT_SUCCESS; - else if (eap_peer_was_failure_expected(sm->eap)) - result = EAPOL_SUPP_RESULT_EXPECTED_FAILURE; - else - result = EAPOL_SUPP_RESULT_FAILURE; - sm->cb_status = EAPOL_CB_IN_PROGRESS; - sm->ctx->cb(sm, result, sm->ctx->cb_ctx); - } -} - - -#ifdef CONFIG_CTRL_IFACE -static const char *eapol_supp_pae_state(int state) -{ - switch (state) { - case SUPP_PAE_LOGOFF: - return "LOGOFF"; - case SUPP_PAE_DISCONNECTED: - return "DISCONNECTED"; - case SUPP_PAE_CONNECTING: - return "CONNECTING"; - case SUPP_PAE_AUTHENTICATING: - return "AUTHENTICATING"; - case SUPP_PAE_HELD: - return "HELD"; - case SUPP_PAE_AUTHENTICATED: - return "AUTHENTICATED"; - case SUPP_PAE_RESTART: - return "RESTART"; - default: - return "UNKNOWN"; - } -} - - -static const char *eapol_supp_be_state(int state) -{ - switch (state) { - case SUPP_BE_REQUEST: - return "REQUEST"; - case SUPP_BE_RESPONSE: - return "RESPONSE"; - case SUPP_BE_SUCCESS: - return "SUCCESS"; - case SUPP_BE_FAIL: - return "FAIL"; - case SUPP_BE_TIMEOUT: - return "TIMEOUT"; - case SUPP_BE_IDLE: - return "IDLE"; - case SUPP_BE_INITIALIZE: - return "INITIALIZE"; - case SUPP_BE_RECEIVE: - return "RECEIVE"; - default: - return "UNKNOWN"; - } -} - - -static const char * eapol_port_status(PortStatus status) -{ - if (status == Authorized) - return "Authorized"; - else - return "Unauthorized"; -} -#endif /* CONFIG_CTRL_IFACE */ - - -#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) -static const char * eapol_port_control(PortControl ctrl) -{ - switch (ctrl) { - case Auto: - return "Auto"; - case ForceUnauthorized: - return "ForceUnauthorized"; - case ForceAuthorized: - return "ForceAuthorized"; - default: - return "Unknown"; - } -} -#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ - - -/** - * eapol_sm_configure - Set EAPOL variables - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @heldPeriod: dot1xSuppHeldPeriod - * @authPeriod: dot1xSuppAuthPeriod - * @startPeriod: dot1xSuppStartPeriod - * @maxStart: dot1xSuppMaxStart - * - * Set configurable EAPOL state machine variables. Each variable can be set to - * the given value or ignored if set to -1 (to set only some of the variables). - */ -void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod, - int startPeriod, int maxStart) -{ - if (sm == NULL) - return; - if (heldPeriod >= 0) - sm->heldPeriod = heldPeriod; - if (authPeriod >= 0) - sm->authPeriod = authPeriod; - if (startPeriod >= 0) - sm->startPeriod = startPeriod; - if (maxStart >= 0) - sm->maxStart = maxStart; -} - - -/** - * eapol_sm_get_method_name - Get EAPOL method name - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * Returns: Static string containing name of current eap method or NULL - */ -const char * eapol_sm_get_method_name(struct eapol_sm *sm) -{ - if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED || - sm->suppPortStatus != Authorized) - return NULL; - - return eap_sm_get_method_name(sm->eap); -} - - -#ifdef CONFIG_CTRL_IFACE -/** - * eapol_sm_get_status - Get EAPOL state machine status - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @buf: Buffer for status information - * @buflen: Maximum buffer length - * @verbose: Whether to include verbose status information - * Returns: Number of bytes written to buf. - * - * Query EAPOL state machine for status information. This function fills in a - * text area with current status information from the EAPOL state machine. If - * the buffer (buf) is not large enough, status information will be truncated - * to fit the buffer. - */ -int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen, - int verbose) -{ - int len, ret; - if (sm == NULL) - return 0; - - len = os_snprintf(buf, buflen, - "Supplicant PAE state=%s\n" - "suppPortStatus=%s\n", - eapol_supp_pae_state(sm->SUPP_PAE_state), - eapol_port_status(sm->suppPortStatus)); - if (len < 0 || (size_t) len >= buflen) - return 0; - - if (verbose) { - ret = os_snprintf(buf + len, buflen - len, - "heldPeriod=%u\n" - "authPeriod=%u\n" - "startPeriod=%u\n" - "maxStart=%u\n" - "portControl=%s\n" - "Supplicant Backend state=%s\n", - sm->heldPeriod, - sm->authPeriod, - sm->startPeriod, - sm->maxStart, - eapol_port_control(sm->portControl), - eapol_supp_be_state(sm->SUPP_BE_state)); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - } - -#ifdef CONFIG_EAP_PROXY - if (sm->use_eap_proxy) - len += eap_proxy_sm_get_status(sm->eap_proxy, - buf + len, buflen - len, - verbose); - else -#endif /* CONFIG_EAP_PROXY */ - len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose); - - return len; -} - - -/** - * eapol_sm_get_mib - Get EAPOL state machine MIBs - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @buf: Buffer for MIB information - * @buflen: Maximum buffer length - * Returns: Number of bytes written to buf. - * - * Query EAPOL state machine for MIB information. This function fills in a - * text area with current MIB information from the EAPOL state machine. If - * the buffer (buf) is not large enough, MIB information will be truncated to - * fit the buffer. - */ -int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen) -{ - size_t len; - int ret; - - if (sm == NULL) - return 0; - ret = os_snprintf(buf, buflen, - "dot1xSuppPaeState=%d\n" - "dot1xSuppHeldPeriod=%u\n" - "dot1xSuppAuthPeriod=%u\n" - "dot1xSuppStartPeriod=%u\n" - "dot1xSuppMaxStart=%u\n" - "dot1xSuppSuppControlledPortStatus=%s\n" - "dot1xSuppBackendPaeState=%d\n", - sm->SUPP_PAE_state, - sm->heldPeriod, - sm->authPeriod, - sm->startPeriod, - sm->maxStart, - sm->suppPortStatus == Authorized ? - "Authorized" : "Unauthorized", - sm->SUPP_BE_state); - - if (ret < 0 || (size_t) ret >= buflen) - return 0; - len = ret; - - ret = os_snprintf(buf + len, buflen - len, - "dot1xSuppEapolFramesRx=%u\n" - "dot1xSuppEapolFramesTx=%u\n" - "dot1xSuppEapolStartFramesTx=%u\n" - "dot1xSuppEapolLogoffFramesTx=%u\n" - "dot1xSuppEapolRespFramesTx=%u\n" - "dot1xSuppEapolReqIdFramesRx=%u\n" - "dot1xSuppEapolReqFramesRx=%u\n" - "dot1xSuppInvalidEapolFramesRx=%u\n" - "dot1xSuppEapLengthErrorFramesRx=%u\n" - "dot1xSuppLastEapolFrameVersion=%u\n" - "dot1xSuppLastEapolFrameSource=" MACSTR "\n", - sm->dot1xSuppEapolFramesRx, - sm->dot1xSuppEapolFramesTx, - sm->dot1xSuppEapolStartFramesTx, - sm->dot1xSuppEapolLogoffFramesTx, - sm->dot1xSuppEapolRespFramesTx, - sm->dot1xSuppEapolReqIdFramesRx, - sm->dot1xSuppEapolReqFramesRx, - sm->dot1xSuppInvalidEapolFramesRx, - sm->dot1xSuppEapLengthErrorFramesRx, - sm->dot1xSuppLastEapolFrameVersion, - MAC2STR(sm->dot1xSuppLastEapolFrameSource)); - - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - - return len; -} -#endif /* CONFIG_CTRL_IFACE */ - - -/** - * eapol_sm_rx_eapol - Process received EAPOL frames - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @src: Source MAC address of the EAPOL packet - * @buf: Pointer to the beginning of the EAPOL data (EAPOL header) - * @len: Length of the EAPOL frame - * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine, - * -1 failure - */ -int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, - size_t len) -{ - const struct ieee802_1x_hdr *hdr; - const struct ieee802_1x_eapol_key *key; - int data_len; - int res = 1; - size_t plen; - - if (sm == NULL) - return 0; - sm->dot1xSuppEapolFramesRx++; - if (len < sizeof(*hdr)) { - sm->dot1xSuppInvalidEapolFramesRx++; - return 0; - } - hdr = (const struct ieee802_1x_hdr *) buf; - sm->dot1xSuppLastEapolFrameVersion = hdr->version; - os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN); - if (hdr->version < EAPOL_VERSION) { - /* TODO: backwards compatibility */ - } - plen = be_to_host16(hdr->length); - if (plen > len - sizeof(*hdr)) { - sm->dot1xSuppEapLengthErrorFramesRx++; - return 0; - } -#ifdef CONFIG_WPS - if (sm->conf.workaround && - plen < len - sizeof(*hdr) && - hdr->type == IEEE802_1X_TYPE_EAP_PACKET && - len - sizeof(*hdr) > sizeof(struct eap_hdr)) { - const struct eap_hdr *ehdr = - (const struct eap_hdr *) (hdr + 1); - u16 elen; - - elen = be_to_host16(ehdr->length); - if (elen > plen && elen <= len - sizeof(*hdr)) { - /* - * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS - * packets with too short EAPOL header length field - * (14 octets). This is fixed in firmware Ver.1.49. - * As a workaround, fix the EAPOL header based on the - * correct length in the EAP packet. - */ - wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL " - "payload length based on EAP header: " - "%d -> %d", (int) plen, elen); - plen = elen; - } - } -#endif /* CONFIG_WPS */ - data_len = plen + sizeof(*hdr); - - switch (hdr->type) { - case IEEE802_1X_TYPE_EAP_PACKET: - if (sm->conf.workaround) { - /* - * An AP has been reported to send out EAP message with - * undocumented code 10 at some point near the - * completion of EAP authentication. This can result in - * issues with the unexpected EAP message triggering - * restart of EAPOL authentication. Avoid this by - * skipping the message without advancing the state - * machine. - */ - const struct eap_hdr *ehdr = - (const struct eap_hdr *) (hdr + 1); - if (plen >= sizeof(*ehdr) && ehdr->code == 10) { - wpa_printf(MSG_DEBUG, "EAPOL: Ignore EAP packet with unknown code 10"); - break; - } - } - - if (sm->cached_pmk) { - /* Trying to use PMKSA caching, but Authenticator did - * not seem to have a matching entry. Need to restart - * EAPOL state machines. - */ - eapol_sm_abort_cached(sm); - } - wpabuf_free(sm->eapReqData); - sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen); - if (sm->eapReqData) { - wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet " - "frame"); - sm->eapolEap = TRUE; -#ifdef CONFIG_EAP_PROXY - if (sm->use_eap_proxy) { - eap_proxy_packet_update( - sm->eap_proxy, - wpabuf_mhead_u8(sm->eapReqData), - wpabuf_len(sm->eapReqData)); - wpa_printf(MSG_DEBUG, "EAPOL: eap_proxy " - "EAP Req updated"); - } -#endif /* CONFIG_EAP_PROXY */ - eapol_sm_step(sm); - } - break; - case IEEE802_1X_TYPE_EAPOL_KEY: - if (plen < sizeof(*key)) { - wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key " - "frame received"); - break; - } - key = (const struct ieee802_1x_eapol_key *) (hdr + 1); - if (key->type == EAPOL_KEY_TYPE_WPA || - key->type == EAPOL_KEY_TYPE_RSN) { - /* WPA Supplicant takes care of this frame. */ - wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key " - "frame in EAPOL state machines"); - res = 0; - break; - } - if (key->type != EAPOL_KEY_TYPE_RC4) { - wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown " - "EAPOL-Key type %d", key->type); - break; - } - os_free(sm->last_rx_key); - sm->last_rx_key = os_malloc(data_len); - if (sm->last_rx_key) { - wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key " - "frame"); - os_memcpy(sm->last_rx_key, buf, data_len); - sm->last_rx_key_len = data_len; - sm->rxKey = TRUE; - eapol_sm_step(sm); - } - break; - default: - wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d", - hdr->type); - sm->dot1xSuppInvalidEapolFramesRx++; - break; - } - - return res; -} - - -/** - * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * - * Notify EAPOL state machine about transmitted EAPOL packet from an external - * component, e.g., WPA. This will update the statistics. - */ -void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm) -{ - if (sm) - sm->dot1xSuppEapolFramesTx++; -} - - -/** - * eapol_sm_notify_portEnabled - Notification about portEnabled change - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @enabled: New portEnabled value - * - * Notify EAPOL state machine about new portEnabled value. - */ -void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled) -{ - if (sm == NULL) - return; - wpa_printf(MSG_DEBUG, "EAPOL: External notification - " - "portEnabled=%d", enabled); - if (sm->portEnabled != enabled) - sm->force_authorized_update = TRUE; - sm->portEnabled = enabled; - eapol_sm_step(sm); -} - - -/** - * eapol_sm_notify_portValid - Notification about portValid change - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @valid: New portValid value - * - * Notify EAPOL state machine about new portValid value. - */ -void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid) -{ - if (sm == NULL) - return; - wpa_printf(MSG_DEBUG, "EAPOL: External notification - " - "portValid=%d", valid); - sm->portValid = valid; - eapol_sm_step(sm); -} - - -/** - * eapol_sm_notify_eap_success - Notification of external EAP success trigger - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @success: %TRUE = set success, %FALSE = clear success - * - * Notify the EAPOL state machine that external event has forced EAP state to - * success (success = %TRUE). This can be cleared by setting success = %FALSE. - * - * This function is called to update EAP state when WPA-PSK key handshake has - * been completed successfully since WPA-PSK does not use EAP state machine. - */ -void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success) -{ - if (sm == NULL) - return; - wpa_printf(MSG_DEBUG, "EAPOL: External notification - " - "EAP success=%d", success); - sm->eapSuccess = success; - sm->altAccept = success; - if (success) - eap_notify_success(sm->eap); - eapol_sm_step(sm); -} - - -/** - * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @fail: %TRUE = set failure, %FALSE = clear failure - * - * Notify EAPOL state machine that external event has forced EAP state to - * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE. - */ -void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail) -{ - if (sm == NULL) - return; - wpa_printf(MSG_DEBUG, "EAPOL: External notification - " - "EAP fail=%d", fail); - sm->eapFail = fail; - sm->altReject = fail; - eapol_sm_step(sm); -} - - -/** - * eapol_sm_notify_config - Notification of EAPOL configuration change - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @config: Pointer to current network EAP configuration - * @conf: Pointer to EAPOL configuration data - * - * Notify EAPOL state machine that configuration has changed. config will be - * stored as a backpointer to network configuration. This can be %NULL to clear - * the stored pointed. conf will be copied to local EAPOL/EAP configuration - * data. If conf is %NULL, this part of the configuration change will be - * skipped. - */ -void eapol_sm_notify_config(struct eapol_sm *sm, - struct eap_peer_config *config, - const struct eapol_config *conf) -{ - if (sm == NULL) - return; - - sm->config = config; -#ifdef CONFIG_EAP_PROXY - sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0; -#endif /* CONFIG_EAP_PROXY */ - - if (conf == NULL) - return; - - sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys; - sm->conf.required_keys = conf->required_keys; - sm->conf.fast_reauth = conf->fast_reauth; - sm->conf.workaround = conf->workaround; -#ifdef CONFIG_EAP_PROXY - if (sm->use_eap_proxy) { - /* Using EAP Proxy, so skip EAP state machine update */ - return; - } -#endif /* CONFIG_EAP_PROXY */ - if (sm->eap) { - eap_set_fast_reauth(sm->eap, conf->fast_reauth); - eap_set_workaround(sm->eap, conf->workaround); - eap_set_force_disabled(sm->eap, conf->eap_disabled); - eap_set_external_sim(sm->eap, conf->external_sim); - } -} - - -/** - * eapol_sm_get_key - Get master session key (MSK) from EAP - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @key: Pointer for key buffer - * @len: Number of bytes to copy to key - * Returns: 0 on success (len of key available), maximum available key len - * (>0) if key is available but it is shorter than len, or -1 on failure. - * - * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key - * is available only after a successful authentication. - */ -int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len) -{ - const u8 *eap_key; - size_t eap_len; - -#ifdef CONFIG_EAP_PROXY - if (sm->use_eap_proxy) { - /* Get key from EAP proxy */ - if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) { - wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available"); - return -1; - } - eap_key = eap_proxy_get_eapKeyData(sm->eap_proxy, &eap_len); - if (eap_key == NULL) { - wpa_printf(MSG_DEBUG, "EAPOL: Failed to get " - "eapKeyData"); - return -1; - } - goto key_fetched; - } -#endif /* CONFIG_EAP_PROXY */ - if (sm == NULL || !eap_key_available(sm->eap)) { - wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available"); - return -1; - } - eap_key = eap_get_eapKeyData(sm->eap, &eap_len); - if (eap_key == NULL) { - wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData"); - return -1; - } -#ifdef CONFIG_EAP_PROXY -key_fetched: -#endif /* CONFIG_EAP_PROXY */ - if (len > eap_len) { - wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not " - "available (len=%lu)", - (unsigned long) len, (unsigned long) eap_len); - return eap_len; - } - os_memcpy(key, eap_key, len); - wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)", - (unsigned long) len); - return 0; -} - - -/** - * eapol_sm_notify_logoff - Notification of logon/logoff commands - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @logoff: Whether command was logoff - * - * Notify EAPOL state machines that user requested logon/logoff. - */ -void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff) -{ - if (sm) { - sm->userLogoff = logoff; - if (!logoff) { - /* If there is a delayed txStart queued, start now. */ - sm->startWhen = 0; - } - eapol_sm_step(sm); - } -} - - -/** - * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * - * Notify EAPOL state machines that PMKSA caching was successful. This is used - * to move EAPOL and EAP state machines into authenticated/successful state. - */ -void eapol_sm_notify_cached(struct eapol_sm *sm) -{ - if (sm == NULL) - return; - wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL"); - sm->eapSuccess = TRUE; - eap_notify_success(sm->eap); - eapol_sm_step(sm); -} - - -/** - * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @attempt: Whether PMKSA caching is tried - * - * Notify EAPOL state machines whether PMKSA caching is used. - */ -void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt) -{ - if (sm == NULL) - return; - if (attempt) { - wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA"); - sm->cached_pmk = TRUE; - } else { - wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA"); - sm->cached_pmk = FALSE; - } -} - - -static void eapol_sm_abort_cached(struct eapol_sm *sm) -{ - wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, " - "doing full EAP authentication"); - if (sm == NULL) - return; - sm->cached_pmk = FALSE; - sm->SUPP_PAE_state = SUPP_PAE_CONNECTING; - eapol_sm_set_port_unauthorized(sm); - - /* Make sure we do not start sending EAPOL-Start frames first, but - * instead move to RESTART state to start EAPOL authentication. */ - sm->startWhen = 3; - eapol_enable_timer_tick(sm); - - if (sm->ctx->aborted_cached) - sm->ctx->aborted_cached(sm->ctx->ctx); -} - - -/** - * eapol_sm_register_scard_ctx - Notification of smart card context - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @ctx: Context data for smart card operations - * - * Notify EAPOL state machines of context data for smart card operations. This - * context data will be used as a parameter for scard_*() functions. - */ -void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx) -{ - if (sm) { - sm->ctx->scard_ctx = ctx; - eap_register_scard_ctx(sm->eap, ctx); - } -} - - -/** - * eapol_sm_notify_portControl - Notification of portControl changes - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @portControl: New value for portControl variable - * - * Notify EAPOL state machines that portControl variable has changed. - */ -void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl) -{ - if (sm == NULL) - return; - wpa_printf(MSG_DEBUG, "EAPOL: External notification - " - "portControl=%s", eapol_port_control(portControl)); - sm->portControl = portControl; - eapol_sm_step(sm); -} - - -/** - * eapol_sm_notify_ctrl_attached - Notification of attached monitor - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * - * Notify EAPOL state machines that a monitor was attached to the control - * interface to trigger re-sending of pending requests for user input. - */ -void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm) -{ - if (sm == NULL) - return; - eap_sm_notify_ctrl_attached(sm->eap); -} - - -/** - * eapol_sm_notify_ctrl_response - Notification of received user input - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * - * Notify EAPOL state machines that a control response, i.e., user - * input, was received in order to trigger retrying of a pending EAP request. - */ -void eapol_sm_notify_ctrl_response(struct eapol_sm *sm) -{ - if (sm == NULL) - return; - if (sm->eapReqData && !sm->eapReq) { - wpa_printf(MSG_DEBUG, "EAPOL: received control response (user " - "input) notification - retrying pending EAP " - "Request"); - sm->eapolEap = TRUE; - sm->eapReq = TRUE; - eapol_sm_step(sm); - } -} - - -/** - * eapol_sm_request_reauth - Request reauthentication - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * - * This function can be used to request EAPOL reauthentication, e.g., when the - * current PMKSA entry is nearing expiration. - */ -void eapol_sm_request_reauth(struct eapol_sm *sm) -{ - if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED) - return; - eapol_sm_txStart(sm); -} - - -/** - * eapol_sm_notify_lower_layer_success - Notification of lower layer success - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * @in_eapol_sm: Whether the caller is already running inside EAPOL state - * machine loop (eapol_sm_step()) - * - * Notify EAPOL (and EAP) state machines that a lower layer has detected a - * successful authentication. This is used to recover from dropped EAP-Success - * messages. - */ -void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm) -{ - if (sm == NULL) - return; - eap_notify_lower_layer_success(sm->eap); - if (!in_eapol_sm) - eapol_sm_step(sm); -} - - -/** - * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - */ -void eapol_sm_invalidate_cached_session(struct eapol_sm *sm) -{ - if (sm) - eap_invalidate_cached_session(sm->eap); -} - - -static struct eap_peer_config * eapol_sm_get_config(void *ctx) -{ - struct eapol_sm *sm = ctx; - return sm ? sm->config : NULL; -} - - -static struct wpabuf * eapol_sm_get_eapReqData(void *ctx) -{ - struct eapol_sm *sm = ctx; - if (sm == NULL || sm->eapReqData == NULL) - return NULL; - - return sm->eapReqData; -} - - -static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable) -{ - struct eapol_sm *sm = ctx; - if (sm == NULL) - return FALSE; - switch (variable) { - case EAPOL_eapSuccess: - return sm->eapSuccess; - case EAPOL_eapRestart: - return sm->eapRestart; - case EAPOL_eapFail: - return sm->eapFail; - case EAPOL_eapResp: - return sm->eapResp; - case EAPOL_eapNoResp: - return sm->eapNoResp; - case EAPOL_eapReq: - return sm->eapReq; - case EAPOL_portEnabled: - return sm->portEnabled; - case EAPOL_altAccept: - return sm->altAccept; - case EAPOL_altReject: - return sm->altReject; - } - return FALSE; -} - - -static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable, - Boolean value) -{ - struct eapol_sm *sm = ctx; - if (sm == NULL) - return; - switch (variable) { - case EAPOL_eapSuccess: - sm->eapSuccess = value; - break; - case EAPOL_eapRestart: - sm->eapRestart = value; - break; - case EAPOL_eapFail: - sm->eapFail = value; - break; - case EAPOL_eapResp: - sm->eapResp = value; - break; - case EAPOL_eapNoResp: - sm->eapNoResp = value; - break; - case EAPOL_eapReq: - sm->eapReq = value; - break; - case EAPOL_portEnabled: - sm->portEnabled = value; - break; - case EAPOL_altAccept: - sm->altAccept = value; - break; - case EAPOL_altReject: - sm->altReject = value; - break; - } -} - - -static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable) -{ - struct eapol_sm *sm = ctx; - if (sm == NULL) - return 0; - switch (variable) { - case EAPOL_idleWhile: - return sm->idleWhile; - } - return 0; -} - - -static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable, - unsigned int value) -{ - struct eapol_sm *sm = ctx; - if (sm == NULL) - return; - switch (variable) { - case EAPOL_idleWhile: - sm->idleWhile = value; - if (sm->idleWhile > 0) - eapol_enable_timer_tick(sm); - break; - } -} - - -static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob) -{ -#ifndef CONFIG_NO_CONFIG_BLOBS - struct eapol_sm *sm = ctx; - if (sm && sm->ctx && sm->ctx->set_config_blob) - sm->ctx->set_config_blob(sm->ctx->ctx, blob); -#endif /* CONFIG_NO_CONFIG_BLOBS */ -} - - -static const struct wpa_config_blob * -eapol_sm_get_config_blob(void *ctx, const char *name) -{ -#ifndef CONFIG_NO_CONFIG_BLOBS - struct eapol_sm *sm = ctx; - if (sm && sm->ctx && sm->ctx->get_config_blob) - return sm->ctx->get_config_blob(sm->ctx->ctx, name); - else - return NULL; -#else /* CONFIG_NO_CONFIG_BLOBS */ - return NULL; -#endif /* CONFIG_NO_CONFIG_BLOBS */ -} - - -static void eapol_sm_notify_pending(void *ctx) -{ - struct eapol_sm *sm = ctx; - if (sm == NULL) - return; - if (sm->eapReqData && !sm->eapReq) { - wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP " - "state machine - retrying pending EAP Request"); - sm->eapolEap = TRUE; - sm->eapReq = TRUE; - eapol_sm_step(sm); - } -} - - -#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) -static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field, - const char *txt) -{ - struct eapol_sm *sm = ctx; - wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed"); - if (sm->ctx->eap_param_needed) - sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt); -} -#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ -#define eapol_sm_eap_param_needed NULL -#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ - -static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject, - const char *cert_hash, - const struct wpabuf *cert) -{ - struct eapol_sm *sm = ctx; - if (sm->ctx->cert_cb) - sm->ctx->cert_cb(sm->ctx->ctx, depth, subject, - cert_hash, cert); -} - - -static void eapol_sm_notify_status(void *ctx, const char *status, - const char *parameter) -{ - struct eapol_sm *sm = ctx; - - if (sm->ctx->status_cb) - sm->ctx->status_cb(sm->ctx->ctx, status, parameter); -} - - -static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len) -{ - struct eapol_sm *sm = ctx; - - if (sm->ctx->set_anon_id) - sm->ctx->set_anon_id(sm->ctx->ctx, id, len); -} - - -static struct eapol_callbacks eapol_cb = -{ - eapol_sm_get_config, - eapol_sm_get_bool, - eapol_sm_set_bool, - eapol_sm_get_int, - eapol_sm_set_int, - eapol_sm_get_eapReqData, - eapol_sm_set_config_blob, - eapol_sm_get_config_blob, - eapol_sm_notify_pending, - eapol_sm_eap_param_needed, - eapol_sm_notify_cert, - eapol_sm_notify_status, - eapol_sm_set_anon_id -}; - - -/** - * eapol_sm_init - Initialize EAPOL state machine - * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer - * and EAPOL state machine will free it in eapol_sm_deinit() - * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure - * - * Allocate and initialize an EAPOL state machine. - */ -struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx) -{ - struct eapol_sm *sm; - struct eap_config conf; - sm = os_zalloc(sizeof(*sm)); - if (sm == NULL) - return NULL; - sm->ctx = ctx; - - sm->portControl = Auto; - - /* Supplicant PAE state machine */ - sm->heldPeriod = 60; - sm->startPeriod = 30; - sm->maxStart = 3; - - /* Supplicant Backend state machine */ - sm->authPeriod = 30; - - os_memset(&conf, 0, sizeof(conf)); - conf.opensc_engine_path = ctx->opensc_engine_path; - 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) { - os_free(sm); - return NULL; - } - -#ifdef CONFIG_EAP_PROXY - sm->use_eap_proxy = FALSE; - sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx); - if (sm->eap_proxy == NULL) { - wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy"); - } -#endif /* CONFIG_EAP_PROXY */ - - /* Initialize EAPOL state machines */ - sm->force_authorized_update = TRUE; - sm->initialize = TRUE; - eapol_sm_step(sm); - sm->initialize = FALSE; - eapol_sm_step(sm); - - sm->timer_tick_enabled = 1; - eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm); - - return sm; -} - - -/** - * eapol_sm_deinit - Deinitialize EAPOL state machine - * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() - * - * Deinitialize and free EAPOL state machine. - */ -void eapol_sm_deinit(struct eapol_sm *sm) -{ - if (sm == NULL) - return; - eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm); - eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm); - eap_peer_sm_deinit(sm->eap); -#ifdef CONFIG_EAP_PROXY - eap_proxy_deinit(sm->eap_proxy); -#endif /* CONFIG_EAP_PROXY */ - os_free(sm->last_rx_key); - wpabuf_free(sm->eapReqData); - os_free(sm->ctx); - os_free(sm); -} - - -void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm, - struct ext_password_data *ext) -{ - if (sm && sm->eap) - eap_sm_set_ext_pw_ctx(sm->eap, ext); -} - - -int eapol_sm_failed(struct eapol_sm *sm) -{ - if (sm == NULL) - return 0; - return !sm->eapSuccess && sm->eapFail; -} - - -int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len) -{ -#ifdef CONFIG_EAP_PROXY - if (sm->eap_proxy == NULL) - return -1; - return eap_proxy_get_imsi(sm->eap_proxy, imsi, len); -#else /* CONFIG_EAP_PROXY */ - return -1; -#endif /* CONFIG_EAP_PROXY */ -} diff --git a/contrib/hostapd/src/eapol_supp/eapol_supp_sm.h b/contrib/hostapd/src/eapol_supp/eapol_supp_sm.h deleted file mode 100644 index 934eda0109..0000000000 --- a/contrib/hostapd/src/eapol_supp/eapol_supp_sm.h +++ /dev/null @@ -1,404 +0,0 @@ -/* - * EAPOL supplicant state machines - * Copyright (c) 2004-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAPOL_SUPP_SM_H -#define EAPOL_SUPP_SM_H - -#include "common/defs.h" - -typedef enum { Unauthorized, Authorized } PortStatus; -typedef enum { Auto, ForceUnauthorized, ForceAuthorized } PortControl; - -/** - * struct eapol_config - Per network configuration for EAPOL state machines - */ -struct eapol_config { - /** - * accept_802_1x_keys - Accept IEEE 802.1X (non-WPA) EAPOL-Key frames - * - * This variable should be set to 1 when using EAPOL state machines - * with non-WPA security policy to generate dynamic WEP keys. When - * using WPA, this should be set to 0 so that WPA state machine can - * process the EAPOL-Key frames. - */ - int accept_802_1x_keys; - -#define EAPOL_REQUIRE_KEY_UNICAST BIT(0) -#define EAPOL_REQUIRE_KEY_BROADCAST BIT(1) - /** - * required_keys - Which EAPOL-Key packets are required - * - * This variable determines which EAPOL-Key packets are required before - * marking connection authenticated. This is a bit field of - * EAPOL_REQUIRE_KEY_UNICAST and EAPOL_REQUIRE_KEY_BROADCAST flags. - */ - int required_keys; - - /** - * fast_reauth - Whether fast EAP reauthentication is enabled - */ - int fast_reauth; - - /** - * workaround - Whether EAP workarounds are enabled - */ - unsigned int workaround; - - /** - * eap_disabled - Whether EAP is disabled - */ - int eap_disabled; - - /** - * external_sim - Use external processing for SIM/USIM operations - */ - int external_sim; -}; - -struct eapol_sm; -struct wpa_config_blob; - -enum eapol_supp_result { - EAPOL_SUPP_RESULT_FAILURE, - EAPOL_SUPP_RESULT_SUCCESS, - EAPOL_SUPP_RESULT_EXPECTED_FAILURE -}; - -/** - * struct eapol_ctx - Global (for all networks) EAPOL state machine context - */ -struct eapol_ctx { - /** - * ctx - Pointer to arbitrary upper level context - */ - void *ctx; - - /** - * preauth - IEEE 802.11i/RSN pre-authentication - * - * This EAPOL state machine is used for IEEE 802.11i/RSN - * pre-authentication - */ - int preauth; - - /** - * cb - Function to be called when EAPOL negotiation has been completed - * @eapol: Pointer to EAPOL state machine data - * @result: Whether the authentication was completed successfully - * @ctx: Pointer to context data (cb_ctx) - * - * This optional callback function will be called when the EAPOL - * authentication has been completed. This allows the owner of the - * EAPOL state machine to process the key and terminate the EAPOL state - * machine. Currently, this is used only in RSN pre-authentication. - */ - void (*cb)(struct eapol_sm *eapol, enum eapol_supp_result result, - void *ctx); - - /** - * cb_ctx - Callback context for cb() - */ - void *cb_ctx; - - /** - * msg_ctx - Callback context for wpa_msg() calls - */ - void *msg_ctx; - - /** - * scard_ctx - Callback context for PC/SC scard_*() function calls - * - * This context can be updated with eapol_sm_register_scard_ctx(). - */ - void *scard_ctx; - - /** - * eapol_send_ctx - Callback context for eapol_send() calls - */ - void *eapol_send_ctx; - - /** - * eapol_done_cb - Function to be called at successful completion - * @ctx: Callback context (ctx) - * - * This function is called at the successful completion of EAPOL - * authentication. If dynamic WEP keys are used, this is called only - * after all the expected keys have been received. - */ - void (*eapol_done_cb)(void *ctx); - - /** - * eapol_send - Send EAPOL packets - * @ctx: Callback context (eapol_send_ctx) - * @type: EAPOL type (IEEE802_1X_TYPE_*) - * @buf: Pointer to EAPOL payload - * @len: Length of the EAPOL payload - * Returns: 0 on success, -1 on failure - */ - int (*eapol_send)(void *ctx, int type, const u8 *buf, size_t len); - - /** - * set_wep_key - Configure WEP keys - * @ctx: Callback context (ctx) - * @unicast: Non-zero = unicast, 0 = multicast/broadcast key - * @keyidx: Key index (0..3) - * @key: WEP key - * @keylen: Length of the WEP key - * Returns: 0 on success, -1 on failure - */ - int (*set_wep_key)(void *ctx, int unicast, int keyidx, - const u8 *key, size_t keylen); - - /** - * set_config_blob - Set or add a named configuration blob - * @ctx: Callback context (ctx) - * @blob: New value for the blob - * - * Adds a new configuration blob or replaces the current value of an - * existing blob. - */ - void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob); - - /** - * get_config_blob - Get a named configuration blob - * @ctx: Callback context (ctx) - * @name: Name of the blob - * Returns: Pointer to blob data or %NULL if not found - */ - const struct wpa_config_blob * (*get_config_blob)(void *ctx, - const char *name); - - /** - * aborted_cached - Notify that cached PMK attempt was aborted - * @ctx: Callback context (ctx) - */ - void (*aborted_cached)(void *ctx); - - /** - * opensc_engine_path - Path to the OpenSSL engine for opensc - * - * This is an OpenSSL specific configuration option for loading OpenSC - * engine (engine_opensc.so); if %NULL, this engine is not loaded. - */ - const char *opensc_engine_path; - - /** - * pkcs11_engine_path - Path to the OpenSSL engine for PKCS#11 - * - * This is an OpenSSL specific configuration option for loading PKCS#11 - * engine (engine_pkcs11.so); if %NULL, this engine is not loaded. - */ - const char *pkcs11_engine_path; - - /** - * pkcs11_module_path - Path to the OpenSSL OpenSC/PKCS#11 module - * - * This is an OpenSSL specific configuration option for configuring - * path to OpenSC/PKCS#11 engine (opensc-pkcs11.so); if %NULL, this - * module is not loaded. - */ - const char *pkcs11_module_path; - - /** - * wps - WPS context data - * - * This is only used by EAP-WSC and can be left %NULL if not available. - */ - struct wps_context *wps; - - /** - * eap_param_needed - Notify that EAP parameter is needed - * @ctx: Callback context (ctx) - * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY) - * @txt: User readable text describing the required parameter - */ - void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field, - const char *txt); - - /** - * port_cb - Set port authorized/unauthorized callback (optional) - * @ctx: Callback context (ctx) - * @authorized: Whether the supplicant port is now in authorized state - */ - void (*port_cb)(void *ctx, int authorized); - - /** - * cert_cb - Notification of a peer certificate - * @ctx: Callback context (ctx) - * @depth: Depth in certificate chain (0 = server) - * @subject: Subject of the peer certificate - * @cert_hash: SHA-256 hash of the certificate - * @cert: Peer certificate - */ - 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; - - /** - * status_cb - Notification of a change in EAP status - * @ctx: Callback context (ctx) - * @status: Step in the process of EAP authentication - * @parameter: Step-specific parameter, e.g., EAP method name - */ - void (*status_cb)(void *ctx, const char *status, - const char *parameter); - - /** - * set_anon_id - Set or add anonymous identity - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @id: Anonymous identity (e.g., EAP-SIM pseudonym) - * @len: Length of anonymous identity in octets - */ - void (*set_anon_id)(void *ctx, const u8 *id, size_t len); -}; - - -struct eap_peer_config; -struct ext_password_data; - -#ifdef IEEE8021X_EAPOL -struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx); -void eapol_sm_deinit(struct eapol_sm *sm); -void eapol_sm_step(struct eapol_sm *sm); -int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen, - int verbose); -int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen); -void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod, - int startPeriod, int maxStart); -int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, - size_t len); -void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm); -void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled); -void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid); -void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success); -void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail); -void eapol_sm_notify_config(struct eapol_sm *sm, - struct eap_peer_config *config, - const struct eapol_config *conf); -int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len); -void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff); -void eapol_sm_notify_cached(struct eapol_sm *sm); -void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt); -void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx); -void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl); -void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm); -void eapol_sm_notify_ctrl_response(struct eapol_sm *sm); -void eapol_sm_request_reauth(struct eapol_sm *sm); -void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm); -void eapol_sm_invalidate_cached_session(struct eapol_sm *sm); -const char * eapol_sm_get_method_name(struct eapol_sm *sm); -void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm, - struct ext_password_data *ext); -int eapol_sm_failed(struct eapol_sm *sm); -int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len); -#else /* IEEE8021X_EAPOL */ -static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx) -{ - free(ctx); - return (struct eapol_sm *) 1; -} -static inline void eapol_sm_deinit(struct eapol_sm *sm) -{ -} -static inline void eapol_sm_step(struct eapol_sm *sm) -{ -} -static inline int eapol_sm_get_status(struct eapol_sm *sm, char *buf, - size_t buflen, int verbose) -{ - return 0; -} -static inline int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, - size_t buflen) -{ - return 0; -} -static inline void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, - int authPeriod, int startPeriod, - int maxStart) -{ -} -static inline int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, - const u8 *buf, size_t len) -{ - return 0; -} -static inline void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm) -{ -} -static inline void eapol_sm_notify_portEnabled(struct eapol_sm *sm, - Boolean enabled) -{ -} -static inline void eapol_sm_notify_portValid(struct eapol_sm *sm, - Boolean valid) -{ -} -static inline void eapol_sm_notify_eap_success(struct eapol_sm *sm, - Boolean success) -{ -} -static inline void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail) -{ -} -static inline void eapol_sm_notify_config(struct eapol_sm *sm, - struct eap_peer_config *config, - struct eapol_config *conf) -{ -} -static inline int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len) -{ - return -1; -} -static inline void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff) -{ -} -static inline void eapol_sm_notify_cached(struct eapol_sm *sm) -{ -} -#define eapol_sm_notify_pmkid_attempt(sm, attempt) do { } while (0) -#define eapol_sm_register_scard_ctx(sm, ctx) do { } while (0) -static inline void eapol_sm_notify_portControl(struct eapol_sm *sm, - PortControl portControl) -{ -} -static inline void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm) -{ -} -static inline void eapol_sm_notify_ctrl_response(struct eapol_sm *sm) -{ -} -static inline void eapol_sm_request_reauth(struct eapol_sm *sm) -{ -} -static inline void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, - int in_eapol_sm) -{ -} -static inline void eapol_sm_invalidate_cached_session(struct eapol_sm *sm) -{ -} -static inline const char * eapol_sm_get_method_name(struct eapol_sm *sm) -{ - return NULL; -} -static inline void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm, - struct ext_password_data *ext) -{ -} -static inline int eapol_sm_failed(struct eapol_sm *sm) -{ - return 0; -} -#endif /* IEEE8021X_EAPOL */ - -#endif /* EAPOL_SUPP_SM_H */ diff --git a/contrib/hostapd/src/l2_packet/l2_packet.h b/contrib/hostapd/src/l2_packet/l2_packet.h deleted file mode 100644 index dd825b5689..0000000000 --- a/contrib/hostapd/src/l2_packet/l2_packet.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * WPA Supplicant - Layer2 packet interface definition - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file defines an interface for layer 2 (link layer) packet sending and - * receiving. l2_packet_linux.c is one implementation for such a layer 2 - * implementation using Linux packet sockets and l2_packet_pcap.c another one - * using libpcap and libdnet. When porting %wpa_supplicant to other operating - * systems, a new l2_packet implementation may need to be added. - */ - -#ifndef L2_PACKET_H -#define L2_PACKET_H - -/** - * struct l2_packet_data - Internal l2_packet data structure - * - * This structure is used by the l2_packet implementation to store its private - * data. Other files use a pointer to this data when calling the l2_packet - * functions, but the contents of this structure should not be used directly - * outside l2_packet implementation. - */ -struct l2_packet_data; - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct l2_ethhdr { - u8 h_dest[ETH_ALEN]; - u8 h_source[ETH_ALEN]; - be16 h_proto; -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - -/** - * l2_packet_init - Initialize l2_packet interface - * @ifname: Interface name - * @own_addr: Optional own MAC address if available from driver interface or - * %NULL if not available - * @protocol: Ethernet protocol number in host byte order - * @rx_callback: Callback function that will be called for each received packet - * @rx_callback_ctx: Callback data (ctx) for calls to rx_callback() - * @l2_hdr: 1 = include layer 2 header, 0 = do not include header - * Returns: Pointer to internal data or %NULL on failure - * - * rx_callback function will be called with src_addr pointing to the source - * address (MAC address) of the the packet. If l2_hdr is set to 0, buf - * points to len bytes of the payload after the layer 2 header and similarly, - * TX buffers start with payload. This behavior can be changed by setting - * l2_hdr=1 to include the layer 2 header in the data buffer. - */ -struct l2_packet_data * l2_packet_init( - const char *ifname, const u8 *own_addr, unsigned short protocol, - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len), - void *rx_callback_ctx, int l2_hdr); - -/** - * l2_packet_deinit - Deinitialize l2_packet interface - * @l2: Pointer to internal l2_packet data from l2_packet_init() - */ -void l2_packet_deinit(struct l2_packet_data *l2); - -/** - * l2_packet_get_own_addr - Get own layer 2 address - * @l2: Pointer to internal l2_packet data from l2_packet_init() - * @addr: Buffer for the own address (6 bytes) - * Returns: 0 on success, -1 on failure - */ -int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr); - -/** - * l2_packet_send - Send a packet - * @l2: Pointer to internal l2_packet data from l2_packet_init() - * @dst_addr: Destination address for the packet (only used if l2_hdr == 0) - * @proto: Protocol/ethertype for the packet in host byte order (only used if - * l2_hdr == 0) - * @buf: Packet contents to be sent; including layer 2 header if l2_hdr was - * set to 1 in l2_packet_init() call. Otherwise, only the payload of the packet - * is included. - * @len: Length of the buffer (including l2 header only if l2_hdr == 1) - * Returns: >=0 on success, <0 on failure - */ -int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, - const u8 *buf, size_t len); - -/** - * l2_packet_get_ip_addr - Get the current IP address from the interface - * @l2: Pointer to internal l2_packet data from l2_packet_init() - * @buf: Buffer for the IP address in text format - * @len: Maximum buffer length - * Returns: 0 on success, -1 on failure - * - * This function can be used to get the current IP address from the interface - * bound to the l2_packet. This is mainly for status information and the IP - * address will be stored as an ASCII string. This function is not essential - * for %wpa_supplicant operation, so full implementation is not required. - * l2_packet implementation will need to define the function, but it can return - * -1 if the IP address information is not available. - */ -int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len); - - -/** - * l2_packet_notify_auth_start - Notify l2_packet about start of authentication - * @l2: Pointer to internal l2_packet data from l2_packet_init() - * - * This function is called when authentication is expected to start, e.g., when - * association has been completed, in order to prepare l2_packet implementation - * for EAPOL frames. This function is used mainly if the l2_packet code needs - * to do polling in which case it can increasing polling frequency. This can - * also be an empty function if the l2_packet implementation does not benefit - * from knowing about the starting authentication. - */ -void l2_packet_notify_auth_start(struct l2_packet_data *l2); - -#endif /* L2_PACKET_H */ diff --git a/contrib/hostapd/src/l2_packet/l2_packet_freebsd.c b/contrib/hostapd/src/l2_packet/l2_packet_freebsd.c deleted file mode 100644 index 2e9a04c894..0000000000 --- a/contrib/hostapd/src/l2_packet/l2_packet_freebsd.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * WPA Supplicant - Layer2 packet handling with FreeBSD - * Copyright (c) 2003-2005, Jouni Malinen - * Copyright (c) 2005, Sam Leffler - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#if defined(__APPLE__) || defined(__GLIBC__) -#include -#endif /* __APPLE__ */ -#include - -#include -#ifdef __sun__ -#include -#else /* __sun__ */ -#include -#endif /* __sun__ */ - -#include -#include -#include -#include - -#include "common.h" -#include "eloop.h" -#include "l2_packet.h" - - -static const u8 pae_group_addr[ETH_ALEN] = -{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; - -struct l2_packet_data { - pcap_t *pcap; - char ifname[100]; - u8 own_addr[ETH_ALEN]; - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len); - void *rx_callback_ctx; - int l2_hdr; /* whether to include layer 2 (Ethernet) header data - * buffers */ -}; - - -int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -{ - os_memcpy(addr, l2->own_addr, ETH_ALEN); - return 0; -} - - -int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, - const u8 *buf, size_t len) -{ - if (!l2->l2_hdr) { - int ret; - struct l2_ethhdr *eth = os_malloc(sizeof(*eth) + len); - if (eth == NULL) - return -1; - os_memcpy(eth->h_dest, dst_addr, ETH_ALEN); - os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN); - eth->h_proto = htons(proto); - os_memcpy(eth + 1, buf, len); - ret = pcap_inject(l2->pcap, (u8 *) eth, len + sizeof(*eth)); - os_free(eth); - return ret; - } else - return pcap_inject(l2->pcap, buf, len); -} - - -static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct l2_packet_data *l2 = eloop_ctx; - pcap_t *pcap = sock_ctx; - struct pcap_pkthdr hdr; - const u_char *packet; - struct l2_ethhdr *ethhdr; - unsigned char *buf; - size_t len; - - packet = pcap_next(pcap, &hdr); - - if (packet == NULL || hdr.caplen < sizeof(*ethhdr)) - return; - - ethhdr = (struct l2_ethhdr *) packet; - if (l2->l2_hdr) { - buf = (unsigned char *) ethhdr; - len = hdr.caplen; - } else { - buf = (unsigned char *) (ethhdr + 1); - len = hdr.caplen - sizeof(*ethhdr); - } - l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len); -} - - -static int l2_packet_init_libpcap(struct l2_packet_data *l2, - unsigned short protocol) -{ - bpf_u_int32 pcap_maskp, pcap_netp; - char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE]; - struct bpf_program pcap_fp; - - pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err); - l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 10, pcap_err); - if (l2->pcap == NULL) { - fprintf(stderr, "pcap_open_live: %s\n", pcap_err); - fprintf(stderr, "ifname='%s'\n", l2->ifname); - return -1; - } - if (pcap_datalink(l2->pcap) != DLT_EN10MB && - pcap_set_datalink(l2->pcap, DLT_EN10MB) < 0) { - fprintf(stderr, "pcap_set_datalink(DLT_EN10MB): %s\n", - pcap_geterr(l2->pcap)); - return -1; - } - os_snprintf(pcap_filter, sizeof(pcap_filter), - "not ether src " MACSTR " and " - "( ether dst " MACSTR " or ether dst " MACSTR " ) and " - "ether proto 0x%x", - MAC2STR(l2->own_addr), /* do not receive own packets */ - MAC2STR(l2->own_addr), MAC2STR(pae_group_addr), - protocol); - if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) { - fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap)); - return -1; - } - - if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) { - fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap)); - return -1; - } - - pcap_freecode(&pcap_fp); -#ifndef __sun__ - /* - * When libpcap uses BPF we must enable "immediate mode" to - * receive frames right away; otherwise the system may - * buffer them for us. - */ - { - unsigned int on = 1; - if (ioctl(pcap_fileno(l2->pcap), BIOCIMMEDIATE, &on) < 0) { - fprintf(stderr, "%s: cannot enable immediate mode on " - "interface %s: %s\n", - __func__, l2->ifname, strerror(errno)); - /* XXX should we fail? */ - } - } -#endif /* __sun__ */ - - eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap), - l2_packet_receive, l2, l2->pcap); - - return 0; -} - - -static int eth_get(const char *device, u8 ea[ETH_ALEN]) -{ -#ifdef __sun__ - dlpi_handle_t dh; - u32 physaddrlen = DLPI_PHYSADDR_MAX; - u8 physaddr[DLPI_PHYSADDR_MAX]; - int retval; - - retval = dlpi_open(device, &dh, 0); - if (retval != DLPI_SUCCESS) { - wpa_printf(MSG_ERROR, "dlpi_open error: %s", - dlpi_strerror(retval)); - return -1; - } - - retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, physaddr, - &physaddrlen); - if (retval != DLPI_SUCCESS) { - wpa_printf(MSG_ERROR, "dlpi_get_physaddr error: %s", - dlpi_strerror(retval)); - dlpi_close(dh); - return -1; - } - os_memcpy(ea, physaddr, ETH_ALEN); - dlpi_close(dh); -#else /* __sun__ */ - struct if_msghdr *ifm; - struct sockaddr_dl *sdl; - u_char *p, *buf; - size_t len; - int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 }; - - if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) - return -1; - if ((buf = os_malloc(len)) == NULL) - return -1; - if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { - os_free(buf); - return -1; - } - for (p = buf; p < buf + len; p += ifm->ifm_msglen) { - ifm = (struct if_msghdr *)p; - sdl = (struct sockaddr_dl *)(ifm + 1); - if (ifm->ifm_type != RTM_IFINFO || - (ifm->ifm_addrs & RTA_IFP) == 0) - continue; - if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 || - os_memcmp(sdl->sdl_data, device, sdl->sdl_nlen) != 0) - continue; - os_memcpy(ea, LLADDR(sdl), sdl->sdl_alen); - break; - } - os_free(buf); - - if (p >= buf + len) { - errno = ESRCH; - return -1; - } -#endif /* __sun__ */ - return 0; -} - - -struct l2_packet_data * l2_packet_init( - const char *ifname, const u8 *own_addr, unsigned short protocol, - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len), - void *rx_callback_ctx, int l2_hdr) -{ - struct l2_packet_data *l2; - - l2 = os_zalloc(sizeof(struct l2_packet_data)); - if (l2 == NULL) - return NULL; - os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); - l2->rx_callback = rx_callback; - l2->rx_callback_ctx = rx_callback_ctx; - l2->l2_hdr = l2_hdr; - - if (eth_get(l2->ifname, l2->own_addr) < 0) { - fprintf(stderr, "Failed to get link-level address for " - "interface '%s'.\n", l2->ifname); - os_free(l2); - return NULL; - } - - if (l2_packet_init_libpcap(l2, protocol)) { - os_free(l2); - return NULL; - } - - return l2; -} - - -void l2_packet_deinit(struct l2_packet_data *l2) -{ - if (l2 != NULL) { - if (l2->pcap) { - eloop_unregister_read_sock( - pcap_get_selectable_fd(l2->pcap)); - pcap_close(l2->pcap); - } - os_free(l2); - } -} - - -int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -{ - pcap_if_t *devs, *dev; - struct pcap_addr *addr; - struct sockaddr_in *saddr; - int found = 0; - char err[PCAP_ERRBUF_SIZE + 1]; - - if (pcap_findalldevs(&devs, err) < 0) { - wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err); - return -1; - } - - for (dev = devs; dev && !found; dev = dev->next) { - if (os_strcmp(dev->name, l2->ifname) != 0) - continue; - - addr = dev->addresses; - while (addr) { - saddr = (struct sockaddr_in *) addr->addr; - if (saddr && saddr->sin_family == AF_INET) { - os_strlcpy(buf, inet_ntoa(saddr->sin_addr), - len); - found = 1; - break; - } - addr = addr->next; - } - } - - pcap_freealldevs(devs); - - return found ? 0 : -1; -} - - -void l2_packet_notify_auth_start(struct l2_packet_data *l2) -{ -} diff --git a/contrib/hostapd/src/l2_packet/l2_packet_linux.c b/contrib/hostapd/src/l2_packet/l2_packet_linux.c deleted file mode 100644 index 1419830db7..0000000000 --- a/contrib/hostapd/src/l2_packet/l2_packet_linux.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * WPA Supplicant - Layer2 packet handling with Linux packet sockets - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include -#include -#include - -#include "common.h" -#include "eloop.h" -#include "l2_packet.h" - - -struct l2_packet_data { - int fd; /* packet socket for EAPOL frames */ - char ifname[IFNAMSIZ + 1]; - int ifindex; - u8 own_addr[ETH_ALEN]; - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len); - void *rx_callback_ctx; - int l2_hdr; /* whether to include layer 2 (Ethernet) header data - * buffers */ -}; - - -int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -{ - os_memcpy(addr, l2->own_addr, ETH_ALEN); - return 0; -} - - -int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, - const u8 *buf, size_t len) -{ - int ret; - if (l2 == NULL) - return -1; - if (l2->l2_hdr) { - ret = send(l2->fd, buf, len, 0); - if (ret < 0) - wpa_printf(MSG_ERROR, "l2_packet_send - send: %s", - strerror(errno)); - } else { - struct sockaddr_ll ll; - os_memset(&ll, 0, sizeof(ll)); - ll.sll_family = AF_PACKET; - ll.sll_ifindex = l2->ifindex; - ll.sll_protocol = htons(proto); - ll.sll_halen = ETH_ALEN; - os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN); - ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll, - sizeof(ll)); - if (ret < 0) { - wpa_printf(MSG_ERROR, "l2_packet_send - sendto: %s", - strerror(errno)); - } - } - return ret; -} - - -static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct l2_packet_data *l2 = eloop_ctx; - u8 buf[2300]; - int res; - struct sockaddr_ll ll; - socklen_t fromlen; - - os_memset(&ll, 0, sizeof(ll)); - fromlen = sizeof(ll); - res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll, - &fromlen); - if (res < 0) { - wpa_printf(MSG_DEBUG, "l2_packet_receive - recvfrom: %s", - strerror(errno)); - return; - } - - l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res); -} - - -struct l2_packet_data * l2_packet_init( - const char *ifname, const u8 *own_addr, unsigned short protocol, - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len), - void *rx_callback_ctx, int l2_hdr) -{ - struct l2_packet_data *l2; - struct ifreq ifr; - struct sockaddr_ll ll; - - l2 = os_zalloc(sizeof(struct l2_packet_data)); - if (l2 == NULL) - return NULL; - os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); - l2->rx_callback = rx_callback; - l2->rx_callback_ctx = rx_callback_ctx; - l2->l2_hdr = l2_hdr; - - l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM, - htons(protocol)); - if (l2->fd < 0) { - wpa_printf(MSG_ERROR, "%s: socket(PF_PACKET): %s", - __func__, strerror(errno)); - os_free(l2); - return NULL; - } - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name)); - if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) { - wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFINDEX]: %s", - __func__, strerror(errno)); - close(l2->fd); - os_free(l2); - return NULL; - } - l2->ifindex = ifr.ifr_ifindex; - - os_memset(&ll, 0, sizeof(ll)); - ll.sll_family = PF_PACKET; - ll.sll_ifindex = ifr.ifr_ifindex; - ll.sll_protocol = htons(protocol); - if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) { - wpa_printf(MSG_ERROR, "%s: bind[PF_PACKET]: %s", - __func__, strerror(errno)); - close(l2->fd); - os_free(l2); - return NULL; - } - - if (ioctl(l2->fd, SIOCGIFHWADDR, &ifr) < 0) { - wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFHWADDR]: %s", - __func__, strerror(errno)); - close(l2->fd); - os_free(l2); - return NULL; - } - os_memcpy(l2->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); - - eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); - - return l2; -} - - -void l2_packet_deinit(struct l2_packet_data *l2) -{ - if (l2 == NULL) - return; - - if (l2->fd >= 0) { - eloop_unregister_read_sock(l2->fd); - close(l2->fd); - } - - os_free(l2); -} - - -int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -{ - int s; - struct ifreq ifr; - struct sockaddr_in *saddr; - size_t res; - - s = socket(PF_INET, SOCK_DGRAM, 0); - if (s < 0) { - wpa_printf(MSG_ERROR, "%s: socket: %s", - __func__, strerror(errno)); - return -1; - } - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { - if (errno != EADDRNOTAVAIL) - wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFADDR]: %s", - __func__, strerror(errno)); - close(s); - return -1; - } - close(s); - saddr = aliasing_hide_typecast(&ifr.ifr_addr, struct sockaddr_in); - if (saddr->sin_family != AF_INET) - return -1; - res = os_strlcpy(buf, inet_ntoa(saddr->sin_addr), len); - if (res >= len) - return -1; - return 0; -} - - -void l2_packet_notify_auth_start(struct l2_packet_data *l2) -{ -} diff --git a/contrib/hostapd/src/l2_packet/l2_packet_ndis.c b/contrib/hostapd/src/l2_packet/l2_packet_ndis.c deleted file mode 100644 index 23b8ddcc9e..0000000000 --- a/contrib/hostapd/src/l2_packet/l2_packet_ndis.c +++ /dev/null @@ -1,516 +0,0 @@ -/* - * WPA Supplicant - Layer2 packet handling with Microsoft NDISUIO - * Copyright (c) 2003-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This implementation requires Windows specific event loop implementation, - * i.e., eloop_win.c. In addition, the NDISUIO connection is shared with - * driver_ndis.c, so only that driver interface can be used and - * CONFIG_USE_NDISUIO must be defined. - * - * WinXP version of the code uses overlapped I/O and a single threaded design - * with callback functions from I/O code. WinCE version uses a separate RX - * thread that blocks on ReadFile() whenever the media status is connected. - */ - -#include "includes.h" -#include -#include - -#ifdef _WIN32_WCE -#include -#include -#endif /* _WIN32_WCE */ - -#include "common.h" -#include "eloop.h" -#include "l2_packet.h" - -#ifndef _WIN32_WCE -/* from nuiouser.h */ -#define FSCTL_NDISUIO_BASE FILE_DEVICE_NETWORK -#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \ - CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access) -#define IOCTL_NDISUIO_SET_ETHER_TYPE \ - _NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#endif /* _WIN32_WCE */ - -/* From driver_ndis.c to shared the handle to NDISUIO */ -HANDLE driver_ndis_get_ndisuio_handle(void); - -/* - * NDISUIO supports filtering of only one ethertype at the time, so we must - * fake support for two (EAPOL and RSN pre-auth) by switching to pre-auth - * whenever wpa_supplicant is trying to pre-authenticate and then switching - * back to EAPOL when pre-authentication has been completed. - */ - -struct l2_packet_data; - -struct l2_packet_ndisuio_global { - int refcount; - unsigned short first_proto; - struct l2_packet_data *l2[2]; -#ifdef _WIN32_WCE - HANDLE rx_thread; - HANDLE stop_request; - HANDLE ready_for_read; - HANDLE rx_processed; -#endif /* _WIN32_WCE */ -}; - -static struct l2_packet_ndisuio_global *l2_ndisuio_global = NULL; - -struct l2_packet_data { - char ifname[100]; - u8 own_addr[ETH_ALEN]; - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len); - void *rx_callback_ctx; - int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to - * rx_callback and l2_packet_send() */ - HANDLE rx_avail; -#ifndef _WIN32_WCE - OVERLAPPED rx_overlapped; -#endif /* _WIN32_WCE */ - u8 rx_buf[1514]; - DWORD rx_written; -}; - - -int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -{ - os_memcpy(addr, l2->own_addr, ETH_ALEN); - return 0; -} - - -int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, - const u8 *buf, size_t len) -{ - BOOL res; - DWORD written; - struct l2_ethhdr *eth; -#ifndef _WIN32_WCE - OVERLAPPED overlapped; -#endif /* _WIN32_WCE */ - OVERLAPPED *o; - - if (l2 == NULL) - return -1; - -#ifdef _WIN32_WCE - o = NULL; -#else /* _WIN32_WCE */ - os_memset(&overlapped, 0, sizeof(overlapped)); - o = &overlapped; -#endif /* _WIN32_WCE */ - - if (l2->l2_hdr) { - res = WriteFile(driver_ndis_get_ndisuio_handle(), buf, len, - &written, o); - } else { - size_t mlen = sizeof(*eth) + len; - eth = os_malloc(mlen); - if (eth == NULL) - return -1; - - os_memcpy(eth->h_dest, dst_addr, ETH_ALEN); - os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN); - eth->h_proto = htons(proto); - os_memcpy(eth + 1, buf, len); - res = WriteFile(driver_ndis_get_ndisuio_handle(), eth, mlen, - &written, o); - os_free(eth); - } - - if (!res) { - DWORD err = GetLastError(); -#ifndef _WIN32_WCE - if (err == ERROR_IO_PENDING) { - wpa_printf(MSG_DEBUG, "L2(NDISUIO): Wait for pending " - "write to complete"); - res = GetOverlappedResult( - driver_ndis_get_ndisuio_handle(), &overlapped, - &written, TRUE); - if (!res) { - wpa_printf(MSG_DEBUG, "L2(NDISUIO): " - "GetOverlappedResult failed: %d", - (int) GetLastError()); - return -1; - } - return 0; - } -#endif /* _WIN32_WCE */ - wpa_printf(MSG_DEBUG, "L2(NDISUIO): WriteFile failed: %d", - (int) GetLastError()); - return -1; - } - - return 0; -} - - -static void l2_packet_callback(struct l2_packet_data *l2); - -#ifdef _WIN32_WCE -static void l2_packet_rx_thread_try_read(struct l2_packet_data *l2) -{ - HANDLE handles[2]; - - wpa_printf(MSG_MSGDUMP, "l2_packet_rx_thread: -> ReadFile"); - if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf, - sizeof(l2->rx_buf), &l2->rx_written, NULL)) { - DWORD err = GetLastError(); - wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: ReadFile failed: " - "%d", (int) err); - /* - * ReadFile on NDISUIO/WinCE returns ERROR_DEVICE_NOT_CONNECTED - * error whenever the connection is not up. Yield the thread to - * avoid triggering a busy loop. Connection event should stop - * us from looping for long, but we need to allow enough CPU - * for the main thread to process the media disconnection. - */ - Sleep(100); - return; - } - - wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Read %d byte packet", - (int) l2->rx_written); - - /* - * Notify the main thread about the availability of a frame and wait - * for the frame to be processed. - */ - SetEvent(l2->rx_avail); - handles[0] = l2_ndisuio_global->stop_request; - handles[1] = l2_ndisuio_global->rx_processed; - WaitForMultipleObjects(2, handles, FALSE, INFINITE); - ResetEvent(l2_ndisuio_global->rx_processed); -} - - -static DWORD WINAPI l2_packet_rx_thread(LPVOID arg) -{ - struct l2_packet_data *l2 = arg; - DWORD res; - HANDLE handles[2]; - int run = 1; - - wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread started"); - handles[0] = l2_ndisuio_global->stop_request; - handles[1] = l2_ndisuio_global->ready_for_read; - - /* - * Unfortunately, NDISUIO on WinCE does not seem to support waiting - * on the handle. There do not seem to be anything else that we could - * wait for either. If one were to modify NDISUIO to set a named event - * whenever packets are available, this event could be used here to - * avoid having to poll for new packets or we could even move to use a - * single threaded design. - * - * In addition, NDISUIO on WinCE is returning - * ERROR_DEVICE_NOT_CONNECTED whenever ReadFile() is attempted while - * the adapter is not in connected state. For now, we are just using a - * local event to allow ReadFile calls only after having received NDIS - * media connect event. This event could be easily converted to handle - * another event if the protocol driver is replaced with somewhat more - * useful design. - */ - - while (l2_ndisuio_global && run) { - res = WaitForMultipleObjects(2, handles, FALSE, INFINITE); - switch (res) { - case WAIT_OBJECT_0: - wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Received " - "request to stop RX thread"); - run = 0; - break; - case WAIT_OBJECT_0 + 1: - l2_packet_rx_thread_try_read(l2); - break; - case WAIT_FAILED: - default: - wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: " - "WaitForMultipleObjects failed: %d", - (int) GetLastError()); - run = 0; - break; - } - } - - wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread stopped"); - - return 0; -} -#else /* _WIN32_WCE */ -static int l2_ndisuio_start_read(struct l2_packet_data *l2, int recursive) -{ - os_memset(&l2->rx_overlapped, 0, sizeof(l2->rx_overlapped)); - l2->rx_overlapped.hEvent = l2->rx_avail; - if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf, - sizeof(l2->rx_buf), &l2->rx_written, &l2->rx_overlapped)) - { - DWORD err = GetLastError(); - if (err != ERROR_IO_PENDING) { - wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile failed: " - "%d", (int) err); - return -1; - } - /* - * Once read is completed, l2_packet_rx_event() will be - * called. - */ - } else { - wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile returned data " - "without wait for completion"); - if (!recursive) - l2_packet_callback(l2); - } - - return 0; -} -#endif /* _WIN32_WCE */ - - -static void l2_packet_callback(struct l2_packet_data *l2) -{ - const u8 *rx_buf, *rx_src; - size_t rx_len; - struct l2_ethhdr *ethhdr = (struct l2_ethhdr *) l2->rx_buf; - - wpa_printf(MSG_DEBUG, "L2(NDISUIO): Read %d bytes", - (int) l2->rx_written); - - if (l2->l2_hdr || l2->rx_written < sizeof(*ethhdr)) { - rx_buf = (u8 *) ethhdr; - rx_len = l2->rx_written; - } else { - rx_buf = (u8 *) (ethhdr + 1); - rx_len = l2->rx_written - sizeof(*ethhdr); - } - rx_src = ethhdr->h_source; - - l2->rx_callback(l2->rx_callback_ctx, rx_src, rx_buf, rx_len); -#ifndef _WIN32_WCE - l2_ndisuio_start_read(l2, 1); -#endif /* _WIN32_WCE */ -} - - -static void l2_packet_rx_event(void *eloop_data, void *user_data) -{ - struct l2_packet_data *l2 = eloop_data; - - if (l2_ndisuio_global) - l2 = l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1]; - - ResetEvent(l2->rx_avail); - -#ifndef _WIN32_WCE - if (!GetOverlappedResult(driver_ndis_get_ndisuio_handle(), - &l2->rx_overlapped, &l2->rx_written, FALSE)) { - wpa_printf(MSG_DEBUG, "L2(NDISUIO): GetOverlappedResult " - "failed: %d", (int) GetLastError()); - return; - } -#endif /* _WIN32_WCE */ - - l2_packet_callback(l2); - -#ifdef _WIN32_WCE - SetEvent(l2_ndisuio_global->rx_processed); -#endif /* _WIN32_WCE */ -} - - -static int l2_ndisuio_set_ether_type(unsigned short protocol) -{ - USHORT proto = htons(protocol); - DWORD written; - - if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(), - IOCTL_NDISUIO_SET_ETHER_TYPE, &proto, - sizeof(proto), NULL, 0, &written, NULL)) { - wpa_printf(MSG_ERROR, "L2(NDISUIO): " - "IOCTL_NDISUIO_SET_ETHER_TYPE failed: %d", - (int) GetLastError()); - return -1; - } - - return 0; -} - - -struct l2_packet_data * l2_packet_init( - const char *ifname, const u8 *own_addr, unsigned short protocol, - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len), - void *rx_callback_ctx, int l2_hdr) -{ - struct l2_packet_data *l2; - - if (l2_ndisuio_global == NULL) { - l2_ndisuio_global = os_zalloc(sizeof(*l2_ndisuio_global)); - if (l2_ndisuio_global == NULL) - return NULL; - l2_ndisuio_global->first_proto = protocol; - } - if (l2_ndisuio_global->refcount >= 2) { - wpa_printf(MSG_ERROR, "L2(NDISUIO): Not more than two " - "simultaneous connections allowed"); - return NULL; - } - l2_ndisuio_global->refcount++; - - l2 = os_zalloc(sizeof(struct l2_packet_data)); - if (l2 == NULL) - return NULL; - l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1] = l2; - - os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); - l2->rx_callback = rx_callback; - l2->rx_callback_ctx = rx_callback_ctx; - l2->l2_hdr = l2_hdr; - - if (own_addr) - os_memcpy(l2->own_addr, own_addr, ETH_ALEN); - - if (l2_ndisuio_set_ether_type(protocol) < 0) { - os_free(l2); - return NULL; - } - - if (l2_ndisuio_global->refcount > 1) { - wpa_printf(MSG_DEBUG, "L2(NDISUIO): Temporarily setting " - "filtering ethertype to %04x", protocol); - if (l2_ndisuio_global->l2[0]) - l2->rx_avail = l2_ndisuio_global->l2[0]->rx_avail; - return l2; - } - - l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL); - if (l2->rx_avail == NULL) { - os_free(l2); - return NULL; - } - - eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail), - l2_packet_rx_event, l2, NULL); - -#ifdef _WIN32_WCE - l2_ndisuio_global->stop_request = CreateEvent(NULL, TRUE, FALSE, NULL); - /* - * This event is being set based on media connect/disconnect - * notifications in driver_ndis.c. - */ - l2_ndisuio_global->ready_for_read = - CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected")); - l2_ndisuio_global->rx_processed = CreateEvent(NULL, TRUE, FALSE, NULL); - if (l2_ndisuio_global->stop_request == NULL || - l2_ndisuio_global->ready_for_read == NULL || - l2_ndisuio_global->rx_processed == NULL) { - if (l2_ndisuio_global->stop_request) { - CloseHandle(l2_ndisuio_global->stop_request); - l2_ndisuio_global->stop_request = NULL; - } - if (l2_ndisuio_global->ready_for_read) { - CloseHandle(l2_ndisuio_global->ready_for_read); - l2_ndisuio_global->ready_for_read = NULL; - } - if (l2_ndisuio_global->rx_processed) { - CloseHandle(l2_ndisuio_global->rx_processed); - l2_ndisuio_global->rx_processed = NULL; - } - eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail)); - os_free(l2); - return NULL; - } - - l2_ndisuio_global->rx_thread = CreateThread(NULL, 0, - l2_packet_rx_thread, l2, 0, - NULL); - if (l2_ndisuio_global->rx_thread == NULL) { - wpa_printf(MSG_INFO, "L2(NDISUIO): Failed to create RX " - "thread: %d", (int) GetLastError()); - eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail)); - CloseHandle(l2_ndisuio_global->stop_request); - l2_ndisuio_global->stop_request = NULL; - os_free(l2); - return NULL; - } -#else /* _WIN32_WCE */ - l2_ndisuio_start_read(l2, 0); -#endif /* _WIN32_WCE */ - - return l2; -} - - -void l2_packet_deinit(struct l2_packet_data *l2) -{ - if (l2 == NULL) - return; - - if (l2_ndisuio_global) { - l2_ndisuio_global->refcount--; - l2_ndisuio_global->l2[l2_ndisuio_global->refcount] = NULL; - if (l2_ndisuio_global->refcount) { - wpa_printf(MSG_DEBUG, "L2(NDISUIO): restore filtering " - "ethertype to %04x", - l2_ndisuio_global->first_proto); - l2_ndisuio_set_ether_type( - l2_ndisuio_global->first_proto); - return; - } - -#ifdef _WIN32_WCE - wpa_printf(MSG_DEBUG, "L2(NDISUIO): Waiting for RX thread to " - "stop"); - SetEvent(l2_ndisuio_global->stop_request); - /* - * Cancel pending ReadFile() in the RX thread (if we were still - * connected at this point). - */ - if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(), - IOCTL_CANCEL_READ, NULL, 0, NULL, 0, NULL, - NULL)) { - wpa_printf(MSG_DEBUG, "L2(NDISUIO): IOCTL_CANCEL_READ " - "failed: %d", (int) GetLastError()); - /* RX thread will exit blocking ReadFile once NDISUIO - * notices that the adapter is disconnected. */ - } - WaitForSingleObject(l2_ndisuio_global->rx_thread, INFINITE); - wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread exited"); - CloseHandle(l2_ndisuio_global->rx_thread); - CloseHandle(l2_ndisuio_global->stop_request); - CloseHandle(l2_ndisuio_global->ready_for_read); - CloseHandle(l2_ndisuio_global->rx_processed); -#endif /* _WIN32_WCE */ - - os_free(l2_ndisuio_global); - l2_ndisuio_global = NULL; - } - -#ifndef _WIN32_WCE - CancelIo(driver_ndis_get_ndisuio_handle()); -#endif /* _WIN32_WCE */ - - eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail)); - CloseHandle(l2->rx_avail); - os_free(l2); -} - - -int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -{ - return -1; -} - - -void l2_packet_notify_auth_start(struct l2_packet_data *l2) -{ -} diff --git a/contrib/hostapd/src/l2_packet/l2_packet_none.c b/contrib/hostapd/src/l2_packet/l2_packet_none.c deleted file mode 100644 index b01e830220..0000000000 --- a/contrib/hostapd/src/l2_packet/l2_packet_none.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * WPA Supplicant - Layer2 packet handling example with dummy functions - * Copyright (c) 2003-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file can be used as a starting point for layer2 packet implementation. - */ - -#include "includes.h" - -#include "common.h" -#include "eloop.h" -#include "l2_packet.h" - - -struct l2_packet_data { - char ifname[17]; - u8 own_addr[ETH_ALEN]; - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len); - void *rx_callback_ctx; - int l2_hdr; /* whether to include layer 2 (Ethernet) header data - * buffers */ - int fd; -}; - - -int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -{ - os_memcpy(addr, l2->own_addr, ETH_ALEN); - return 0; -} - - -int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, - const u8 *buf, size_t len) -{ - if (l2 == NULL) - return -1; - - /* - * TODO: Send frame (may need different implementation depending on - * whether l2->l2_hdr is set). - */ - - return 0; -} - - -static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct l2_packet_data *l2 = eloop_ctx; - u8 buf[2300]; - int res; - - /* TODO: receive frame (e.g., recv() using sock */ - buf[0] = 0; - res = 0; - - l2->rx_callback(l2->rx_callback_ctx, NULL /* TODO: src addr */, - buf, res); -} - - -struct l2_packet_data * l2_packet_init( - const char *ifname, const u8 *own_addr, unsigned short protocol, - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len), - void *rx_callback_ctx, int l2_hdr) -{ - struct l2_packet_data *l2; - - l2 = os_zalloc(sizeof(struct l2_packet_data)); - if (l2 == NULL) - return NULL; - os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); - l2->rx_callback = rx_callback; - l2->rx_callback_ctx = rx_callback_ctx; - l2->l2_hdr = l2_hdr; - - /* - * TODO: open connection for receiving frames - */ - l2->fd = -1; - eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); - - return l2; -} - - -void l2_packet_deinit(struct l2_packet_data *l2) -{ - if (l2 == NULL) - return; - - if (l2->fd >= 0) { - eloop_unregister_read_sock(l2->fd); - /* TODO: close connection */ - } - - os_free(l2); -} - - -int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -{ - /* TODO: get interface IP address */ - return -1; -} - - -void l2_packet_notify_auth_start(struct l2_packet_data *l2) -{ - /* This function can be left empty */ -} diff --git a/contrib/hostapd/src/l2_packet/l2_packet_pcap.c b/contrib/hostapd/src/l2_packet/l2_packet_pcap.c deleted file mode 100644 index 45aef56bcd..0000000000 --- a/contrib/hostapd/src/l2_packet/l2_packet_pcap.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * WPA Supplicant - Layer2 packet handling with libpcap/libdnet and WinPcap - * Copyright (c) 2003-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#ifndef CONFIG_NATIVE_WINDOWS -#include -#endif /* CONFIG_NATIVE_WINDOWS */ -#include -#ifndef CONFIG_WINPCAP -#include -#endif /* CONFIG_WINPCAP */ - -#include "common.h" -#include "eloop.h" -#include "l2_packet.h" - - -static const u8 pae_group_addr[ETH_ALEN] = -{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; - -struct l2_packet_data { - pcap_t *pcap; -#ifdef CONFIG_WINPCAP - unsigned int num_fast_poll; -#else /* CONFIG_WINPCAP */ - eth_t *eth; -#endif /* CONFIG_WINPCAP */ - char ifname[100]; - u8 own_addr[ETH_ALEN]; - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len); - void *rx_callback_ctx; - int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls - * to rx_callback */ -}; - - -int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -{ - os_memcpy(addr, l2->own_addr, ETH_ALEN); - return 0; -} - - -#ifndef CONFIG_WINPCAP -static int l2_packet_init_libdnet(struct l2_packet_data *l2) -{ - eth_addr_t own_addr; - - l2->eth = eth_open(l2->ifname); - if (!l2->eth) { - printf("Failed to open interface '%s'.\n", l2->ifname); - perror("eth_open"); - return -1; - } - - if (eth_get(l2->eth, &own_addr) < 0) { - printf("Failed to get own hw address from interface '%s'.\n", - l2->ifname); - perror("eth_get"); - eth_close(l2->eth); - l2->eth = NULL; - return -1; - } - os_memcpy(l2->own_addr, own_addr.data, ETH_ALEN); - - return 0; -} -#endif /* CONFIG_WINPCAP */ - - -int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, - const u8 *buf, size_t len) -{ - int ret; - struct l2_ethhdr *eth; - - if (l2 == NULL) - return -1; - - if (l2->l2_hdr) { -#ifdef CONFIG_WINPCAP - ret = pcap_sendpacket(l2->pcap, buf, len); -#else /* CONFIG_WINPCAP */ - ret = eth_send(l2->eth, buf, len); -#endif /* CONFIG_WINPCAP */ - } else { - size_t mlen = sizeof(*eth) + len; - eth = os_malloc(mlen); - if (eth == NULL) - return -1; - - os_memcpy(eth->h_dest, dst_addr, ETH_ALEN); - os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN); - eth->h_proto = htons(proto); - os_memcpy(eth + 1, buf, len); - -#ifdef CONFIG_WINPCAP - ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen); -#else /* CONFIG_WINPCAP */ - ret = eth_send(l2->eth, (u8 *) eth, mlen); -#endif /* CONFIG_WINPCAP */ - - os_free(eth); - } - - return ret; -} - - -#ifndef CONFIG_WINPCAP -static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct l2_packet_data *l2 = eloop_ctx; - pcap_t *pcap = sock_ctx; - struct pcap_pkthdr hdr; - const u_char *packet; - struct l2_ethhdr *ethhdr; - unsigned char *buf; - size_t len; - - packet = pcap_next(pcap, &hdr); - - if (packet == NULL || hdr.caplen < sizeof(*ethhdr)) - return; - - ethhdr = (struct l2_ethhdr *) packet; - if (l2->l2_hdr) { - buf = (unsigned char *) ethhdr; - len = hdr.caplen; - } else { - buf = (unsigned char *) (ethhdr + 1); - len = hdr.caplen - sizeof(*ethhdr); - } - l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len); -} -#endif /* CONFIG_WINPCAP */ - - -#ifdef CONFIG_WINPCAP -static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr, - const u_char *pkt_data) -{ - struct l2_packet_data *l2 = (struct l2_packet_data *) user; - struct l2_ethhdr *ethhdr; - unsigned char *buf; - size_t len; - - if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr)) - return; - - ethhdr = (struct l2_ethhdr *) pkt_data; - if (l2->l2_hdr) { - buf = (unsigned char *) ethhdr; - len = hdr->caplen; - } else { - buf = (unsigned char *) (ethhdr + 1); - len = hdr->caplen - sizeof(*ethhdr); - } - l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len); - /* - * Use shorter poll interval for 3 seconds to reduce latency during key - * handshake. - */ - l2->num_fast_poll = 3 * 50; -} - - -static void l2_packet_receive_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct l2_packet_data *l2 = eloop_ctx; - pcap_t *pcap = timeout_ctx; - int timeout; - - if (l2->num_fast_poll > 0) { - timeout = 20000; - l2->num_fast_poll--; - } else - timeout = 100000; - - /* Register new timeout before calling l2_packet_receive() since - * receive handler may free this l2_packet instance (which will - * cancel this timeout). */ - eloop_register_timeout(0, timeout, l2_packet_receive_timeout, - l2, pcap); - pcap_dispatch(pcap, 10, l2_packet_receive_cb, (u_char *) l2); -} -#endif /* CONFIG_WINPCAP */ - - -static int l2_packet_init_libpcap(struct l2_packet_data *l2, - unsigned short protocol) -{ - bpf_u_int32 pcap_maskp, pcap_netp; - char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE]; - struct bpf_program pcap_fp; - -#ifdef CONFIG_WINPCAP - char ifname[128]; - os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", l2->ifname); - pcap_lookupnet(ifname, &pcap_netp, &pcap_maskp, pcap_err); - l2->pcap = pcap_open_live(ifname, 2500, 0, 10, pcap_err); - if (l2->pcap == NULL) { - fprintf(stderr, "pcap_open_live: %s\n", pcap_err); - fprintf(stderr, "ifname='%s'\n", ifname); - return -1; - } - if (pcap_setnonblock(l2->pcap, 1, pcap_err) < 0) - fprintf(stderr, "pcap_setnonblock: %s\n", - pcap_geterr(l2->pcap)); -#else /* CONFIG_WINPCAP */ - pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err); - l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 10, pcap_err); - if (l2->pcap == NULL) { - fprintf(stderr, "pcap_open_live: %s\n", pcap_err); - fprintf(stderr, "ifname='%s'\n", l2->ifname); - return -1; - } - if (pcap_datalink(l2->pcap) != DLT_EN10MB && - pcap_set_datalink(l2->pcap, DLT_EN10MB) < 0) { - fprintf(stderr, "pcap_set_datalink(DLT_EN10MB): %s\n", - pcap_geterr(l2->pcap)); - return -1; - } -#endif /* CONFIG_WINPCAP */ - os_snprintf(pcap_filter, sizeof(pcap_filter), - "not ether src " MACSTR " and " - "( ether dst " MACSTR " or ether dst " MACSTR " ) and " - "ether proto 0x%x", - MAC2STR(l2->own_addr), /* do not receive own packets */ - MAC2STR(l2->own_addr), MAC2STR(pae_group_addr), - protocol); - if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) { - fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap)); - return -1; - } - - if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) { - fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap)); - return -1; - } - - pcap_freecode(&pcap_fp); -#ifdef BIOCIMMEDIATE - /* - * When libpcap uses BPF we must enable "immediate mode" to - * receive frames right away; otherwise the system may - * buffer them for us. - */ - { - unsigned int on = 1; - if (ioctl(pcap_fileno(l2->pcap), BIOCIMMEDIATE, &on) < 0) { - fprintf(stderr, "%s: cannot enable immediate mode on " - "interface %s: %s\n", - __func__, l2->ifname, strerror(errno)); - /* XXX should we fail? */ - } - } -#endif /* BIOCIMMEDIATE */ - -#ifdef CONFIG_WINPCAP - eloop_register_timeout(0, 100000, l2_packet_receive_timeout, - l2, l2->pcap); -#else /* CONFIG_WINPCAP */ - eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap), - l2_packet_receive, l2, l2->pcap); -#endif /* CONFIG_WINPCAP */ - - return 0; -} - - -struct l2_packet_data * l2_packet_init( - const char *ifname, const u8 *own_addr, unsigned short protocol, - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len), - void *rx_callback_ctx, int l2_hdr) -{ - struct l2_packet_data *l2; - - l2 = os_zalloc(sizeof(struct l2_packet_data)); - if (l2 == NULL) - return NULL; - os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); - l2->rx_callback = rx_callback; - l2->rx_callback_ctx = rx_callback_ctx; - l2->l2_hdr = l2_hdr; - -#ifdef CONFIG_WINPCAP - if (own_addr) - os_memcpy(l2->own_addr, own_addr, ETH_ALEN); -#else /* CONFIG_WINPCAP */ - if (l2_packet_init_libdnet(l2)) - return NULL; -#endif /* CONFIG_WINPCAP */ - - if (l2_packet_init_libpcap(l2, protocol)) { -#ifndef CONFIG_WINPCAP - eth_close(l2->eth); -#endif /* CONFIG_WINPCAP */ - os_free(l2); - return NULL; - } - - return l2; -} - - -void l2_packet_deinit(struct l2_packet_data *l2) -{ - if (l2 == NULL) - return; - -#ifdef CONFIG_WINPCAP - eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap); -#else /* CONFIG_WINPCAP */ - if (l2->eth) - eth_close(l2->eth); - eloop_unregister_read_sock(pcap_get_selectable_fd(l2->pcap)); -#endif /* CONFIG_WINPCAP */ - if (l2->pcap) - pcap_close(l2->pcap); - os_free(l2); -} - - -int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -{ - pcap_if_t *devs, *dev; - struct pcap_addr *addr; - struct sockaddr_in *saddr; - int found = 0; - char err[PCAP_ERRBUF_SIZE + 1]; - - if (pcap_findalldevs(&devs, err) < 0) { - wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err); - return -1; - } - - for (dev = devs; dev && !found; dev = dev->next) { - if (os_strcmp(dev->name, l2->ifname) != 0) - continue; - - addr = dev->addresses; - while (addr) { - saddr = (struct sockaddr_in *) addr->addr; - if (saddr && saddr->sin_family == AF_INET) { - os_strlcpy(buf, inet_ntoa(saddr->sin_addr), - len); - found = 1; - break; - } - addr = addr->next; - } - } - - pcap_freealldevs(devs); - - return found ? 0 : -1; -} - - -void l2_packet_notify_auth_start(struct l2_packet_data *l2) -{ -#ifdef CONFIG_WINPCAP - /* - * Use shorter poll interval for 3 seconds to reduce latency during key - * handshake. - */ - l2->num_fast_poll = 3 * 50; - eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap); - eloop_register_timeout(0, 10000, l2_packet_receive_timeout, - l2, l2->pcap); -#endif /* CONFIG_WINPCAP */ -} diff --git a/contrib/hostapd/src/l2_packet/l2_packet_privsep.c b/contrib/hostapd/src/l2_packet/l2_packet_privsep.c deleted file mode 100644 index 6b117ca2b9..0000000000 --- a/contrib/hostapd/src/l2_packet/l2_packet_privsep.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * WPA Supplicant - Layer2 packet handling with privilege separation - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "eloop.h" -#include "l2_packet.h" -#include "common/privsep_commands.h" - - -struct l2_packet_data { - int fd; /* UNIX domain socket for privsep access */ - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len); - void *rx_callback_ctx; - u8 own_addr[ETH_ALEN]; - char *own_socket_path; - struct sockaddr_un priv_addr; -}; - - -static int wpa_priv_cmd(struct l2_packet_data *l2, int cmd, - const void *data, size_t data_len) -{ - struct msghdr msg; - struct iovec io[2]; - - io[0].iov_base = &cmd; - io[0].iov_len = sizeof(cmd); - io[1].iov_base = (u8 *) data; - io[1].iov_len = data_len; - - os_memset(&msg, 0, sizeof(msg)); - msg.msg_iov = io; - msg.msg_iovlen = data ? 2 : 1; - msg.msg_name = &l2->priv_addr; - msg.msg_namelen = sizeof(l2->priv_addr); - - if (sendmsg(l2->fd, &msg, 0) < 0) { - perror("L2: sendmsg(cmd)"); - return -1; - } - - return 0; -} - - -int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -{ - os_memcpy(addr, l2->own_addr, ETH_ALEN); - return 0; -} - - -int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, - const u8 *buf, size_t len) -{ - struct msghdr msg; - struct iovec io[4]; - int cmd = PRIVSEP_CMD_L2_SEND; - - io[0].iov_base = &cmd; - io[0].iov_len = sizeof(cmd); - io[1].iov_base = &dst_addr; - io[1].iov_len = ETH_ALEN; - io[2].iov_base = &proto; - io[2].iov_len = 2; - io[3].iov_base = (u8 *) buf; - io[3].iov_len = len; - - os_memset(&msg, 0, sizeof(msg)); - msg.msg_iov = io; - msg.msg_iovlen = 4; - msg.msg_name = &l2->priv_addr; - msg.msg_namelen = sizeof(l2->priv_addr); - - if (sendmsg(l2->fd, &msg, 0) < 0) { - perror("L2: sendmsg(packet_send)"); - return -1; - } - - return 0; -} - - -static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct l2_packet_data *l2 = eloop_ctx; - u8 buf[2300]; - int res; - struct sockaddr_un from; - socklen_t fromlen = sizeof(from); - - os_memset(&from, 0, sizeof(from)); - res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from, - &fromlen); - if (res < 0) { - perror("l2_packet_receive - recvfrom"); - return; - } - if (res < ETH_ALEN) { - wpa_printf(MSG_DEBUG, "L2: Too show packet received"); - return; - } - - if (from.sun_family != AF_UNIX || - os_strncmp(from.sun_path, l2->priv_addr.sun_path, - sizeof(from.sun_path)) != 0) { - wpa_printf(MSG_DEBUG, "L2: Received message from unexpected " - "source"); - return; - } - - l2->rx_callback(l2->rx_callback_ctx, buf, buf + ETH_ALEN, - res - ETH_ALEN); -} - - -struct l2_packet_data * l2_packet_init( - const char *ifname, const u8 *own_addr, unsigned short protocol, - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len), - void *rx_callback_ctx, int l2_hdr) -{ - struct l2_packet_data *l2; - char *own_dir = "/tmp"; - char *priv_dir = "/var/run/wpa_priv"; - size_t len; - static unsigned int counter = 0; - struct sockaddr_un addr; - fd_set rfds; - struct timeval tv; - int res; - u8 reply[ETH_ALEN + 1]; - int reg_cmd[2]; - - l2 = os_zalloc(sizeof(struct l2_packet_data)); - if (l2 == NULL) - return NULL; - l2->rx_callback = rx_callback; - l2->rx_callback_ctx = rx_callback_ctx; - - len = os_strlen(own_dir) + 50; - l2->own_socket_path = os_malloc(len); - if (l2->own_socket_path == NULL) { - os_free(l2); - return NULL; - } - os_snprintf(l2->own_socket_path, len, "%s/wpa_privsep-l2-%d-%d", - own_dir, getpid(), counter++); - - l2->priv_addr.sun_family = AF_UNIX; - os_snprintf(l2->priv_addr.sun_path, sizeof(l2->priv_addr.sun_path), - "%s/%s", priv_dir, ifname); - - l2->fd = socket(PF_UNIX, SOCK_DGRAM, 0); - if (l2->fd < 0) { - perror("socket(PF_UNIX)"); - os_free(l2->own_socket_path); - l2->own_socket_path = NULL; - os_free(l2); - return NULL; - } - - os_memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path)); - if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("l2-pkt-privsep: bind(PF_UNIX)"); - goto fail; - } - - reg_cmd[0] = protocol; - reg_cmd[1] = l2_hdr; - if (wpa_priv_cmd(l2, PRIVSEP_CMD_L2_REGISTER, reg_cmd, sizeof(reg_cmd)) - < 0) { - wpa_printf(MSG_ERROR, "L2: Failed to register with wpa_priv"); - goto fail; - } - - FD_ZERO(&rfds); - FD_SET(l2->fd, &rfds); - tv.tv_sec = 5; - tv.tv_usec = 0; - res = select(l2->fd + 1, &rfds, NULL, NULL, &tv); - if (res < 0 && errno != EINTR) { - perror("select"); - goto fail; - } - - if (FD_ISSET(l2->fd, &rfds)) { - res = recv(l2->fd, reply, sizeof(reply), 0); - if (res < 0) { - perror("recv"); - goto fail; - } - } else { - wpa_printf(MSG_DEBUG, "L2: Timeout while waiting for " - "registration reply"); - goto fail; - } - - if (res != ETH_ALEN) { - wpa_printf(MSG_DEBUG, "L2: Unexpected registration reply " - "(len=%d)", res); - } - os_memcpy(l2->own_addr, reply, ETH_ALEN); - - eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); - - return l2; - -fail: - close(l2->fd); - l2->fd = -1; - unlink(l2->own_socket_path); - os_free(l2->own_socket_path); - l2->own_socket_path = NULL; - os_free(l2); - return NULL; -} - - -void l2_packet_deinit(struct l2_packet_data *l2) -{ - if (l2 == NULL) - return; - - if (l2->fd >= 0) { - wpa_priv_cmd(l2, PRIVSEP_CMD_L2_UNREGISTER, NULL, 0); - eloop_unregister_read_sock(l2->fd); - close(l2->fd); - } - - if (l2->own_socket_path) { - unlink(l2->own_socket_path); - os_free(l2->own_socket_path); - } - - os_free(l2); -} - - -int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -{ - /* TODO */ - return -1; -} - - -void l2_packet_notify_auth_start(struct l2_packet_data *l2) -{ - wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0); -} diff --git a/contrib/hostapd/src/l2_packet/l2_packet_winpcap.c b/contrib/hostapd/src/l2_packet/l2_packet_winpcap.c deleted file mode 100644 index b6e5088938..0000000000 --- a/contrib/hostapd/src/l2_packet/l2_packet_winpcap.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * WPA Supplicant - Layer2 packet handling with WinPcap RX thread - * Copyright (c) 2003-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This l2_packet implementation is explicitly for WinPcap and Windows events. - * l2_packet_pcap.c has support for WinPcap, but it requires polling to receive - * frames which means relatively long latency for EAPOL RX processing. The - * implementation here uses a separate thread to allow WinPcap to be receiving - * all the time to reduce latency for EAPOL receiving from about 100 ms to 3 ms - * when comparing l2_packet_pcap.c to l2_packet_winpcap.c. Extra sleep of 50 ms - * is added in to receive thread whenever no EAPOL frames has been received for - * a while. Whenever an EAPOL handshake is expected, this sleep is removed. - * - * The RX thread receives a frame and signals main thread through Windows event - * about the availability of a new frame. Processing the received frame is - * synchronized with pair of Windows events so that no extra buffer or queuing - * mechanism is needed. This implementation requires Windows specific event - * loop implementation, i.e., eloop_win.c. - * - * WinPcap has pcap_getevent() that could, in theory at least, be used to - * implement this kind of waiting with a simpler single-thread design. However, - * that event handle is not really signaled immediately when receiving each - * frame, so it does not really work for this kind of use. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "eloop.h" -#include "l2_packet.h" - - -static const u8 pae_group_addr[ETH_ALEN] = -{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; - -/* - * Number of pcap_dispatch() iterations to do without extra wait after each - * received EAPOL packet or authentication notification. This is used to reduce - * latency for EAPOL receive. - */ -static const size_t no_wait_count = 750; - -struct l2_packet_data { - pcap_t *pcap; - unsigned int num_fast_poll; - char ifname[100]; - u8 own_addr[ETH_ALEN]; - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len); - void *rx_callback_ctx; - int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to - * rx_callback and l2_packet_send() */ - int running; - HANDLE rx_avail, rx_done, rx_thread, rx_thread_done, rx_notify; - u8 *rx_buf, *rx_src; - size_t rx_len; - size_t rx_no_wait; -}; - - -int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -{ - os_memcpy(addr, l2->own_addr, ETH_ALEN); - return 0; -} - - -int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, - const u8 *buf, size_t len) -{ - int ret; - struct l2_ethhdr *eth; - - if (l2 == NULL) - return -1; - - if (l2->l2_hdr) { - ret = pcap_sendpacket(l2->pcap, buf, len); - } else { - size_t mlen = sizeof(*eth) + len; - eth = os_malloc(mlen); - if (eth == NULL) - return -1; - - os_memcpy(eth->h_dest, dst_addr, ETH_ALEN); - os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN); - eth->h_proto = htons(proto); - os_memcpy(eth + 1, buf, len); - ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen); - os_free(eth); - } - - return ret; -} - - -/* pcap_dispatch() callback for the RX thread */ -static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr, - const u_char *pkt_data) -{ - struct l2_packet_data *l2 = (struct l2_packet_data *) user; - struct l2_ethhdr *ethhdr; - - if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr)) - return; - - ethhdr = (struct l2_ethhdr *) pkt_data; - if (l2->l2_hdr) { - l2->rx_buf = (u8 *) ethhdr; - l2->rx_len = hdr->caplen; - } else { - l2->rx_buf = (u8 *) (ethhdr + 1); - l2->rx_len = hdr->caplen - sizeof(*ethhdr); - } - l2->rx_src = ethhdr->h_source; - SetEvent(l2->rx_avail); - WaitForSingleObject(l2->rx_done, INFINITE); - ResetEvent(l2->rx_done); - l2->rx_no_wait = no_wait_count; -} - - -/* main RX loop that is running in a separate thread */ -static DWORD WINAPI l2_packet_receive_thread(LPVOID arg) -{ - struct l2_packet_data *l2 = arg; - - while (l2->running) { - pcap_dispatch(l2->pcap, 1, l2_packet_receive_cb, - (u_char *) l2); - if (l2->rx_no_wait > 0) - l2->rx_no_wait--; - if (WaitForSingleObject(l2->rx_notify, - l2->rx_no_wait ? 0 : 50) == - WAIT_OBJECT_0) { - l2->rx_no_wait = no_wait_count; - ResetEvent(l2->rx_notify); - } - } - SetEvent(l2->rx_thread_done); - ExitThread(0); - return 0; -} - - -/* main thread RX event handler */ -static void l2_packet_rx_event(void *eloop_data, void *user_data) -{ - struct l2_packet_data *l2 = eloop_data; - l2->rx_callback(l2->rx_callback_ctx, l2->rx_src, l2->rx_buf, - l2->rx_len); - ResetEvent(l2->rx_avail); - SetEvent(l2->rx_done); -} - - -static int l2_packet_init_libpcap(struct l2_packet_data *l2, - unsigned short protocol) -{ - bpf_u_int32 pcap_maskp, pcap_netp; - char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE]; - struct bpf_program pcap_fp; - - pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err); - l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 1, pcap_err); - if (l2->pcap == NULL) { - fprintf(stderr, "pcap_open_live: %s\n", pcap_err); - fprintf(stderr, "ifname='%s'\n", l2->ifname); - return -1; - } - os_snprintf(pcap_filter, sizeof(pcap_filter), - "not ether src " MACSTR " and " - "( ether dst " MACSTR " or ether dst " MACSTR " ) and " - "ether proto 0x%x", - MAC2STR(l2->own_addr), /* do not receive own packets */ - MAC2STR(l2->own_addr), MAC2STR(pae_group_addr), - protocol); - if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) { - fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap)); - return -1; - } - - if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) { - fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap)); - return -1; - } - - pcap_freecode(&pcap_fp); - - return 0; -} - - -struct l2_packet_data * l2_packet_init( - const char *ifname, const u8 *own_addr, unsigned short protocol, - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len), - void *rx_callback_ctx, int l2_hdr) -{ - struct l2_packet_data *l2; - DWORD thread_id; - - l2 = os_zalloc(sizeof(struct l2_packet_data)); - if (l2 == NULL) - return NULL; - if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0) - os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); - else - os_snprintf(l2->ifname, sizeof(l2->ifname), "\\Device\\NPF_%s", - ifname); - l2->rx_callback = rx_callback; - l2->rx_callback_ctx = rx_callback_ctx; - l2->l2_hdr = l2_hdr; - - if (own_addr) - os_memcpy(l2->own_addr, own_addr, ETH_ALEN); - - if (l2_packet_init_libpcap(l2, protocol)) { - os_free(l2); - return NULL; - } - - l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL); - l2->rx_done = CreateEvent(NULL, TRUE, FALSE, NULL); - l2->rx_notify = CreateEvent(NULL, TRUE, FALSE, NULL); - if (l2->rx_avail == NULL || l2->rx_done == NULL || - l2->rx_notify == NULL) { - CloseHandle(l2->rx_avail); - CloseHandle(l2->rx_done); - CloseHandle(l2->rx_notify); - pcap_close(l2->pcap); - os_free(l2); - return NULL; - } - - eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail), - l2_packet_rx_event, l2, NULL); - - l2->running = 1; - l2->rx_thread = CreateThread(NULL, 0, l2_packet_receive_thread, l2, 0, - &thread_id); - - return l2; -} - - -static void l2_packet_deinit_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct l2_packet_data *l2 = eloop_ctx; - - if (l2->rx_thread_done && - WaitForSingleObject(l2->rx_thread_done, 2000) != WAIT_OBJECT_0) { - wpa_printf(MSG_DEBUG, "l2_packet_winpcap: RX thread did not " - "exit - kill it\n"); - TerminateThread(l2->rx_thread, 0); - } - CloseHandle(l2->rx_thread_done); - CloseHandle(l2->rx_thread); - if (l2->pcap) - pcap_close(l2->pcap); - eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail)); - CloseHandle(l2->rx_avail); - CloseHandle(l2->rx_done); - CloseHandle(l2->rx_notify); - os_free(l2); -} - - -void l2_packet_deinit(struct l2_packet_data *l2) -{ - if (l2 == NULL) - return; - - l2->rx_thread_done = CreateEvent(NULL, TRUE, FALSE, NULL); - - l2->running = 0; - pcap_breakloop(l2->pcap); - - /* - * RX thread may be waiting in l2_packet_receive_cb() for l2->rx_done - * event and this event is set in l2_packet_rx_event(). However, - * l2_packet_deinit() may end up being called from l2->rx_callback(), - * so we need to return from here and complete deinitialization in - * a registered timeout to avoid having to forcefully kill the RX - * thread. - */ - eloop_register_timeout(0, 0, l2_packet_deinit_timeout, l2, NULL); -} - - -int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -{ - pcap_if_t *devs, *dev; - struct pcap_addr *addr; - struct sockaddr_in *saddr; - int found = 0; - char err[PCAP_ERRBUF_SIZE + 1]; - - if (pcap_findalldevs(&devs, err) < 0) { - wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err); - return -1; - } - - for (dev = devs; dev && !found; dev = dev->next) { - if (os_strcmp(dev->name, l2->ifname) != 0) - continue; - - addr = dev->addresses; - while (addr) { - saddr = (struct sockaddr_in *) addr->addr; - if (saddr && saddr->sin_family == AF_INET) { - os_strlcpy(buf, inet_ntoa(saddr->sin_addr), - len); - found = 1; - break; - } - addr = addr->next; - } - } - - pcap_freealldevs(devs); - - return found ? 0 : -1; -} - - -void l2_packet_notify_auth_start(struct l2_packet_data *l2) -{ - if (l2) - SetEvent(l2->rx_notify); -} diff --git a/contrib/hostapd/src/p2p/p2p.c b/contrib/hostapd/src/p2p/p2p.c deleted file mode 100644 index 957dee5bd9..0000000000 --- a/contrib/hostapd/src/p2p/p2p.c +++ /dev/null @@ -1,4598 +0,0 @@ -/* - * Wi-Fi Direct - P2P module - * Copyright (c) 2009-2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eloop.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "wps/wps_i.h" -#include "p2p_i.h" -#include "p2p.h" - - -static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx); -static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev); -static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da, - const u8 *sa, const u8 *data, size_t len, - int rx_freq); -static void p2p_process_presence_resp(struct p2p_data *p2p, const u8 *da, - const u8 *sa, const u8 *data, - size_t len); -static void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx); -static void p2p_scan_timeout(void *eloop_ctx, void *timeout_ctx); - - -/* - * p2p_scan recovery timeout - * - * Many drivers are using 30 second timeout on scan results. Allow a bit larger - * timeout for this to avoid hitting P2P timeout unnecessarily. - */ -#define P2P_SCAN_TIMEOUT 35 - -/** - * P2P_PEER_EXPIRATION_AGE - Number of seconds after which inactive peer - * entries will be removed - */ -#ifndef P2P_PEER_EXPIRATION_AGE -#define P2P_PEER_EXPIRATION_AGE 60 -#endif /* P2P_PEER_EXPIRATION_AGE */ - -#define P2P_PEER_EXPIRATION_INTERVAL (P2P_PEER_EXPIRATION_AGE / 2) - -static void p2p_expire_peers(struct p2p_data *p2p) -{ - struct p2p_device *dev, *n; - struct os_reltime now; - size_t i; - - os_get_reltime(&now); - dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) { - if (dev->last_seen.sec + P2P_PEER_EXPIRATION_AGE >= now.sec) - continue; - - if (dev == p2p->go_neg_peer) { - /* - * GO Negotiation is in progress with the peer, so - * don't expire the peer entry until GO Negotiation - * fails or times out. - */ - continue; - } - - if (p2p->cfg->go_connected && - p2p->cfg->go_connected(p2p->cfg->cb_ctx, - dev->info.p2p_device_addr)) { - /* - * We are connected as a client to a group in which the - * peer is the GO, so do not expire the peer entry. - */ - os_get_reltime(&dev->last_seen); - continue; - } - - for (i = 0; i < p2p->num_groups; i++) { - if (p2p_group_is_client_connected( - p2p->groups[i], dev->info.p2p_device_addr)) - break; - } - if (i < p2p->num_groups) { - /* - * The peer is connected as a client in a group where - * we are the GO, so do not expire the peer entry. - */ - os_get_reltime(&dev->last_seen); - continue; - } - - p2p_dbg(p2p, "Expiring old peer entry " MACSTR, - MAC2STR(dev->info.p2p_device_addr)); - dl_list_del(&dev->list); - p2p_device_free(p2p, dev); - } -} - - -static void p2p_expiration_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct p2p_data *p2p = eloop_ctx; - p2p_expire_peers(p2p); - eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0, - p2p_expiration_timeout, p2p, NULL); -} - - -static const char * p2p_state_txt(int state) -{ - switch (state) { - case P2P_IDLE: - return "IDLE"; - case P2P_SEARCH: - return "SEARCH"; - case P2P_CONNECT: - return "CONNECT"; - case P2P_CONNECT_LISTEN: - return "CONNECT_LISTEN"; - case P2P_GO_NEG: - return "GO_NEG"; - case P2P_LISTEN_ONLY: - return "LISTEN_ONLY"; - case P2P_WAIT_PEER_CONNECT: - return "WAIT_PEER_CONNECT"; - case P2P_WAIT_PEER_IDLE: - return "WAIT_PEER_IDLE"; - case P2P_SD_DURING_FIND: - return "SD_DURING_FIND"; - case P2P_PROVISIONING: - return "PROVISIONING"; - case P2P_PD_DURING_FIND: - return "PD_DURING_FIND"; - case P2P_INVITE: - return "INVITE"; - case P2P_INVITE_LISTEN: - return "INVITE_LISTEN"; - default: - return "?"; - } -} - - -const char * p2p_get_state_txt(struct p2p_data *p2p) -{ - return p2p_state_txt(p2p->state); -} - - -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 *addr) -{ - struct p2p_device *dev = NULL; - - if (!addr || !p2p) - return; - - dev = p2p_get_device(p2p, addr); - if (dev) - dev->wps_prov_info = 0; -} - - -void p2p_set_state(struct p2p_data *p2p, int new_state) -{ - p2p_dbg(p2p, "State %s -> %s", - p2p_state_txt(p2p->state), p2p_state_txt(new_state)); - p2p->state = new_state; -} - - -void p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, unsigned int usec) -{ - p2p_dbg(p2p, "Set timeout (state=%s): %u.%06u sec", - p2p_state_txt(p2p->state), sec, usec); - eloop_cancel_timeout(p2p_state_timeout, p2p, NULL); - eloop_register_timeout(sec, usec, p2p_state_timeout, p2p, NULL); -} - - -void p2p_clear_timeout(struct p2p_data *p2p) -{ - p2p_dbg(p2p, "Clear timeout (state=%s)", p2p_state_txt(p2p->state)); - eloop_cancel_timeout(p2p_state_timeout, p2p, NULL); -} - - -void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer, - int status) -{ - 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->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE; - p2p->go_neg_peer->wps_method = WPS_NOT_READY; - p2p->go_neg_peer->oob_pw_id = 0; - } - p2p->go_neg_peer = NULL; - - os_memset(&res, 0, sizeof(res)); - res.status = status; - if (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); - } - p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res); -} - - -static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc) -{ - unsigned int r, tu; - int freq; - struct wpabuf *ies; - - p2p_dbg(p2p, "Starting short listen state (state=%s)", - p2p_state_txt(p2p->state)); - - freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel); - if (freq < 0) { - p2p_dbg(p2p, "Unknown regulatory class/channel"); - return; - } - - os_get_random((u8 *) &r, sizeof(r)); - tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) + - p2p->min_disc_int) * 100; - if (p2p->max_disc_tu >= 0 && tu > (unsigned int) p2p->max_disc_tu) - tu = p2p->max_disc_tu; - if (!dev_disc && tu < 100) - tu = 100; /* Need to wait in non-device discovery use cases */ - if (p2p->cfg->max_listen && 1024 * tu / 1000 > p2p->cfg->max_listen) - tu = p2p->cfg->max_listen * 1000 / 1024; - - if (tu == 0) { - p2p_dbg(p2p, "Skip listen state since duration was 0 TU"); - p2p_set_timeout(p2p, 0, 0); - return; - } - - p2p->pending_listen_freq = freq; - p2p->pending_listen_sec = 0; - p2p->pending_listen_usec = 1024 * tu; - - ies = p2p_build_probe_resp_ies(p2p); - if (ies == NULL) - return; - - if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, 1024 * tu / 1000, - ies) < 0) { - p2p_dbg(p2p, "Failed to start listen mode"); - p2p->pending_listen_freq = 0; - } - wpabuf_free(ies); -} - - -int p2p_listen(struct p2p_data *p2p, unsigned int timeout) -{ - int freq; - struct wpabuf *ies; - - p2p_dbg(p2p, "Going to listen(only) state"); - - freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel); - if (freq < 0) { - p2p_dbg(p2p, "Unknown regulatory class/channel"); - return -1; - } - - p2p->pending_listen_freq = freq; - p2p->pending_listen_sec = timeout / 1000; - p2p->pending_listen_usec = (timeout % 1000) * 1000; - - if (p2p->p2p_scan_running) { - if (p2p->start_after_scan == P2P_AFTER_SCAN_CONNECT) { - p2p_dbg(p2p, "p2p_scan running - connect is already pending - skip listen"); - return 0; - } - p2p_dbg(p2p, "p2p_scan running - delay start of listen state"); - p2p->start_after_scan = P2P_AFTER_SCAN_LISTEN; - return 0; - } - - ies = p2p_build_probe_resp_ies(p2p); - if (ies == NULL) - return -1; - - if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, timeout, ies) < 0) { - p2p_dbg(p2p, "Failed to start listen mode"); - p2p->pending_listen_freq = 0; - wpabuf_free(ies); - return -1; - } - wpabuf_free(ies); - - p2p_set_state(p2p, P2P_LISTEN_ONLY); - - return 0; -} - - -static void p2p_device_clear_reported(struct p2p_data *p2p) -{ - struct p2p_device *dev; - dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) - dev->flags &= ~P2P_DEV_REPORTED; -} - - -/** - * p2p_get_device - Fetch a peer entry - * @p2p: P2P module context from p2p_init() - * @addr: P2P Device Address of the peer - * Returns: Pointer to the device entry or %NULL if not found - */ -struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr) -{ - struct p2p_device *dev; - dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { - if (os_memcmp(dev->info.p2p_device_addr, addr, ETH_ALEN) == 0) - return dev; - } - return NULL; -} - - -/** - * p2p_get_device_interface - Fetch a peer entry based on P2P Interface Address - * @p2p: P2P module context from p2p_init() - * @addr: P2P Interface Address of the peer - * Returns: Pointer to the device entry or %NULL if not found - */ -struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p, - const u8 *addr) -{ - struct p2p_device *dev; - dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { - if (os_memcmp(dev->interface_addr, addr, ETH_ALEN) == 0) - return dev; - } - return NULL; -} - - -/** - * p2p_create_device - Create a peer entry - * @p2p: P2P module context from p2p_init() - * @addr: P2P Device Address of the peer - * Returns: Pointer to the device entry or %NULL on failure - * - * If there is already an entry for the peer, it will be returned instead of - * creating a new one. - */ -static struct p2p_device * p2p_create_device(struct p2p_data *p2p, - const u8 *addr) -{ - struct p2p_device *dev, *oldest = NULL; - size_t count = 0; - - dev = p2p_get_device(p2p, addr); - if (dev) - return dev; - - dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { - count++; - if (oldest == NULL || - os_reltime_before(&dev->last_seen, &oldest->last_seen)) - oldest = dev; - } - if (count + 1 > p2p->cfg->max_peers && oldest) { - p2p_dbg(p2p, "Remove oldest peer entry to make room for a new peer"); - dl_list_del(&oldest->list); - p2p_device_free(p2p, oldest); - } - - dev = os_zalloc(sizeof(*dev)); - if (dev == NULL) - return NULL; - dl_list_add(&p2p->devices, &dev->list); - os_memcpy(dev->info.p2p_device_addr, addr, ETH_ALEN); - - return dev; -} - - -static void p2p_copy_client_info(struct p2p_device *dev, - struct p2p_client_info *cli) -{ - os_memcpy(dev->info.device_name, cli->dev_name, cli->dev_name_len); - dev->info.device_name[cli->dev_name_len] = '\0'; - dev->info.dev_capab = cli->dev_capab; - dev->info.config_methods = cli->config_methods; - os_memcpy(dev->info.pri_dev_type, cli->pri_dev_type, 8); - dev->info.wps_sec_dev_type_list_len = 8 * cli->num_sec_dev_types; - os_memcpy(dev->info.wps_sec_dev_type_list, cli->sec_dev_types, - dev->info.wps_sec_dev_type_list_len); -} - - -static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr, - const u8 *go_interface_addr, int freq, - const u8 *gi, size_t gi_len) -{ - struct p2p_group_info info; - size_t c; - struct p2p_device *dev; - - if (gi == NULL) - return 0; - - if (p2p_group_info_parse(gi, gi_len, &info) < 0) - return -1; - - /* - * Clear old data for this group; if the devices are still in the - * group, the information will be restored in the loop following this. - */ - dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { - 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); - } - } - - 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) { - if (dev->flags & (P2P_DEV_GROUP_CLIENT_ONLY | - P2P_DEV_PROBE_REQ_ONLY)) { - /* - * Update information since we have not - * received this directly from the client. - */ - p2p_copy_client_info(dev, cli); - } else { - /* - * Need to update P2P Client Discoverability - * flag since it is valid only in P2P Group - * Info attribute. - */ - dev->info.dev_capab &= - ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; - dev->info.dev_capab |= - cli->dev_capab & - P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; - } - if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) { - dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY; - } - } else { - dev = p2p_create_device(p2p, cli->p2p_device_addr); - if (dev == NULL) - continue; - dev->flags |= P2P_DEV_GROUP_CLIENT_ONLY; - p2p_copy_client_info(dev, cli); - dev->oper_freq = freq; - p2p->cfg->dev_found(p2p->cfg->cb_ctx, - dev->info.p2p_device_addr, - &dev->info, 1); - dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE; - } - - os_memcpy(dev->interface_addr, cli->p2p_interface_addr, - ETH_ALEN); - os_get_reltime(&dev->last_seen); - os_memcpy(dev->member_in_go_dev, go_dev_addr, ETH_ALEN); - os_memcpy(dev->member_in_go_iface, go_interface_addr, - ETH_ALEN); - } - - return 0; -} - - -static void p2p_copy_wps_info(struct p2p_data *p2p, struct p2p_device *dev, - int probe_req, const struct p2p_message *msg) -{ - os_memcpy(dev->info.device_name, msg->device_name, - sizeof(dev->info.device_name)); - - if (msg->manufacturer && - msg->manufacturer_len < sizeof(dev->info.manufacturer)) { - os_memset(dev->info.manufacturer, 0, - sizeof(dev->info.manufacturer)); - os_memcpy(dev->info.manufacturer, msg->manufacturer, - msg->manufacturer_len); - } - - if (msg->model_name && - msg->model_name_len < sizeof(dev->info.model_name)) { - os_memset(dev->info.model_name, 0, - sizeof(dev->info.model_name)); - os_memcpy(dev->info.model_name, msg->model_name, - msg->model_name_len); - } - - if (msg->model_number && - msg->model_number_len < sizeof(dev->info.model_number)) { - os_memset(dev->info.model_number, 0, - sizeof(dev->info.model_number)); - os_memcpy(dev->info.model_number, msg->model_number, - msg->model_number_len); - } - - if (msg->serial_number && - msg->serial_number_len < sizeof(dev->info.serial_number)) { - os_memset(dev->info.serial_number, 0, - sizeof(dev->info.serial_number)); - os_memcpy(dev->info.serial_number, msg->serial_number, - msg->serial_number_len); - } - - if (msg->pri_dev_type) - os_memcpy(dev->info.pri_dev_type, msg->pri_dev_type, - sizeof(dev->info.pri_dev_type)); - else if (msg->wps_pri_dev_type) - os_memcpy(dev->info.pri_dev_type, msg->wps_pri_dev_type, - sizeof(dev->info.pri_dev_type)); - - if (msg->wps_sec_dev_type_list) { - os_memcpy(dev->info.wps_sec_dev_type_list, - msg->wps_sec_dev_type_list, - msg->wps_sec_dev_type_list_len); - dev->info.wps_sec_dev_type_list_len = - msg->wps_sec_dev_type_list_len; - } - - if (msg->capability) { - /* - * P2P Client Discoverability bit is reserved in all frames - * that use this function, so do not change its value here. - */ - dev->info.dev_capab &= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; - dev->info.dev_capab |= msg->capability[0] & - ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; - dev->info.group_capab = msg->capability[1]; - } - - if (msg->ext_listen_timing) { - dev->ext_listen_period = WPA_GET_LE16(msg->ext_listen_timing); - dev->ext_listen_interval = - WPA_GET_LE16(msg->ext_listen_timing + 2); - } - - if (!probe_req) { - u16 new_config_methods; - new_config_methods = msg->config_methods ? - msg->config_methods : msg->wps_config_methods; - if (new_config_methods && - dev->info.config_methods != new_config_methods) { - p2p_dbg(p2p, "Update peer " MACSTR - " config_methods 0x%x -> 0x%x", - MAC2STR(dev->info.p2p_device_addr), - dev->info.config_methods, - new_config_methods); - dev->info.config_methods = new_config_methods; - } - } -} - - -/** - * p2p_add_device - Add peer entries based on scan results or P2P frames - * @p2p: P2P module context from p2p_init() - * @addr: Source address of Beacon or Probe Response frame (may be either - * P2P Device Address or P2P Interface Address) - * @level: Signal level (signal strength of the received frame from the peer) - * @freq: Frequency on which the Beacon or Probe Response frame was received - * @rx_time: Time when the result was received - * @ies: IEs from the Beacon or Probe Response frame - * @ies_len: Length of ies buffer in octets - * @scan_res: Whether this was based on scan results - * Returns: 0 on success, -1 on failure - * - * If the scan result is for a GO, the clients in the group will also be added - * to the peer table. This function can also be used with some other frames - * like Provision Discovery Request that contains P2P Capability and P2P Device - * Info attributes. - */ -int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, - struct os_reltime *rx_time, int level, const u8 *ies, - size_t ies_len, int scan_res) -{ - struct p2p_device *dev; - struct p2p_message msg; - const u8 *p2p_dev_addr; - int i; - struct os_reltime time_now; - - os_memset(&msg, 0, sizeof(msg)); - if (p2p_parse_ies(ies, ies_len, &msg)) { - p2p_dbg(p2p, "Failed to parse P2P IE for a device entry"); - p2p_parse_free(&msg); - return -1; - } - - if (msg.p2p_device_addr) - p2p_dev_addr = msg.p2p_device_addr; - else if (msg.device_id) - p2p_dev_addr = msg.device_id; - else { - p2p_dbg(p2p, "Ignore scan data without P2P Device Info or P2P Device Id"); - p2p_parse_free(&msg); - return -1; - } - - if (!is_zero_ether_addr(p2p->peer_filter) && - os_memcmp(p2p_dev_addr, p2p->peer_filter, ETH_ALEN) != 0) { - p2p_dbg(p2p, "Do not add peer filter for " MACSTR - " due to peer filter", MAC2STR(p2p_dev_addr)); - p2p_parse_free(&msg); - return 0; - } - - dev = p2p_create_device(p2p, p2p_dev_addr); - if (dev == NULL) { - p2p_parse_free(&msg); - return -1; - } - - if (rx_time == NULL) { - os_get_reltime(&time_now); - rx_time = &time_now; - } - - /* - * Update the device entry only if the new peer - * entry is newer than the one previously stored. - */ - if (dev->last_seen.sec > 0 && - os_reltime_before(rx_time, &dev->last_seen)) { - p2p_dbg(p2p, "Do not update peer entry based on old frame (rx_time=%u.%06u last_seen=%u.%06u)", - (unsigned int) rx_time->sec, - (unsigned int) rx_time->usec, - (unsigned int) dev->last_seen.sec, - (unsigned int) dev->last_seen.usec); - p2p_parse_free(&msg); - return -1; - } - - os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_reltime)); - - dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY); - - if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0) - os_memcpy(dev->interface_addr, addr, ETH_ALEN); - if (msg.ssid && - (msg.ssid[1] != P2P_WILDCARD_SSID_LEN || - os_memcmp(msg.ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) - != 0)) { - os_memcpy(dev->oper_ssid, msg.ssid + 2, msg.ssid[1]); - dev->oper_ssid_len = msg.ssid[1]; - } - - if (freq >= 2412 && freq <= 2484 && msg.ds_params && - *msg.ds_params >= 1 && *msg.ds_params <= 14) { - int ds_freq; - if (*msg.ds_params == 14) - ds_freq = 2484; - else - ds_freq = 2407 + *msg.ds_params * 5; - if (freq != ds_freq) { - p2p_dbg(p2p, "Update Listen frequency based on DS Parameter Set IE: %d -> %d MHz", - freq, ds_freq); - freq = ds_freq; - } - } - - if (dev->listen_freq && dev->listen_freq != freq && scan_res) { - p2p_dbg(p2p, "Update Listen frequency based on scan results (" - MACSTR " %d -> %d MHz (DS param %d)", - MAC2STR(dev->info.p2p_device_addr), dev->listen_freq, - freq, msg.ds_params ? *msg.ds_params : -1); - } - if (scan_res) { - dev->listen_freq = freq; - if (msg.group_info) - dev->oper_freq = freq; - } - dev->info.level = level; - - p2p_copy_wps_info(p2p, dev, 0, &msg); - - for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { - wpabuf_free(dev->info.wps_vendor_ext[i]); - dev->info.wps_vendor_ext[i] = NULL; - } - - for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { - if (msg.wps_vendor_ext[i] == NULL) - break; - dev->info.wps_vendor_ext[i] = wpabuf_alloc_copy( - msg.wps_vendor_ext[i], msg.wps_vendor_ext_len[i]); - if (dev->info.wps_vendor_ext[i] == NULL) - break; - } - - if (msg.wfd_subelems) { - wpabuf_free(dev->info.wfd_subelems); - dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); - } - - if (scan_res) { - p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq, - msg.group_info, msg.group_info_len); - } - - p2p_parse_free(&msg); - - if (p2p_pending_sd_req(p2p, dev)) - dev->flags |= P2P_DEV_SD_SCHEDULE; - - if (dev->flags & P2P_DEV_REPORTED) - return 0; - - p2p_dbg(p2p, "Peer found with Listen frequency %d MHz (rx_time=%u.%06u)", - freq, (unsigned int) rx_time->sec, - (unsigned int) rx_time->usec); - if (dev->flags & P2P_DEV_USER_REJECTED) { - p2p_dbg(p2p, "Do not report rejected device"); - return 0; - } - - if (dev->info.config_methods == 0 && - (freq == 2412 || freq == 2437 || freq == 2462)) { - /* - * If we have only seen a Beacon frame from a GO, we do not yet - * know what WPS config methods it supports. Since some - * applications use config_methods value from P2P-DEVICE-FOUND - * events, postpone reporting this peer until we've fully - * discovered its capabilities. - * - * At least for now, do this only if the peer was detected on - * one of the social channels since that peer can be easily be - * found again and there are no limitations of having to use - * passive scan on this channels, so this can be done through - * Probe Response frame that includes the config_methods - * information. - */ - p2p_dbg(p2p, "Do not report peer " MACSTR - " with unknown config methods", MAC2STR(addr)); - return 0; - } - - p2p->cfg->dev_found(p2p->cfg->cb_ctx, addr, &dev->info, - !(dev->flags & P2P_DEV_REPORTED_ONCE)); - dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE; - - return 0; -} - - -static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev) -{ - int i; - - if (p2p->go_neg_peer == dev) { - /* - * If GO Negotiation is in progress, report that it has failed. - */ - p2p_go_neg_failed(p2p, dev, -1); - p2p->go_neg_peer = NULL; - } - if (p2p->invite_peer == dev) - p2p->invite_peer = NULL; - if (p2p->sd_peer == dev) - p2p->sd_peer = NULL; - if (p2p->pending_client_disc_go == dev) - p2p->pending_client_disc_go = NULL; - - /* dev_lost() device, but only if it was previously dev_found() */ - if (dev->flags & P2P_DEV_REPORTED_ONCE) - p2p->cfg->dev_lost(p2p->cfg->cb_ctx, - dev->info.p2p_device_addr); - - for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { - wpabuf_free(dev->info.wps_vendor_ext[i]); - dev->info.wps_vendor_ext[i] = NULL; - } - - wpabuf_free(dev->info.wfd_subelems); - - os_free(dev); -} - - -static int p2p_get_next_prog_freq(struct p2p_data *p2p) -{ - struct p2p_channels *c; - struct p2p_reg_class *cla; - size_t cl, ch; - int found = 0; - u8 reg_class; - u8 channel; - int freq; - - c = &p2p->cfg->channels; - for (cl = 0; cl < c->reg_classes; cl++) { - cla = &c->reg_class[cl]; - if (cla->reg_class != p2p->last_prog_scan_class) - continue; - for (ch = 0; ch < cla->channels; ch++) { - if (cla->channel[ch] == p2p->last_prog_scan_chan) { - found = 1; - break; - } - } - if (found) - break; - } - - if (!found) { - /* Start from beginning */ - reg_class = c->reg_class[0].reg_class; - channel = c->reg_class[0].channel[0]; - } else { - /* Pick the next channel */ - ch++; - if (ch == cla->channels) { - cl++; - if (cl == c->reg_classes) - cl = 0; - ch = 0; - } - reg_class = c->reg_class[cl].reg_class; - channel = c->reg_class[cl].channel[ch]; - } - - freq = p2p_channel_to_freq(reg_class, channel); - p2p_dbg(p2p, "Next progressive search channel: reg_class %u channel %u -> %d MHz", - reg_class, channel, freq); - p2p->last_prog_scan_class = reg_class; - p2p->last_prog_scan_chan = channel; - - if (freq == 2412 || freq == 2437 || freq == 2462) - return 0; /* No need to add social channels */ - return freq; -} - - -static void p2p_search(struct p2p_data *p2p) -{ - int freq = 0; - enum p2p_scan_type type; - u16 pw_id = DEV_PW_DEFAULT; - int res; - - if (p2p->drv_in_listen) { - p2p_dbg(p2p, "Driver is still in Listen state - wait for it to end before continuing"); - return; - } - p2p->cfg->stop_listen(p2p->cfg->cb_ctx); - - if (p2p->find_type == P2P_FIND_PROGRESSIVE && - (freq = p2p_get_next_prog_freq(p2p)) > 0) { - type = P2P_SCAN_SOCIAL_PLUS_ONE; - p2p_dbg(p2p, "Starting search (+ freq %u)", freq); - } else { - type = P2P_SCAN_SOCIAL; - p2p_dbg(p2p, "Starting search"); - } - - res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq, - p2p->num_req_dev_types, p2p->req_dev_types, - p2p->find_dev_id, pw_id); - if (res < 0) { - p2p_dbg(p2p, "Scan request failed"); - p2p_continue_find(p2p); - } else { - p2p_dbg(p2p, "Running p2p_scan"); - p2p->p2p_scan_running = 1; - eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL); - eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout, - p2p, NULL); - } -} - - -static void p2p_find_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct p2p_data *p2p = eloop_ctx; - p2p_dbg(p2p, "Find timeout -> stop"); - p2p_stop_find(p2p); -} - - -static int p2p_run_after_scan(struct p2p_data *p2p) -{ - struct p2p_device *dev; - enum p2p_after_scan op; - - if (p2p->after_scan_tx) { - p2p->after_scan_tx_in_progress = 1; - p2p_dbg(p2p, "Send pending Action frame at p2p_scan completion"); - 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; - } - - op = p2p->start_after_scan; - p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; - switch (op) { - case P2P_AFTER_SCAN_NOTHING: - break; - case P2P_AFTER_SCAN_LISTEN: - p2p_dbg(p2p, "Start previously requested Listen state"); - p2p_listen(p2p, p2p->pending_listen_sec * 1000 + - p2p->pending_listen_usec / 1000); - return 1; - case P2P_AFTER_SCAN_CONNECT: - p2p_dbg(p2p, "Start previously requested connect with " MACSTR, - MAC2STR(p2p->after_scan_peer)); - dev = p2p_get_device(p2p, p2p->after_scan_peer); - if (dev == NULL) { - p2p_dbg(p2p, "Peer not known anymore"); - break; - } - p2p_connect_send(p2p, dev); - return 1; - } - - return 0; -} - - -static void p2p_scan_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct p2p_data *p2p = eloop_ctx; - int running; - p2p_dbg(p2p, "p2p_scan timeout (running=%d)", p2p->p2p_scan_running); - running = p2p->p2p_scan_running; - /* Make sure we recover from missed scan results callback */ - p2p->p2p_scan_running = 0; - - if (running) - p2p_run_after_scan(p2p); -} - - -static void p2p_free_req_dev_types(struct p2p_data *p2p) -{ - p2p->num_req_dev_types = 0; - os_free(p2p->req_dev_types); - p2p->req_dev_types = NULL; -} - - -int p2p_find(struct p2p_data *p2p, unsigned int timeout, - enum p2p_discovery_type type, - unsigned int num_req_dev_types, const u8 *req_dev_types, - const u8 *dev_id, unsigned int search_delay) -{ - int res; - - p2p_dbg(p2p, "Starting find (type=%d)", type); - os_get_reltime(&p2p->find_start); - if (p2p->p2p_scan_running) { - p2p_dbg(p2p, "p2p_scan is already running"); - } - - p2p_free_req_dev_types(p2p); - if (req_dev_types && num_req_dev_types) { - p2p->req_dev_types = os_malloc(num_req_dev_types * - WPS_DEV_TYPE_LEN); - if (p2p->req_dev_types == NULL) - return -1; - os_memcpy(p2p->req_dev_types, req_dev_types, - num_req_dev_types * WPS_DEV_TYPE_LEN); - p2p->num_req_dev_types = num_req_dev_types; - } - - if (dev_id) { - os_memcpy(p2p->find_dev_id_buf, dev_id, ETH_ALEN); - p2p->find_dev_id = p2p->find_dev_id_buf; - } else - p2p->find_dev_id = NULL; - - p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; - p2p_clear_timeout(p2p); - p2p->cfg->stop_listen(p2p->cfg->cb_ctx); - p2p->find_type = type; - p2p_device_clear_reported(p2p); - p2p_set_state(p2p, P2P_SEARCH); - p2p->search_delay = search_delay; - p2p->in_search_delay = 0; - 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); - switch (type) { - case P2P_FIND_START_WITH_FULL: - case P2P_FIND_PROGRESSIVE: - res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0, - p2p->num_req_dev_types, - p2p->req_dev_types, dev_id, - DEV_PW_DEFAULT); - break; - case P2P_FIND_ONLY_SOCIAL: - res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0, - p2p->num_req_dev_types, - p2p->req_dev_types, dev_id, - DEV_PW_DEFAULT); - break; - default: - return -1; - } - - if (res == 0) { - p2p_dbg(p2p, "Running p2p_scan"); - p2p->p2p_scan_running = 1; - eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL); - eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout, - p2p, NULL); - } else if (p2p->p2p_scan_running) { - p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running"); - /* wait for the previous p2p_scan to complete */ - } else { - p2p_dbg(p2p, "Failed to start p2p_scan"); - p2p_set_state(p2p, P2P_IDLE); - eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); - } - - return res; -} - - -void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq) -{ - p2p_dbg(p2p, "Stopping find"); - eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); - p2p_clear_timeout(p2p); - if (p2p->state == P2P_SEARCH) - p2p->cfg->find_stopped(p2p->cfg->cb_ctx); - p2p_set_state(p2p, P2P_IDLE); - p2p_free_req_dev_types(p2p); - p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; - if (p2p->go_neg_peer) - p2p->go_neg_peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE; - p2p->go_neg_peer = NULL; - p2p->sd_peer = NULL; - p2p->invite_peer = NULL; - p2p_stop_listen_for_freq(p2p, freq); -} - - -void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq) -{ - if (freq > 0 && p2p->drv_in_listen == freq && p2p->in_listen) { - p2p_dbg(p2p, "Skip stop_listen since we are on correct channel for response"); - return; - } - if (p2p->in_listen) { - p2p->in_listen = 0; - p2p_clear_timeout(p2p); - } - if (p2p->drv_in_listen) { - /* - * The driver may not deliver callback to p2p_listen_end() - * when the operation gets canceled, so clear the internal - * variable that is tracking driver state. - */ - p2p_dbg(p2p, "Clear drv_in_listen (%d)", p2p->drv_in_listen); - p2p->drv_in_listen = 0; - } - p2p->cfg->stop_listen(p2p->cfg->cb_ctx); -} - - -void p2p_stop_listen(struct p2p_data *p2p) -{ - if (p2p->state != P2P_LISTEN_ONLY) { - p2p_dbg(p2p, "Skip stop_listen since not in listen_only state."); - return; - } - - p2p_stop_listen_for_freq(p2p, 0); - p2p_set_state(p2p, P2P_IDLE); -} - - -void p2p_stop_find(struct p2p_data *p2p) -{ - p2p_stop_find_for_freq(p2p, 0); -} - - -static int p2p_prepare_channel_pref(struct p2p_data *p2p, - unsigned int force_freq, - unsigned int pref_freq, int go) -{ - u8 op_class, op_channel; - unsigned int freq = force_freq ? force_freq : pref_freq; - - p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u go=%d", - force_freq, pref_freq, go); - if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) { - p2p_dbg(p2p, "Unsupported frequency %u MHz", freq); - return -1; - } - - if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel) && - (go || !p2p_channels_includes(&p2p->cfg->cli_channels, op_class, - op_channel))) { - p2p_dbg(p2p, "Frequency %u MHz (oper_class %u channel %u) not allowed for P2P", - freq, op_class, op_channel); - return -1; - } - - p2p->op_reg_class = op_class; - p2p->op_channel = op_channel; - - if (force_freq) { - p2p->channels.reg_classes = 1; - p2p->channels.reg_class[0].channels = 1; - p2p->channels.reg_class[0].reg_class = p2p->op_reg_class; - p2p->channels.reg_class[0].channel[0] = p2p->op_channel; - } else { - os_memcpy(&p2p->channels, &p2p->cfg->channels, - sizeof(struct p2p_channels)); - } - - return 0; -} - - -static void p2p_prepare_channel_best(struct p2p_data *p2p) -{ - u8 op_class, op_channel; - const int op_classes_5ghz[] = { 124, 115, 0 }; - const int op_classes_ht40[] = { 126, 127, 116, 117, 0 }; - const int op_classes_vht[] = { 128, 0 }; - - p2p_dbg(p2p, "Prepare channel best"); - - if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 && - p2p_supported_freq(p2p, p2p->best_freq_overall) && - p2p_freq_to_channel(p2p->best_freq_overall, &op_class, &op_channel) - == 0) { - p2p_dbg(p2p, "Select best overall channel as operating channel preference"); - p2p->op_reg_class = op_class; - p2p->op_channel = op_channel; - } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 && - p2p_supported_freq(p2p, p2p->best_freq_5) && - p2p_freq_to_channel(p2p->best_freq_5, &op_class, &op_channel) - == 0) { - p2p_dbg(p2p, "Select best 5 GHz channel as operating channel preference"); - p2p->op_reg_class = op_class; - p2p->op_channel = op_channel; - } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_24 > 0 && - p2p_supported_freq(p2p, p2p->best_freq_24) && - p2p_freq_to_channel(p2p->best_freq_24, &op_class, - &op_channel) == 0) { - p2p_dbg(p2p, "Select best 2.4 GHz channel as operating channel preference"); - p2p->op_reg_class = op_class; - p2p->op_channel = op_channel; - } else if (p2p->cfg->num_pref_chan > 0 && - p2p_channels_includes(&p2p->cfg->channels, - p2p->cfg->pref_chan[0].op_class, - p2p->cfg->pref_chan[0].chan)) { - p2p_dbg(p2p, "Select first pref_chan entry as operating channel preference"); - p2p->op_reg_class = p2p->cfg->pref_chan[0].op_class; - p2p->op_channel = p2p->cfg->pref_chan[0].chan; - } else if (p2p_channel_select(&p2p->cfg->channels, op_classes_vht, - &p2p->op_reg_class, &p2p->op_channel) == - 0) { - p2p_dbg(p2p, "Select possible VHT channel (op_class %u channel %u) as operating channel preference", - p2p->op_reg_class, p2p->op_channel); - } else if (p2p_channel_select(&p2p->cfg->channels, op_classes_ht40, - &p2p->op_reg_class, &p2p->op_channel) == - 0) { - p2p_dbg(p2p, "Select possible HT40 channel (op_class %u channel %u) as operating channel preference", - p2p->op_reg_class, p2p->op_channel); - } else if (p2p_channel_select(&p2p->cfg->channels, op_classes_5ghz, - &p2p->op_reg_class, &p2p->op_channel) == - 0) { - p2p_dbg(p2p, "Select possible 5 GHz channel (op_class %u channel %u) as operating channel preference", - p2p->op_reg_class, p2p->op_channel); - } else { - p2p_dbg(p2p, "Select pre-configured channel as operating channel preference"); - p2p->op_reg_class = p2p->cfg->op_reg_class; - p2p->op_channel = p2p->cfg->op_channel; - } - - os_memcpy(&p2p->channels, &p2p->cfg->channels, - sizeof(struct p2p_channels)); -} - - -/** - * p2p_prepare_channel - Select operating channel for GO Negotiation - * @p2p: P2P module context from p2p_init() - * @dev: Selected peer device - * @force_freq: Forced frequency in MHz or 0 if not forced - * @pref_freq: Preferred frequency in MHz or 0 if no preference - * @go: Whether the local end will be forced to be GO - * Returns: 0 on success, -1 on failure (channel not supported for P2P) - * - * This function is used to do initial operating channel selection for GO - * Negotiation prior to having received peer information. The selected channel - * may be further optimized in p2p_reselect_channel() once the peer information - * is available. - */ -int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev, - unsigned int force_freq, unsigned int pref_freq, int go) -{ - p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u go=%d", - force_freq, pref_freq, go); - if (force_freq || pref_freq) { - if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq, go) < - 0) - return -1; - } else { - p2p_prepare_channel_best(p2p); - } - p2p_channels_dump(p2p, "prepared channels", &p2p->channels); - if (go) - p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq); - else if (!force_freq) - p2p_channels_union(&p2p->channels, &p2p->cfg->cli_channels, - &p2p->channels); - p2p_channels_dump(p2p, "after go/cli filter/add", &p2p->channels); - - p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s", - p2p->op_reg_class, p2p->op_channel, - force_freq ? " (forced)" : ""); - - if (force_freq) - dev->flags |= P2P_DEV_FORCE_FREQ; - else - dev->flags &= ~P2P_DEV_FORCE_FREQ; - - return 0; -} - - -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, - unsigned int force_freq, int persistent_group, - const u8 *force_ssid, size_t force_ssid_len, - int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id) -{ - struct p2p_device *dev; - - p2p_dbg(p2p, "Request to start group negotiation - peer=" MACSTR - " GO Intent=%d Intended Interface Address=" MACSTR - " wps_method=%d persistent_group=%d pd_before_go_neg=%d " - "oob_pw_id=%u", - MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr), - wps_method, persistent_group, pd_before_go_neg, oob_pw_id); - - dev = p2p_get_device(p2p, peer_addr); - if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { - p2p_dbg(p2p, "Cannot connect to unknown P2P Device " MACSTR, - MAC2STR(peer_addr)); - return -1; - } - - if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq, - go_intent == 15) < 0) - return -1; - - if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) { - if (!(dev->info.dev_capab & - P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { - p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR - " that is in a group and is not discoverable", - MAC2STR(peer_addr)); - return -1; - } - if (dev->oper_freq <= 0) { - p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR - " with incomplete information", - MAC2STR(peer_addr)); - return -1; - } - - /* - * First, try to connect directly. If the peer does not - * acknowledge frames, assume it is sleeping and use device - * discoverability via the GO at that point. - */ - } - - p2p->ssid_set = 0; - if (force_ssid) { - wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID", - force_ssid, force_ssid_len); - os_memcpy(p2p->ssid, force_ssid, force_ssid_len); - p2p->ssid_len = force_ssid_len; - p2p->ssid_set = 1; - } - - dev->flags &= ~P2P_DEV_NOT_YET_READY; - dev->flags &= ~P2P_DEV_USER_REJECTED; - dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE; - dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM; - if (pd_before_go_neg) - dev->flags |= P2P_DEV_PD_BEFORE_GO_NEG; - else { - dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG; - /* - * Assign dialog token and tie breaker here to use the same - * values in each retry within the same GO Negotiation exchange. - */ - dev->dialog_token++; - if (dev->dialog_token == 0) - dev->dialog_token = 1; - dev->tie_breaker = p2p->next_tie_breaker; - p2p->next_tie_breaker = !p2p->next_tie_breaker; - } - dev->connect_reqs = 0; - dev->go_neg_req_sent = 0; - dev->go_state = UNKNOWN_GO; - p2p_set_dev_persistent(dev, persistent_group); - p2p->go_intent = go_intent; - os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN); - - if (p2p->state != P2P_IDLE) - p2p_stop_find(p2p); - - if (p2p->after_scan_tx) { - /* - * We need to drop the pending frame to avoid issues with the - * new GO Negotiation, e.g., when the pending frame was from a - * previous attempt at starting a GO Negotiation. - */ - p2p_dbg(p2p, "Dropped previous pending Action frame TX that was waiting for p2p_scan completion"); - os_free(p2p->after_scan_tx); - p2p->after_scan_tx = NULL; - } - - dev->wps_method = wps_method; - dev->oob_pw_id = oob_pw_id; - dev->status = P2P_SC_SUCCESS; - - if (p2p->p2p_scan_running) { - p2p_dbg(p2p, "p2p_scan running - delay connect send"); - p2p->start_after_scan = P2P_AFTER_SCAN_CONNECT; - os_memcpy(p2p->after_scan_peer, peer_addr, ETH_ALEN); - return 0; - } - p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; - - return p2p_connect_send(p2p, dev); -} - - -int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, - enum p2p_wps_method wps_method, - int go_intent, const u8 *own_interface_addr, - unsigned int force_freq, int persistent_group, - const u8 *force_ssid, size_t force_ssid_len, - unsigned int pref_freq, u16 oob_pw_id) -{ - struct p2p_device *dev; - - p2p_dbg(p2p, "Request to authorize group negotiation - peer=" MACSTR - " GO Intent=%d Intended Interface Address=" MACSTR - " wps_method=%d persistent_group=%d oob_pw_id=%u", - MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr), - wps_method, persistent_group, oob_pw_id); - - dev = p2p_get_device(p2p, peer_addr); - if (dev == NULL) { - p2p_dbg(p2p, "Cannot authorize unknown P2P Device " MACSTR, - MAC2STR(peer_addr)); - return -1; - } - - if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq, go_intent == - 15) < 0) - return -1; - - p2p->ssid_set = 0; - if (force_ssid) { - wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID", - force_ssid, force_ssid_len); - os_memcpy(p2p->ssid, force_ssid, force_ssid_len); - p2p->ssid_len = force_ssid_len; - p2p->ssid_set = 1; - } - - dev->flags &= ~P2P_DEV_NOT_YET_READY; - dev->flags &= ~P2P_DEV_USER_REJECTED; - dev->go_neg_req_sent = 0; - dev->go_state = UNKNOWN_GO; - p2p_set_dev_persistent(dev, persistent_group); - p2p->go_intent = go_intent; - os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN); - - dev->wps_method = wps_method; - dev->oob_pw_id = oob_pw_id; - dev->status = P2P_SC_SUCCESS; - - return 0; -} - - -void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr, - struct p2p_device *dev, struct p2p_message *msg) -{ - os_get_reltime(&dev->last_seen); - - p2p_copy_wps_info(p2p, dev, 0, msg); - - if (msg->listen_channel) { - int freq; - freq = p2p_channel_to_freq(msg->listen_channel[3], - msg->listen_channel[4]); - if (freq < 0) { - p2p_dbg(p2p, "Unknown peer Listen channel: " - "country=%c%c(0x%02x) reg_class=%u channel=%u", - msg->listen_channel[0], - msg->listen_channel[1], - msg->listen_channel[2], - msg->listen_channel[3], - msg->listen_channel[4]); - } else { - p2p_dbg(p2p, "Update peer " MACSTR - " Listen channel: %u -> %u MHz", - MAC2STR(dev->info.p2p_device_addr), - dev->listen_freq, freq); - dev->listen_freq = freq; - } - } - - if (msg->wfd_subelems) { - wpabuf_free(dev->info.wfd_subelems); - dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems); - } - - if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) { - dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY; - p2p_dbg(p2p, "Completed device entry based on data from GO Negotiation Request"); - } else { - p2p_dbg(p2p, "Created device entry based on GO Neg Req: " - MACSTR " dev_capab=0x%x group_capab=0x%x name='%s' " - "listen_freq=%d", - MAC2STR(dev->info.p2p_device_addr), - dev->info.dev_capab, dev->info.group_capab, - dev->info.device_name, dev->listen_freq); - } - - dev->flags &= ~P2P_DEV_GROUP_CLIENT_ONLY; - - if (dev->flags & P2P_DEV_USER_REJECTED) { - p2p_dbg(p2p, "Do not report rejected device"); - return; - } - - p2p->cfg->dev_found(p2p->cfg->cb_ctx, addr, &dev->info, - !(dev->flags & P2P_DEV_REPORTED_ONCE)); - dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE; -} - - -void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len) -{ - os_memcpy(ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN); - p2p_random((char *) &ssid[P2P_WILDCARD_SSID_LEN], 2); - os_memcpy(&ssid[P2P_WILDCARD_SSID_LEN + 2], - p2p->cfg->ssid_postfix, p2p->cfg->ssid_postfix_len); - *ssid_len = P2P_WILDCARD_SSID_LEN + 2 + p2p->cfg->ssid_postfix_len; -} - - -int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params) -{ - p2p_build_ssid(p2p, params->ssid, ¶ms->ssid_len); - p2p_random(params->passphrase, 8); - return 0; -} - - -void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) -{ - struct p2p_go_neg_results res; - int go = peer->go_state == LOCAL_GO; - struct p2p_channels intersection; - int freqs; - size_t i, j; - - p2p_dbg(p2p, "GO Negotiation with " MACSTR " completed (%s will be GO)", - MAC2STR(peer->info.p2p_device_addr), go ? "local end" : "peer"); - - os_memset(&res, 0, sizeof(res)); - res.role_go = go; - 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) { - 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 */ - res.freq = p2p_channel_to_freq(p2p->op_reg_class, - p2p->op_channel); - os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len); - res.ssid_len = p2p->ssid_len; - p2p_random(res.passphrase, 8); - } else { - res.freq = peer->oper_freq; - if (p2p->ssid_len) { - os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len); - res.ssid_len = p2p->ssid_len; - } - } - - p2p_channels_dump(p2p, "own channels", &p2p->channels); - p2p_channels_dump(p2p, "peer channels", &peer->channels); - p2p_channels_intersect(&p2p->channels, &peer->channels, - &intersection); - if (go) { - p2p_channels_remove_freqs(&intersection, &p2p->no_go_freq); - p2p_channels_dump(p2p, "intersection after no-GO removal", - &intersection); - } - freqs = 0; - for (i = 0; i < intersection.reg_classes; i++) { - struct p2p_reg_class *c = &intersection.reg_class[i]; - if (freqs + 1 == P2P_MAX_CHANNELS) - break; - for (j = 0; j < c->channels; j++) { - int freq; - if (freqs + 1 == P2P_MAX_CHANNELS) - break; - freq = p2p_channel_to_freq(c->reg_class, c->channel[j]); - if (freq < 0) - continue; - res.freq_list[freqs++] = freq; - } - } - - 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; - peer->oob_pw_id = 0; - - p2p_set_state(p2p, P2P_PROVISIONING); - p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res); -} - - -static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) -{ - p2p_dbg(p2p, "RX P2P Public Action from " MACSTR, MAC2STR(sa)); - wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Public Action contents", data, len); - - if (len < 1) - return; - - switch (data[0]) { - case P2P_GO_NEG_REQ: - p2p_process_go_neg_req(p2p, sa, data + 1, len - 1, rx_freq); - break; - case P2P_GO_NEG_RESP: - p2p_process_go_neg_resp(p2p, sa, data + 1, len - 1, rx_freq); - break; - case P2P_GO_NEG_CONF: - p2p_process_go_neg_conf(p2p, sa, data + 1, len - 1); - break; - case P2P_INVITATION_REQ: - p2p_process_invitation_req(p2p, sa, data + 1, len - 1, - rx_freq); - break; - case P2P_INVITATION_RESP: - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - p2p_process_invitation_resp(p2p, sa, data + 1, len - 1); - break; - case P2P_PROV_DISC_REQ: - p2p_process_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq); - break; - case P2P_PROV_DISC_RESP: - p2p_process_prov_disc_resp(p2p, sa, data + 1, len - 1); - break; - case P2P_DEV_DISC_REQ: - p2p_process_dev_disc_req(p2p, sa, data + 1, len - 1, rx_freq); - break; - case P2P_DEV_DISC_RESP: - p2p_process_dev_disc_resp(p2p, sa, data + 1, len - 1); - break; - default: - p2p_dbg(p2p, "Unsupported P2P Public Action frame type %d", - data[0]); - break; - } -} - - -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; - - switch (data[0]) { - case WLAN_PA_VENDOR_SPECIFIC: - data++; - len--; - if (len < 3) - return; - if (WPA_GET_BE24(data) != OUI_WFA) - return; - - data += 3; - len -= 3; - if (len < 1) - return; - - if (*data != P2P_OUI_TYPE) - return; - - p2p_rx_p2p_action(p2p, sa, data + 1, len - 1, freq); - break; - case WLAN_PA_GAS_INITIAL_REQ: - p2p_rx_gas_initial_req(p2p, sa, data + 1, len - 1, freq); - break; - case WLAN_PA_GAS_INITIAL_RESP: - p2p_rx_gas_initial_resp(p2p, sa, data + 1, len - 1, freq); - break; - case WLAN_PA_GAS_COMEBACK_REQ: - p2p_rx_gas_comeback_req(p2p, sa, data + 1, len - 1, freq); - break; - case WLAN_PA_GAS_COMEBACK_RESP: - p2p_rx_gas_comeback_resp(p2p, sa, data + 1, len - 1, freq); - break; - } -} - - -void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa, - const u8 *bssid, u8 category, - const u8 *data, size_t len, int freq) -{ - if (category == WLAN_ACTION_PUBLIC) { - p2p_rx_action_public(p2p, da, sa, bssid, data, len, freq); - return; - } - - if (category != WLAN_ACTION_VENDOR_SPECIFIC) - return; - - if (len < 4) - return; - - if (WPA_GET_BE24(data) != OUI_WFA) - return; - data += 3; - len -= 3; - - if (*data != P2P_OUI_TYPE) - return; - data++; - len--; - - /* P2P action frame */ - p2p_dbg(p2p, "RX P2P Action from " MACSTR, MAC2STR(sa)); - wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Action contents", data, len); - - if (len < 1) - return; - switch (data[0]) { - case P2P_NOA: - p2p_dbg(p2p, "Received P2P Action - Notice of Absence"); - /* TODO */ - break; - case P2P_PRESENCE_REQ: - p2p_process_presence_req(p2p, da, sa, data + 1, len - 1, freq); - break; - case P2P_PRESENCE_RESP: - p2p_process_presence_resp(p2p, da, sa, data + 1, len - 1); - break; - case P2P_GO_DISC_REQ: - p2p_process_go_disc_req(p2p, da, sa, data + 1, len - 1, freq); - break; - default: - p2p_dbg(p2p, "Received P2P Action - unknown type %u", data[0]); - break; - } -} - - -static void p2p_go_neg_start(void *eloop_ctx, void *timeout_ctx) -{ - struct p2p_data *p2p = eloop_ctx; - if (p2p->go_neg_peer == NULL) - return; - p2p->cfg->stop_listen(p2p->cfg->cb_ctx); - p2p->go_neg_peer->status = P2P_SC_SUCCESS; - p2p_connect_send(p2p, p2p->go_neg_peer); -} - - -static void p2p_invite_start(void *eloop_ctx, void *timeout_ctx) -{ - struct p2p_data *p2p = eloop_ctx; - if (p2p->invite_peer == NULL) - return; - p2p->cfg->stop_listen(p2p->cfg->cb_ctx); - p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr, - p2p->invite_dev_pw_id); -} - - -static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr, - const u8 *ie, size_t ie_len) -{ - struct p2p_message msg; - struct p2p_device *dev; - - os_memset(&msg, 0, sizeof(msg)); - if (p2p_parse_ies(ie, ie_len, &msg) < 0 || msg.p2p_attributes == NULL) - { - p2p_parse_free(&msg); - return; /* not a P2P probe */ - } - - if (msg.ssid == NULL || msg.ssid[1] != P2P_WILDCARD_SSID_LEN || - os_memcmp(msg.ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) - != 0) { - /* The Probe Request is not part of P2P Device Discovery. It is - * not known whether the source address of the frame is the P2P - * Device Address or P2P Interface Address. Do not add a new - * peer entry based on this frames. - */ - p2p_parse_free(&msg); - return; - } - - dev = p2p_get_device(p2p, addr); - if (dev) { - if (dev->country[0] == 0 && msg.listen_channel) - os_memcpy(dev->country, msg.listen_channel, 3); - os_get_reltime(&dev->last_seen); - p2p_parse_free(&msg); - return; /* already known */ - } - - dev = p2p_create_device(p2p, addr); - if (dev == NULL) { - p2p_parse_free(&msg); - return; - } - - os_get_reltime(&dev->last_seen); - dev->flags |= P2P_DEV_PROBE_REQ_ONLY; - - if (msg.listen_channel) { - os_memcpy(dev->country, msg.listen_channel, 3); - dev->listen_freq = p2p_channel_to_freq(msg.listen_channel[3], - msg.listen_channel[4]); - } - - p2p_copy_wps_info(p2p, dev, 1, &msg); - - if (msg.wfd_subelems) { - wpabuf_free(dev->info.wfd_subelems); - dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); - } - - p2p_parse_free(&msg); - - p2p_dbg(p2p, "Created device entry based on Probe Req: " MACSTR - " dev_capab=0x%x group_capab=0x%x name='%s' listen_freq=%d", - MAC2STR(dev->info.p2p_device_addr), dev->info.dev_capab, - dev->info.group_capab, dev->info.device_name, - dev->listen_freq); -} - - -struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p, - const u8 *addr, - struct p2p_message *msg) -{ - struct p2p_device *dev; - - dev = p2p_get_device(p2p, addr); - if (dev) { - os_get_reltime(&dev->last_seen); - return dev; /* already known */ - } - - dev = p2p_create_device(p2p, addr); - if (dev == NULL) - return NULL; - - p2p_add_dev_info(p2p, addr, dev, msg); - - return dev; -} - - -static int dev_type_match(const u8 *dev_type, const u8 *req_dev_type) -{ - if (os_memcmp(dev_type, req_dev_type, WPS_DEV_TYPE_LEN) == 0) - return 1; - if (os_memcmp(dev_type, req_dev_type, 2) == 0 && - WPA_GET_BE32(&req_dev_type[2]) == 0 && - WPA_GET_BE16(&req_dev_type[6]) == 0) - return 1; /* Category match with wildcard OUI/sub-category */ - return 0; -} - - -int dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[], - size_t num_req_dev_type) -{ - size_t i; - for (i = 0; i < num_req_dev_type; i++) { - if (dev_type_match(dev_type, req_dev_type[i])) - return 1; - } - return 0; -} - - -/** - * p2p_match_dev_type - Match local device type with requested type - * @p2p: P2P module context from p2p_init() - * @wps: WPS TLVs from Probe Request frame (concatenated WPS IEs) - * Returns: 1 on match, 0 on mismatch - * - * This function can be used to match the Requested Device Type attribute in - * WPS IE with the local device types for deciding whether to reply to a Probe - * Request frame. - */ -int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps) -{ - struct wps_parse_attr attr; - size_t i; - - if (wps_parse_msg(wps, &attr)) - return 1; /* assume no Requested Device Type attributes */ - - if (attr.num_req_dev_type == 0) - return 1; /* no Requested Device Type attributes -> match */ - - if (dev_type_list_match(p2p->cfg->pri_dev_type, attr.req_dev_type, - attr.num_req_dev_type)) - return 1; /* Own Primary Device Type matches */ - - for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) - if (dev_type_list_match(p2p->cfg->sec_dev_type[i], - attr.req_dev_type, - attr.num_req_dev_type)) - return 1; /* Own Secondary Device Type matches */ - - /* No matching device type found */ - return 0; -} - - -struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p) -{ - struct wpabuf *buf; - u8 *len; - int pw_id = -1; - size_t extra = 0; - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p->wfd_ie_probe_resp) - extra = wpabuf_len(p2p->wfd_ie_probe_resp); -#endif /* CONFIG_WIFI_DISPLAY */ - - buf = wpabuf_alloc(1000 + extra); - if (buf == NULL) - return NULL; - - if (p2p->go_neg_peer) { - /* Advertise immediate availability of WPS credential */ - pw_id = p2p_wps_method_pw_id(p2p->go_neg_peer->wps_method); - } - - if (p2p_build_wps_ie(p2p, buf, pw_id, 1) < 0) { - p2p_dbg(p2p, "Failed to build WPS IE for Probe Response"); - wpabuf_free(buf); - return NULL; - } - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p->wfd_ie_probe_resp) - wpabuf_put_buf(buf, p2p->wfd_ie_probe_resp); -#endif /* CONFIG_WIFI_DISPLAY */ - - /* P2P IE */ - len = p2p_buf_add_ie_hdr(buf); - p2p_buf_add_capability(buf, p2p->dev_capab & - ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0); - if (p2p->ext_listen_interval) - p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period, - p2p->ext_listen_interval); - p2p_buf_add_device_info(buf, p2p, NULL); - p2p_buf_update_ie_hdr(buf, len); - - return buf; -} - - -static enum p2p_probe_req_status -p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst, - const u8 *bssid, const u8 *ie, size_t ie_len) -{ - struct ieee802_11_elems elems; - struct wpabuf *buf; - struct ieee80211_mgmt *resp; - struct p2p_message msg; - struct wpabuf *ies; - - if (!p2p->in_listen || !p2p->drv_in_listen) { - /* not in Listen state - ignore Probe Request */ - return P2P_PREQ_NOT_LISTEN; - } - - if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) == - ParseFailed) { - /* Ignore invalid Probe Request frames */ - return P2P_PREQ_MALFORMED; - } - - if (elems.p2p == NULL) { - /* not a P2P probe - ignore it */ - return P2P_PREQ_NOT_P2P; - } - - if (dst && !is_broadcast_ether_addr(dst) && - os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) { - /* Not sent to the broadcast address or our P2P Device Address - */ - return P2P_PREQ_NOT_PROCESSED; - } - - if (bssid && !is_broadcast_ether_addr(bssid)) { - /* Not sent to the Wildcard BSSID */ - return P2P_PREQ_NOT_PROCESSED; - } - - if (elems.ssid == NULL || elems.ssid_len != P2P_WILDCARD_SSID_LEN || - os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) != - 0) { - /* not using P2P Wildcard SSID - ignore */ - return P2P_PREQ_NOT_PROCESSED; - } - - if (supp_rates_11b_only(&elems)) { - /* Indicates support for 11b rates only */ - return P2P_PREQ_NOT_P2P; - } - - os_memset(&msg, 0, sizeof(msg)); - if (p2p_parse_ies(ie, ie_len, &msg) < 0) { - /* Could not parse P2P attributes */ - return P2P_PREQ_NOT_P2P; - } - - 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 P2P_PREQ_NOT_PROCESSED; - } - - /* Check Requested Device Type match */ - if (msg.wps_attributes && - !p2p_match_dev_type(p2p, msg.wps_attributes)) { - /* No match with Requested Device Type */ - p2p_parse_free(&msg); - return P2P_PREQ_NOT_PROCESSED; - } - p2p_parse_free(&msg); - - if (!p2p->cfg->send_probe_resp) { - /* Response generated elsewhere */ - return P2P_PREQ_NOT_PROCESSED; - } - - p2p_dbg(p2p, "Reply to P2P Probe Request in Listen state"); - - /* - * We do not really have a specific BSS that this frame is advertising, - * so build a frame that has some information in valid format. This is - * really only used for discovery purposes, not to learn exact BSS - * parameters. - */ - ies = p2p_build_probe_resp_ies(p2p); - if (ies == NULL) - return P2P_PREQ_NOT_PROCESSED; - - buf = wpabuf_alloc(200 + wpabuf_len(ies)); - if (buf == NULL) { - wpabuf_free(ies); - return P2P_PREQ_NOT_PROCESSED; - } - - resp = NULL; - resp = wpabuf_put(buf, resp->u.probe_resp.variable - (u8 *) resp); - - resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) | - (WLAN_FC_STYPE_PROBE_RESP << 4)); - os_memcpy(resp->da, addr, ETH_ALEN); - os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN); - os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN); - resp->u.probe_resp.beacon_int = host_to_le16(100); - /* hardware or low-level driver will setup seq_ctrl and timestamp */ - resp->u.probe_resp.capab_info = - host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE | - WLAN_CAPABILITY_PRIVACY | - WLAN_CAPABILITY_SHORT_SLOT_TIME); - - wpabuf_put_u8(buf, WLAN_EID_SSID); - wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN); - wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN); - - wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES); - wpabuf_put_u8(buf, 8); - wpabuf_put_u8(buf, (60 / 5) | 0x80); - wpabuf_put_u8(buf, 90 / 5); - wpabuf_put_u8(buf, (120 / 5) | 0x80); - wpabuf_put_u8(buf, 180 / 5); - wpabuf_put_u8(buf, (240 / 5) | 0x80); - wpabuf_put_u8(buf, 360 / 5); - wpabuf_put_u8(buf, 480 / 5); - wpabuf_put_u8(buf, 540 / 5); - - wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS); - wpabuf_put_u8(buf, 1); - wpabuf_put_u8(buf, p2p->cfg->channel); - - wpabuf_put_buf(buf, ies); - wpabuf_free(ies); - - p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf); - - wpabuf_free(buf); - - return P2P_PREQ_NOT_PROCESSED; -} - - -enum p2p_probe_req_status -p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst, - const u8 *bssid, const u8 *ie, size_t ie_len) -{ - enum p2p_probe_req_status res; - - p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len); - - res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len); - - if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) && - p2p->go_neg_peer && - os_memcmp(addr, p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN) - == 0 && - !(p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) { - /* Received a Probe Request from GO Negotiation peer */ - p2p_dbg(p2p, "Found GO Negotiation peer - try to start GO negotiation from timeout"); - eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL); - eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL); - return P2P_PREQ_PROCESSED; - } - - if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) && - p2p->invite_peer && - os_memcmp(addr, p2p->invite_peer->info.p2p_device_addr, ETH_ALEN) - == 0) { - /* Received a Probe Request from Invite peer */ - p2p_dbg(p2p, "Found Invite peer - try to start Invite from timeout"); - eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL); - return P2P_PREQ_PROCESSED; - } - - return res; -} - - -static int p2p_assoc_req_ie_wlan_ap(struct p2p_data *p2p, const u8 *bssid, - u8 *buf, size_t len, struct wpabuf *p2p_ie) -{ - struct wpabuf *tmp; - u8 *lpos; - size_t tmplen; - int res; - u8 group_capab; - - if (p2p_ie == NULL) - return 0; /* WLAN AP is not a P2P manager */ - - /* - * (Re)Association Request - P2P IE - * P2P Capability attribute (shall be present) - * P2P Interface attribute (present if concurrent device and - * P2P Management is enabled) - */ - tmp = wpabuf_alloc(200); - if (tmp == NULL) - return -1; - - lpos = p2p_buf_add_ie_hdr(tmp); - group_capab = 0; - if (p2p->num_groups > 0) { - group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER; - if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) && - (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED) && - p2p->cross_connect) - group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; - } - p2p_buf_add_capability(tmp, p2p->dev_capab, group_capab); - if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) && - (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED)) - p2p_buf_add_p2p_interface(tmp, p2p); - p2p_buf_update_ie_hdr(tmp, lpos); - - tmplen = wpabuf_len(tmp); - if (tmplen > len) - res = -1; - else { - os_memcpy(buf, wpabuf_head(tmp), tmplen); - res = tmplen; - } - wpabuf_free(tmp); - - return res; -} - - -int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf, - size_t len, int p2p_group, struct wpabuf *p2p_ie) -{ - struct wpabuf *tmp; - u8 *lpos; - struct p2p_device *peer; - size_t tmplen; - int res; - size_t extra = 0; - - if (!p2p_group) - return p2p_assoc_req_ie_wlan_ap(p2p, bssid, buf, len, p2p_ie); - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p->wfd_ie_assoc_req) - extra = wpabuf_len(p2p->wfd_ie_assoc_req); -#endif /* CONFIG_WIFI_DISPLAY */ - - /* - * (Re)Association Request - P2P IE - * P2P Capability attribute (shall be present) - * Extended Listen Timing (may be present) - * P2P Device Info attribute (shall be present) - */ - tmp = wpabuf_alloc(200 + extra); - if (tmp == NULL) - return -1; - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p->wfd_ie_assoc_req) - wpabuf_put_buf(tmp, p2p->wfd_ie_assoc_req); -#endif /* CONFIG_WIFI_DISPLAY */ - - peer = bssid ? p2p_get_device(p2p, bssid) : NULL; - - lpos = p2p_buf_add_ie_hdr(tmp); - p2p_buf_add_capability(tmp, p2p->dev_capab, 0); - if (p2p->ext_listen_interval) - p2p_buf_add_ext_listen_timing(tmp, p2p->ext_listen_period, - p2p->ext_listen_interval); - p2p_buf_add_device_info(tmp, p2p, peer); - p2p_buf_update_ie_hdr(tmp, lpos); - - tmplen = wpabuf_len(tmp); - if (tmplen > len) - res = -1; - else { - os_memcpy(buf, wpabuf_head(tmp), tmplen); - res = tmplen; - } - wpabuf_free(tmp); - - return res; -} - - -int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end) -{ - struct wpabuf *p2p_ie; - int ret; - - p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len, P2P_IE_VENDOR_TYPE); - if (p2p_ie == NULL) - return 0; - - ret = p2p_attr_text(p2p_ie, buf, end); - wpabuf_free(p2p_ie); - return ret; -} - - -int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr) -{ - struct p2p_message msg; - - os_memset(&msg, 0, sizeof(msg)); - if (p2p_parse_p2p_ie(p2p_ie, &msg)) - return -1; - - if (msg.p2p_device_addr) { - os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN); - return 0; - } else if (msg.device_id) { - os_memcpy(dev_addr, msg.device_id, ETH_ALEN); - return 0; - } - return -1; -} - - -int p2p_parse_dev_addr(const u8 *ies, size_t ies_len, u8 *dev_addr) -{ - struct wpabuf *p2p_ie; - int ret; - - p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len, - P2P_IE_VENDOR_TYPE); - if (p2p_ie == NULL) - return -1; - ret = p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr); - wpabuf_free(p2p_ie); - return ret; -} - - -static void p2p_clear_go_neg(struct p2p_data *p2p) -{ - p2p->go_neg_peer = NULL; - p2p_clear_timeout(p2p); - p2p_set_state(p2p, P2P_IDLE); -} - - -void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr) -{ - if (p2p->go_neg_peer == NULL) { - p2p_dbg(p2p, "No pending Group Formation - ignore WPS registration success notification"); - return; /* No pending Group Formation */ - } - - if (os_memcmp(mac_addr, p2p->go_neg_peer->intended_addr, ETH_ALEN) != - 0) { - p2p_dbg(p2p, "Ignore WPS registration success notification for " - MACSTR " (GO Negotiation peer " MACSTR ")", - MAC2STR(mac_addr), - MAC2STR(p2p->go_neg_peer->intended_addr)); - return; /* Ignore unexpected peer address */ - } - - p2p_dbg(p2p, "Group Formation completed successfully with " MACSTR, - MAC2STR(mac_addr)); - - p2p_clear_go_neg(p2p); -} - - -void p2p_group_formation_failed(struct p2p_data *p2p) -{ - if (p2p->go_neg_peer == NULL) { - p2p_dbg(p2p, "No pending Group Formation - ignore group formation failure notification"); - return; /* No pending Group Formation */ - } - - p2p_dbg(p2p, "Group Formation failed with " MACSTR, - MAC2STR(p2p->go_neg_peer->intended_addr)); - - p2p_clear_go_neg(p2p); -} - - -struct p2p_data * p2p_init(const struct p2p_config *cfg) -{ - struct p2p_data *p2p; - - if (cfg->max_peers < 1) - return NULL; - - p2p = os_zalloc(sizeof(*p2p) + sizeof(*cfg)); - if (p2p == NULL) - return NULL; - p2p->cfg = (struct p2p_config *) (p2p + 1); - os_memcpy(p2p->cfg, cfg, sizeof(*cfg)); - if (cfg->dev_name) - p2p->cfg->dev_name = os_strdup(cfg->dev_name); - if (cfg->manufacturer) - p2p->cfg->manufacturer = os_strdup(cfg->manufacturer); - if (cfg->model_name) - p2p->cfg->model_name = os_strdup(cfg->model_name); - if (cfg->model_number) - p2p->cfg->model_number = os_strdup(cfg->model_number); - if (cfg->serial_number) - p2p->cfg->serial_number = os_strdup(cfg->serial_number); - if (cfg->pref_chan) { - p2p->cfg->pref_chan = os_malloc(cfg->num_pref_chan * - sizeof(struct p2p_channel)); - if (p2p->cfg->pref_chan) { - os_memcpy(p2p->cfg->pref_chan, cfg->pref_chan, - cfg->num_pref_chan * - sizeof(struct p2p_channel)); - } else - p2p->cfg->num_pref_chan = 0; - } - - p2p->min_disc_int = 1; - p2p->max_disc_int = 3; - p2p->max_disc_tu = -1; - - os_get_random(&p2p->next_tie_breaker, 1); - p2p->next_tie_breaker &= 0x01; - if (cfg->sd_request) - p2p->dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY; - p2p->dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE; - if (cfg->concurrent_operations) - p2p->dev_capab |= P2P_DEV_CAPAB_CONCURRENT_OPER; - p2p->dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; - - dl_list_init(&p2p->devices); - - eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0, - p2p_expiration_timeout, p2p, NULL); - - p2p->go_timeout = 100; - p2p->client_timeout = 20; - - p2p_dbg(p2p, "initialized"); - p2p_channels_dump(p2p, "channels", &p2p->cfg->channels); - p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels); - - return p2p; -} - - -void p2p_deinit(struct p2p_data *p2p) -{ -#ifdef CONFIG_WIFI_DISPLAY - wpabuf_free(p2p->wfd_ie_beacon); - wpabuf_free(p2p->wfd_ie_probe_req); - wpabuf_free(p2p->wfd_ie_probe_resp); - wpabuf_free(p2p->wfd_ie_assoc_req); - wpabuf_free(p2p->wfd_ie_invitation); - wpabuf_free(p2p->wfd_ie_prov_disc_req); - wpabuf_free(p2p->wfd_ie_prov_disc_resp); - wpabuf_free(p2p->wfd_ie_go_neg); - wpabuf_free(p2p->wfd_dev_info); - wpabuf_free(p2p->wfd_assoc_bssid); - wpabuf_free(p2p->wfd_coupled_sink_info); -#endif /* CONFIG_WIFI_DISPLAY */ - - eloop_cancel_timeout(p2p_expiration_timeout, p2p, NULL); - eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL); - eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL); - eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL); - p2p_flush(p2p); - p2p_free_req_dev_types(p2p); - os_free(p2p->cfg->dev_name); - os_free(p2p->cfg->manufacturer); - os_free(p2p->cfg->model_name); - os_free(p2p->cfg->model_number); - os_free(p2p->cfg->serial_number); - os_free(p2p->cfg->pref_chan); - os_free(p2p->groups); - wpabuf_free(p2p->sd_resp); - os_free(p2p->after_scan_tx); - p2p_remove_wps_vendor_extensions(p2p); - os_free(p2p->no_go_freq.range); - os_free(p2p); -} - - -void p2p_flush(struct p2p_data *p2p) -{ - struct p2p_device *dev, *prev; - p2p_stop_find(p2p); - dl_list_for_each_safe(dev, prev, &p2p->devices, struct p2p_device, - list) { - dl_list_del(&dev->list); - p2p_device_free(p2p, dev); - } - p2p_free_sd_queries(p2p); - os_free(p2p->after_scan_tx); - p2p->after_scan_tx = NULL; -} - - -int p2p_unauthorize(struct p2p_data *p2p, const u8 *addr) -{ - struct p2p_device *dev; - - dev = p2p_get_device(p2p, addr); - if (dev == NULL) - return -1; - - p2p_dbg(p2p, "Unauthorizing " MACSTR, MAC2STR(addr)); - - if (p2p->go_neg_peer == dev) - p2p->go_neg_peer = NULL; - - dev->wps_method = WPS_NOT_READY; - dev->oob_pw_id = 0; - dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE; - dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM; - - /* Check if after_scan_tx is for this peer. If so free it */ - if (p2p->after_scan_tx && - os_memcmp(addr, p2p->after_scan_tx->dst, ETH_ALEN) == 0) { - os_free(p2p->after_scan_tx); - p2p->after_scan_tx = NULL; - } - - return 0; -} - - -int p2p_set_dev_name(struct p2p_data *p2p, const char *dev_name) -{ - os_free(p2p->cfg->dev_name); - if (dev_name) { - p2p->cfg->dev_name = os_strdup(dev_name); - if (p2p->cfg->dev_name == NULL) - return -1; - } else - p2p->cfg->dev_name = NULL; - return 0; -} - - -int p2p_set_manufacturer(struct p2p_data *p2p, const char *manufacturer) -{ - os_free(p2p->cfg->manufacturer); - p2p->cfg->manufacturer = NULL; - if (manufacturer) { - p2p->cfg->manufacturer = os_strdup(manufacturer); - if (p2p->cfg->manufacturer == NULL) - return -1; - } - - return 0; -} - - -int p2p_set_model_name(struct p2p_data *p2p, const char *model_name) -{ - os_free(p2p->cfg->model_name); - p2p->cfg->model_name = NULL; - if (model_name) { - p2p->cfg->model_name = os_strdup(model_name); - if (p2p->cfg->model_name == NULL) - return -1; - } - - return 0; -} - - -int p2p_set_model_number(struct p2p_data *p2p, const char *model_number) -{ - os_free(p2p->cfg->model_number); - p2p->cfg->model_number = NULL; - if (model_number) { - p2p->cfg->model_number = os_strdup(model_number); - if (p2p->cfg->model_number == NULL) - return -1; - } - - return 0; -} - - -int p2p_set_serial_number(struct p2p_data *p2p, const char *serial_number) -{ - os_free(p2p->cfg->serial_number); - p2p->cfg->serial_number = NULL; - if (serial_number) { - p2p->cfg->serial_number = os_strdup(serial_number); - if (p2p->cfg->serial_number == NULL) - return -1; - } - - return 0; -} - - -void p2p_set_config_methods(struct p2p_data *p2p, u16 config_methods) -{ - p2p->cfg->config_methods = config_methods; -} - - -void p2p_set_uuid(struct p2p_data *p2p, const u8 *uuid) -{ - os_memcpy(p2p->cfg->uuid, uuid, 16); -} - - -int p2p_set_pri_dev_type(struct p2p_data *p2p, const u8 *pri_dev_type) -{ - os_memcpy(p2p->cfg->pri_dev_type, pri_dev_type, 8); - return 0; -} - - -int p2p_set_sec_dev_types(struct p2p_data *p2p, const u8 dev_types[][8], - size_t num_dev_types) -{ - if (num_dev_types > P2P_SEC_DEVICE_TYPES) - num_dev_types = P2P_SEC_DEVICE_TYPES; - p2p->cfg->num_sec_dev_types = num_dev_types; - os_memcpy(p2p->cfg->sec_dev_type, dev_types, num_dev_types * 8); - return 0; -} - - -void p2p_remove_wps_vendor_extensions(struct p2p_data *p2p) -{ - int i; - - for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { - wpabuf_free(p2p->wps_vendor_ext[i]); - p2p->wps_vendor_ext[i] = NULL; - } -} - - -int p2p_add_wps_vendor_extension(struct p2p_data *p2p, - const struct wpabuf *vendor_ext) -{ - int i; - - if (vendor_ext == NULL) - return -1; - - for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { - if (p2p->wps_vendor_ext[i] == NULL) - break; - } - if (i >= P2P_MAX_WPS_VENDOR_EXT) - return -1; - - p2p->wps_vendor_ext[i] = wpabuf_dup(vendor_ext); - if (p2p->wps_vendor_ext[i] == NULL) - return -1; - - return 0; -} - - -int p2p_set_country(struct p2p_data *p2p, const char *country) -{ - os_memcpy(p2p->cfg->country, country, 3); - return 0; -} - - -void p2p_continue_find(struct p2p_data *p2p) -{ - struct p2p_device *dev; - p2p_set_state(p2p, P2P_SEARCH); - dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { - if (dev->flags & P2P_DEV_SD_SCHEDULE) { - if (p2p_start_sd(p2p, dev) == 0) - return; - else - break; - } else if (dev->req_config_methods && - !(dev->flags & P2P_DEV_PD_FOR_JOIN)) { - p2p_dbg(p2p, "Send 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) == 0) - return; - } - } - - p2p_listen_in_find(p2p, 1); -} - - -static void p2p_sd_cb(struct p2p_data *p2p, int success) -{ - p2p_dbg(p2p, "Service Discovery Query TX callback: success=%d", - success); - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - - if (!success) { - if (p2p->sd_peer) { - p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE; - p2p->sd_peer = NULL; - } - p2p_continue_find(p2p); - return; - } - - if (p2p->sd_peer == NULL) { - p2p_dbg(p2p, "No SD peer entry known"); - p2p_continue_find(p2p); - return; - } - - /* Wait for response from the peer */ - p2p_set_state(p2p, P2P_SD_DURING_FIND); - p2p_set_timeout(p2p, 0, 200000); -} - - -/** - * p2p_retry_pd - Retry any pending provision disc requests in IDLE state - * @p2p: P2P module context from p2p_init() - */ -static void p2p_retry_pd(struct p2p_data *p2p) -{ - struct p2p_device *dev; - - if (p2p->state != P2P_IDLE) - return; - - /* - * Retry the prov disc req attempt only for the peer that the user had - * requested. - */ - - 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) != 0) - continue; - if (!dev->req_config_methods) - continue; - - p2p_dbg(p2p, "Send 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, - dev->flags & P2P_DEV_PD_FOR_JOIN, - p2p->pd_force_freq); - return; - } -} - - -static void p2p_prov_disc_cb(struct p2p_data *p2p, int success) -{ - p2p_dbg(p2p, "Provision Discovery Request TX callback: success=%d", - success); - - /* - * Postpone resetting the pending action state till after we actually - * time out. This allows us to take some action like notifying any - * interested parties about no response to the request. - * - * When the timer (below) goes off we check in IDLE, SEARCH, or - * LISTEN_ONLY state, which are the only allowed states to issue a PD - * requests in, if this was still pending and then raise notification. - */ - - if (!success) { - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - - if (p2p->user_initiated_pd && - (p2p->state == P2P_SEARCH || p2p->state == P2P_LISTEN_ONLY)) - { - /* Retry request from timeout to avoid busy loops */ - p2p->pending_action_state = P2P_PENDING_PD; - p2p_set_timeout(p2p, 0, 50000); - } else if (p2p->state != P2P_IDLE) - p2p_continue_find(p2p); - else if (p2p->user_initiated_pd) { - p2p->pending_action_state = P2P_PENDING_PD; - p2p_set_timeout(p2p, 0, 300000); - } - return; - } - - /* - * This postponing, of resetting pending_action_state, needs to be - * done only for user initiated PD requests and not internal ones. - */ - if (p2p->user_initiated_pd) - p2p->pending_action_state = P2P_PENDING_PD; - else - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - - /* Wait for response from the peer */ - if (p2p->state == P2P_SEARCH) - p2p_set_state(p2p, P2P_PD_DURING_FIND); - p2p_set_timeout(p2p, 0, 200000); -} - - -int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq, - struct os_reltime *rx_time, int level, const u8 *ies, - size_t ies_len) -{ - if (os_reltime_before(rx_time, &p2p->find_start)) { - /* - * The driver may have cached (e.g., in cfg80211 BSS table) the - * scan results for relatively long time. To avoid reporting - * stale information, update P2P peers only based on results - * that have based on frames received after the last p2p_find - * operation was started. - */ - p2p_dbg(p2p, "Ignore old scan result for " MACSTR - " (rx_time=%u.%06u)", - MAC2STR(bssid), (unsigned int) rx_time->sec, - (unsigned int) rx_time->usec); - return 0; - } - - p2p_add_device(p2p, bssid, freq, rx_time, level, ies, ies_len, 1); - - return 0; -} - - -void p2p_scan_res_handled(struct p2p_data *p2p) -{ - if (!p2p->p2p_scan_running) { - p2p_dbg(p2p, "p2p_scan was not running, but scan results received"); - } - p2p->p2p_scan_running = 0; - eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL); - - if (p2p_run_after_scan(p2p)) - return; - if (p2p->state == P2P_SEARCH) - p2p_continue_find(p2p); -} - - -void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id) -{ - u8 *len; - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p->wfd_ie_probe_req) - wpabuf_put_buf(ies, p2p->wfd_ie_probe_req); -#endif /* CONFIG_WIFI_DISPLAY */ - - len = p2p_buf_add_ie_hdr(ies); - p2p_buf_add_capability(ies, p2p->dev_capab & - ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0); - if (dev_id) - p2p_buf_add_device_id(ies, dev_id); - if (p2p->cfg->reg_class && p2p->cfg->channel) - p2p_buf_add_listen_channel(ies, p2p->cfg->country, - p2p->cfg->reg_class, - p2p->cfg->channel); - if (p2p->ext_listen_interval) - p2p_buf_add_ext_listen_timing(ies, p2p->ext_listen_period, - p2p->ext_listen_interval); - /* TODO: p2p_buf_add_operating_channel() if GO */ - p2p_buf_update_ie_hdr(ies, len); -} - - -size_t p2p_scan_ie_buf_len(struct p2p_data *p2p) -{ - size_t len = 100; - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p && p2p->wfd_ie_probe_req) - len += wpabuf_len(p2p->wfd_ie_probe_req); -#endif /* CONFIG_WIFI_DISPLAY */ - - return len; -} - - -int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end) -{ - return p2p_attr_text(p2p_ie, buf, end); -} - - -static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success) -{ - struct p2p_device *dev = p2p->go_neg_peer; - int timeout; - - p2p_dbg(p2p, "GO Negotiation Request TX callback: success=%d", success); - - if (dev == NULL) { - p2p_dbg(p2p, "No pending GO Negotiation"); - return; - } - - if (success) { - if (dev->flags & P2P_DEV_USER_REJECTED) { - p2p_set_state(p2p, P2P_IDLE); - return; - } - } else if (dev->go_neg_req_sent) { - /* Cancel the increment from p2p_connect_send() on failure */ - dev->go_neg_req_sent--; - } - - if (!success && - (dev->info.dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY) && - !is_zero_ether_addr(dev->member_in_go_dev)) { - p2p_dbg(p2p, "Peer " MACSTR " did not acknowledge request - try to use device discoverability through its GO", - MAC2STR(dev->info.p2p_device_addr)); - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - p2p_send_dev_disc_req(p2p, dev); - return; - } - - /* - * Use P2P find, if needed, to find the other device from its listen - * channel. - */ - p2p_set_state(p2p, P2P_CONNECT); - timeout = success ? 500000 : 100000; - if (!success && p2p->go_neg_peer && - (p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE)) { - unsigned int r; - /* - * Peer is expected to wait our response and we will skip the - * listen phase. Add some randomness to the wait time here to - * make it less likely to hit cases where we could end up in - * sync with peer not listening. - */ - os_get_random((u8 *) &r, sizeof(r)); - timeout += r % 100000; - } - p2p_set_timeout(p2p, 0, timeout); -} - - -static void p2p_go_neg_resp_cb(struct p2p_data *p2p, int success) -{ - p2p_dbg(p2p, "GO Negotiation Response TX callback: success=%d", - success); - if (!p2p->go_neg_peer && p2p->state == P2P_PROVISIONING) { - p2p_dbg(p2p, "Ignore TX callback event - GO Negotiation is not running anymore"); - return; - } - p2p_set_state(p2p, P2P_CONNECT); - p2p_set_timeout(p2p, 0, 500000); -} - - -static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success, - const u8 *addr) -{ - p2p_dbg(p2p, "GO Negotiation Response (failure) TX callback: success=%d", success); - if (p2p->go_neg_peer && p2p->go_neg_peer->status != P2P_SC_SUCCESS) { - p2p_go_neg_failed(p2p, p2p->go_neg_peer, - p2p->go_neg_peer->status); - } else if (success) { - struct p2p_device *dev; - dev = p2p_get_device(p2p, addr); - if (dev && - dev->status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) - dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE; - } -} - - -static void p2p_go_neg_conf_cb(struct p2p_data *p2p, - enum p2p_send_action_result result) -{ - struct p2p_device *dev; - - p2p_dbg(p2p, "GO Negotiation Confirm TX callback: result=%d", result); - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - if (result == P2P_SEND_ACTION_FAILED) { - p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1); - return; - } - if (result == P2P_SEND_ACTION_NO_ACK) { - /* - * It looks like the TX status for GO Negotiation Confirm is - * often showing failure even when the peer has actually - * received the frame. Since the peer may change channels - * immediately after having received the frame, we may not see - * an Ack for retries, so just dropping a single frame may - * trigger this. To allow the group formation to succeed if the - * peer did indeed receive the frame, continue regardless of - * the TX status. - */ - p2p_dbg(p2p, "Assume GO Negotiation Confirm TX was actually received by the peer even though Ack was not reported"); - } - - dev = p2p->go_neg_peer; - if (dev == NULL) - return; - - p2p_go_complete(p2p, dev); -} - - -void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst, - const u8 *src, const u8 *bssid, - enum p2p_send_action_result result) -{ - enum p2p_pending_action_state state; - int success; - - p2p_dbg(p2p, "Action frame TX callback (state=%d freq=%u dst=" MACSTR - " src=" MACSTR " bssid=" MACSTR " result=%d", - p2p->pending_action_state, freq, MAC2STR(dst), MAC2STR(src), - MAC2STR(bssid), result); - success = result == P2P_SEND_ACTION_SUCCESS; - state = p2p->pending_action_state; - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - switch (state) { - case P2P_NO_PENDING_ACTION: - if (p2p->after_scan_tx_in_progress) { - p2p->after_scan_tx_in_progress = 0; - if (p2p->start_after_scan != P2P_AFTER_SCAN_NOTHING && - p2p_run_after_scan(p2p)) - break; - if (p2p->state == P2P_SEARCH) { - p2p_dbg(p2p, "Continue find after after_scan_tx completion"); - p2p_continue_find(p2p); - } - } - break; - case P2P_PENDING_GO_NEG_REQUEST: - p2p_go_neg_req_cb(p2p, success); - break; - case P2P_PENDING_GO_NEG_RESPONSE: - p2p_go_neg_resp_cb(p2p, success); - break; - case P2P_PENDING_GO_NEG_RESPONSE_FAILURE: - p2p_go_neg_resp_failure_cb(p2p, success, dst); - break; - case P2P_PENDING_GO_NEG_CONFIRM: - p2p_go_neg_conf_cb(p2p, result); - break; - case P2P_PENDING_SD: - p2p_sd_cb(p2p, success); - break; - case P2P_PENDING_PD: - p2p_prov_disc_cb(p2p, success); - break; - case P2P_PENDING_INVITATION_REQUEST: - p2p_invitation_req_cb(p2p, success); - break; - case P2P_PENDING_INVITATION_RESPONSE: - p2p_invitation_resp_cb(p2p, success); - break; - case P2P_PENDING_DEV_DISC_REQUEST: - p2p_dev_disc_req_cb(p2p, success); - break; - case P2P_PENDING_DEV_DISC_RESPONSE: - p2p_dev_disc_resp_cb(p2p, success); - break; - case P2P_PENDING_GO_DISC_REQ: - p2p_go_disc_req_cb(p2p, success); - break; - } - - p2p->after_scan_tx_in_progress = 0; -} - - -void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq, - unsigned int duration) -{ - if (freq == p2p->pending_client_disc_freq) { - p2p_dbg(p2p, "Client discoverability remain-awake completed"); - p2p->pending_client_disc_freq = 0; - return; - } - - if (freq != p2p->pending_listen_freq) { - p2p_dbg(p2p, "Unexpected listen callback for freq=%u duration=%u (pending_listen_freq=%u)", - freq, duration, p2p->pending_listen_freq); - return; - } - - p2p_dbg(p2p, "Starting Listen timeout(%u,%u) on freq=%u based on callback", - p2p->pending_listen_sec, p2p->pending_listen_usec, - p2p->pending_listen_freq); - p2p->in_listen = 1; - p2p->drv_in_listen = freq; - if (p2p->pending_listen_sec || p2p->pending_listen_usec) { - /* - * Add 20 msec extra wait to avoid race condition with driver - * remain-on-channel end event, i.e., give driver more time to - * complete the operation before our timeout expires. - */ - p2p_set_timeout(p2p, p2p->pending_listen_sec, - p2p->pending_listen_usec + 20000); - } - - p2p->pending_listen_freq = 0; -} - - -int p2p_listen_end(struct p2p_data *p2p, unsigned int freq) -{ - p2p_dbg(p2p, "Driver ended Listen state (freq=%u)", freq); - p2p->drv_in_listen = 0; - if (p2p->in_listen) - return 0; /* Internal timeout will trigger the next step */ - - if (p2p->state == P2P_CONNECT_LISTEN && p2p->go_neg_peer) { - if (p2p->go_neg_peer->connect_reqs >= 120) { - p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response"); - p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1); - return 0; - } - - p2p_set_state(p2p, P2P_CONNECT); - p2p_connect_send(p2p, p2p->go_neg_peer); - return 1; - } else if (p2p->state == P2P_SEARCH) { - if (p2p->p2p_scan_running) { - /* - * Search is already in progress. This can happen if - * an Action frame RX is reported immediately after - * the end of a remain-on-channel operation and the - * response frame to that is sent using an offchannel - * operation while in p2p_find. Avoid an attempt to - * restart a scan here. - */ - p2p_dbg(p2p, "p2p_scan already in progress - do not try to start a new one"); - return 1; - } - if (p2p->pending_listen_freq) { - /* - * Better wait a bit if the driver is unable to start - * offchannel operation for some reason. p2p_search() - * will be started from internal timeout. - */ - p2p_dbg(p2p, "Listen operation did not seem to start - delay search phase to avoid busy loop"); - p2p_set_timeout(p2p, 0, 100000); - return 1; - } - if (p2p->search_delay) { - p2p_dbg(p2p, "Delay search operation by %u ms", - p2p->search_delay); - p2p_set_timeout(p2p, p2p->search_delay / 1000, - (p2p->search_delay % 1000) * 1000); - return 1; - } - p2p_search(p2p); - return 1; - } - - return 0; -} - - -static void p2p_timeout_connect(struct p2p_data *p2p) -{ - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - if (p2p->go_neg_peer && - (p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) { - p2p_dbg(p2p, "Wait for GO Negotiation Confirm timed out - assume GO Negotiation failed"); - p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1); - return; - } - if (p2p->go_neg_peer && - (p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE) && - p2p->go_neg_peer->connect_reqs < 120) { - p2p_dbg(p2p, "Peer expected to wait our response - skip listen"); - p2p_connect_send(p2p, p2p->go_neg_peer); - return; - } - if (p2p->go_neg_peer && p2p->go_neg_peer->oob_go_neg_freq > 0) { - p2p_dbg(p2p, "Skip connect-listen since GO Neg channel known (OOB)"); - p2p_set_state(p2p, P2P_CONNECT_LISTEN); - p2p_set_timeout(p2p, 0, 30000); - return; - } - p2p_set_state(p2p, P2P_CONNECT_LISTEN); - p2p_listen_in_find(p2p, 0); -} - - -static void p2p_timeout_connect_listen(struct p2p_data *p2p) -{ - if (p2p->go_neg_peer) { - if (p2p->drv_in_listen) { - p2p_dbg(p2p, "Driver is still in Listen state; wait for it to complete"); - return; - } - - if (p2p->go_neg_peer->connect_reqs >= 120) { - p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response"); - p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1); - return; - } - - p2p_set_state(p2p, P2P_CONNECT); - p2p_connect_send(p2p, p2p->go_neg_peer); - } else - p2p_set_state(p2p, P2P_IDLE); -} - - -static void p2p_timeout_wait_peer_connect(struct p2p_data *p2p) -{ - p2p_set_state(p2p, P2P_WAIT_PEER_IDLE); - - if (p2p->cfg->is_concurrent_session_active && - p2p->cfg->is_concurrent_session_active(p2p->cfg->cb_ctx)) - p2p_set_timeout(p2p, 0, 500000); - else - p2p_set_timeout(p2p, 0, 200000); -} - - -static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p) -{ - struct p2p_device *dev = p2p->go_neg_peer; - - if (dev == NULL) { - p2p_dbg(p2p, "Unknown GO Neg peer - stop GO Neg wait"); - return; - } - - dev->wait_count++; - if (dev->wait_count >= 120) { - p2p_dbg(p2p, "Timeout on waiting peer to become ready for GO Negotiation"); - p2p_go_neg_failed(p2p, dev, -1); - return; - } - - p2p_dbg(p2p, "Go to Listen state while waiting for the peer to become ready for GO Negotiation"); - p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT); - p2p_listen_in_find(p2p, 0); -} - - -static void p2p_timeout_sd_during_find(struct p2p_data *p2p) -{ - p2p_dbg(p2p, "Service Discovery Query timeout"); - if (p2p->sd_peer) { - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE; - p2p->sd_peer = NULL; - } - p2p_continue_find(p2p); -} - - -static void p2p_timeout_prov_disc_during_find(struct p2p_data *p2p) -{ - p2p_dbg(p2p, "Provision Discovery Request timeout"); - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - p2p_continue_find(p2p); -} - - -static void p2p_timeout_prov_disc_req(struct p2p_data *p2p) -{ - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - - /* - * For user initiated PD requests that we have not gotten any responses - * for while in IDLE state, we retry them a couple of times before - * giving up. - */ - if (!p2p->user_initiated_pd) - return; - - p2p_dbg(p2p, "User initiated Provision Discovery Request timeout"); - - if (p2p->pd_retries) { - p2p->pd_retries--; - p2p_retry_pd(p2p); - } else { - struct p2p_device *dev; - int for_join = 0; - - 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) != 0) - continue; - if (dev->req_config_methods && - (dev->flags & P2P_DEV_PD_FOR_JOIN)) - for_join = 1; - } - - if (p2p->cfg->prov_disc_fail) - p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, - p2p->pending_pd_devaddr, - for_join ? - P2P_PROV_DISC_TIMEOUT_JOIN : - P2P_PROV_DISC_TIMEOUT); - p2p_reset_pending_pd(p2p); - } -} - - -static void p2p_timeout_invite(struct p2p_data *p2p) -{ - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - p2p_set_state(p2p, P2P_INVITE_LISTEN); - if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO) { - /* - * Better remain on operating channel instead of listen channel - * when running a group. - */ - p2p_dbg(p2p, "Inviting in active GO role - wait on operating channel"); - p2p_set_timeout(p2p, 0, 100000); - return; - } - p2p_listen_in_find(p2p, 0); -} - - -static void p2p_timeout_invite_listen(struct p2p_data *p2p) -{ - if (p2p->invite_peer && p2p->invite_peer->invitation_reqs < 100) { - p2p_set_state(p2p, P2P_INVITE); - p2p_invite_send(p2p, p2p->invite_peer, - p2p->invite_go_dev_addr, p2p->invite_dev_pw_id); - } else { - if (p2p->invite_peer) { - p2p_dbg(p2p, "Invitation Request retry limit reached"); - if (p2p->cfg->invitation_result) - p2p->cfg->invitation_result( - p2p->cfg->cb_ctx, -1, NULL, NULL, - p2p->invite_peer->info.p2p_device_addr, - 0); - } - p2p_set_state(p2p, P2P_IDLE); - } -} - - -static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct p2p_data *p2p = eloop_ctx; - - p2p_dbg(p2p, "Timeout (state=%s)", p2p_state_txt(p2p->state)); - - p2p->in_listen = 0; - - switch (p2p->state) { - case P2P_IDLE: - /* Check if we timed out waiting for PD req */ - if (p2p->pending_action_state == P2P_PENDING_PD) - p2p_timeout_prov_disc_req(p2p); - break; - case P2P_SEARCH: - /* Check if we timed out waiting for PD req */ - if (p2p->pending_action_state == P2P_PENDING_PD) - p2p_timeout_prov_disc_req(p2p); - if (p2p->search_delay && !p2p->in_search_delay) { - p2p_dbg(p2p, "Delay search operation by %u ms", - p2p->search_delay); - p2p->in_search_delay = 1; - p2p_set_timeout(p2p, p2p->search_delay / 1000, - (p2p->search_delay % 1000) * 1000); - break; - } - p2p->in_search_delay = 0; - p2p_search(p2p); - break; - case P2P_CONNECT: - p2p_timeout_connect(p2p); - break; - case P2P_CONNECT_LISTEN: - p2p_timeout_connect_listen(p2p); - break; - case P2P_GO_NEG: - break; - case P2P_LISTEN_ONLY: - /* Check if we timed out waiting for PD req */ - if (p2p->pending_action_state == P2P_PENDING_PD) - p2p_timeout_prov_disc_req(p2p); - - if (p2p->ext_listen_only) { - p2p_dbg(p2p, "Extended Listen Timing - Listen State completed"); - p2p->ext_listen_only = 0; - p2p_set_state(p2p, P2P_IDLE); - } - break; - case P2P_WAIT_PEER_CONNECT: - p2p_timeout_wait_peer_connect(p2p); - break; - case P2P_WAIT_PEER_IDLE: - p2p_timeout_wait_peer_idle(p2p); - break; - case P2P_SD_DURING_FIND: - p2p_timeout_sd_during_find(p2p); - break; - case P2P_PROVISIONING: - break; - case P2P_PD_DURING_FIND: - p2p_timeout_prov_disc_during_find(p2p); - break; - case P2P_INVITE: - p2p_timeout_invite(p2p); - break; - case P2P_INVITE_LISTEN: - p2p_timeout_invite_listen(p2p); - break; - } -} - - -int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr) -{ - struct p2p_device *dev; - - dev = p2p_get_device(p2p, peer_addr); - p2p_dbg(p2p, "Local request to reject connection attempts by peer " - MACSTR, MAC2STR(peer_addr)); - if (dev == NULL) { - p2p_dbg(p2p, "Peer " MACSTR " unknown", MAC2STR(peer_addr)); - return -1; - } - dev->status = P2P_SC_FAIL_REJECTED_BY_USER; - dev->flags |= P2P_DEV_USER_REJECTED; - return 0; -} - - -const char * p2p_wps_method_text(enum p2p_wps_method method) -{ - switch (method) { - case WPS_NOT_READY: - return "not-ready"; - case WPS_PIN_DISPLAY: - return "Display"; - case WPS_PIN_KEYPAD: - return "Keypad"; - case WPS_PBC: - return "PBC"; - case WPS_NFC: - return "NFC"; - } - - return "??"; -} - - -static const char * p2p_go_state_text(enum p2p_go_state go_state) -{ - switch (go_state) { - case UNKNOWN_GO: - return "unknown"; - case LOCAL_GO: - return "local"; - case REMOTE_GO: - return "remote"; - } - - return "??"; -} - - -const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p, - const u8 *addr, int next) -{ - struct p2p_device *dev; - - if (addr) - dev = p2p_get_device(p2p, addr); - else - dev = dl_list_first(&p2p->devices, struct p2p_device, list); - - if (dev && next) { - dev = dl_list_first(&dev->list, struct p2p_device, list); - if (&dev->list == &p2p->devices) - dev = NULL; - } - - 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_reltime now; - - if (info == NULL) - return -1; - - dev = (struct p2p_device *) (((u8 *) info) - - offsetof(struct p2p_device, info)); - - pos = buf; - end = buf + buflen; - - os_get_reltime(&now); - res = os_snprintf(pos, end - pos, - "age=%d\n" - "listen_freq=%d\n" - "wps_method=%s\n" - "interface_addr=" MACSTR "\n" - "member_in_go_dev=" MACSTR "\n" - "member_in_go_iface=" MACSTR "\n" - "go_neg_req_sent=%d\n" - "go_state=%s\n" - "dialog_token=%u\n" - "intended_addr=" MACSTR "\n" - "country=%c%c\n" - "oper_freq=%d\n" - "req_config_methods=0x%x\n" - "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n" - "status=%d\n" - "wait_count=%u\n" - "invitation_reqs=%u\n", - (int) (now.sec - dev->last_seen.sec), - dev->listen_freq, - p2p_wps_method_text(dev->wps_method), - MAC2STR(dev->interface_addr), - MAC2STR(dev->member_in_go_dev), - MAC2STR(dev->member_in_go_iface), - dev->go_neg_req_sent, - p2p_go_state_text(dev->go_state), - dev->dialog_token, - MAC2STR(dev->intended_addr), - dev->country[0] ? dev->country[0] : '_', - dev->country[1] ? dev->country[1] : '_', - dev->oper_freq, - dev->req_config_methods, - dev->flags & P2P_DEV_PROBE_REQ_ONLY ? - "[PROBE_REQ_ONLY]" : "", - dev->flags & P2P_DEV_REPORTED ? "[REPORTED]" : "", - dev->flags & P2P_DEV_NOT_YET_READY ? - "[NOT_YET_READY]" : "", - dev->flags & P2P_DEV_SD_INFO ? "[SD_INFO]" : "", - dev->flags & P2P_DEV_SD_SCHEDULE ? "[SD_SCHEDULE]" : - "", - dev->flags & P2P_DEV_PD_PEER_DISPLAY ? - "[PD_PEER_DISPLAY]" : "", - dev->flags & P2P_DEV_PD_PEER_KEYPAD ? - "[PD_PEER_KEYPAD]" : "", - dev->flags & P2P_DEV_USER_REJECTED ? - "[USER_REJECTED]" : "", - dev->flags & P2P_DEV_PEER_WAITING_RESPONSE ? - "[PEER_WAITING_RESPONSE]" : "", - dev->flags & P2P_DEV_PREFER_PERSISTENT_GROUP ? - "[PREFER_PERSISTENT_GROUP]" : "", - dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE ? - "[WAIT_GO_NEG_RESPONSE]" : "", - dev->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM ? - "[WAIT_GO_NEG_CONFIRM]" : "", - dev->flags & P2P_DEV_GROUP_CLIENT_ONLY ? - "[GROUP_CLIENT_ONLY]" : "", - dev->flags & P2P_DEV_FORCE_FREQ ? - "[FORCE_FREQ]" : "", - dev->flags & P2P_DEV_PD_FOR_JOIN ? - "[PD_FOR_JOIN]" : "", - dev->status, - dev->wait_count, - dev->invitation_reqs); - if (res < 0 || res >= end - pos) - return pos - buf; - pos += res; - - if (dev->ext_listen_period) { - res = os_snprintf(pos, end - pos, - "ext_listen_period=%u\n" - "ext_listen_interval=%u\n", - dev->ext_listen_period, - dev->ext_listen_interval); - if (res < 0 || res >= end - pos) - return pos - buf; - pos += res; - } - - if (dev->oper_ssid_len) { - res = os_snprintf(pos, end - pos, - "oper_ssid=%s\n", - wpa_ssid_txt(dev->oper_ssid, - dev->oper_ssid_len)); - if (res < 0 || res >= end - pos) - return pos - buf; - pos += res; - } - -#ifdef CONFIG_WIFI_DISPLAY - if (dev->info.wfd_subelems) { - res = os_snprintf(pos, end - pos, "wfd_subelems="); - if (res < 0 || res >= end - pos) - return pos - buf; - pos += res; - - pos += wpa_snprintf_hex(pos, end - pos, - wpabuf_head(dev->info.wfd_subelems), - wpabuf_len(dev->info.wfd_subelems)); - - res = os_snprintf(pos, end - pos, "\n"); - if (res < 0 || res >= end - pos) - return pos - buf; - pos += res; - } -#endif /* CONFIG_WIFI_DISPLAY */ - - return pos - buf; -} - - -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) { - p2p_dbg(p2p, "Client discoverability enabled"); - p2p->dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; - } else { - p2p_dbg(p2p, "Client discoverability disabled"); - p2p->dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; - } -} - - -static struct wpabuf * p2p_build_presence_req(u32 duration1, u32 interval1, - u32 duration2, u32 interval2) -{ - struct wpabuf *req; - struct p2p_noa_desc desc1, desc2, *ptr1 = NULL, *ptr2 = NULL; - u8 *len; - - req = wpabuf_alloc(100); - if (req == NULL) - return NULL; - - if (duration1 || interval1) { - os_memset(&desc1, 0, sizeof(desc1)); - desc1.count_type = 1; - desc1.duration = duration1; - desc1.interval = interval1; - ptr1 = &desc1; - - if (duration2 || interval2) { - os_memset(&desc2, 0, sizeof(desc2)); - desc2.count_type = 2; - desc2.duration = duration2; - desc2.interval = interval2; - ptr2 = &desc2; - } - } - - p2p_buf_add_action_hdr(req, P2P_PRESENCE_REQ, 1); - len = p2p_buf_add_ie_hdr(req); - p2p_buf_add_noa(req, 0, 0, 0, ptr1, ptr2); - p2p_buf_update_ie_hdr(req, len); - - return req; -} - - -int p2p_presence_req(struct p2p_data *p2p, const u8 *go_interface_addr, - const u8 *own_interface_addr, unsigned int freq, - u32 duration1, u32 interval1, u32 duration2, - u32 interval2) -{ - struct wpabuf *req; - - p2p_dbg(p2p, "Send Presence Request to GO " MACSTR - " (own interface " MACSTR ") freq=%u dur1=%u int1=%u " - "dur2=%u int2=%u", - MAC2STR(go_interface_addr), MAC2STR(own_interface_addr), - freq, duration1, interval1, duration2, interval2); - - req = p2p_build_presence_req(duration1, interval1, duration2, - interval2); - if (req == NULL) - return -1; - - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - if (p2p_send_action(p2p, freq, go_interface_addr, own_interface_addr, - go_interface_addr, - wpabuf_head(req), wpabuf_len(req), 200) < 0) { - p2p_dbg(p2p, "Failed to send Action frame"); - } - wpabuf_free(req); - - return 0; -} - - -static struct wpabuf * p2p_build_presence_resp(u8 status, const u8 *noa, - size_t noa_len, u8 dialog_token) -{ - struct wpabuf *resp; - u8 *len; - - resp = wpabuf_alloc(100 + noa_len); - if (resp == NULL) - return NULL; - - p2p_buf_add_action_hdr(resp, P2P_PRESENCE_RESP, dialog_token); - len = p2p_buf_add_ie_hdr(resp); - p2p_buf_add_status(resp, status); - if (noa) { - wpabuf_put_u8(resp, P2P_ATTR_NOTICE_OF_ABSENCE); - wpabuf_put_le16(resp, noa_len); - wpabuf_put_data(resp, noa, noa_len); - } else - p2p_buf_add_noa(resp, 0, 0, 0, NULL, NULL); - p2p_buf_update_ie_hdr(resp, len); - - return resp; -} - - -static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da, - const u8 *sa, const u8 *data, size_t len, - int rx_freq) -{ - struct p2p_message msg; - u8 status; - struct wpabuf *resp; - size_t g; - struct p2p_group *group = NULL; - int parsed = 0; - u8 noa[50]; - int noa_len; - - p2p_dbg(p2p, "Received P2P Action - P2P Presence Request"); - - for (g = 0; g < p2p->num_groups; g++) { - if (os_memcmp(da, p2p_group_get_interface_addr(p2p->groups[g]), - ETH_ALEN) == 0) { - group = p2p->groups[g]; - break; - } - } - if (group == NULL) { - p2p_dbg(p2p, "Ignore P2P Presence Request for unknown group " - MACSTR, MAC2STR(da)); - return; - } - - if (p2p_parse(data, len, &msg) < 0) { - p2p_dbg(p2p, "Failed to parse P2P Presence Request"); - status = P2P_SC_FAIL_INVALID_PARAMS; - goto fail; - } - parsed = 1; - - if (msg.noa == NULL) { - p2p_dbg(p2p, "No NoA attribute in P2P Presence Request"); - status = P2P_SC_FAIL_INVALID_PARAMS; - goto fail; - } - - status = p2p_group_presence_req(group, sa, msg.noa, msg.noa_len); - -fail: - if (p2p->cfg->get_noa) - noa_len = p2p->cfg->get_noa(p2p->cfg->cb_ctx, da, noa, - sizeof(noa)); - else - noa_len = -1; - resp = p2p_build_presence_resp(status, noa_len > 0 ? noa : NULL, - noa_len > 0 ? noa_len : 0, - msg.dialog_token); - if (parsed) - p2p_parse_free(&msg); - if (resp == NULL) - return; - - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - if (p2p_send_action(p2p, rx_freq, sa, da, da, - wpabuf_head(resp), wpabuf_len(resp), 200) < 0) { - p2p_dbg(p2p, "Failed to send Action frame"); - } - wpabuf_free(resp); -} - - -static void p2p_process_presence_resp(struct p2p_data *p2p, const u8 *da, - const u8 *sa, const u8 *data, size_t len) -{ - struct p2p_message msg; - - p2p_dbg(p2p, "Received P2P Action - P2P Presence Response"); - - if (p2p_parse(data, len, &msg) < 0) { - p2p_dbg(p2p, "Failed to parse P2P Presence Response"); - return; - } - - if (msg.status == NULL || msg.noa == NULL) { - p2p_dbg(p2p, "No Status or NoA attribute in P2P Presence Response"); - p2p_parse_free(&msg); - return; - } - - if (p2p->cfg->presence_resp) { - p2p->cfg->presence_resp(p2p->cfg->cb_ctx, sa, *msg.status, - msg.noa, msg.noa_len); - } - - if (*msg.status) { - p2p_dbg(p2p, "P2P Presence Request was rejected: status %u", - *msg.status); - p2p_parse_free(&msg); - return; - } - - p2p_dbg(p2p, "P2P Presence Request was accepted"); - wpa_hexdump(MSG_DEBUG, "P2P: P2P Presence Response - NoA", - msg.noa, msg.noa_len); - /* TODO: process NoA */ - p2p_parse_free(&msg); -} - - -static void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct p2p_data *p2p = eloop_ctx; - - if (p2p->ext_listen_interval) { - /* Schedule next extended listen timeout */ - eloop_register_timeout(p2p->ext_listen_interval_sec, - p2p->ext_listen_interval_usec, - p2p_ext_listen_timeout, p2p, NULL); - } - - if (p2p->state == P2P_LISTEN_ONLY && p2p->ext_listen_only) { - /* - * This should not really happen, but it looks like the Listen - * command may fail is something else (e.g., a scan) was - * running at an inconvenient time. As a workaround, allow new - * Extended Listen operation to be started. - */ - p2p_dbg(p2p, "Previous Extended Listen operation had not been completed - try again"); - p2p->ext_listen_only = 0; - p2p_set_state(p2p, P2P_IDLE); - } - - if (p2p->state != P2P_IDLE) { - p2p_dbg(p2p, "Skip Extended Listen timeout in active state (%s)", p2p_state_txt(p2p->state)); - return; - } - - p2p_dbg(p2p, "Extended Listen timeout"); - p2p->ext_listen_only = 1; - if (p2p_listen(p2p, p2p->ext_listen_period) < 0) { - p2p_dbg(p2p, "Failed to start Listen state for Extended Listen Timing"); - p2p->ext_listen_only = 0; - } -} - - -int p2p_ext_listen(struct p2p_data *p2p, unsigned int period, - unsigned int interval) -{ - if (period > 65535 || interval > 65535 || period > interval || - (period == 0 && interval > 0) || (period > 0 && interval == 0)) { - p2p_dbg(p2p, "Invalid Extended Listen Timing request: period=%u interval=%u", - period, interval); - return -1; - } - - eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL); - - if (interval == 0) { - p2p_dbg(p2p, "Disabling Extended Listen Timing"); - p2p->ext_listen_period = 0; - p2p->ext_listen_interval = 0; - return 0; - } - - p2p_dbg(p2p, "Enabling Extended Listen Timing: period %u msec, interval %u msec", - period, interval); - p2p->ext_listen_period = period; - p2p->ext_listen_interval = interval; - p2p->ext_listen_interval_sec = interval / 1000; - p2p->ext_listen_interval_usec = (interval % 1000) * 1000; - - eloop_register_timeout(p2p->ext_listen_interval_sec, - p2p->ext_listen_interval_usec, - p2p_ext_listen_timeout, p2p, NULL); - - return 0; -} - - -void p2p_deauth_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code, - const u8 *ie, size_t ie_len) -{ - struct p2p_message msg; - - if (bssid == NULL || ie == NULL) - return; - - os_memset(&msg, 0, sizeof(msg)); - if (p2p_parse_ies(ie, ie_len, &msg)) - return; - if (msg.minor_reason_code == NULL) { - p2p_parse_free(&msg); - return; - } - - p2p_dbg(p2p, "Deauthentication notification BSSID " MACSTR - " reason_code=%u minor_reason_code=%u", - MAC2STR(bssid), reason_code, *msg.minor_reason_code); - - p2p_parse_free(&msg); -} - - -void p2p_disassoc_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code, - const u8 *ie, size_t ie_len) -{ - struct p2p_message msg; - - if (bssid == NULL || ie == NULL) - return; - - os_memset(&msg, 0, sizeof(msg)); - if (p2p_parse_ies(ie, ie_len, &msg)) - return; - if (msg.minor_reason_code == NULL) { - p2p_parse_free(&msg); - return; - } - - p2p_dbg(p2p, "Disassociation notification BSSID " MACSTR - " reason_code=%u minor_reason_code=%u", - MAC2STR(bssid), reason_code, *msg.minor_reason_code); - - p2p_parse_free(&msg); -} - - -void p2p_set_managed_oper(struct p2p_data *p2p, int enabled) -{ - if (enabled) { - p2p_dbg(p2p, "Managed P2P Device operations enabled"); - p2p->dev_capab |= P2P_DEV_CAPAB_INFRA_MANAGED; - } else { - p2p_dbg(p2p, "Managed P2P Device operations disabled"); - p2p->dev_capab &= ~P2P_DEV_CAPAB_INFRA_MANAGED; - } -} - - -int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel) -{ - if (p2p_channel_to_freq(reg_class, channel) < 0) - return -1; - - p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u", - reg_class, channel); - p2p->cfg->reg_class = reg_class; - p2p->cfg->channel = channel; - - return 0; -} - - -int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len) -{ - p2p_dbg(p2p, "New SSID postfix: %s", wpa_ssid_txt(postfix, len)); - if (postfix == NULL) { - p2p->cfg->ssid_postfix_len = 0; - return 0; - } - if (len > sizeof(p2p->cfg->ssid_postfix)) - return -1; - os_memcpy(p2p->cfg->ssid_postfix, postfix, len); - p2p->cfg->ssid_postfix_len = len; - return 0; -} - - -int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel, - int cfg_op_channel) -{ - if (p2p_channel_to_freq(op_reg_class, op_channel) < 0) - return -1; - - p2p_dbg(p2p, "Set Operating channel: reg_class %u channel %u", - op_reg_class, op_channel); - p2p->cfg->op_reg_class = op_reg_class; - p2p->cfg->op_channel = op_channel; - p2p->cfg->cfg_op_channel = cfg_op_channel; - return 0; -} - - -int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan, - const struct p2p_channel *pref_chan) -{ - struct p2p_channel *n; - - if (pref_chan) { - n = os_malloc(num_pref_chan * sizeof(struct p2p_channel)); - if (n == NULL) - return -1; - os_memcpy(n, pref_chan, - num_pref_chan * sizeof(struct p2p_channel)); - } else - n = NULL; - - os_free(p2p->cfg->pref_chan); - p2p->cfg->pref_chan = n; - p2p->cfg->num_pref_chan = num_pref_chan; - - return 0; -} - - -int p2p_set_no_go_freq(struct p2p_data *p2p, - const struct wpa_freq_range_list *list) -{ - struct wpa_freq_range *tmp; - - if (list == NULL || list->num == 0) { - os_free(p2p->no_go_freq.range); - p2p->no_go_freq.range = NULL; - p2p->no_go_freq.num = 0; - return 0; - } - - tmp = os_calloc(list->num, sizeof(struct wpa_freq_range)); - if (tmp == NULL) - return -1; - os_memcpy(tmp, list->range, list->num * sizeof(struct wpa_freq_range)); - os_free(p2p->no_go_freq.range); - p2p->no_go_freq.range = tmp; - p2p->no_go_freq.num = list->num; - p2p_dbg(p2p, "Updated no GO chan list"); - - return 0; -} - - -int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr, - u8 *iface_addr) -{ - struct p2p_device *dev = p2p_get_device(p2p, dev_addr); - if (dev == NULL || is_zero_ether_addr(dev->interface_addr)) - return -1; - os_memcpy(iface_addr, dev->interface_addr, ETH_ALEN); - return 0; -} - - -int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr, - u8 *dev_addr) -{ - struct p2p_device *dev = p2p_get_device_interface(p2p, iface_addr); - if (dev == NULL) - return -1; - os_memcpy(dev_addr, dev->info.p2p_device_addr, ETH_ALEN); - return 0; -} - - -void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr) -{ - os_memcpy(p2p->peer_filter, addr, ETH_ALEN); - if (is_zero_ether_addr(p2p->peer_filter)) - p2p_dbg(p2p, "Disable peer filter"); - else - p2p_dbg(p2p, "Enable peer filter for " MACSTR, - MAC2STR(p2p->peer_filter)); -} - - -void p2p_set_cross_connect(struct p2p_data *p2p, int enabled) -{ - p2p_dbg(p2p, "Cross connection %s", enabled ? "enabled" : "disabled"); - if (p2p->cross_connect == enabled) - return; - p2p->cross_connect = enabled; - /* TODO: may need to tear down any action group where we are GO(?) */ -} - - -int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr) -{ - struct p2p_device *dev = p2p_get_device_interface(p2p, iface_addr); - if (dev == NULL) - return -1; - if (dev->oper_freq <= 0) - return -1; - return dev->oper_freq; -} - - -void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled) -{ - p2p_dbg(p2p, "Intra BSS distribution %s", - enabled ? "enabled" : "disabled"); - p2p->cfg->p2p_intra_bss = enabled; -} - - -void p2p_update_channel_list(struct p2p_data *p2p, - const struct p2p_channels *chan, - const struct p2p_channels *cli_chan) -{ - p2p_dbg(p2p, "Update channel list"); - os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels)); - p2p_channels_dump(p2p, "channels", &p2p->cfg->channels); - os_memcpy(&p2p->cfg->cli_channels, cli_chan, - sizeof(struct p2p_channels)); - p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels); -} - - -int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst, - const u8 *src, const u8 *bssid, const u8 *buf, - size_t len, unsigned int wait_time) -{ - if (p2p->p2p_scan_running) { - p2p_dbg(p2p, "Delay Action frame TX until p2p_scan completes"); - if (p2p->after_scan_tx) { - p2p_dbg(p2p, "Dropped previous pending Action frame TX"); - os_free(p2p->after_scan_tx); - } - p2p->after_scan_tx = os_malloc(sizeof(*p2p->after_scan_tx) + - len); - if (p2p->after_scan_tx == NULL) - return -1; - p2p->after_scan_tx->freq = freq; - os_memcpy(p2p->after_scan_tx->dst, dst, ETH_ALEN); - os_memcpy(p2p->after_scan_tx->src, src, ETH_ALEN); - os_memcpy(p2p->after_scan_tx->bssid, bssid, ETH_ALEN); - p2p->after_scan_tx->len = len; - p2p->after_scan_tx->wait_time = wait_time; - os_memcpy(p2p->after_scan_tx + 1, buf, len); - return 0; - } - - return p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid, - buf, len, wait_time); -} - - -void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5, - int freq_overall) -{ - p2p_dbg(p2p, "Best channel: 2.4 GHz: %d, 5 GHz: %d, overall: %d", - freq_24, freq_5, freq_overall); - p2p->best_freq_24 = freq_24; - p2p->best_freq_5 = freq_5; - p2p->best_freq_overall = freq_overall; -} - - -void p2p_set_own_freq_preference(struct p2p_data *p2p, int freq) -{ - p2p_dbg(p2p, "Own frequency preference: %d MHz", freq); - p2p->own_freq_preference = freq; -} - - -const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p) -{ - if (p2p == NULL || p2p->go_neg_peer == NULL) - return NULL; - return p2p->go_neg_peer->info.p2p_device_addr; -} - - -const struct p2p_peer_info * -p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next) -{ - struct p2p_device *dev; - - if (addr) { - dev = p2p_get_device(p2p, addr); - if (!dev) - return NULL; - - if (!next) { - if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) - return NULL; - - return &dev->info; - } else { - do { - dev = dl_list_first(&dev->list, - struct p2p_device, - list); - if (&dev->list == &p2p->devices) - return NULL; - } while (dev->flags & P2P_DEV_PROBE_REQ_ONLY); - } - } else { - dev = dl_list_first(&p2p->devices, struct p2p_device, list); - if (!dev) - return NULL; - while (dev->flags & P2P_DEV_PROBE_REQ_ONLY) { - dev = dl_list_first(&dev->list, - struct p2p_device, - list); - if (&dev->list == &p2p->devices) - return NULL; - } - } - - return &dev->info; -} - - -int p2p_in_progress(struct p2p_data *p2p) -{ - if (p2p == NULL) - return 0; - if (p2p->state == P2P_SEARCH) - return 2; - return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING; -} - - -void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout, - u8 client_timeout) -{ - if (p2p) { - p2p->go_timeout = go_timeout; - p2p->client_timeout = client_timeout; - } -} - - -#ifdef CONFIG_WIFI_DISPLAY - -static void p2p_update_wfd_ie_groups(struct p2p_data *p2p) -{ - size_t g; - struct p2p_group *group; - - for (g = 0; g < p2p->num_groups; g++) { - group = p2p->groups[g]; - p2p_group_force_beacon_update_ies(group); - } -} - - -int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie) -{ - wpabuf_free(p2p->wfd_ie_beacon); - p2p->wfd_ie_beacon = ie; - p2p_update_wfd_ie_groups(p2p); - return 0; -} - - -int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie) -{ - wpabuf_free(p2p->wfd_ie_probe_req); - p2p->wfd_ie_probe_req = ie; - return 0; -} - - -int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie) -{ - wpabuf_free(p2p->wfd_ie_probe_resp); - p2p->wfd_ie_probe_resp = ie; - p2p_update_wfd_ie_groups(p2p); - return 0; -} - - -int p2p_set_wfd_ie_assoc_req(struct p2p_data *p2p, struct wpabuf *ie) -{ - wpabuf_free(p2p->wfd_ie_assoc_req); - p2p->wfd_ie_assoc_req = ie; - return 0; -} - - -int p2p_set_wfd_ie_invitation(struct p2p_data *p2p, struct wpabuf *ie) -{ - wpabuf_free(p2p->wfd_ie_invitation); - p2p->wfd_ie_invitation = ie; - return 0; -} - - -int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie) -{ - wpabuf_free(p2p->wfd_ie_prov_disc_req); - p2p->wfd_ie_prov_disc_req = ie; - return 0; -} - - -int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie) -{ - wpabuf_free(p2p->wfd_ie_prov_disc_resp); - p2p->wfd_ie_prov_disc_resp = ie; - return 0; -} - - -int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie) -{ - wpabuf_free(p2p->wfd_ie_go_neg); - p2p->wfd_ie_go_neg = ie; - return 0; -} - - -int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem) -{ - wpabuf_free(p2p->wfd_dev_info); - if (elem) { - p2p->wfd_dev_info = wpabuf_dup(elem); - if (p2p->wfd_dev_info == NULL) - return -1; - } else - p2p->wfd_dev_info = NULL; - - return 0; -} - - -int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem) -{ - wpabuf_free(p2p->wfd_assoc_bssid); - if (elem) { - p2p->wfd_assoc_bssid = wpabuf_dup(elem); - if (p2p->wfd_assoc_bssid == NULL) - return -1; - } else - p2p->wfd_assoc_bssid = NULL; - - return 0; -} - - -int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p, - const struct wpabuf *elem) -{ - wpabuf_free(p2p->wfd_coupled_sink_info); - if (elem) { - p2p->wfd_coupled_sink_info = wpabuf_dup(elem); - if (p2p->wfd_coupled_sink_info == NULL) - return -1; - } else - p2p->wfd_coupled_sink_info = NULL; - - return 0; -} - -#endif /* CONFIG_WIFI_DISPLAY */ - - -int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int, - int max_disc_tu) -{ - if (min_disc_int > max_disc_int || min_disc_int < 0 || max_disc_int < 0) - return -1; - - p2p->min_disc_int = min_disc_int; - p2p->max_disc_int = max_disc_int; - p2p->max_disc_tu = max_disc_tu; - p2p_dbg(p2p, "Set discoverable interval: min=%d max=%d max_tu=%d", - min_disc_int, max_disc_int, max_disc_tu); - - return 0; -} - - -void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...) -{ - va_list ap; - char buf[500]; - - if (!p2p->cfg->debug_print) - return; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - buf[sizeof(buf) - 1] = '\0'; - va_end(ap); - p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_DEBUG, buf); -} - - -void p2p_info(struct p2p_data *p2p, const char *fmt, ...) -{ - va_list ap; - char buf[500]; - - if (!p2p->cfg->debug_print) - return; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - buf[sizeof(buf) - 1] = '\0'; - va_end(ap); - p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_INFO, buf); -} - - -void p2p_err(struct p2p_data *p2p, const char *fmt, ...) -{ - va_list ap; - char buf[500]; - - if (!p2p->cfg->debug_print) - return; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - buf[sizeof(buf) - 1] = '\0'; - va_end(ap); - p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_ERROR, buf); -} - - -#ifdef CONFIG_WPS_NFC - -static struct wpabuf * p2p_build_nfc_handover(struct p2p_data *p2p, - int client_freq, - const u8 *go_dev_addr, - const u8 *ssid, size_t ssid_len) -{ - struct wpabuf *buf; - u8 op_class, channel; - enum p2p_role_indication role = P2P_DEVICE_NOT_IN_GROUP; - - buf = wpabuf_alloc(1000); - if (buf == NULL) - return NULL; - - op_class = p2p->cfg->reg_class; - channel = p2p->cfg->channel; - - p2p_buf_add_capability(buf, p2p->dev_capab & - ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0); - p2p_buf_add_device_info(buf, p2p, NULL); - - if (p2p->num_groups > 0) { - role = P2P_GO_IN_A_GROUP; - p2p_freq_to_channel(p2p_group_get_freq(p2p->groups[0]), - &op_class, &channel); - } else if (client_freq > 0) { - role = P2P_CLIENT_IN_A_GROUP; - p2p_freq_to_channel(client_freq, &op_class, &channel); - } - - p2p_buf_add_oob_go_neg_channel(buf, p2p->cfg->country, op_class, - channel, role); - - if (p2p->num_groups > 0) { - /* Limit number of clients to avoid very long message */ - p2p_buf_add_group_info(p2p->groups[0], buf, 5); - p2p_group_buf_add_id(p2p->groups[0], buf); - } else if (client_freq > 0 && - go_dev_addr && !is_zero_ether_addr(go_dev_addr) && - ssid && ssid_len > 0) { - /* - * Add the optional P2P Group ID to indicate in which group this - * device is a P2P Client. - */ - p2p_buf_add_group_id(buf, go_dev_addr, ssid, ssid_len); - } - - return buf; -} - - -struct wpabuf * p2p_build_nfc_handover_req(struct p2p_data *p2p, - int client_freq, - const u8 *go_dev_addr, - const u8 *ssid, size_t ssid_len) -{ - return p2p_build_nfc_handover(p2p, client_freq, go_dev_addr, ssid, - ssid_len); -} - - -struct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p, - int client_freq, - const u8 *go_dev_addr, - const u8 *ssid, size_t ssid_len) -{ - return p2p_build_nfc_handover(p2p, client_freq, go_dev_addr, ssid, - ssid_len); -} - - -int p2p_process_nfc_connection_handover(struct p2p_data *p2p, - struct p2p_nfc_params *params) -{ - struct p2p_message msg; - struct p2p_device *dev; - const u8 *p2p_dev_addr; - int freq; - enum p2p_role_indication role; - - params->next_step = NO_ACTION; - - if (p2p_parse_ies_separate(params->wsc_attr, params->wsc_len, - params->p2p_attr, params->p2p_len, &msg)) { - p2p_dbg(p2p, "Failed to parse WSC/P2P attributes from NFC"); - p2p_parse_free(&msg); - return -1; - } - - if (msg.p2p_device_addr) - p2p_dev_addr = msg.p2p_device_addr; - else if (msg.device_id) - p2p_dev_addr = msg.device_id; - else { - p2p_dbg(p2p, "Ignore scan data without P2P Device Info or P2P Device Id"); - p2p_parse_free(&msg); - return -1; - } - - if (msg.oob_dev_password) { - os_memcpy(params->oob_dev_pw, msg.oob_dev_password, - msg.oob_dev_password_len); - params->oob_dev_pw_len = msg.oob_dev_password_len; - } - - dev = p2p_create_device(p2p, p2p_dev_addr); - if (dev == NULL) { - p2p_parse_free(&msg); - return -1; - } - - params->peer = &dev->info; - - os_get_reltime(&dev->last_seen); - dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY); - p2p_copy_wps_info(p2p, dev, 0, &msg); - - if (!msg.oob_go_neg_channel) { - p2p_dbg(p2p, "OOB GO Negotiation Channel attribute not included"); - return -1; - } - - if (msg.oob_go_neg_channel[3] == 0 && - msg.oob_go_neg_channel[4] == 0) - freq = 0; - else - freq = p2p_channel_to_freq(msg.oob_go_neg_channel[3], - msg.oob_go_neg_channel[4]); - if (freq < 0) { - p2p_dbg(p2p, "Unknown peer OOB GO Neg channel"); - return -1; - } - role = msg.oob_go_neg_channel[5]; - - if (role == P2P_GO_IN_A_GROUP) { - p2p_dbg(p2p, "Peer OOB GO operating channel: %u MHz", freq); - params->go_freq = freq; - } else if (role == P2P_CLIENT_IN_A_GROUP) { - p2p_dbg(p2p, "Peer (client) OOB GO operating channel: %u MHz", - freq); - params->go_freq = freq; - } else - p2p_dbg(p2p, "Peer OOB GO Neg channel: %u MHz", freq); - dev->oob_go_neg_freq = freq; - - if (!params->sel && role != P2P_GO_IN_A_GROUP) { - freq = p2p_channel_to_freq(p2p->cfg->reg_class, - p2p->cfg->channel); - if (freq < 0) { - p2p_dbg(p2p, "Own listen channel not known"); - return -1; - } - p2p_dbg(p2p, "Use own Listen channel as OOB GO Neg channel: %u MHz", freq); - dev->oob_go_neg_freq = freq; - } - - if (msg.group_id) { - os_memcpy(params->go_dev_addr, msg.group_id, ETH_ALEN); - params->go_ssid_len = msg.group_id_len - ETH_ALEN; - os_memcpy(params->go_ssid, msg.group_id + ETH_ALEN, - params->go_ssid_len); - } - - p2p_parse_free(&msg); - - if (dev->flags & P2P_DEV_USER_REJECTED) { - p2p_dbg(p2p, "Do not report rejected device"); - return 0; - } - - if (!(dev->flags & P2P_DEV_REPORTED)) { - p2p->cfg->dev_found(p2p->cfg->cb_ctx, p2p_dev_addr, &dev->info, - !(dev->flags & P2P_DEV_REPORTED_ONCE)); - dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE; - } - - if (role == P2P_GO_IN_A_GROUP && p2p->num_groups > 0) - params->next_step = BOTH_GO; - else if (role == P2P_GO_IN_A_GROUP) - params->next_step = JOIN_GROUP; - else if (role == P2P_CLIENT_IN_A_GROUP) { - dev->flags |= P2P_DEV_GROUP_CLIENT_ONLY; - params->next_step = PEER_CLIENT; - } else if (p2p->num_groups > 0) - params->next_step = AUTH_JOIN; - else if (params->sel) - params->next_step = INIT_GO_NEG; - else - params->next_step = RESP_GO_NEG; - - return 0; -} - - -void p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id, - int go_intent, - const u8 *own_interface_addr) -{ - - p2p->authorized_oob_dev_pw_id = dev_pw_id; - if (dev_pw_id == 0) { - p2p_dbg(p2p, "NFC OOB Password unauthorized for static handover"); - return; - } - - p2p_dbg(p2p, "NFC OOB Password (id=%u) authorized for static handover", - dev_pw_id); - - p2p->go_intent = go_intent; - os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN); -} - -#endif /* CONFIG_WPS_NFC */ diff --git a/contrib/hostapd/src/p2p/p2p.h b/contrib/hostapd/src/p2p/p2p.h deleted file mode 100644 index 08e7176c1d..0000000000 --- a/contrib/hostapd/src/p2p/p2p.h +++ /dev/null @@ -1,1944 +0,0 @@ -/* - * Wi-Fi Direct - P2P module - * Copyright (c) 2009-2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef P2P_H -#define P2P_H - -#include "wps/wps_defs.h" - -/** - * P2P_MAX_REG_CLASSES - Maximum number of regulatory classes - */ -#define P2P_MAX_REG_CLASSES 10 - -/** - * P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class - */ -#define P2P_MAX_REG_CLASS_CHANNELS 20 - -/** - * struct p2p_channels - List of supported channels - */ -struct p2p_channels { - /** - * struct p2p_reg_class - Supported regulatory class - */ - struct p2p_reg_class { - /** - * reg_class - Regulatory class (IEEE 802.11-2007, Annex J) - */ - u8 reg_class; - - /** - * channel - Supported channels - */ - u8 channel[P2P_MAX_REG_CLASS_CHANNELS]; - - /** - * channels - Number of channel entries in use - */ - size_t channels; - } reg_class[P2P_MAX_REG_CLASSES]; - - /** - * reg_classes - Number of reg_class entries in use - */ - size_t reg_classes; -}; - -enum p2p_wps_method { - WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC, WPS_NFC -}; - -/** - * struct p2p_go_neg_results - P2P Group Owner Negotiation results - */ -struct p2p_go_neg_results { - /** - * status - Negotiation result (Status Code) - * - * 0 (P2P_SC_SUCCESS) indicates success. Non-zero values indicate - * failed negotiation. - */ - int status; - - /** - * role_go - Whether local end is Group Owner - */ - int role_go; - - /** - * freq - Frequency of the group operational channel in MHz - */ - int freq; - - int ht40; - - int vht; - - /** - * ssid - SSID of the group - */ - u8 ssid[32]; - - /** - * ssid_len - Length of SSID in octets - */ - size_t ssid_len; - - /** - * psk - WPA pre-shared key (256 bits) (GO only) - */ - u8 psk[32]; - - /** - * psk_set - Whether PSK field is configured (GO only) - */ - int psk_set; - - /** - * passphrase - WPA2-Personal passphrase for the group (GO only) - */ - char passphrase[64]; - - /** - * peer_device_addr - P2P Device Address of the peer - */ - u8 peer_device_addr[ETH_ALEN]; - - /** - * peer_interface_addr - P2P Interface Address of the peer - */ - u8 peer_interface_addr[ETH_ALEN]; - - /** - * wps_method - WPS method to be used during provisioning - */ - enum p2p_wps_method wps_method; - -#define P2P_MAX_CHANNELS 50 - - /** - * freq_list - Zero-terminated list of possible operational channels - */ - int freq_list[P2P_MAX_CHANNELS]; - - /** - * 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; - - /** - * peer_config_timeout - Peer configuration timeout (in 10 msec units) - */ - unsigned int peer_config_timeout; -}; - -struct p2p_data; - -enum p2p_scan_type { - P2P_SCAN_SOCIAL, - P2P_SCAN_FULL, - P2P_SCAN_SOCIAL_PLUS_ONE -}; - -#define P2P_MAX_WPS_VENDOR_EXT 10 - -/** - * struct p2p_peer_info - P2P peer information - */ -struct p2p_peer_info { - /** - * p2p_device_addr - P2P Device Address of the peer - */ - u8 p2p_device_addr[ETH_ALEN]; - - /** - * pri_dev_type - Primary Device Type - */ - u8 pri_dev_type[8]; - - /** - * device_name - Device Name (0..32 octets encoded in UTF-8) - */ - char device_name[33]; - - /** - * manufacturer - Manufacturer (0..64 octets encoded in UTF-8) - */ - char manufacturer[65]; - - /** - * model_name - Model Name (0..32 octets encoded in UTF-8) - */ - char model_name[33]; - - /** - * model_number - Model Number (0..32 octets encoded in UTF-8) - */ - char model_number[33]; - - /** - * serial_number - Serial Number (0..32 octets encoded in UTF-8) - */ - char serial_number[33]; - - /** - * level - Signal level - */ - int level; - - /** - * config_methods - WPS Configuration Methods - */ - u16 config_methods; - - /** - * dev_capab - Device Capabilities - */ - u8 dev_capab; - - /** - * group_capab - Group Capabilities - */ - u8 group_capab; - - /** - * wps_sec_dev_type_list - WPS secondary device type list - * - * This list includes from 0 to 16 Secondary Device Types as indicated - * by wps_sec_dev_type_list_len (8 * number of types). - */ - u8 wps_sec_dev_type_list[128]; - - /** - * wps_sec_dev_type_list_len - Length of secondary device type list - */ - size_t wps_sec_dev_type_list_len; - - struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT]; - - /** - * wfd_subelems - Wi-Fi Display subelements from WFD IE(s) - */ - struct wpabuf *wfd_subelems; -}; - -enum p2p_prov_disc_status { - P2P_PROV_DISC_SUCCESS, - P2P_PROV_DISC_TIMEOUT, - P2P_PROV_DISC_REJECTED, - P2P_PROV_DISC_TIMEOUT_JOIN, -}; - -struct p2p_channel { - u8 op_class; - u8 chan; -}; - -/** - * struct p2p_config - P2P configuration - * - * This configuration is provided to the P2P module during initialization with - * p2p_init(). - */ -struct p2p_config { - /** - * country - Country code to use in P2P operations - */ - char country[3]; - - /** - * reg_class - Regulatory class for own listen channel - */ - u8 reg_class; - - /** - * channel - Own listen channel - */ - u8 channel; - - /** - * Regulatory class for own operational channel - */ - u8 op_reg_class; - - /** - * op_channel - Own operational channel - */ - u8 op_channel; - - /** - * cfg_op_channel - Whether op_channel is hardcoded in configuration - */ - u8 cfg_op_channel; - - /** - * channels - Own supported regulatory classes and channels - * - * List of supposerted channels per regulatory class. The regulatory - * classes are defined in IEEE Std 802.11-2007 Annex J and the - * numbering of the clases depends on the configured country code. - */ - struct p2p_channels channels; - - /** - * cli_channels - Additional client channels - * - * This list of channels (if any) will be used when advertising local - * channels during GO Negotiation or Invitation for the cases where the - * local end may become the client. This may allow the peer to become a - * GO on additional channels if it supports these options. The main use - * case for this is to include passive-scan channels on devices that may - * not know their current location and have configured most channels to - * not allow initiation of radition (i.e., another device needs to take - * master responsibilities). - */ - struct p2p_channels cli_channels; - - /** - * num_pref_chan - Number of pref_chan entries - */ - unsigned int num_pref_chan; - - /** - * pref_chan - Preferred channels for GO Negotiation - */ - struct p2p_channel *pref_chan; - - /** - * pri_dev_type - Primary Device Type (see WPS) - */ - u8 pri_dev_type[8]; - - /** - * P2P_SEC_DEVICE_TYPES - Maximum number of secondary device types - */ -#define P2P_SEC_DEVICE_TYPES 5 - - /** - * sec_dev_type - Optional secondary device types - */ - u8 sec_dev_type[P2P_SEC_DEVICE_TYPES][8]; - - /** - * num_sec_dev_types - Number of sec_dev_type entries - */ - size_t num_sec_dev_types; - - /** - * dev_addr - P2P Device Address - */ - u8 dev_addr[ETH_ALEN]; - - /** - * dev_name - Device Name - */ - char *dev_name; - - char *manufacturer; - char *model_name; - char *model_number; - char *serial_number; - - u8 uuid[16]; - u16 config_methods; - - /** - * concurrent_operations - Whether concurrent operations are supported - */ - int concurrent_operations; - - /** - * max_peers - Maximum number of discovered peers to remember - * - * If more peers are discovered, older entries will be removed to make - * room for the new ones. - */ - size_t max_peers; - - /** - * p2p_intra_bss - Intra BSS communication is supported - */ - int p2p_intra_bss; - - /** - * ssid_postfix - Postfix data to add to the SSID - * - * This data will be added to the end of the SSID after the - * DIRECT- prefix. - */ - u8 ssid_postfix[32 - 9]; - - /** - * ssid_postfix_len - Length of the ssid_postfix data - */ - size_t ssid_postfix_len; - - /** - * max_listen - Maximum listen duration in ms - */ - unsigned int max_listen; - - /** - * cb_ctx - Context to use with callback functions - */ - void *cb_ctx; - - /** - * debug_print - Debug print - * @ctx: Callback context from cb_ctx - * @level: Debug verbosity level (MSG_*) - * @msg: Debug message - */ - void (*debug_print)(void *ctx, int level, const char *msg); - - - /* Callbacks to request lower layer driver operations */ - - /** - * p2p_scan - Request a P2P scan/search - * @ctx: Callback context from cb_ctx - * @type: Scan type - * @freq: Specific frequency (MHz) to scan or 0 for no restriction - * @num_req_dev_types: Number of requested device types - * @req_dev_types: Array containing requested device types - * @dev_id: Device ID to search for or %NULL to find all devices - * @pw_id: Device Password ID - * Returns: 0 on success, -1 on failure - * - * This callback function is used to request a P2P scan or search - * operation to be completed. Type type argument specifies which type - * of scan is to be done. @P2P_SCAN_SOCIAL indicates that only the - * social channels (1, 6, 11) should be scanned. @P2P_SCAN_FULL - * indicates that all channels are to be scanned. - * @P2P_SCAN_SOCIAL_PLUS_ONE request scan of all the social channels - * plus one extra channel specified by freq. - * - * The full scan is used for the initial scan to find group owners from - * all. The other types are used during search phase scan of the social - * channels (with potential variation if the Listen channel of the - * target peer is known or if other channels are scanned in steps). - * - * The scan results are returned after this call by calling - * p2p_scan_res_handler() for each scan result that has a P2P IE and - * then calling p2p_scan_res_handled() to indicate that all scan - * results have been indicated. - */ - int (*p2p_scan)(void *ctx, enum p2p_scan_type type, int freq, - unsigned int num_req_dev_types, - const u8 *req_dev_types, const u8 *dev_id, u16 pw_id); - - /** - * send_probe_resp - Transmit a Probe Response frame - * @ctx: Callback context from cb_ctx - * @buf: Probe Response frame (including the header and body) - * Returns: 0 on success, -1 on failure - * - * This function is used to reply to Probe Request frames that were - * indicated with a call to p2p_probe_req_rx(). The response is to be - * sent on the same channel or to be dropped if the driver is not - * anymore listening to Probe Request frames. - * - * Alternatively, the responsibility for building the Probe Response - * frames in Listen state may be in another system component in which - * case this function need to be implemented (i.e., the function - * pointer can be %NULL). The WPS and P2P IEs to be added for Probe - * Response frames in such a case are available from the - * start_listen() callback. It should be noted that the received Probe - * Request frames must be indicated by calling p2p_probe_req_rx() even - * if this send_probe_resp() is not used. - */ - int (*send_probe_resp)(void *ctx, const struct wpabuf *buf); - - /** - * send_action - Transmit an Action frame - * @ctx: Callback context from cb_ctx - * @freq: Frequency in MHz for the channel on which to transmit - * @dst: Destination MAC address (Address 1) - * @src: Source MAC address (Address 2) - * @bssid: BSSID (Address 3) - * @buf: Frame body (starting from Category field) - * @len: Length of buf in octets - * @wait_time: How many msec to wait for a response frame - * Returns: 0 on success, -1 on failure - * - * The Action frame may not be transmitted immediately and the status - * of the transmission must be reported by calling - * p2p_send_action_cb() once the frame has either been transmitted or - * it has been dropped due to excessive retries or other failure to - * transmit. - */ - int (*send_action)(void *ctx, unsigned int freq, const u8 *dst, - const u8 *src, const u8 *bssid, const u8 *buf, - size_t len, unsigned int wait_time); - - /** - * send_action_done - Notify that Action frame sequence was completed - * @ctx: Callback context from cb_ctx - * - * This function is called when the Action frame sequence that was - * started with send_action() has been completed, i.e., when there is - * no need to wait for a response from the destination peer anymore. - */ - void (*send_action_done)(void *ctx); - - /** - * start_listen - Start Listen state - * @ctx: Callback context from cb_ctx - * @freq: Frequency of the listen channel in MHz - * @duration: Duration for the Listen state in milliseconds - * @probe_resp_ie: IE(s) to be added to Probe Response frames - * Returns: 0 on success, -1 on failure - * - * This Listen state may not start immediately since the driver may - * have other pending operations to complete first. Once the Listen - * state has started, p2p_listen_cb() must be called to notify the P2P - * module. Once the Listen state is stopped, p2p_listen_end() must be - * called to notify the P2P module that the driver is not in the Listen - * state anymore. - * - * If the send_probe_resp() is not used for generating the response, - * the IEs from probe_resp_ie need to be added to the end of the Probe - * Response frame body. If send_probe_resp() is used, the probe_resp_ie - * information can be ignored. - */ - int (*start_listen)(void *ctx, unsigned int freq, - unsigned int duration, - const struct wpabuf *probe_resp_ie); - /** - * stop_listen - Stop Listen state - * @ctx: Callback context from cb_ctx - * - * This callback can be used to stop a Listen state operation that was - * previously requested with start_listen(). - */ - void (*stop_listen)(void *ctx); - - /** - * get_noa - Get current Notice of Absence attribute payload - * @ctx: Callback context from cb_ctx - * @interface_addr: P2P Interface Address of the GO - * @buf: Buffer for returning NoA - * @buf_len: Buffer length in octets - * Returns: Number of octets used in buf, 0 to indicate no NoA is being - * advertized, or -1 on failure - * - * This function is used to fetch the current Notice of Absence - * attribute value from GO. - */ - int (*get_noa)(void *ctx, const u8 *interface_addr, u8 *buf, - size_t buf_len); - - /* Callbacks to notify events to upper layer management entity */ - - /** - * dev_found - Notification of a found P2P Device - * @ctx: Callback context from cb_ctx - * @addr: Source address of the message triggering this notification - * @info: P2P peer information - * @new_device: Inform if the peer is newly found - * - * This callback is used to notify that a new P2P Device has been - * found. This may happen, e.g., during Search state based on scan - * results or during Listen state based on receive Probe Request and - * Group Owner Negotiation Request. - */ - void (*dev_found)(void *ctx, const u8 *addr, - const struct p2p_peer_info *info, - int new_device); - - /** - * dev_lost - Notification of a lost P2P Device - * @ctx: Callback context from cb_ctx - * @dev_addr: P2P Device Address of the lost P2P Device - * - * This callback is used to notify that a P2P Device has been deleted. - */ - void (*dev_lost)(void *ctx, const u8 *dev_addr); - - /** - * find_stopped - Notification of a p2p_find operation stopping - * @ctx: Callback context from cb_ctx - */ - void (*find_stopped)(void *ctx); - - /** - * go_neg_req_rx - Notification of a receive GO Negotiation Request - * @ctx: Callback context from cb_ctx - * @src: Source address of the message triggering this notification - * @dev_passwd_id: WPS Device Password ID - * - * This callback is used to notify that a P2P Device is requesting - * group owner negotiation with us, but we do not have all the - * necessary information to start GO Negotiation. This indicates that - * the local user has not authorized the connection yet by providing a - * PIN or PBC button press. This information can be provided with a - * call to p2p_connect(). - */ - void (*go_neg_req_rx)(void *ctx, const u8 *src, u16 dev_passwd_id); - - /** - * go_neg_completed - Notification of GO Negotiation results - * @ctx: Callback context from cb_ctx - * @res: GO Negotiation results - * - * This callback is used to notify that Group Owner Negotiation has - * been completed. Non-zero struct p2p_go_neg_results::status indicates - * failed negotiation. In case of success, this function is responsible - * for creating a new group interface (or using the existing interface - * depending on driver features), setting up the group interface in - * proper mode based on struct p2p_go_neg_results::role_go and - * initializing WPS provisioning either as a Registrar (if GO) or as an - * Enrollee. Successful WPS provisioning must be indicated by calling - * p2p_wps_success_cb(). The callee is responsible for timing out group - * formation if WPS provisioning cannot be completed successfully - * within 15 seconds. - */ - void (*go_neg_completed)(void *ctx, struct p2p_go_neg_results *res); - - /** - * sd_request - Callback on Service Discovery Request - * @ctx: Callback context from cb_ctx - * @freq: Frequency (in MHz) of the channel - * @sa: Source address of the request - * @dialog_token: Dialog token - * @update_indic: Service Update Indicator from the source of request - * @tlvs: P2P Service Request TLV(s) - * @tlvs_len: Length of tlvs buffer in octets - * - * This callback is used to indicate reception of a service discovery - * request. Response to the query must be indicated by calling - * p2p_sd_response() with the context information from the arguments to - * this callback function. - * - * This callback handler can be set to %NULL to indicate that service - * discovery is not supported. - */ - void (*sd_request)(void *ctx, int freq, const u8 *sa, u8 dialog_token, - u16 update_indic, const u8 *tlvs, size_t tlvs_len); - - /** - * sd_response - Callback on Service Discovery Response - * @ctx: Callback context from cb_ctx - * @sa: Source address of the request - * @update_indic: Service Update Indicator from the source of response - * @tlvs: P2P Service Response TLV(s) - * @tlvs_len: Length of tlvs buffer in octets - * - * This callback is used to indicate reception of a service discovery - * response. This callback handler can be set to %NULL if no service - * discovery requests are used. The information provided with this call - * is replies to the queries scheduled with p2p_sd_request(). - */ - void (*sd_response)(void *ctx, const u8 *sa, u16 update_indic, - const u8 *tlvs, size_t tlvs_len); - - /** - * prov_disc_req - Callback on Provisiong Discovery Request - * @ctx: Callback context from cb_ctx - * @peer: Source address of the request - * @config_methods: Requested WPS Config Method - * @dev_addr: P2P Device Address of the found P2P Device - * @pri_dev_type: Primary Device Type - * @dev_name: Device Name - * @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. - */ - 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, - const u8 *group_id, size_t group_id_len); - - /** - * prov_disc_resp - Callback on Provisiong Discovery Response - * @ctx: Callback context from cb_ctx - * @peer: Source address of the response - * @config_methods: Value from p2p_prov_disc_req() or 0 on failure - * - * This callback is used to indicate reception of a Provision Discovery - * Response frame for a pending request scheduled with - * p2p_prov_disc_req(). This callback handler can be set to %NULL if - * provision discovery is not used. - */ - void (*prov_disc_resp)(void *ctx, const u8 *peer, u16 config_methods); - - /** - * prov_disc_fail - Callback on Provision Discovery failure - * @ctx: Callback context from cb_ctx - * @peer: Source address of the response - * @status: Cause of failure, will not be %P2P_PROV_DISC_SUCCESS - * - * This callback is used to indicate either a failure or no response - * to an earlier provision discovery request. - * - * This callback handler can be set to %NULL if provision discovery - * is not used or failures do not need to be indicated. - */ - void (*prov_disc_fail)(void *ctx, const u8 *peer, - enum p2p_prov_disc_status status); - - /** - * invitation_process - Optional callback for processing Invitations - * @ctx: Callback context from cb_ctx - * @sa: Source address of the Invitation Request - * @bssid: P2P Group BSSID from the request or %NULL if not included - * @go_dev_addr: GO Device Address from P2P Group ID - * @ssid: SSID from P2P Group ID - * @ssid_len: Length of ssid buffer in octets - * @go: Variable for returning whether the local end is GO in the group - * @group_bssid: Buffer for returning P2P Group BSSID (if local end GO) - * @force_freq: Variable for returning forced frequency for the group - * @persistent_group: Whether this is an invitation to reinvoke a - * persistent group (instead of invitation to join an active - * group) - * @channels: Available operating channels for the group - * @dev_pw_id: Device Password ID for NFC static handover or -1 if not - * used - * Returns: Status code (P2P_SC_*) - * - * This optional callback can be used to implement persistent reconnect - * by allowing automatic restarting of persistent groups without user - * interaction. If this callback is not implemented (i.e., is %NULL), - * the received Invitation Request frames are replied with - * %P2P_SC_REQ_RECEIVED status and indicated to upper layer with the - * invitation_result() callback. - * - * If the requested parameters are acceptable and the group is known, - * %P2P_SC_SUCCESS may be returned. If the requested group is unknown, - * %P2P_SC_FAIL_UNKNOWN_GROUP should be returned. %P2P_SC_REQ_RECEIVED - * can be returned if there is not enough data to provide immediate - * response, i.e., if some sort of user interaction is needed. The - * invitation_received() callback will be called in that case - * immediately after this call. - */ - u8 (*invitation_process)(void *ctx, const u8 *sa, const u8 *bssid, - const u8 *go_dev_addr, const u8 *ssid, - size_t ssid_len, int *go, u8 *group_bssid, - int *force_freq, int persistent_group, - const struct p2p_channels *channels, - int dev_pw_id); - - /** - * invitation_received - Callback on Invitation Request RX - * @ctx: Callback context from cb_ctx - * @sa: Source address of the Invitation Request - * @bssid: P2P Group BSSID or %NULL if not received - * @ssid: SSID of the group - * @ssid_len: Length of ssid in octets - * @go_dev_addr: GO Device Address - * @status: Response Status - * @op_freq: Operational frequency for the group - * - * This callback is used to indicate sending of an Invitation Response - * for a received Invitation Request. If status == 0 (success), the - * upper layer code is responsible for starting the group. status == 1 - * indicates need to get user authorization for the group. Other status - * values indicate that the invitation request was rejected. - */ - void (*invitation_received)(void *ctx, const u8 *sa, const u8 *bssid, - const u8 *ssid, size_t ssid_len, - const u8 *go_dev_addr, u8 status, - int op_freq); - - /** - * invitation_result - Callback on Invitation result - * @ctx: Callback context from cb_ctx - * @status: Negotiation result (Status Code) - * @bssid: P2P Group BSSID or %NULL if not received - * @channels: Available operating channels for the group - * @addr: Peer address - * @freq: Frequency (in MHz) indicated during invitation or 0 - * - * This callback is used to indicate result of an Invitation procedure - * started with a call to p2p_invite(). The indicated status code is - * the value received from the peer in Invitation Response with 0 - * (P2P_SC_SUCCESS) indicating success or -1 to indicate a timeout or a - * local failure in transmitting the Invitation Request. - */ - void (*invitation_result)(void *ctx, int status, const u8 *bssid, - const struct p2p_channels *channels, - const u8 *addr, int freq); - - /** - * go_connected - Check whether we are connected to a GO - * @ctx: Callback context from cb_ctx - * @dev_addr: P2P Device Address of a GO - * Returns: 1 if we are connected as a P2P client to the specified GO - * or 0 if not. - */ - int (*go_connected)(void *ctx, const u8 *dev_addr); - - /** - * presence_resp - Callback on Presence Response - * @ctx: Callback context from cb_ctx - * @src: Source address (GO's P2P Interface Address) - * @status: Result of the request (P2P_SC_*) - * @noa: Returned NoA value - * @noa_len: Length of the NoA buffer in octets - */ - void (*presence_resp)(void *ctx, const u8 *src, u8 status, - const u8 *noa, size_t noa_len); - - /** - * is_concurrent_session_active - Check whether concurrent session is - * active on other virtual interfaces - * @ctx: Callback context from cb_ctx - * Returns: 1 if concurrent session is active on other virtual interface - * or 0 if not. - */ - int (*is_concurrent_session_active)(void *ctx); -}; - - -/* P2P module initialization/deinitialization */ - -/** - * p2p_init - Initialize P2P module - * @cfg: P2P module configuration - * Returns: Pointer to private data or %NULL on failure - * - * This function is used to initialize global P2P module context (one per - * device). The P2P module will keep a copy of the configuration data, so the - * caller does not need to maintain this structure. However, the callback - * functions and the context parameters to them must be kept available until - * the P2P module is deinitialized with p2p_deinit(). - */ -struct p2p_data * p2p_init(const struct p2p_config *cfg); - -/** - * p2p_deinit - Deinitialize P2P module - * @p2p: P2P module context from p2p_init() - */ -void p2p_deinit(struct p2p_data *p2p); - -/** - * p2p_flush - Flush P2P module state - * @p2p: P2P module context from p2p_init() - * - * This command removes the P2P module state like peer device entries. - */ -void p2p_flush(struct p2p_data *p2p); - -/** - * p2p_unauthorize - Unauthorize the specified peer device - * @p2p: P2P module context from p2p_init() - * @addr: P2P peer entry to be unauthorized - * Returns: 0 on success, -1 on failure - * - * This command removes any connection authorization from the specified P2P - * peer device address. This can be used, e.g., to cancel effect of a previous - * p2p_authorize() or p2p_connect() call that has not yet resulted in completed - * GO Negotiation. - */ -int p2p_unauthorize(struct p2p_data *p2p, const u8 *addr); - -/** - * p2p_set_dev_name - Set device name - * @p2p: P2P module context from p2p_init() - * Returns: 0 on success, -1 on failure - * - * This function can be used to update the P2P module configuration with - * information that was not available at the time of the p2p_init() call. - */ -int p2p_set_dev_name(struct p2p_data *p2p, const char *dev_name); - -int p2p_set_manufacturer(struct p2p_data *p2p, const char *manufacturer); -int p2p_set_model_name(struct p2p_data *p2p, const char *model_name); -int p2p_set_model_number(struct p2p_data *p2p, const char *model_number); -int p2p_set_serial_number(struct p2p_data *p2p, const char *serial_number); - -void p2p_set_config_methods(struct p2p_data *p2p, u16 config_methods); -void p2p_set_uuid(struct p2p_data *p2p, const u8 *uuid); - -/** - * p2p_set_pri_dev_type - Set primary device type - * @p2p: P2P module context from p2p_init() - * Returns: 0 on success, -1 on failure - * - * This function can be used to update the P2P module configuration with - * information that was not available at the time of the p2p_init() call. - */ -int p2p_set_pri_dev_type(struct p2p_data *p2p, const u8 *pri_dev_type); - -/** - * p2p_set_sec_dev_types - Set secondary device types - * @p2p: P2P module context from p2p_init() - * Returns: 0 on success, -1 on failure - * - * This function can be used to update the P2P module configuration with - * information that was not available at the time of the p2p_init() call. - */ -int p2p_set_sec_dev_types(struct p2p_data *p2p, const u8 dev_types[][8], - size_t num_dev_types); - -int p2p_set_country(struct p2p_data *p2p, const char *country); - - -/* Commands from upper layer management entity */ - -enum p2p_discovery_type { - P2P_FIND_START_WITH_FULL, - P2P_FIND_ONLY_SOCIAL, - P2P_FIND_PROGRESSIVE -}; - -/** - * p2p_find - Start P2P Find (Device Discovery) - * @p2p: P2P module context from p2p_init() - * @timeout: Timeout for find operation in seconds or 0 for no timeout - * @type: Device Discovery type - * @num_req_dev_types: Number of requested device types - * @req_dev_types: Requested device types array, must be an array - * containing num_req_dev_types * WPS_DEV_TYPE_LEN bytes; %NULL if no - * requested device types. - * @dev_id: Device ID to search for or %NULL to find all devices - * @search_delay: Extra delay in milliseconds between search iterations - * Returns: 0 on success, -1 on failure - */ -int p2p_find(struct p2p_data *p2p, unsigned int timeout, - enum p2p_discovery_type type, - unsigned int num_req_dev_types, const u8 *req_dev_types, - const u8 *dev_id, unsigned int search_delay); - -/** - * p2p_stop_find - Stop P2P Find (Device Discovery) - * @p2p: P2P module context from p2p_init() - */ -void p2p_stop_find(struct p2p_data *p2p); - -/** - * p2p_stop_find_for_freq - Stop P2P Find for next oper on specific freq - * @p2p: P2P module context from p2p_init() - * @freq: Frequency in MHz for next operation - * - * This is like p2p_stop_find(), but Listen state is not stopped if we are - * already on the same frequency. - */ -void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq); - -/** - * p2p_listen - Start P2P Listen state for specified duration - * @p2p: P2P module context from p2p_init() - * @timeout: Listen state duration in milliseconds - * Returns: 0 on success, -1 on failure - * - * This function can be used to request the P2P module to keep the device - * discoverable on the listen channel for an extended set of time. At least in - * its current form, this is mainly used for testing purposes and may not be of - * much use for normal P2P operations. - */ -int p2p_listen(struct p2p_data *p2p, unsigned int timeout); - -/** - * p2p_stop_listen - Stop P2P Listen - * @p2p: P2P module context from p2p_init() - */ -void p2p_stop_listen(struct p2p_data *p2p); - -/** - * p2p_connect - Start P2P group formation (GO negotiation) - * @p2p: P2P module context from p2p_init() - * @peer_addr: MAC address of the peer P2P client - * @wps_method: WPS method to be used in provisioning - * @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 (0 = no, 1 = - * persistent group without persistent reconnect, 2 = persistent group with - * persistent reconnect) - * @force_ssid: Forced SSID for the group if we become GO or %NULL to generate - * a new SSID - * @force_ssid_len: Length of $force_ssid buffer - * @pd_before_go_neg: Whether to send Provision Discovery prior to GO - * Negotiation as an interoperability workaround when initiating group - * formation - * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if - * force_freq == 0) - * Returns: 0 on success, -1 on failure - */ -int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, - enum p2p_wps_method wps_method, - int go_intent, const u8 *own_interface_addr, - unsigned int force_freq, int persistent_group, - const u8 *force_ssid, size_t force_ssid_len, - int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id); - -/** - * p2p_authorize - Authorize P2P group formation (GO negotiation) - * @p2p: P2P module context from p2p_init() - * @peer_addr: MAC address of the peer P2P client - * @wps_method: WPS method to be used in provisioning - * @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 (0 = no, 1 = - * persistent group without persistent reconnect, 2 = persistent group with - * persistent reconnect) - * @force_ssid: Forced SSID for the group if we become GO or %NULL to generate - * a new SSID - * @force_ssid_len: Length of $force_ssid buffer - * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if - * force_freq == 0) - * Returns: 0 on success, -1 on failure - * - * This is like p2p_connect(), but the actual group negotiation is not - * initiated automatically, i.e., the other end is expected to do that. - */ -int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, - enum p2p_wps_method wps_method, - int go_intent, const u8 *own_interface_addr, - unsigned int force_freq, int persistent_group, - const u8 *force_ssid, size_t force_ssid_len, - unsigned int pref_freq, u16 oob_pw_id); - -/** - * p2p_reject - Reject peer device (explicitly block connection attempts) - * @p2p: P2P module context from p2p_init() - * @peer_addr: MAC address of the peer P2P client - * Returns: 0 on success, -1 on failure - */ -int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr); - -/** - * p2p_prov_disc_req - Send Provision Discovery Request - * @p2p: P2P module context from p2p_init() - * @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) - * @user_initiated_pd: Flag to indicate if initiated by user or not - * Returns: 0 on success, -1 on failure - * - * This function can be used to request a discovered P2P peer to display a PIN - * (config_methods = WPS_CONFIG_DISPLAY) or be prepared to enter a PIN from us - * (config_methods = WPS_CONFIG_KEYPAD). The Provision Discovery Request frame - * is transmitted once immediately and if no response is received, the frame - * will be sent again whenever the target device is discovered during device - * dsicovery (start with a p2p_find() call). Response from the peer is - * 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, int force_freq, - int user_initiated_pd); - -/** - * p2p_sd_request - Schedule a service discovery query - * @p2p: P2P module context from p2p_init() - * @dst: Destination peer or %NULL to apply for all peers - * @tlvs: P2P Service Query TLV(s) - * Returns: Reference to the query or %NULL on failure - * - * Response to the query is indicated with the p2p_config::sd_response() - * callback. - */ -void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst, - const struct wpabuf *tlvs); - -#ifdef CONFIG_WIFI_DISPLAY -void * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst, - const struct wpabuf *tlvs); -#endif /* CONFIG_WIFI_DISPLAY */ - -/** - * p2p_sd_cancel_request - Cancel a pending service discovery query - * @p2p: P2P module context from p2p_init() - * @req: Query reference from p2p_sd_request() - * Returns: 0 if request for cancelled; -1 if not found - */ -int p2p_sd_cancel_request(struct p2p_data *p2p, void *req); - -/** - * p2p_sd_response - Send response to a service discovery query - * @p2p: P2P module context from p2p_init() - * @freq: Frequency from p2p_config::sd_request() callback - * @dst: Destination address from p2p_config::sd_request() callback - * @dialog_token: Dialog token from p2p_config::sd_request() callback - * @resp_tlvs: P2P Service Response TLV(s) - * - * This function is called as a response to the request indicated with - * p2p_config::sd_request() callback. - */ -void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst, - u8 dialog_token, const struct wpabuf *resp_tlvs); - -/** - * p2p_sd_service_update - Indicate a change in local services - * @p2p: P2P module context from p2p_init() - * - * This function needs to be called whenever there is a change in availability - * of the local services. This will increment the Service Update Indicator - * value which will be used in SD Request and Response frames. - */ -void p2p_sd_service_update(struct p2p_data *p2p); - - -enum p2p_invite_role { - P2P_INVITE_ROLE_GO, - P2P_INVITE_ROLE_ACTIVE_GO, - P2P_INVITE_ROLE_CLIENT -}; - -/** - * p2p_invite - Invite a P2P Device into a group - * @p2p: P2P module context from p2p_init() - * @peer: Device Address of the peer P2P Device - * @role: Local role in the group - * @bssid: Group BSSID or %NULL if not known - * @ssid: Group SSID - * @ssid_len: Length of ssid in octets - * @force_freq: The only allowed channel frequency in MHz or 0 - * @go_dev_addr: Forced GO Device Address or %NULL if none - * @persistent_group: Whether this is to reinvoke a persistent group - * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if - * force_freq == 0) - * @dev_pw_id: Device Password ID from OOB Device Password (NFC) static handover - * case or -1 if not used - * Returns: 0 on success, -1 on failure - */ -int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, - const u8 *bssid, const u8 *ssid, size_t ssid_len, - unsigned int force_freq, const u8 *go_dev_addr, - int persistent_group, unsigned int pref_freq, int dev_pw_id); - -/** - * p2p_presence_req - Request GO presence - * @p2p: P2P module context from p2p_init() - * @go_interface_addr: GO P2P Interface Address - * @own_interface_addr: Own P2P Interface Address for this group - * @freq: Group operating frequence (in MHz) - * @duration1: Preferred presence duration in microseconds - * @interval1: Preferred presence interval in microseconds - * @duration2: Acceptable presence duration in microseconds - * @interval2: Acceptable presence interval in microseconds - * Returns: 0 on success, -1 on failure - * - * If both duration and interval values are zero, the parameter pair is not - * specified (i.e., to remove Presence Request, use duration1 = interval1 = 0). - */ -int p2p_presence_req(struct p2p_data *p2p, const u8 *go_interface_addr, - const u8 *own_interface_addr, unsigned int freq, - u32 duration1, u32 interval1, u32 duration2, - u32 interval2); - -/** - * p2p_ext_listen - Set Extended Listen Timing - * @p2p: P2P module context from p2p_init() - * @freq: Group operating frequence (in MHz) - * @period: Availability period in milliseconds (1-65535; 0 to disable) - * @interval: Availability interval in milliseconds (1-65535; 0 to disable) - * Returns: 0 on success, -1 on failure - * - * This function can be used to enable or disable (period = interval = 0) - * Extended Listen Timing. When enabled, the P2P Device will become - * discoverable (go into Listen State) every @interval milliseconds for at - * least @period milliseconds. - */ -int p2p_ext_listen(struct p2p_data *p2p, unsigned int period, - unsigned int interval); - -/* Event notifications from upper layer management operations */ - -/** - * p2p_wps_success_cb - Report successfully completed WPS provisioning - * @p2p: P2P module context from p2p_init() - * @mac_addr: Peer address - * - * This function is used to report successfully completed WPS provisioning - * during group formation in both GO/Registrar and client/Enrollee roles. - */ -void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr); - -/** - * p2p_group_formation_failed - Report failed WPS provisioning - * @p2p: P2P module context from p2p_init() - * - * This function is used to report failed group formation. This can happen - * either due to failed WPS provisioning or due to 15 second timeout during - * the provisioning phase. - */ -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 Device Address - * - * This function is used to clear stored WPS provisioning info for the given - * peer. - */ -void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr); - - -/* Event notifications from lower layer driver operations */ - -/** - * enum p2p_probe_req_status - * - * @P2P_PREQ_MALFORMED: frame was not well-formed - * @P2P_PREQ_NOT_LISTEN: device isn't in listen state, frame ignored - * @P2P_PREQ_NOT_P2P: frame was not a P2P probe request - * @P2P_PREQ_P2P_NOT_PROCESSED: frame was P2P but wasn't processed - * @P2P_PREQ_P2P_PROCESSED: frame has been processed by P2P - */ -enum p2p_probe_req_status { - P2P_PREQ_MALFORMED, - P2P_PREQ_NOT_LISTEN, - P2P_PREQ_NOT_P2P, - P2P_PREQ_NOT_PROCESSED, - P2P_PREQ_PROCESSED -}; - -/** - * p2p_probe_req_rx - Report reception of a Probe Request frame - * @p2p: P2P module context from p2p_init() - * @addr: Source MAC address - * @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: value indicating the type and status of the probe request - */ -enum p2p_probe_req_status -p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst, - const u8 *bssid, const u8 *ie, size_t ie_len); - -/** - * p2p_rx_action - Report received Action frame - * @p2p: P2P module context from p2p_init() - * @da: Destination address of the received Action frame - * @sa: Source address of the received Action frame - * @bssid: Address 3 of the received Action frame - * @category: Category of the received Action frame - * @data: Action frame body after the Category field - * @len: Length of the data buffer in octets - * @freq: Frequency (in MHz) on which the frame was received - */ -void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa, - const u8 *bssid, u8 category, - const u8 *data, size_t len, int freq); - -/** - * p2p_scan_res_handler - Indicate a P2P scan results - * @p2p: P2P module context from p2p_init() - * @bssid: BSSID of the scan result - * @freq: Frequency of the channel on which the device was found in MHz - * @rx_time: Time when the result was received - * @level: Signal level (signal strength of the received Beacon/Probe Response - * frame) - * @ies: Pointer to IEs from the scan result - * @ies_len: Length of the ies buffer - * Returns: 0 to continue or 1 to stop scan result indication - * - * This function is called to indicate a scan result entry with P2P IE from a - * scan requested with struct p2p_config::p2p_scan(). This can be called during - * the actual scan process (i.e., whenever a new device is found) or as a - * sequence of calls after the full scan has been completed. The former option - * can result in optimized operations, but may not be supported by all - * driver/firmware designs. The ies buffer need to include at least the P2P IE, - * but it is recommended to include all IEs received from the device. The - * caller does not need to check that the IEs contain a P2P IE before calling - * this function since frames will be filtered internally if needed. - * - * This function will return 1 if it wants to stop scan result iteration (and - * scan in general if it is still in progress). This is used to allow faster - * start of a pending operation, e.g., to start a pending GO negotiation. - */ -int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq, - struct os_reltime *rx_time, int level, const u8 *ies, - size_t ies_len); - -/** - * p2p_scan_res_handled - Indicate end of scan results - * @p2p: P2P module context from p2p_init() - * - * This function is called to indicate that all P2P scan results from a scan - * have been reported with zero or more calls to p2p_scan_res_handler(). This - * function must be called as a response to successful - * struct p2p_config::p2p_scan() call if none of the p2p_scan_res_handler() - * calls stopped iteration. - */ -void p2p_scan_res_handled(struct p2p_data *p2p); - -enum p2p_send_action_result { - P2P_SEND_ACTION_SUCCESS /* Frame was send and acknowledged */, - P2P_SEND_ACTION_NO_ACK /* Frame was sent, but not acknowledged */, - P2P_SEND_ACTION_FAILED /* Frame was not sent due to a failure */ -}; - -/** - * p2p_send_action_cb - Notify TX status of an Action frame - * @p2p: P2P module context from p2p_init() - * @freq: Channel frequency in MHz - * @dst: Destination MAC address (Address 1) - * @src: Source MAC address (Address 2) - * @bssid: BSSID (Address 3) - * @result: Result of the transmission attempt - * - * This function is used to indicate the result of an Action frame transmission - * that was requested with struct p2p_config::send_action() callback. - */ -void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst, - const u8 *src, const u8 *bssid, - enum p2p_send_action_result result); - -/** - * p2p_listen_cb - Indicate the start of a requested Listen state - * @p2p: P2P module context from p2p_init() - * @freq: Listen channel frequency in MHz - * @duration: Duration for the Listen state in milliseconds - * - * This function is used to indicate that a Listen state requested with - * struct p2p_config::start_listen() callback has started. - */ -void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq, - unsigned int duration); - -/** - * p2p_listen_end - Indicate the end of a requested Listen state - * @p2p: P2P module context from p2p_init() - * @freq: Listen channel frequency in MHz - * Returns: 0 if no operations were started, 1 if an operation was started - * - * This function is used to indicate that a Listen state requested with - * struct p2p_config::start_listen() callback has ended. - */ -int p2p_listen_end(struct p2p_data *p2p, unsigned int freq); - -void p2p_deauth_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code, - const u8 *ie, size_t ie_len); - -void p2p_disassoc_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code, - const u8 *ie, size_t ie_len); - - -/* Per-group P2P state for GO */ - -struct p2p_group; - -/** - * struct p2p_group_config - P2P group configuration - * - * This configuration is provided to the P2P module during initialization of - * the per-group information with p2p_group_init(). - */ -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; - - /** - * interface_addr - P2P Interface Address of the group - */ - u8 interface_addr[ETH_ALEN]; - - /** - * max_clients - Maximum number of clients in the group - */ - unsigned int max_clients; - - /** - * ssid - Group SSID - */ - u8 ssid[32]; - - /** - * ssid_len - Length of SSID - */ - size_t ssid_len; - - /** - * freq - Operating channel of the group - */ - int freq; - - /** - * cb_ctx - Context to use with callback functions - */ - void *cb_ctx; - - /** - * ie_update - Notification of IE update - * @ctx: Callback context from cb_ctx - * @beacon_ies: P2P IE for Beacon frames or %NULL if no change - * @proberesp_ies: P2P Ie for Probe Response frames - * - * P2P module uses this callback function to notify whenever the P2P IE - * in Beacon or Probe Response frames should be updated based on group - * events. - * - * The callee is responsible for freeing the returned buffer(s) with - * wpabuf_free(). - */ - void (*ie_update)(void *ctx, struct wpabuf *beacon_ies, - struct wpabuf *proberesp_ies); - - /** - * idle_update - Notification of changes in group idle state - * @ctx: Callback context from cb_ctx - * @idle: Whether the group is idle (no associated stations) - */ - void (*idle_update)(void *ctx, int idle); -}; - -/** - * p2p_group_init - Initialize P2P group - * @p2p: P2P module context from p2p_init() - * @config: P2P group configuration (will be freed by p2p_group_deinit()) - * Returns: Pointer to private data or %NULL on failure - * - * This function is used to initialize per-group P2P module context. Currently, - * this is only used to manage GO functionality and P2P clients do not need to - * create an instance of this per-group information. - */ -struct p2p_group * p2p_group_init(struct p2p_data *p2p, - struct p2p_group_config *config); - -/** - * p2p_group_deinit - Deinitialize P2P group - * @group: P2P group context from p2p_group_init() - */ -void p2p_group_deinit(struct p2p_group *group); - -/** - * p2p_group_notif_assoc - Notification of P2P client association with GO - * @group: P2P group context from p2p_group_init() - * @addr: Interface address of the P2P client - * @ie: IEs from the (Re)association Request frame - * @len: Length of the ie buffer in octets - * Returns: 0 on success, -1 on failure - */ -int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr, - const u8 *ie, size_t len); - -/** - * p2p_group_assoc_resp_ie - Build P2P IE for (re)association response - * @group: P2P group context from p2p_group_init() - * @status: Status value (P2P_SC_SUCCESS if association succeeded) - * Returns: P2P IE for (Re)association Response or %NULL on failure - * - * The caller is responsible for freeing the returned buffer with - * wpabuf_free(). - */ -struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status); - -/** - * p2p_group_notif_disassoc - Notification of P2P client disassociation from GO - * @group: P2P group context from p2p_group_init() - * @addr: Interface address of the P2P client - */ -void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr); - -/** - * p2p_group_notif_formation_done - Notification of completed group formation - * @group: P2P group context from p2p_group_init() - */ -void p2p_group_notif_formation_done(struct p2p_group *group); - -/** - * p2p_group_notif_noa - Notification of NoA change - * @group: P2P group context from p2p_group_init() - * @noa: Notice of Absence attribute payload, %NULL if none - * @noa_len: Length of noa buffer in octets - * Returns: 0 on success, -1 on failure - * - * Notify the P2P group management about a new NoA contents. This will be - * inserted into the P2P IEs in Beacon and Probe Response frames with rest of - * the group information. - */ -int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa, - size_t noa_len); - -/** - * p2p_group_match_dev_type - Match device types in group with requested type - * @group: P2P group context from p2p_group_init() - * @wps: WPS TLVs from Probe Request frame (concatenated WPS IEs) - * Returns: 1 on match, 0 on mismatch - * - * This function can be used to match the Requested Device Type attribute in - * WPS IE with the device types of a group member for deciding whether a GO - * should reply to a Probe Request frame. Match will be reported if the WPS IE - * is not requested any specific device type. - */ -int p2p_group_match_dev_type(struct p2p_group *group, struct wpabuf *wps); - -/** - * p2p_group_match_dev_id - Match P2P Device Address in group with requested device id - */ -int p2p_group_match_dev_id(struct p2p_group *group, struct wpabuf *p2p); - -/** - * p2p_group_go_discover - Send GO Discoverability Request to a group client - * @group: P2P group context from p2p_group_init() - * Returns: 0 on success (frame scheduled); -1 if client was not found - */ -int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id, - const u8 *searching_dev, int rx_freq); - - -/* Generic helper functions */ - -/** - * p2p_ie_text - Build text format description of P2P IE - * @p2p_ie: P2P IE - * @buf: Buffer for returning text - * @end: Pointer to the end of the buf area - * Returns: Number of octets written to the buffer or -1 on failure - * - * This function can be used to parse P2P IE contents into text format - * field=value lines. - */ -int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end); - -/** - * p2p_scan_result_text - Build text format description of P2P IE - * @ies: Information elements from scan results - * @ies_len: ies buffer length in octets - * @buf: Buffer for returning text - * @end: Pointer to the end of the buf area - * Returns: Number of octets written to the buffer or -1 on failure - * - * This function can be used to parse P2P IE contents into text format - * field=value lines. - */ -int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end); - -/** - * p2p_parse_dev_addr_in_p2p_ie - Parse P2P Device Address from a concatenated - * P2P IE - * @p2p_ie: P2P IE - * @dev_addr: Buffer for returning P2P Device Address - * Returns: 0 on success or -1 if P2P Device Address could not be parsed - */ -int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr); - -/** - * p2p_parse_dev_addr - Parse P2P Device Address from P2P IE(s) - * @ies: Information elements from scan results - * @ies_len: ies buffer length in octets - * @dev_addr: Buffer for returning P2P Device Address - * Returns: 0 on success or -1 if P2P Device Address could not be parsed - */ -int p2p_parse_dev_addr(const u8 *ies, size_t ies_len, u8 *dev_addr); - -/** - * p2p_assoc_req_ie - Build P2P IE for (Re)Association Request frame - * @p2p: P2P module context from p2p_init() - * @bssid: BSSID - * @buf: Buffer for writing the P2P IE - * @len: Maximum buf length in octets - * @p2p_group: Whether this is for association with a P2P GO - * @p2p_ie: Reassembled P2P IE data from scan results or %NULL if none - * Returns: Number of octets written into buf or -1 on failure - */ -int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf, - size_t len, int p2p_group, struct wpabuf *p2p_ie); - -/** - * p2p_scan_ie - Build P2P IE for Probe Request - * @p2p: P2P module context from p2p_init() - * @ies: Buffer for writing P2P IE - * @dev_id: Device ID to search for or %NULL for any - */ -void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id); - -/** - * 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 - * Returns: 0 on success, -1 on failure - */ -int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params); - -/** - * p2p_get_group_capab - Get Group Capability from P2P IE data - * @p2p_ie: P2P IE(s) contents - * Returns: Group Capability - */ -u8 p2p_get_group_capab(const struct wpabuf *p2p_ie); - -/** - * p2p_get_cross_connect_disallowed - Does WLAN AP disallows cross connection - * @p2p_ie: P2P IE(s) contents - * Returns: 0 if cross connection is allow, 1 if not - */ -int p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie); - -/** - * p2p_get_go_dev_addr - Get P2P Device Address from P2P IE data - * @p2p_ie: P2P IE(s) contents - * Returns: Pointer to P2P Device Address or %NULL if not included - */ -const u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie); - -/** - * 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_peer_known(struct p2p_data *p2p, const u8 *addr); - -/** - * p2p_set_client_discoverability - Set client discoverability capability - * @p2p: P2P module context from p2p_init() - * @enabled: Whether client discoverability will be enabled - * - * This function can be used to disable (and re-enable) client discoverability. - * This capability is enabled by default and should not be disabled in normal - * use cases, i.e., this is mainly for testing purposes. - */ -void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled); - -/** - * 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 - */ -void p2p_set_managed_oper(struct p2p_data *p2p, int enabled); - -int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel); - -int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len); - -int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr, - u8 *iface_addr); -int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr, - u8 *dev_addr); - -void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr); - -/** - * p2p_set_cross_connect - Set cross connection capability - * @p2p: P2P module context from p2p_init() - * @enabled: Whether cross connection will be enabled - */ -void p2p_set_cross_connect(struct p2p_data *p2p, int enabled); - -int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr); - -/** - * p2p_set_intra_bss_dist - Set intra BSS distribution - * @p2p: P2P module context from p2p_init() - * @enabled: Whether intra BSS distribution will be enabled - */ -void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled); - -int p2p_channels_includes_freq(const struct p2p_channels *channels, - unsigned int freq); - -/** - * p2p_supported_freq - Check whether channel is supported for P2P - * @p2p: P2P module context from p2p_init() - * @freq: Channel frequency in MHz - * Returns: 0 if channel not usable for P2P, 1 if usable for P2P - */ -int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq); - -/** - * p2p_supported_freq_go - Check whether channel is supported for P2P GO operation - * @p2p: P2P module context from p2p_init() - * @freq: Channel frequency in MHz - * Returns: 0 if channel not usable for P2P, 1 if usable for P2P - */ -int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq); - -/** - * p2p_supported_freq_cli - Check whether channel is supported for P2P client operation - * @p2p: P2P module context from p2p_init() - * @freq: Channel frequency in MHz - * Returns: 0 if channel not usable for P2P, 1 if usable for P2P - */ -int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq); - -/** - * p2p_get_pref_freq - Get channel from preferred channel list - * @p2p: P2P module context from p2p_init() - * @channels: List of channels - * Returns: Preferred channel - */ -unsigned int p2p_get_pref_freq(struct p2p_data *p2p, - const struct p2p_channels *channels); - -void p2p_update_channel_list(struct p2p_data *p2p, - const struct p2p_channels *chan, - const struct p2p_channels *cli_chan); - -/** - * p2p_set_best_channels - Update best channel information - * @p2p: P2P module context from p2p_init() - * @freq_24: Frequency (MHz) of best channel in 2.4 GHz band - * @freq_5: Frequency (MHz) of best channel in 5 GHz band - * @freq_overall: Frequency (MHz) of best channel overall - */ -void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5, - int freq_overall); - -/** - * p2p_set_own_freq_preference - Set own preference for channel - * @p2p: P2P module context from p2p_init() - * @freq: Frequency (MHz) of the preferred channel or 0 if no preference - * - * This function can be used to set a preference on the operating channel based - * on frequencies used on the other virtual interfaces that share the same - * radio. If non-zero, this is used to try to avoid multi-channel concurrency. - */ -void p2p_set_own_freq_preference(struct p2p_data *p2p, int freq); - -const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p); - -/** - * p2p_get_group_num_members - Get number of members in group - * @group: P2P group context from p2p_group_init() - * Returns: Number of members in the group - */ -unsigned int p2p_get_group_num_members(struct p2p_group *group); - -/** - * p2p_iterate_group_members - Iterate group members - * @group: P2P group context from p2p_group_init() - * @next: iteration pointer, must be a pointer to a void * that is set to %NULL - * on the first call and not modified later - * Returns: A P2P Interface Address for each call and %NULL for no more members - */ -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_group_is_client_connected - Check whether a specific client is connected - * @group: P2P group context from p2p_group_init() - * @addr: P2P Device Address of the client - * Returns: 1 if client is connected or 0 if not - */ -int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_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 - * @next: Whether to select the peer entry following the one indicated by addr - * Returns: The first P2P peer info available or %NULL if no such peer exists - */ -const struct p2p_peer_info * -p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next); - -/** - * p2p_remove_wps_vendor_extensions - Remove WPS vendor extensions - * @p2p: P2P module context from p2p_init() - */ -void p2p_remove_wps_vendor_extensions(struct p2p_data *p2p); - -/** - * p2p_add_wps_vendor_extension - Add a WPS vendor extension - * @p2p: P2P module context from p2p_init() - * @vendor_ext: The vendor extensions to add - * Returns: 0 on success, -1 on failure - * - * The wpabuf structures in the array are owned by the P2P - * module after this call. - */ -int p2p_add_wps_vendor_extension(struct p2p_data *p2p, - const struct wpabuf *vendor_ext); - -/** - * p2p_set_oper_channel - Set the P2P operating channel - * @p2p: P2P module context from p2p_init() - * @op_reg_class: Operating regulatory class to set - * @op_channel: operating channel to set - * @cfg_op_channel : Whether op_channel is hardcoded in configuration - * Returns: 0 on success, -1 on failure - */ -int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel, - int cfg_op_channel); - -/** - * p2p_set_pref_chan - Set P2P preferred channel list - * @p2p: P2P module context from p2p_init() - * @num_pref_chan: Number of entries in pref_chan list - * @pref_chan: Preferred channels or %NULL to remove preferences - * Returns: 0 on success, -1 on failure - */ -int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan, - const struct p2p_channel *pref_chan); - -/** - * p2p_set_no_go_freq - Set no GO channel ranges - * @p2p: P2P module context from p2p_init() - * @list: Channel ranges or %NULL to remove restriction - * Returns: 0 on success, -1 on failure - */ -int p2p_set_no_go_freq(struct p2p_data *p2p, - const struct wpa_freq_range_list *list); - -/** - * 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); - -const char * p2p_wps_method_text(enum p2p_wps_method method); - -/** - * p2p_set_config_timeout - Set local config timeouts - * @p2p: P2P module context from p2p_init() - * @go_timeout: Time in 10 ms units it takes to start the GO mode - * @client_timeout: Time in 10 ms units it takes to start the client mode - */ -void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout, - u8 client_timeout); - -int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie); -int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie); -int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie); -int p2p_set_wfd_ie_assoc_req(struct p2p_data *p2p, struct wpabuf *ie); -int p2p_set_wfd_ie_invitation(struct p2p_data *p2p, struct wpabuf *ie); -int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie); -int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie); -int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie); -int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem); -int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem); -int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p, - const struct wpabuf *elem); -struct wpabuf * wifi_display_encaps(struct wpabuf *subelems); - -/** - * p2p_set_disc_int - Set min/max discoverable interval for p2p_find - * @p2p: P2P module context from p2p_init() - * @min_disc_int: minDiscoverableInterval (in units of 100 TU); default 1 - * @max_disc_int: maxDiscoverableInterval (in units of 100 TU); default 3 - * @max_disc_tu: Maximum number of TUs (1.024 ms) for discoverable interval; or - * -1 not to limit - * Returns: 0 on success, or -1 on failure - * - * This function can be used to configure minDiscoverableInterval and - * maxDiscoverableInterval parameters for the Listen state during device - * discovery (p2p_find). A random number of 100 TU units is picked for each - * Listen state iteration from [min_disc_int,max_disc_int] range. - * - * max_disc_tu can be used to futher limit the discoverable duration. However, - * it should be noted that use of this parameter is not recommended since it - * would not be compliant with the P2P specification. - */ -int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int, - int max_disc_tu); - -/** - * p2p_get_state_txt - Get current P2P state for debug purposes - * @p2p: P2P module context from p2p_init() - * Returns: Name of the current P2P module state - * - * It should be noted that the P2P module state names are internal information - * and subject to change at any point, i.e., this information should be used - * mainly for debugging purposes. - */ -const char * p2p_get_state_txt(struct p2p_data *p2p); - -struct wpabuf * p2p_build_nfc_handover_req(struct p2p_data *p2p, - int client_freq, - const u8 *go_dev_addr, - const u8 *ssid, size_t ssid_len); -struct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p, - int client_freq, - const u8 *go_dev_addr, - const u8 *ssid, size_t ssid_len); - -struct p2p_nfc_params { - int sel; - const u8 *wsc_attr; - size_t wsc_len; - const u8 *p2p_attr; - size_t p2p_len; - - enum { - NO_ACTION, JOIN_GROUP, AUTH_JOIN, INIT_GO_NEG, RESP_GO_NEG, - BOTH_GO, PEER_CLIENT - } next_step; - struct p2p_peer_info *peer; - u8 oob_dev_pw[WPS_OOB_PUBKEY_HASH_LEN + 2 + - WPS_OOB_DEVICE_PASSWORD_LEN]; - size_t oob_dev_pw_len; - int go_freq; - u8 go_dev_addr[ETH_ALEN]; - u8 go_ssid[32]; - size_t go_ssid_len; -}; - -int p2p_process_nfc_connection_handover(struct p2p_data *p2p, - struct p2p_nfc_params *params); - -void p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id, - int go_intent, - const u8 *own_interface_addr); - -#endif /* P2P_H */ diff --git a/contrib/hostapd/src/p2p/p2p_build.c b/contrib/hostapd/src/p2p/p2p_build.c deleted file mode 100644 index 664fadec2a..0000000000 --- a/contrib/hostapd/src/p2p/p2p_build.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * P2P - IE builder - * Copyright (c) 2009-2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "common/ieee802_11_defs.h" -#include "wps/wps_i.h" -#include "p2p_i.h" - - -void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token) -{ - wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC); - wpabuf_put_be24(buf, OUI_WFA); - wpabuf_put_u8(buf, P2P_OUI_TYPE); - - wpabuf_put_u8(buf, subtype); /* OUI Subtype */ - wpabuf_put_u8(buf, dialog_token); - wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token); -} - - -void p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype, - u8 dialog_token) -{ - wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); - wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC); - wpabuf_put_be24(buf, OUI_WFA); - wpabuf_put_u8(buf, P2P_OUI_TYPE); - - wpabuf_put_u8(buf, subtype); /* OUI Subtype */ - wpabuf_put_u8(buf, dialog_token); - wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token); -} - - -u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf) -{ - u8 *len; - - /* P2P IE header */ - wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); - len = wpabuf_put(buf, 1); /* IE length to be filled */ - wpabuf_put_be24(buf, OUI_WFA); - wpabuf_put_u8(buf, P2P_OUI_TYPE); - wpa_printf(MSG_DEBUG, "P2P: * P2P IE header"); - return len; -} - - -void p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len) -{ - /* Update P2P IE Length */ - *len = (u8 *) wpabuf_put(buf, 0) - len - 1; -} - - -void p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab) -{ - /* P2P Capability */ - wpabuf_put_u8(buf, P2P_ATTR_CAPABILITY); - wpabuf_put_le16(buf, 2); - wpabuf_put_u8(buf, dev_capab); /* Device Capabilities */ - wpabuf_put_u8(buf, group_capab); /* Group Capabilities */ - wpa_printf(MSG_DEBUG, "P2P: * Capability dev=%02x group=%02x", - dev_capab, group_capab); -} - - -void p2p_buf_add_go_intent(struct wpabuf *buf, u8 go_intent) -{ - /* Group Owner Intent */ - wpabuf_put_u8(buf, P2P_ATTR_GROUP_OWNER_INTENT); - wpabuf_put_le16(buf, 1); - wpabuf_put_u8(buf, go_intent); - wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u Tie breaker %u", - go_intent >> 1, go_intent & 0x01); -} - - -void p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country, - u8 reg_class, u8 channel) -{ - /* Listen Channel */ - wpabuf_put_u8(buf, P2P_ATTR_LISTEN_CHANNEL); - wpabuf_put_le16(buf, 5); - wpabuf_put_data(buf, country, 3); - wpabuf_put_u8(buf, reg_class); /* Regulatory Class */ - wpabuf_put_u8(buf, channel); /* Channel Number */ - wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Regulatory Class %u " - "Channel %u", reg_class, channel); -} - - -void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country, - u8 reg_class, u8 channel) -{ - /* Operating Channel */ - wpabuf_put_u8(buf, P2P_ATTR_OPERATING_CHANNEL); - wpabuf_put_le16(buf, 5); - wpabuf_put_data(buf, country, 3); - wpabuf_put_u8(buf, reg_class); /* Regulatory Class */ - wpabuf_put_u8(buf, channel); /* Channel Number */ - wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: Regulatory Class %u " - "Channel %u", reg_class, channel); -} - - -void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country, - struct p2p_channels *chan) -{ - u8 *len; - size_t i; - - /* Channel List */ - wpabuf_put_u8(buf, P2P_ATTR_CHANNEL_LIST); - len = wpabuf_put(buf, 2); /* IE length to be filled */ - wpabuf_put_data(buf, country, 3); /* Country String */ - - for (i = 0; i < chan->reg_classes; i++) { - struct p2p_reg_class *c = &chan->reg_class[i]; - wpabuf_put_u8(buf, c->reg_class); - wpabuf_put_u8(buf, c->channels); - wpabuf_put_data(buf, c->channel, c->channels); - } - - /* Update attribute length */ - WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); - wpa_hexdump(MSG_DEBUG, "P2P: * Channel List", - len + 2, (u8 *) wpabuf_put(buf, 0) - len - 2); -} - - -void p2p_buf_add_status(struct wpabuf *buf, u8 status) -{ - /* Status */ - wpabuf_put_u8(buf, P2P_ATTR_STATUS); - wpabuf_put_le16(buf, 1); - wpabuf_put_u8(buf, status); - wpa_printf(MSG_DEBUG, "P2P: * Status: %d", status); -} - - -void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p, - struct p2p_device *peer) -{ - u8 *len; - u16 methods; - size_t nlen, i; - - /* P2P Device Info */ - wpabuf_put_u8(buf, P2P_ATTR_DEVICE_INFO); - len = wpabuf_put(buf, 2); /* IE length to be filled */ - - /* P2P Device address */ - wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); - - /* 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_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; - } - wpabuf_put_be16(buf, methods); - - /* Primary Device Type */ - wpabuf_put_data(buf, p2p->cfg->pri_dev_type, - sizeof(p2p->cfg->pri_dev_type)); - - /* Number of Secondary Device Types */ - wpabuf_put_u8(buf, p2p->cfg->num_sec_dev_types); - - /* Secondary Device Type List */ - for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) - wpabuf_put_data(buf, p2p->cfg->sec_dev_type[i], - WPS_DEV_TYPE_LEN); - - /* Device Name */ - nlen = p2p->cfg->dev_name ? os_strlen(p2p->cfg->dev_name) : 0; - wpabuf_put_be16(buf, ATTR_DEV_NAME); - wpabuf_put_be16(buf, nlen); - wpabuf_put_data(buf, p2p->cfg->dev_name, nlen); - - /* Update attribute length */ - WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); - wpa_printf(MSG_DEBUG, "P2P: * Device Info"); -} - - -void p2p_buf_add_device_id(struct wpabuf *buf, const u8 *dev_addr) -{ - /* P2P Device ID */ - wpabuf_put_u8(buf, P2P_ATTR_DEVICE_ID); - wpabuf_put_le16(buf, ETH_ALEN); - wpabuf_put_data(buf, dev_addr, ETH_ALEN); - wpa_printf(MSG_DEBUG, "P2P: * Device ID: " MACSTR, MAC2STR(dev_addr)); -} - - -void p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout, - u8 client_timeout) -{ - /* Configuration Timeout */ - wpabuf_put_u8(buf, P2P_ATTR_CONFIGURATION_TIMEOUT); - wpabuf_put_le16(buf, 2); - wpabuf_put_u8(buf, go_timeout); - wpabuf_put_u8(buf, client_timeout); - wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout: GO %d (*10ms) " - "client %d (*10ms)", go_timeout, client_timeout); -} - - -void p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr) -{ - /* Intended P2P Interface Address */ - wpabuf_put_u8(buf, P2P_ATTR_INTENDED_INTERFACE_ADDR); - wpabuf_put_le16(buf, ETH_ALEN); - wpabuf_put_data(buf, interface_addr, ETH_ALEN); - wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address " MACSTR, - MAC2STR(interface_addr)); -} - - -void p2p_buf_add_group_bssid(struct wpabuf *buf, const u8 *bssid) -{ - /* P2P Group BSSID */ - wpabuf_put_u8(buf, P2P_ATTR_GROUP_BSSID); - wpabuf_put_le16(buf, ETH_ALEN); - wpabuf_put_data(buf, bssid, ETH_ALEN); - wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID " MACSTR, - MAC2STR(bssid)); -} - - -void p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr, - const u8 *ssid, size_t ssid_len) -{ - /* P2P Group ID */ - wpabuf_put_u8(buf, P2P_ATTR_GROUP_ID); - wpabuf_put_le16(buf, ETH_ALEN + ssid_len); - wpabuf_put_data(buf, dev_addr, ETH_ALEN); - wpabuf_put_data(buf, ssid, ssid_len); - wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR, - MAC2STR(dev_addr)); - wpa_hexdump_ascii(MSG_DEBUG, "P2P: P2P Group ID SSID", ssid, ssid_len); -} - - -void p2p_buf_add_invitation_flags(struct wpabuf *buf, u8 flags) -{ - /* Invitation Flags */ - wpabuf_put_u8(buf, P2P_ATTR_INVITATION_FLAGS); - wpabuf_put_le16(buf, 1); - wpabuf_put_u8(buf, flags); - wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", flags); -} - - -static void p2p_buf_add_noa_desc(struct wpabuf *buf, struct p2p_noa_desc *desc) -{ - if (desc == NULL) - return; - - wpabuf_put_u8(buf, desc->count_type); - wpabuf_put_le32(buf, desc->duration); - wpabuf_put_le32(buf, desc->interval); - wpabuf_put_le32(buf, desc->start_time); -} - - -void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow, - struct p2p_noa_desc *desc1, struct p2p_noa_desc *desc2) -{ - /* Notice of Absence */ - wpabuf_put_u8(buf, P2P_ATTR_NOTICE_OF_ABSENCE); - wpabuf_put_le16(buf, 2 + (desc1 ? 13 : 0) + (desc2 ? 13 : 0)); - wpabuf_put_u8(buf, noa_index); - wpabuf_put_u8(buf, (opp_ps ? 0x80 : 0) | (ctwindow & 0x7f)); - p2p_buf_add_noa_desc(buf, desc1); - p2p_buf_add_noa_desc(buf, desc2); - wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence"); -} - - -void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period, - u16 interval) -{ - /* Extended Listen Timing */ - wpabuf_put_u8(buf, P2P_ATTR_EXT_LISTEN_TIMING); - wpabuf_put_le16(buf, 4); - wpabuf_put_le16(buf, period); - wpabuf_put_le16(buf, interval); - wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing (period %u msec " - "interval %u msec)", period, interval); -} - - -void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p) -{ - /* P2P Interface */ - wpabuf_put_u8(buf, P2P_ATTR_INTERFACE); - wpabuf_put_le16(buf, ETH_ALEN + 1 + ETH_ALEN); - /* P2P Device address */ - wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); - /* - * FIX: Fetch interface address list from driver. Do not include - * the P2P Device address if it is never used as interface address. - */ - /* P2P Interface Address Count */ - wpabuf_put_u8(buf, 1); - wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); -} - - -void p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country, - u8 oper_class, u8 channel, - enum p2p_role_indication role) -{ - /* OOB Group Owner Negotiation Channel */ - wpabuf_put_u8(buf, P2P_ATTR_OOB_GO_NEG_CHANNEL); - wpabuf_put_le16(buf, 6); - wpabuf_put_data(buf, country, 3); - wpabuf_put_u8(buf, oper_class); /* Operating Class */ - wpabuf_put_u8(buf, channel); /* Channel Number */ - wpabuf_put_u8(buf, (u8) role); /* Role indication */ - wpa_printf(MSG_DEBUG, "P2P: * OOB GO Negotiation Channel: Operating " - "Class %u Channel %u Role %d", - oper_class, channel, role); -} - - -static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr, - const char *val) -{ - size_t len; - - len = val ? os_strlen(val) : 0; - if (wpabuf_tailroom(buf) < 4 + len) - return -1; - wpabuf_put_be16(buf, attr); -#ifndef CONFIG_WPS_STRICT - if (len == 0) { - /* - * Some deployed WPS implementations fail to parse zeor-length - * attributes. As a workaround, send a space character if the - * device attribute string is empty. - */ - if (wpabuf_tailroom(buf) < 3) - return -1; - wpabuf_put_be16(buf, 1); - wpabuf_put_u8(buf, ' '); - return 0; - } -#endif /* CONFIG_WPS_STRICT */ - wpabuf_put_be16(buf, len); - if (val) - wpabuf_put_data(buf, val, len); - return 0; -} - - -int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id, - int all_attr) -{ - u8 *len; - int i; - - if (wpabuf_tailroom(buf) < 6) - return -1; - wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); - len = wpabuf_put(buf, 1); - wpabuf_put_be32(buf, WPS_DEV_OUI_WFA); - - if (wps_build_version(buf) < 0) - return -1; - - if (all_attr) { - if (wpabuf_tailroom(buf) < 5) - return -1; - wpabuf_put_be16(buf, ATTR_WPS_STATE); - wpabuf_put_be16(buf, 1); - wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED); - } - - if (pw_id >= 0) { - if (wpabuf_tailroom(buf) < 6) - return -1; - /* Device Password ID */ - wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID); - wpabuf_put_be16(buf, 2); - wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d", - pw_id); - wpabuf_put_be16(buf, pw_id); - } - - if (all_attr) { - if (wpabuf_tailroom(buf) < 5) - return -1; - wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE); - wpabuf_put_be16(buf, 1); - wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO); - - if (wps_build_uuid_e(buf, p2p->cfg->uuid) < 0 || - p2p_add_wps_string(buf, ATTR_MANUFACTURER, - p2p->cfg->manufacturer) < 0 || - p2p_add_wps_string(buf, ATTR_MODEL_NAME, - p2p->cfg->model_name) < 0 || - p2p_add_wps_string(buf, ATTR_MODEL_NUMBER, - p2p->cfg->model_number) < 0 || - p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER, - p2p->cfg->serial_number) < 0) - return -1; - - if (wpabuf_tailroom(buf) < 4 + WPS_DEV_TYPE_LEN) - return -1; - wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE); - wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN); - wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN); - - if (p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name) - < 0) - return -1; - - if (wpabuf_tailroom(buf) < 6) - return -1; - wpabuf_put_be16(buf, ATTR_CONFIG_METHODS); - wpabuf_put_be16(buf, 2); - wpabuf_put_be16(buf, p2p->cfg->config_methods); - } - - if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0) - return -1; - - if (all_attr && p2p->cfg->num_sec_dev_types) { - if (wpabuf_tailroom(buf) < - 4 + WPS_DEV_TYPE_LEN * p2p->cfg->num_sec_dev_types) - return -1; - wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST); - wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN * - p2p->cfg->num_sec_dev_types); - wpabuf_put_data(buf, p2p->cfg->sec_dev_type, - WPS_DEV_TYPE_LEN * - p2p->cfg->num_sec_dev_types); - } - - /* Add the WPS vendor extensions */ - for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { - if (p2p->wps_vendor_ext[i] == NULL) - break; - if (wpabuf_tailroom(buf) < - 4 + wpabuf_len(p2p->wps_vendor_ext[i])) - continue; - wpabuf_put_be16(buf, ATTR_VENDOR_EXT); - wpabuf_put_be16(buf, wpabuf_len(p2p->wps_vendor_ext[i])); - wpabuf_put_buf(buf, p2p->wps_vendor_ext[i]); - } - - p2p_buf_update_ie_hdr(buf, len); - - return 0; -} diff --git a/contrib/hostapd/src/p2p/p2p_dev_disc.c b/contrib/hostapd/src/p2p/p2p_dev_disc.c deleted file mode 100644 index 76d01cfc61..0000000000 --- a/contrib/hostapd/src/p2p/p2p_dev_disc.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Wi-Fi Direct - P2P Device Discoverability procedure - * Copyright (c) 2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "common/ieee802_11_defs.h" -#include "p2p_i.h" -#include "p2p.h" - - -static struct wpabuf * p2p_build_dev_disc_req(struct p2p_data *p2p, - struct p2p_device *go, - const u8 *dev_id) -{ - struct wpabuf *buf; - u8 *len; - - buf = wpabuf_alloc(100); - if (buf == NULL) - return NULL; - - go->dialog_token++; - if (go->dialog_token == 0) - go->dialog_token = 1; - p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_REQ, go->dialog_token); - - len = p2p_buf_add_ie_hdr(buf); - p2p_buf_add_device_id(buf, dev_id); - p2p_buf_add_group_id(buf, go->info.p2p_device_addr, go->oper_ssid, - go->oper_ssid_len); - p2p_buf_update_ie_hdr(buf, len); - - return buf; -} - - -void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success) -{ - p2p_dbg(p2p, "Device Discoverability Request TX callback: success=%d", - success); - - if (!success) { - /* - * Use P2P find, if needed, to find the other device or to - * retry device discoverability. - */ - p2p_set_state(p2p, P2P_CONNECT); - p2p_set_timeout(p2p, 0, 100000); - return; - } - - p2p_dbg(p2p, "GO acknowledged Device Discoverability Request - wait for response"); - /* - * TODO: is the remain-on-channel from Action frame TX long enough for - * most cases or should we try to increase its duration and/or start - * another remain-on-channel if needed once the previous one expires? - */ -} - - -int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev) -{ - struct p2p_device *go; - struct wpabuf *req; - - go = p2p_get_device(p2p, dev->member_in_go_dev); - if (go == NULL || dev->oper_freq <= 0) { - p2p_dbg(p2p, "Could not find peer entry for GO and frequency to send Device Discoverability Request"); - return -1; - } - - req = p2p_build_dev_disc_req(p2p, go, dev->info.p2p_device_addr); - if (req == NULL) - return -1; - - p2p_dbg(p2p, "Sending Device Discoverability Request to GO " MACSTR - " for client " MACSTR, - MAC2STR(go->info.p2p_device_addr), - MAC2STR(dev->info.p2p_device_addr)); - - p2p->pending_client_disc_go = go; - os_memcpy(p2p->pending_client_disc_addr, dev->info.p2p_device_addr, - ETH_ALEN); - p2p->pending_action_state = P2P_PENDING_DEV_DISC_REQUEST; - if (p2p_send_action(p2p, dev->oper_freq, go->info.p2p_device_addr, - p2p->cfg->dev_addr, go->info.p2p_device_addr, - wpabuf_head(req), wpabuf_len(req), 1000) < 0) { - p2p_dbg(p2p, "Failed to send Action frame"); - wpabuf_free(req); - /* TODO: how to recover from failure? */ - return -1; - } - - wpabuf_free(req); - - return 0; -} - - -static struct wpabuf * p2p_build_dev_disc_resp(u8 dialog_token, u8 status) -{ - struct wpabuf *buf; - u8 *len; - - buf = wpabuf_alloc(100); - if (buf == NULL) - return NULL; - - p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_RESP, dialog_token); - - len = p2p_buf_add_ie_hdr(buf); - p2p_buf_add_status(buf, status); - p2p_buf_update_ie_hdr(buf, len); - - return buf; -} - - -void p2p_dev_disc_resp_cb(struct p2p_data *p2p, int success) -{ - p2p_dbg(p2p, "Device Discoverability Response TX callback: success=%d", - success); - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -} - - -static void p2p_send_dev_disc_resp(struct p2p_data *p2p, u8 dialog_token, - const u8 *addr, int freq, u8 status) -{ - struct wpabuf *resp; - - resp = p2p_build_dev_disc_resp(dialog_token, status); - if (resp == NULL) - return; - - p2p_dbg(p2p, "Sending Device Discoverability Response to " MACSTR - " (status %u freq %d)", - MAC2STR(addr), status, freq); - - p2p->pending_action_state = P2P_PENDING_DEV_DISC_RESPONSE; - if (p2p_send_action(p2p, freq, addr, p2p->cfg->dev_addr, - p2p->cfg->dev_addr, - wpabuf_head(resp), wpabuf_len(resp), 200) < 0) { - p2p_dbg(p2p, "Failed to send Action frame"); - } - - wpabuf_free(resp); -} - - -void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) -{ - struct p2p_message msg; - size_t g; - - p2p_dbg(p2p, "Received Device Discoverability Request from " MACSTR - " (freq=%d)", MAC2STR(sa), rx_freq); - - if (p2p_parse(data, len, &msg)) - return; - - if (msg.dialog_token == 0) { - p2p_dbg(p2p, "Invalid Dialog Token 0 (must be nonzero) in Device Discoverability Request"); - p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq, - P2P_SC_FAIL_INVALID_PARAMS); - p2p_parse_free(&msg); - return; - } - - if (msg.device_id == NULL) { - p2p_dbg(p2p, "P2P Device ID attribute missing from Device Discoverability Request"); - p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq, - P2P_SC_FAIL_INVALID_PARAMS); - p2p_parse_free(&msg); - return; - } - - for (g = 0; g < p2p->num_groups; g++) { - if (p2p_group_go_discover(p2p->groups[g], msg.device_id, sa, - rx_freq) == 0) { - p2p_dbg(p2p, "Scheduled GO Discoverability Request for the target device"); - /* - * P2P group code will use a callback to indicate TX - * status, so that we can reply to the request once the - * target client has acknowledged the request or it has - * timed out. - */ - p2p->pending_dev_disc_dialog_token = msg.dialog_token; - os_memcpy(p2p->pending_dev_disc_addr, sa, ETH_ALEN); - p2p->pending_dev_disc_freq = rx_freq; - p2p_parse_free(&msg); - return; - } - } - - p2p_dbg(p2p, "Requested client was not found in any group or did not support client discoverability"); - p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq, - P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE); - p2p_parse_free(&msg); -} - - -void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len) -{ - struct p2p_message msg; - struct p2p_device *go; - u8 status; - - p2p_dbg(p2p, "Received Device Discoverability Response from " MACSTR, - MAC2STR(sa)); - - go = p2p->pending_client_disc_go; - if (go == NULL || - os_memcmp(sa, go->info.p2p_device_addr, ETH_ALEN) != 0) { - p2p_dbg(p2p, "Ignore unexpected Device Discoverability Response"); - return; - } - - if (p2p_parse(data, len, &msg)) - return; - - if (msg.status == NULL) { - p2p_parse_free(&msg); - return; - } - - if (msg.dialog_token != go->dialog_token) { - p2p_dbg(p2p, "Ignore Device Discoverability Response with unexpected dialog token %u (expected %u)", - msg.dialog_token, go->dialog_token); - p2p_parse_free(&msg); - return; - } - - status = *msg.status; - p2p_parse_free(&msg); - - p2p_dbg(p2p, "Device Discoverability Response status %u", status); - - if (p2p->go_neg_peer == NULL || - os_memcmp(p2p->pending_client_disc_addr, - p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN) != 0 || - os_memcmp(p2p->go_neg_peer->member_in_go_dev, - go->info.p2p_device_addr, ETH_ALEN) != 0) { - p2p_dbg(p2p, "No pending operation with the client discoverability peer anymore"); - return; - } - - if (status == 0) { - /* - * Peer is expected to be awake for at least 100 TU; try to - * connect immediately. - */ - p2p_dbg(p2p, "Client discoverability request succeeded"); - if (p2p->state == P2P_CONNECT) { - /* - * Change state to force the timeout to start in - * P2P_CONNECT again without going through the short - * Listen state. - */ - p2p_set_state(p2p, P2P_CONNECT_LISTEN); - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - } - p2p_set_timeout(p2p, 0, 0); - } else { - /* - * Client discoverability request failed; try to connect from - * timeout. - */ - p2p_dbg(p2p, "Client discoverability request failed"); - p2p_set_timeout(p2p, 0, 500000); - } - -} - - -void p2p_go_disc_req_cb(struct p2p_data *p2p, int success) -{ - p2p_dbg(p2p, "GO Discoverability Request TX callback: success=%d", - success); - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - - if (p2p->pending_dev_disc_dialog_token == 0) { - p2p_dbg(p2p, "No pending Device Discoverability Request"); - return; - } - - p2p_send_dev_disc_resp(p2p, p2p->pending_dev_disc_dialog_token, - p2p->pending_dev_disc_addr, - p2p->pending_dev_disc_freq, - success ? P2P_SC_SUCCESS : - P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE); - - p2p->pending_dev_disc_dialog_token = 0; -} - - -void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa, - const u8 *data, size_t len, int rx_freq) -{ - unsigned int tu; - struct wpabuf *ies; - - p2p_dbg(p2p, "Received GO Discoverability Request - remain awake for 100 TU"); - - ies = p2p_build_probe_resp_ies(p2p); - if (ies == NULL) - return; - - /* Remain awake 100 TU on operating channel */ - p2p->pending_client_disc_freq = rx_freq; - tu = 100; - if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, rx_freq, 1024 * tu / 1000, - ies) < 0) { - p2p_dbg(p2p, "Failed to start listen mode for client discoverability"); - } - wpabuf_free(ies); -} diff --git a/contrib/hostapd/src/p2p/p2p_go_neg.c b/contrib/hostapd/src/p2p/p2p_go_neg.c deleted file mode 100644 index e28f93ea2b..0000000000 --- a/contrib/hostapd/src/p2p/p2p_go_neg.c +++ /dev/null @@ -1,1223 +0,0 @@ -/* - * Wi-Fi Direct - P2P Group Owner Negotiation - * Copyright (c) 2009-2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "common/ieee802_11_defs.h" -#include "wps/wps_defs.h" -#include "p2p_i.h" -#include "p2p.h" - - -static int p2p_go_det(u8 own_intent, u8 peer_value) -{ - u8 peer_intent = peer_value >> 1; - if (own_intent == peer_intent) { - if (own_intent == P2P_MAX_GO_INTENT) - return -1; /* both devices want to become GO */ - - /* Use tie breaker bit to determine GO */ - return (peer_value & 0x01) ? 0 : 1; - } - - return own_intent > peer_intent; -} - - -int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own, - struct p2p_device *dev, - const u8 *channel_list, size_t channel_list_len) -{ - const u8 *pos, *end; - struct p2p_channels *ch; - size_t channels; - struct p2p_channels intersection; - - ch = &dev->channels; - os_memset(ch, 0, sizeof(*ch)); - pos = channel_list; - end = channel_list + channel_list_len; - - if (end - pos < 3) - return -1; - os_memcpy(dev->country, pos, 3); - wpa_hexdump_ascii(MSG_DEBUG, "P2P: Peer country", pos, 3); - if (pos[2] != 0x04 && os_memcmp(pos, p2p->cfg->country, 2) != 0) { - p2p_info(p2p, "Mismatching country (ours=%c%c peer's=%c%c)", - p2p->cfg->country[0], p2p->cfg->country[1], - pos[0], pos[1]); - return -1; - } - pos += 3; - - while (pos + 2 < end) { - struct p2p_reg_class *cl = &ch->reg_class[ch->reg_classes]; - cl->reg_class = *pos++; - if (pos + 1 + pos[0] > end) { - p2p_info(p2p, "Invalid peer Channel List"); - return -1; - } - channels = *pos++; - cl->channels = channels > P2P_MAX_REG_CLASS_CHANNELS ? - P2P_MAX_REG_CLASS_CHANNELS : channels; - os_memcpy(cl->channel, pos, cl->channels); - pos += channels; - ch->reg_classes++; - if (ch->reg_classes == P2P_MAX_REG_CLASSES) - break; - } - - p2p_channels_intersect(own, &dev->channels, &intersection); - p2p_dbg(p2p, "Own reg_classes %d peer reg_classes %d intersection reg_classes %d", - (int) own->reg_classes, - (int) dev->channels.reg_classes, - (int) intersection.reg_classes); - if (intersection.reg_classes == 0) { - p2p_info(p2p, "No common channels found"); - return -1; - } - return 0; -} - - -static int p2p_peer_channels(struct p2p_data *p2p, struct p2p_device *dev, - const u8 *channel_list, size_t channel_list_len) -{ - return p2p_peer_channels_check(p2p, &p2p->channels, dev, - channel_list, channel_list_len); -} - - -u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method) -{ - switch (wps_method) { - case WPS_PIN_DISPLAY: - return DEV_PW_REGISTRAR_SPECIFIED; - case WPS_PIN_KEYPAD: - return DEV_PW_USER_SPECIFIED; - case WPS_PBC: - return DEV_PW_PUSHBUTTON; - case WPS_NFC: - return DEV_PW_NFC_CONNECTION_HANDOVER; - default: - return DEV_PW_DEFAULT; - } -} - - -static const char * p2p_wps_method_str(enum p2p_wps_method wps_method) -{ - switch (wps_method) { - case WPS_PIN_DISPLAY: - return "Display"; - case WPS_PIN_KEYPAD: - return "Keypad"; - case WPS_PBC: - return "PBC"; - case WPS_NFC: - return "NFC"; - default: - return "??"; - } -} - - -static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, - struct p2p_device *peer) -{ - struct wpabuf *buf; - u8 *len; - u8 group_capab; - size_t extra = 0; - u16 pw_id; - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p->wfd_ie_go_neg) - extra = wpabuf_len(p2p->wfd_ie_go_neg); -#endif /* CONFIG_WIFI_DISPLAY */ - - buf = wpabuf_alloc(1000 + extra); - if (buf == NULL) - return NULL; - - p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_REQ, peer->dialog_token); - - len = p2p_buf_add_ie_hdr(buf); - group_capab = 0; - 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) - group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; - p2p_buf_add_capability(buf, p2p->dev_capab & - ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, - group_capab); - p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | peer->tie_breaker); - p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout); - p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class, - p2p->cfg->channel); - if (p2p->ext_listen_interval) - p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period, - p2p->ext_listen_interval); - p2p_buf_add_intended_addr(buf, p2p->intended_addr); - p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels); - p2p_buf_add_device_info(buf, p2p, peer); - p2p_buf_add_operating_channel(buf, p2p->cfg->country, - p2p->op_reg_class, p2p->op_channel); - p2p_buf_update_ie_hdr(buf, len); - - /* WPS IE with Device Password ID attribute */ - pw_id = p2p_wps_method_pw_id(peer->wps_method); - if (peer->oob_pw_id) - pw_id = peer->oob_pw_id; - if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) { - p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Request"); - wpabuf_free(buf); - return NULL; - } - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p->wfd_ie_go_neg) - wpabuf_put_buf(buf, p2p->wfd_ie_go_neg); -#endif /* CONFIG_WIFI_DISPLAY */ - - return buf; -} - - -int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev) -{ - struct wpabuf *req; - int freq; - - if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) { - u16 config_method; - p2p_dbg(p2p, "Use PD-before-GO-Neg workaround for " MACSTR, - MAC2STR(dev->info.p2p_device_addr)); - if (dev->wps_method == WPS_PIN_DISPLAY) - config_method = WPS_CONFIG_KEYPAD; - else if (dev->wps_method == WPS_PIN_KEYPAD) - config_method = WPS_CONFIG_DISPLAY; - else if (dev->wps_method == WPS_PBC) - config_method = WPS_CONFIG_PUSHBUTTON; - else - return -1; - return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr, - config_method, 0, 0, 1); - } - - freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; - if (dev->oob_go_neg_freq > 0) - freq = dev->oob_go_neg_freq; - if (freq <= 0) { - p2p_dbg(p2p, "No Listen/Operating frequency known for the peer " - MACSTR " to send GO Negotiation Request", - MAC2STR(dev->info.p2p_device_addr)); - return -1; - } - - req = p2p_build_go_neg_req(p2p, dev); - if (req == NULL) - return -1; - p2p_dbg(p2p, "Sending GO Negotiation Request"); - p2p_set_state(p2p, P2P_CONNECT); - p2p->pending_action_state = P2P_PENDING_GO_NEG_REQUEST; - p2p->go_neg_peer = dev; - dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE; - dev->connect_reqs++; - if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, - p2p->cfg->dev_addr, dev->info.p2p_device_addr, - wpabuf_head(req), wpabuf_len(req), 500) < 0) { - p2p_dbg(p2p, "Failed to send Action frame"); - /* Use P2P find to recover and retry */ - p2p_set_timeout(p2p, 0, 0); - } else - dev->go_neg_req_sent++; - - wpabuf_free(req); - - return 0; -} - - -static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, - struct p2p_device *peer, - u8 dialog_token, u8 status, - u8 tie_breaker) -{ - struct wpabuf *buf; - u8 *len; - u8 group_capab; - size_t extra = 0; - u16 pw_id; - - p2p_dbg(p2p, "Building GO Negotiation Response"); - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p->wfd_ie_go_neg) - extra = wpabuf_len(p2p->wfd_ie_go_neg); -#endif /* CONFIG_WIFI_DISPLAY */ - - buf = wpabuf_alloc(1000 + extra); - if (buf == NULL) - return NULL; - - p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_RESP, dialog_token); - - len = p2p_buf_add_ie_hdr(buf); - p2p_buf_add_status(buf, status); - group_capab = 0; - if (peer && peer->go_state == LOCAL_GO) { - 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) - group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; - } - p2p_buf_add_capability(buf, p2p->dev_capab & - ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, - group_capab); - p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker); - p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout); - if (peer && peer->go_state == REMOTE_GO) { - p2p_dbg(p2p, "Omit Operating Channel attribute"); - } else { - p2p_buf_add_operating_channel(buf, p2p->cfg->country, - p2p->op_reg_class, - p2p->op_channel); - } - p2p_buf_add_intended_addr(buf, p2p->intended_addr); - if (status || peer == NULL) { - p2p_buf_add_channel_list(buf, p2p->cfg->country, - &p2p->channels); - } else if (peer->go_state == REMOTE_GO) { - p2p_buf_add_channel_list(buf, p2p->cfg->country, - &p2p->channels); - } else { - struct p2p_channels res; - p2p_channels_intersect(&p2p->channels, &peer->channels, - &res); - p2p_buf_add_channel_list(buf, p2p->cfg->country, &res); - } - p2p_buf_add_device_info(buf, p2p, peer); - if (peer && peer->go_state == LOCAL_GO) { - p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid, - p2p->ssid_len); - } - p2p_buf_update_ie_hdr(buf, len); - - /* WPS IE with Device Password ID attribute */ - pw_id = p2p_wps_method_pw_id(peer ? peer->wps_method : WPS_NOT_READY); - if (peer && peer->oob_pw_id) - pw_id = peer->oob_pw_id; - if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) { - p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Response"); - wpabuf_free(buf); - return NULL; - } - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p->wfd_ie_go_neg) - wpabuf_put_buf(buf, p2p->wfd_ie_go_neg); -#endif /* CONFIG_WIFI_DISPLAY */ - - - return buf; -} - - -/** - * p2p_reselect_channel - Re-select operating channel based on peer information - * @p2p: P2P module context from p2p_init() - * @intersection: Support channel list intersection from local and peer - * - * This function is used to re-select the best channel after having received - * information from the peer to allow supported channel lists to be intersected. - * This can be used to improve initial channel selection done in - * p2p_prepare_channel() prior to the start of GO Negotiation. In addition, this - * can be used for Invitation case. - */ -void p2p_reselect_channel(struct p2p_data *p2p, - struct p2p_channels *intersection) -{ - struct p2p_reg_class *cl; - int freq; - u8 op_reg_class, op_channel; - unsigned int i; - const int op_classes_5ghz[] = { 124, 115, 0 }; - const int op_classes_ht40[] = { 126, 127, 116, 117, 0 }; - const int op_classes_vht[] = { 128, 0 }; - - if (p2p->own_freq_preference > 0 && - p2p_freq_to_channel(p2p->own_freq_preference, - &op_reg_class, &op_channel) == 0 && - p2p_channels_includes(intersection, op_reg_class, op_channel)) { - p2p_dbg(p2p, "Pick own channel preference (reg_class %u channel %u) from intersection", - op_reg_class, op_channel); - p2p->op_reg_class = op_reg_class; - p2p->op_channel = op_channel; - return; - } - - if (p2p->best_freq_overall > 0 && - p2p_freq_to_channel(p2p->best_freq_overall, - &op_reg_class, &op_channel) == 0 && - p2p_channels_includes(intersection, op_reg_class, op_channel)) { - p2p_dbg(p2p, "Pick best overall channel (reg_class %u channel %u) from intersection", - op_reg_class, op_channel); - p2p->op_reg_class = op_reg_class; - p2p->op_channel = op_channel; - return; - } - - /* First, try to pick the best channel from another band */ - freq = p2p_channel_to_freq(p2p->op_reg_class, p2p->op_channel); - if (freq >= 2400 && freq < 2500 && p2p->best_freq_5 > 0 && - !p2p_channels_includes(intersection, p2p->op_reg_class, - p2p->op_channel) && - p2p_freq_to_channel(p2p->best_freq_5, - &op_reg_class, &op_channel) == 0 && - p2p_channels_includes(intersection, op_reg_class, op_channel)) { - p2p_dbg(p2p, "Pick best 5 GHz channel (reg_class %u channel %u) from intersection", - op_reg_class, op_channel); - p2p->op_reg_class = op_reg_class; - p2p->op_channel = op_channel; - return; - } - - if (freq >= 4900 && freq < 6000 && p2p->best_freq_24 > 0 && - !p2p_channels_includes(intersection, p2p->op_reg_class, - p2p->op_channel) && - p2p_freq_to_channel(p2p->best_freq_24, - &op_reg_class, &op_channel) == 0 && - p2p_channels_includes(intersection, op_reg_class, op_channel)) { - p2p_dbg(p2p, "Pick best 2.4 GHz channel (reg_class %u channel %u) from intersection", - op_reg_class, op_channel); - p2p->op_reg_class = op_reg_class; - p2p->op_channel = op_channel; - return; - } - - /* Select channel with highest preference if the peer supports it */ - for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) { - if (p2p_channels_includes(intersection, - p2p->cfg->pref_chan[i].op_class, - p2p->cfg->pref_chan[i].chan)) { - p2p->op_reg_class = p2p->cfg->pref_chan[i].op_class; - p2p->op_channel = p2p->cfg->pref_chan[i].chan; - p2p_dbg(p2p, "Pick highest preferred channel (op_class %u channel %u) from intersection", - p2p->op_reg_class, p2p->op_channel); - return; - } - } - - /* Try a channel where we might be able to use VHT */ - if (p2p_channel_select(intersection, op_classes_vht, - &p2p->op_reg_class, &p2p->op_channel) == 0) { - p2p_dbg(p2p, "Pick possible VHT channel (op_class %u channel %u) from intersection", - p2p->op_reg_class, p2p->op_channel); - return; - } - - /* Try a channel where we might be able to use HT40 */ - if (p2p_channel_select(intersection, op_classes_ht40, - &p2p->op_reg_class, &p2p->op_channel) == 0) { - p2p_dbg(p2p, "Pick possible HT40 channel (op_class %u channel %u) from intersection", - p2p->op_reg_class, p2p->op_channel); - return; - } - - /* Prefer a 5 GHz channel */ - if (p2p_channel_select(intersection, op_classes_5ghz, - &p2p->op_reg_class, &p2p->op_channel) == 0) { - p2p_dbg(p2p, "Pick possible 5 GHz channel (op_class %u channel %u) from intersection", - p2p->op_reg_class, p2p->op_channel); - return; - } - - /* - * Try to see if the original channel is in the intersection. If - * so, no need to change anything, as it already contains some - * randomness. - */ - if (p2p_channels_includes(intersection, p2p->op_reg_class, - p2p->op_channel)) { - p2p_dbg(p2p, "Using original operating class and channel (op_class %u channel %u) from intersection", - p2p->op_reg_class, p2p->op_channel); - return; - } - - /* - * Fall back to whatever is included in the channel intersection since - * no better options seems to be available. - */ - cl = &intersection->reg_class[0]; - p2p_dbg(p2p, "Pick another channel (reg_class %u channel %u) from intersection", - cl->reg_class, cl->channel[0]); - p2p->op_reg_class = cl->reg_class; - p2p->op_channel = cl->channel[0]; -} - - -static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev, - u8 *status) -{ - struct p2p_channels tmp, intersection; - - p2p_channels_dump(p2p, "own channels", &p2p->channels); - p2p_channels_dump(p2p, "peer channels", &dev->channels); - p2p_channels_intersect(&p2p->channels, &dev->channels, &tmp); - p2p_channels_dump(p2p, "intersection", &tmp); - p2p_channels_remove_freqs(&tmp, &p2p->no_go_freq); - p2p_channels_dump(p2p, "intersection after no-GO removal", &tmp); - p2p_channels_intersect(&tmp, &p2p->cfg->channels, &intersection); - p2p_channels_dump(p2p, "intersection with local channel list", - &intersection); - if (intersection.reg_classes == 0 || - intersection.reg_class[0].channels == 0) { - *status = P2P_SC_FAIL_NO_COMMON_CHANNELS; - p2p_dbg(p2p, "No common channels found"); - return -1; - } - - if (!p2p_channels_includes(&intersection, p2p->op_reg_class, - p2p->op_channel)) { - if (dev->flags & P2P_DEV_FORCE_FREQ) { - *status = P2P_SC_FAIL_NO_COMMON_CHANNELS; - p2p_dbg(p2p, "Peer does not support the forced channel"); - return -1; - } - - p2p_dbg(p2p, "Selected operating channel (op_class %u channel %u) not acceptable to the peer", - p2p->op_reg_class, p2p->op_channel); - p2p_reselect_channel(p2p, &intersection); - } else if (!(dev->flags & P2P_DEV_FORCE_FREQ) && - !p2p->cfg->cfg_op_channel) { - p2p_dbg(p2p, "Try to optimize channel selection with peer information received; previously selected op_class %u channel %u", - p2p->op_reg_class, p2p->op_channel); - p2p_reselect_channel(p2p, &intersection); - } - - if (!p2p->ssid_set) { - p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len); - p2p->ssid_set = 1; - } - - return 0; -} - - -void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) -{ - struct p2p_device *dev = NULL; - struct wpabuf *resp; - struct p2p_message msg; - u8 status = P2P_SC_FAIL_INVALID_PARAMS; - int tie_breaker = 0; - int freq; - - p2p_dbg(p2p, "Received GO Negotiation Request from " MACSTR "(freq=%d)", - MAC2STR(sa), rx_freq); - - if (p2p_parse(data, len, &msg)) - return; - - if (!msg.capability) { - p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Request"); -#ifdef CONFIG_P2P_STRICT - goto fail; -#endif /* CONFIG_P2P_STRICT */ - } - - if (msg.go_intent) - tie_breaker = *msg.go_intent & 0x01; - else { - p2p_dbg(p2p, "Mandatory GO Intent attribute missing from GO Negotiation Request"); -#ifdef CONFIG_P2P_STRICT - goto fail; -#endif /* CONFIG_P2P_STRICT */ - } - - if (!msg.config_timeout) { - p2p_dbg(p2p, "Mandatory Configuration Timeout attribute missing from GO Negotiation Request"); -#ifdef CONFIG_P2P_STRICT - goto fail; -#endif /* CONFIG_P2P_STRICT */ - } - - if (!msg.listen_channel) { - p2p_dbg(p2p, "No Listen Channel attribute received"); - goto fail; - } - if (!msg.operating_channel) { - p2p_dbg(p2p, "No Operating Channel attribute received"); - goto fail; - } - if (!msg.channel_list) { - p2p_dbg(p2p, "No Channel List attribute received"); - goto fail; - } - if (!msg.intended_addr) { - p2p_dbg(p2p, "No Intended P2P Interface Address attribute received"); - goto fail; - } - if (!msg.p2p_device_info) { - p2p_dbg(p2p, "No P2P Device Info attribute received"); - goto fail; - } - - if (os_memcmp(msg.p2p_device_addr, sa, ETH_ALEN) != 0) { - p2p_dbg(p2p, "Unexpected GO Negotiation Request SA=" MACSTR - " != dev_addr=" MACSTR, - MAC2STR(sa), MAC2STR(msg.p2p_device_addr)); - goto fail; - } - - dev = p2p_get_device(p2p, sa); - - if (msg.status && *msg.status) { - p2p_dbg(p2p, "Unexpected Status attribute (%d) in GO Negotiation Request", - *msg.status); - goto fail; - } - - if (dev == NULL) - dev = p2p_add_dev_from_go_neg_req(p2p, sa, &msg); - else if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) - p2p_add_dev_info(p2p, sa, dev, &msg); - else if (!dev->listen_freq && !dev->oper_freq) { - /* - * This may happen if the peer entry was added based on PD - * Request and no Probe Request/Response frame has been received - * from this peer (or that information has timed out). - */ - p2p_dbg(p2p, "Update peer " MACSTR - " based on GO Neg Req since listen/oper freq not known", - MAC2STR(dev->info.p2p_device_addr)); - p2p_add_dev_info(p2p, sa, dev, &msg); - } - - if (dev && dev->flags & P2P_DEV_USER_REJECTED) { - p2p_dbg(p2p, "User has rejected this peer"); - status = P2P_SC_FAIL_REJECTED_BY_USER; - } else if (dev == NULL || - (dev->wps_method == WPS_NOT_READY && - (p2p->authorized_oob_dev_pw_id == 0 || - p2p->authorized_oob_dev_pw_id != - msg.dev_password_id))) { - p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR, - MAC2STR(sa)); - status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; - p2p->cfg->go_neg_req_rx(p2p->cfg->cb_ctx, sa, - msg.dev_password_id); - } else if (p2p->go_neg_peer && p2p->go_neg_peer != dev) { - p2p_dbg(p2p, "Already in Group Formation with another peer"); - status = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; - } else { - int go; - - if (!p2p->go_neg_peer) { - p2p_dbg(p2p, "Starting GO Negotiation with previously authorized peer"); - if (!(dev->flags & P2P_DEV_FORCE_FREQ)) { - p2p_dbg(p2p, "Use default channel settings"); - p2p->op_reg_class = p2p->cfg->op_reg_class; - p2p->op_channel = p2p->cfg->op_channel; - os_memcpy(&p2p->channels, &p2p->cfg->channels, - sizeof(struct p2p_channels)); - } else { - p2p_dbg(p2p, "Use previously configured forced channel settings"); - } - } - - dev->flags &= ~P2P_DEV_NOT_YET_READY; - - if (!msg.go_intent) { - p2p_dbg(p2p, "No GO Intent attribute received"); - goto fail; - } - if ((*msg.go_intent >> 1) > P2P_MAX_GO_INTENT) { - p2p_dbg(p2p, "Invalid GO Intent value (%u) received", - *msg.go_intent >> 1); - goto fail; - } - - if (dev->go_neg_req_sent && - os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) { - p2p_dbg(p2p, "Do not reply since peer has higher address and GO Neg Request already sent"); - p2p_parse_free(&msg); - return; - } - - go = p2p_go_det(p2p->go_intent, *msg.go_intent); - if (go < 0) { - p2p_dbg(p2p, "Incompatible GO Intent"); - status = P2P_SC_FAIL_BOTH_GO_INTENT_15; - goto fail; - } - - if (p2p_peer_channels(p2p, dev, msg.channel_list, - msg.channel_list_len) < 0) { - p2p_dbg(p2p, "No common channels found"); - status = P2P_SC_FAIL_NO_COMMON_CHANNELS; - goto fail; - } - - switch (msg.dev_password_id) { - case DEV_PW_REGISTRAR_SPECIFIED: - p2p_dbg(p2p, "PIN from peer Display"); - if (dev->wps_method != WPS_PIN_KEYPAD) { - p2p_dbg(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_USER_SPECIFIED: - p2p_dbg(p2p, "Peer entered PIN on Keypad"); - if (dev->wps_method != WPS_PIN_DISPLAY) { - p2p_dbg(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_PUSHBUTTON: - p2p_dbg(p2p, "Peer using pushbutton"); - if (dev->wps_method != WPS_PBC) { - p2p_dbg(p2p, "We have wps_method=%s -> incompatible", - p2p_wps_method_str(dev->wps_method)); - status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; - goto fail; - } - break; - default: - if (msg.dev_password_id && - msg.dev_password_id == dev->oob_pw_id) { - p2p_dbg(p2p, "Peer using NFC"); - if (dev->wps_method != WPS_NFC) { - p2p_dbg(p2p, "We have wps_method=%s -> incompatible", - p2p_wps_method_str( - dev->wps_method)); - status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; - goto fail; - } - break; - } -#ifdef CONFIG_WPS_NFC - if (p2p->authorized_oob_dev_pw_id && - msg.dev_password_id == - p2p->authorized_oob_dev_pw_id) { - p2p_dbg(p2p, "Using static handover with our device password from NFC Tag"); - dev->wps_method = WPS_NFC; - dev->oob_pw_id = p2p->authorized_oob_dev_pw_id; - break; - } -#endif /* CONFIG_WPS_NFC */ - p2p_dbg(p2p, "Unsupported Device Password ID %d", - msg.dev_password_id); - status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; - goto fail; - } - - if (go && p2p_go_select_channel(p2p, dev, &status) < 0) - goto fail; - - dev->go_state = go ? LOCAL_GO : REMOTE_GO; - dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3], - msg.operating_channel[4]); - p2p_dbg(p2p, "Peer operating channel preference: %d MHz", - dev->oper_freq); - - if (msg.config_timeout) { - dev->go_timeout = msg.config_timeout[0]; - dev->client_timeout = msg.config_timeout[1]; - } - - p2p_dbg(p2p, "GO Negotiation with " MACSTR, MAC2STR(sa)); - if (p2p->state != P2P_IDLE) - p2p_stop_find_for_freq(p2p, rx_freq); - p2p_set_state(p2p, P2P_GO_NEG); - p2p_clear_timeout(p2p); - dev->dialog_token = msg.dialog_token; - os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN); - p2p->go_neg_peer = dev; - status = P2P_SC_SUCCESS; - } - -fail: - if (dev) - dev->status = status; - resp = p2p_build_go_neg_resp(p2p, dev, msg.dialog_token, status, - !tie_breaker); - p2p_parse_free(&msg); - if (resp == NULL) - return; - p2p_dbg(p2p, "Sending GO Negotiation Response"); - if (rx_freq > 0) - freq = rx_freq; - else - freq = p2p_channel_to_freq(p2p->cfg->reg_class, - p2p->cfg->channel); - if (freq < 0) { - p2p_dbg(p2p, "Unknown regulatory class/channel"); - wpabuf_free(resp); - return; - } - if (status == P2P_SC_SUCCESS) { - p2p->pending_action_state = P2P_PENDING_GO_NEG_RESPONSE; - dev->flags |= P2P_DEV_WAIT_GO_NEG_CONFIRM; - if (os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) < 0) { - /* - * Peer has smaller address, so the GO Negotiation - * Response from us is expected to complete - * negotiation. Ignore a GO Negotiation Response from - * the peer if it happens to be received after this - * point due to a race condition in GO Negotiation - * Request transmission and processing. - */ - dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE; - } - } else - p2p->pending_action_state = - P2P_PENDING_GO_NEG_RESPONSE_FAILURE; - if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, - p2p->cfg->dev_addr, - wpabuf_head(resp), wpabuf_len(resp), 500) < 0) { - p2p_dbg(p2p, "Failed to send Action frame"); - } - - wpabuf_free(resp); -} - - -static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, - struct p2p_device *peer, - u8 dialog_token, u8 status, - const u8 *resp_chan, int go) -{ - struct wpabuf *buf; - u8 *len; - struct p2p_channels res; - u8 group_capab; - size_t extra = 0; - - p2p_dbg(p2p, "Building GO Negotiation Confirm"); - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p->wfd_ie_go_neg) - extra = wpabuf_len(p2p->wfd_ie_go_neg); -#endif /* CONFIG_WIFI_DISPLAY */ - - buf = wpabuf_alloc(1000 + extra); - if (buf == NULL) - return NULL; - - p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_CONF, dialog_token); - - len = p2p_buf_add_ie_hdr(buf); - p2p_buf_add_status(buf, status); - group_capab = 0; - if (peer->go_state == LOCAL_GO) { - 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) - group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; - } - p2p_buf_add_capability(buf, p2p->dev_capab & - ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, - group_capab); - if (go || resp_chan == NULL) - p2p_buf_add_operating_channel(buf, p2p->cfg->country, - p2p->op_reg_class, - p2p->op_channel); - else - p2p_buf_add_operating_channel(buf, (const char *) resp_chan, - resp_chan[3], resp_chan[4]); - p2p_channels_intersect(&p2p->channels, &peer->channels, &res); - p2p_buf_add_channel_list(buf, p2p->cfg->country, &res); - if (go) { - p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid, - p2p->ssid_len); - } - p2p_buf_update_ie_hdr(buf, len); - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p->wfd_ie_go_neg) - wpabuf_put_buf(buf, p2p->wfd_ie_go_neg); -#endif /* CONFIG_WIFI_DISPLAY */ - - return buf; -} - - -void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) -{ - struct p2p_device *dev; - struct wpabuf *conf; - int go = -1; - struct p2p_message msg; - u8 status = P2P_SC_SUCCESS; - int freq; - - p2p_dbg(p2p, "Received GO Negotiation Response from " MACSTR - " (freq=%d)", MAC2STR(sa), rx_freq); - dev = p2p_get_device(p2p, sa); - if (dev == NULL || dev->wps_method == WPS_NOT_READY || - dev != p2p->go_neg_peer) { - p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR, - MAC2STR(sa)); - return; - } - - if (p2p_parse(data, len, &msg)) - return; - - if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE)) { - p2p_dbg(p2p, "Was not expecting GO Negotiation Response - ignore"); - p2p_parse_free(&msg); - return; - } - dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE; - - if (msg.dialog_token != dev->dialog_token) { - p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)", - msg.dialog_token, dev->dialog_token); - p2p_parse_free(&msg); - return; - } - - if (!msg.status) { - p2p_dbg(p2p, "No Status attribute received"); - status = P2P_SC_FAIL_INVALID_PARAMS; - goto fail; - } - if (*msg.status) { - p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status); - dev->go_neg_req_sent = 0; - if (*msg.status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { - p2p_dbg(p2p, "Wait for the peer to become ready for GO Negotiation"); - dev->flags |= P2P_DEV_NOT_YET_READY; - dev->wait_count = 0; - p2p_set_state(p2p, P2P_WAIT_PEER_IDLE); - p2p_set_timeout(p2p, 0, 0); - } else { - p2p_dbg(p2p, "Stop GO Negotiation attempt"); - p2p_go_neg_failed(p2p, dev, *msg.status); - } - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - p2p_parse_free(&msg); - return; - } - - if (!msg.capability) { - p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Response"); -#ifdef CONFIG_P2P_STRICT - status = P2P_SC_FAIL_INVALID_PARAMS; - goto fail; -#endif /* CONFIG_P2P_STRICT */ - } - - if (!msg.p2p_device_info) { - p2p_dbg(p2p, "Mandatory P2P Device Info attribute missing from GO Negotiation Response"); -#ifdef CONFIG_P2P_STRICT - status = P2P_SC_FAIL_INVALID_PARAMS; - goto fail; -#endif /* CONFIG_P2P_STRICT */ - } - - if (!msg.intended_addr) { - p2p_dbg(p2p, "No Intended P2P Interface Address attribute received"); - status = P2P_SC_FAIL_INVALID_PARAMS; - goto fail; - } - - if (!msg.go_intent) { - p2p_dbg(p2p, "No GO Intent attribute received"); - status = P2P_SC_FAIL_INVALID_PARAMS; - goto fail; - } - if ((*msg.go_intent >> 1) > P2P_MAX_GO_INTENT) { - p2p_dbg(p2p, "Invalid GO Intent value (%u) received", - *msg.go_intent >> 1); - status = P2P_SC_FAIL_INVALID_PARAMS; - goto fail; - } - - go = p2p_go_det(p2p->go_intent, *msg.go_intent); - if (go < 0) { - p2p_dbg(p2p, "Incompatible GO Intent"); - status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; - goto fail; - } - - if (!go && msg.group_id) { - /* Store SSID for Provisioning step */ - p2p->ssid_len = msg.group_id_len - ETH_ALEN; - os_memcpy(p2p->ssid, msg.group_id + ETH_ALEN, p2p->ssid_len); - } else if (!go) { - p2p_dbg(p2p, "Mandatory P2P Group ID attribute missing from GO Negotiation Response"); - p2p->ssid_len = 0; - status = P2P_SC_FAIL_INVALID_PARAMS; - goto fail; - } - - if (!msg.config_timeout) { - p2p_dbg(p2p, "Mandatory Configuration Timeout attribute missing from GO Negotiation Response"); -#ifdef CONFIG_P2P_STRICT - status = P2P_SC_FAIL_INVALID_PARAMS; - goto fail; -#endif /* CONFIG_P2P_STRICT */ - } else { - dev->go_timeout = msg.config_timeout[0]; - dev->client_timeout = msg.config_timeout[1]; - } - - if (!msg.operating_channel && !go) { - /* - * Note: P2P Client may omit Operating Channel attribute to - * indicate it does not have a preference. - */ - p2p_dbg(p2p, "No Operating Channel attribute received"); - status = P2P_SC_FAIL_INVALID_PARAMS; - goto fail; - } - if (!msg.channel_list) { - p2p_dbg(p2p, "No Channel List attribute received"); - status = P2P_SC_FAIL_INVALID_PARAMS; - goto fail; - } - - if (p2p_peer_channels(p2p, dev, msg.channel_list, - msg.channel_list_len) < 0) { - p2p_dbg(p2p, "No common channels found"); - status = P2P_SC_FAIL_NO_COMMON_CHANNELS; - goto fail; - } - - if (msg.operating_channel) { - dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3], - msg.operating_channel[4]); - p2p_dbg(p2p, "Peer operating channel preference: %d MHz", - dev->oper_freq); - } else - dev->oper_freq = 0; - - switch (msg.dev_password_id) { - case DEV_PW_REGISTRAR_SPECIFIED: - p2p_dbg(p2p, "PIN from peer Display"); - if (dev->wps_method != WPS_PIN_KEYPAD) { - p2p_dbg(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_USER_SPECIFIED: - p2p_dbg(p2p, "Peer entered PIN on Keypad"); - if (dev->wps_method != WPS_PIN_DISPLAY) { - p2p_dbg(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_PUSHBUTTON: - p2p_dbg(p2p, "Peer using pushbutton"); - if (dev->wps_method != WPS_PBC) { - p2p_dbg(p2p, "We have wps_method=%s -> incompatible", - p2p_wps_method_str(dev->wps_method)); - status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; - goto fail; - } - break; - default: - if (msg.dev_password_id && - msg.dev_password_id == dev->oob_pw_id) { - p2p_dbg(p2p, "Peer using NFC"); - if (dev->wps_method != WPS_NFC) { - p2p_dbg(p2p, "We have wps_method=%s -> incompatible", - p2p_wps_method_str(dev->wps_method)); - status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; - goto fail; - } - break; - } - p2p_dbg(p2p, "Unsupported Device Password ID %d", - msg.dev_password_id); - status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; - goto fail; - } - - if (go && p2p_go_select_channel(p2p, dev, &status) < 0) - goto fail; - - p2p_set_state(p2p, P2P_GO_NEG); - p2p_clear_timeout(p2p); - - p2p_dbg(p2p, "GO Negotiation with " MACSTR, MAC2STR(sa)); - os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN); - -fail: - conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token, status, - msg.operating_channel, go); - p2p_parse_free(&msg); - if (conf == NULL) - return; - p2p_dbg(p2p, "Sending GO Negotiation Confirm"); - if (status == P2P_SC_SUCCESS) { - p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM; - dev->go_state = go ? LOCAL_GO : REMOTE_GO; - } else - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - if (rx_freq > 0) - freq = rx_freq; - else - freq = dev->listen_freq; - if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa, - wpabuf_head(conf), wpabuf_len(conf), 200) < 0) { - p2p_dbg(p2p, "Failed to send Action frame"); - p2p_go_neg_failed(p2p, dev, -1); - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - } - wpabuf_free(conf); - if (status != P2P_SC_SUCCESS) { - p2p_dbg(p2p, "GO Negotiation failed"); - p2p_go_neg_failed(p2p, dev, status); - } -} - - -void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len) -{ - struct p2p_device *dev; - struct p2p_message msg; - - p2p_dbg(p2p, "Received GO Negotiation Confirm from " MACSTR, - MAC2STR(sa)); - dev = p2p_get_device(p2p, sa); - if (dev == NULL || dev->wps_method == WPS_NOT_READY || - dev != p2p->go_neg_peer) { - p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR, - MAC2STR(sa)); - return; - } - - if (p2p->pending_action_state == P2P_PENDING_GO_NEG_RESPONSE) { - p2p_dbg(p2p, "Stopped waiting for TX status on GO Negotiation Response since we already received Confirmation"); - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - } - - if (p2p_parse(data, len, &msg)) - return; - - if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) { - p2p_dbg(p2p, "Was not expecting GO Negotiation Confirm - ignore"); - p2p_parse_free(&msg); - return; - } - dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM; - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - - if (msg.dialog_token != dev->dialog_token) { - p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)", - msg.dialog_token, dev->dialog_token); - p2p_parse_free(&msg); - return; - } - - if (!msg.status) { - p2p_dbg(p2p, "No Status attribute received"); - p2p_parse_free(&msg); - return; - } - if (*msg.status) { - p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status); - p2p_go_neg_failed(p2p, dev, *msg.status); - p2p_parse_free(&msg); - return; - } - - if (dev->go_state == REMOTE_GO && msg.group_id) { - /* Store SSID for Provisioning step */ - p2p->ssid_len = msg.group_id_len - ETH_ALEN; - os_memcpy(p2p->ssid, msg.group_id + ETH_ALEN, p2p->ssid_len); - } else if (dev->go_state == REMOTE_GO) { - p2p_dbg(p2p, "Mandatory P2P Group ID attribute missing from GO Negotiation Confirmation"); - p2p->ssid_len = 0; - p2p_go_neg_failed(p2p, dev, P2P_SC_FAIL_INVALID_PARAMS); - p2p_parse_free(&msg); - return; - } - - if (!msg.operating_channel) { - p2p_dbg(p2p, "Mandatory Operating Channel attribute missing from GO Negotiation Confirmation"); -#ifdef CONFIG_P2P_STRICT - p2p_parse_free(&msg); - return; -#endif /* CONFIG_P2P_STRICT */ - } else if (dev->go_state == REMOTE_GO) { - int oper_freq = p2p_channel_to_freq(msg.operating_channel[3], - msg.operating_channel[4]); - if (oper_freq != dev->oper_freq) { - p2p_dbg(p2p, "Updated peer (GO) operating channel preference from %d MHz to %d MHz", - dev->oper_freq, oper_freq); - dev->oper_freq = oper_freq; - } - } - - if (!msg.channel_list) { - p2p_dbg(p2p, "Mandatory Operating Channel attribute missing from GO Negotiation Confirmation"); -#ifdef CONFIG_P2P_STRICT - p2p_parse_free(&msg); - return; -#endif /* CONFIG_P2P_STRICT */ - } - - p2p_parse_free(&msg); - - if (dev->go_state == UNKNOWN_GO) { - /* - * This should not happen since GO negotiation has already - * been completed. - */ - p2p_dbg(p2p, "Unexpected GO Neg state - do not know which end becomes GO"); - return; - } - - /* - * The peer could have missed our ctrl::ack frame for GO Negotiation - * Confirm and continue retransmitting the frame. To reduce the - * likelihood of the peer not getting successful TX status for the - * GO Negotiation Confirm frame, wait a short time here before starting - * the group so that we will remain on the current channel to - * acknowledge any possible retransmission from the peer. - */ - p2p_dbg(p2p, "20 ms wait on current channel before starting group"); - os_sleep(0, 20000); - - p2p_go_complete(p2p, dev); -} diff --git a/contrib/hostapd/src/p2p/p2p_group.c b/contrib/hostapd/src/p2p/p2p_group.c deleted file mode 100644 index 395ca089a8..0000000000 --- a/contrib/hostapd/src/p2p/p2p_group.c +++ /dev/null @@ -1,1015 +0,0 @@ -/* - * Wi-Fi Direct - P2P group operations - * Copyright (c) 2009-2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "wps/wps_defs.h" -#include "wps/wps_i.h" -#include "p2p_i.h" -#include "p2p.h" - - -struct p2p_group_member { - struct p2p_group_member *next; - u8 addr[ETH_ALEN]; /* P2P Interface Address */ - u8 dev_addr[ETH_ALEN]; /* P2P Device Address */ - struct wpabuf *p2p_ie; - struct wpabuf *wfd_ie; - struct wpabuf *client_info; - u8 dev_capab; -}; - -/** - * struct p2p_group - Internal P2P module per-group data - */ -struct p2p_group { - struct p2p_data *p2p; - struct p2p_group_config *cfg; - struct p2p_group_member *members; - unsigned int num_members; - int group_formation; - int beacon_update; - struct wpabuf *noa; - struct wpabuf *wfd_ie; -}; - - -struct p2p_group * p2p_group_init(struct p2p_data *p2p, - struct p2p_group_config *config) -{ - struct p2p_group *group, **groups; - - group = os_zalloc(sizeof(*group)); - if (group == NULL) - return NULL; - - groups = os_realloc_array(p2p->groups, p2p->num_groups + 1, - sizeof(struct p2p_group *)); - if (groups == NULL) { - os_free(group); - return NULL; - } - groups[p2p->num_groups++] = group; - p2p->groups = groups; - - group->p2p = p2p; - group->cfg = config; - group->group_formation = 1; - group->beacon_update = 1; - p2p_group_update_ies(group); - group->cfg->idle_update(group->cfg->cb_ctx, 1); - - return group; -} - - -static void p2p_group_free_member(struct p2p_group_member *m) -{ - wpabuf_free(m->wfd_ie); - wpabuf_free(m->p2p_ie); - wpabuf_free(m->client_info); - os_free(m); -} - - -static void p2p_group_free_members(struct p2p_group *group) -{ - struct p2p_group_member *m, *prev; - m = group->members; - group->members = NULL; - group->num_members = 0; - while (m) { - prev = m; - m = m->next; - p2p_group_free_member(prev); - } -} - - -void p2p_group_deinit(struct p2p_group *group) -{ - size_t g; - struct p2p_data *p2p; - - if (group == NULL) - return; - - p2p = group->p2p; - - for (g = 0; g < p2p->num_groups; g++) { - if (p2p->groups[g] == group) { - while (g + 1 < p2p->num_groups) { - p2p->groups[g] = p2p->groups[g + 1]; - g++; - } - p2p->num_groups--; - break; - } - } - - p2p_group_free_members(group); - os_free(group->cfg); - wpabuf_free(group->noa); - wpabuf_free(group->wfd_ie); - os_free(group); -} - - -static void p2p_client_info(struct wpabuf *ie, struct p2p_group_member *m) -{ - if (m->client_info == NULL) - return; - if (wpabuf_tailroom(ie) < wpabuf_len(m->client_info) + 1) - return; - wpabuf_put_buf(ie, m->client_info); -} - - -static void p2p_group_add_common_ies(struct p2p_group *group, - struct wpabuf *ie) -{ - u8 dev_capab = group->p2p->dev_capab, group_capab = 0; - - /* P2P Capability */ - dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; - group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER; - if (group->cfg->persistent_group) { - group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; - 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) - group_capab |= P2P_GROUP_CAPAB_GROUP_FORMATION; - if (group->p2p->cross_connect) - group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; - if (group->num_members >= group->cfg->max_clients) - group_capab |= P2P_GROUP_CAPAB_GROUP_LIMIT; - group_capab |= P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION; - p2p_buf_add_capability(ie, dev_capab, group_capab); -} - - -static void p2p_group_add_noa(struct wpabuf *ie, struct wpabuf *noa) -{ - if (noa == NULL) - return; - /* Notice of Absence */ - wpabuf_put_u8(ie, P2P_ATTR_NOTICE_OF_ABSENCE); - wpabuf_put_le16(ie, wpabuf_len(noa)); - wpabuf_put_buf(ie, noa); -} - - -static struct wpabuf * p2p_group_encaps_probe_resp(struct wpabuf *subelems) -{ - struct wpabuf *ie; - const u8 *pos, *end; - size_t len; - - if (subelems == NULL) - return NULL; - - len = wpabuf_len(subelems) + 100; - - ie = wpabuf_alloc(len); - if (ie == NULL) - return NULL; - - pos = wpabuf_head(subelems); - end = pos + wpabuf_len(subelems); - - while (end > pos) { - size_t frag_len = end - pos; - if (frag_len > 251) - frag_len = 251; - wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); - wpabuf_put_u8(ie, 4 + frag_len); - wpabuf_put_be32(ie, P2P_IE_VENDOR_TYPE); - wpabuf_put_data(ie, pos, frag_len); - pos += frag_len; - } - - return ie; -} - - -static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) -{ - struct wpabuf *ie; - u8 *len; - size_t extra = 0; - -#ifdef CONFIG_WIFI_DISPLAY - if (group->p2p->wfd_ie_beacon) - extra = wpabuf_len(group->p2p->wfd_ie_beacon); -#endif /* CONFIG_WIFI_DISPLAY */ - - ie = wpabuf_alloc(257 + extra); - if (ie == NULL) - return NULL; - -#ifdef CONFIG_WIFI_DISPLAY - if (group->p2p->wfd_ie_beacon) - wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon); -#endif /* CONFIG_WIFI_DISPLAY */ - - len = p2p_buf_add_ie_hdr(ie); - p2p_group_add_common_ies(group, ie); - p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr); - p2p_group_add_noa(ie, group->noa); - p2p_buf_update_ie_hdr(ie, len); - - return ie; -} - - -#ifdef CONFIG_WIFI_DISPLAY - -struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g) -{ - return g->wfd_ie; -} - - -struct wpabuf * wifi_display_encaps(struct wpabuf *subelems) -{ - struct wpabuf *ie; - const u8 *pos, *end; - - if (subelems == NULL) - return NULL; - - ie = wpabuf_alloc(wpabuf_len(subelems) + 100); - if (ie == NULL) - return NULL; - - pos = wpabuf_head(subelems); - end = pos + wpabuf_len(subelems); - - while (end > pos) { - size_t frag_len = end - pos; - if (frag_len > 251) - frag_len = 251; - wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); - wpabuf_put_u8(ie, 4 + frag_len); - wpabuf_put_be32(ie, WFD_IE_VENDOR_TYPE); - wpabuf_put_data(ie, pos, frag_len); - pos += frag_len; - } - - return ie; -} - - -static int wifi_display_add_dev_info_descr(struct wpabuf *buf, - struct p2p_group_member *m) -{ - const u8 *pos, *end; - const u8 *dev_info = NULL; - const u8 *assoc_bssid = NULL; - const u8 *coupled_sink = NULL; - u8 zero_addr[ETH_ALEN]; - - if (m->wfd_ie == NULL) - return 0; - - os_memset(zero_addr, 0, ETH_ALEN); - pos = wpabuf_head_u8(m->wfd_ie); - end = pos + wpabuf_len(m->wfd_ie); - while (pos + 1 < end) { - u8 id; - u16 len; - - id = *pos++; - len = WPA_GET_BE16(pos); - pos += 2; - if (pos + len > end) - break; - - switch (id) { - case WFD_SUBELEM_DEVICE_INFO: - if (len < 6) - break; - dev_info = pos; - break; - case WFD_SUBELEM_ASSOCIATED_BSSID: - if (len < ETH_ALEN) - break; - assoc_bssid = pos; - break; - case WFD_SUBELEM_COUPLED_SINK: - if (len < 1 + ETH_ALEN) - break; - coupled_sink = pos; - break; - } - - pos += len; - } - - if (dev_info == NULL) - return 0; - - wpabuf_put_u8(buf, 23); - wpabuf_put_data(buf, m->dev_addr, ETH_ALEN); - if (assoc_bssid) - wpabuf_put_data(buf, assoc_bssid, ETH_ALEN); - else - wpabuf_put_data(buf, zero_addr, ETH_ALEN); - wpabuf_put_data(buf, dev_info, 2); /* WFD Device Info */ - wpabuf_put_data(buf, dev_info + 4, 2); /* WFD Device Max Throughput */ - if (coupled_sink) { - wpabuf_put_data(buf, coupled_sink, 1 + ETH_ALEN); - } else { - wpabuf_put_u8(buf, 0); - wpabuf_put_data(buf, zero_addr, ETH_ALEN); - } - - return 1; -} - - -static struct wpabuf * -wifi_display_build_go_ie(struct p2p_group *group) -{ - struct wpabuf *wfd_subelems, *wfd_ie; - struct p2p_group_member *m; - u8 *len; - unsigned int count = 0; - - if (!group->p2p->wfd_ie_probe_resp) - return NULL; - - wfd_subelems = wpabuf_alloc(wpabuf_len(group->p2p->wfd_ie_probe_resp) + - group->num_members * 24 + 100); - if (wfd_subelems == NULL) - return NULL; - if (group->p2p->wfd_dev_info) - wpabuf_put_buf(wfd_subelems, group->p2p->wfd_dev_info); - if (group->p2p->wfd_assoc_bssid) - wpabuf_put_buf(wfd_subelems, - group->p2p->wfd_assoc_bssid); - if (group->p2p->wfd_coupled_sink_info) - wpabuf_put_buf(wfd_subelems, - group->p2p->wfd_coupled_sink_info); - - /* Build WFD Session Info */ - wpabuf_put_u8(wfd_subelems, WFD_SUBELEM_SESSION_INFO); - len = wpabuf_put(wfd_subelems, 2); - m = group->members; - while (m) { - if (wifi_display_add_dev_info_descr(wfd_subelems, m)) - count++; - m = m->next; - } - - if (count == 0) { - /* No Wi-Fi Display clients - do not include subelement */ - wfd_subelems->used -= 3; - } else { - WPA_PUT_BE16(len, (u8 *) wpabuf_put(wfd_subelems, 0) - len - - 2); - p2p_dbg(group->p2p, "WFD: WFD Session Info: %u descriptors", - count); - } - - wfd_ie = wifi_display_encaps(wfd_subelems); - wpabuf_free(wfd_subelems); - - return wfd_ie; -} - -static void wifi_display_group_update(struct p2p_group *group) -{ - wpabuf_free(group->wfd_ie); - group->wfd_ie = wifi_display_build_go_ie(group); -} - -#endif /* CONFIG_WIFI_DISPLAY */ - - -void p2p_buf_add_group_info(struct p2p_group *group, struct wpabuf *buf, - int max_clients) -{ - u8 *group_info; - int count = 0; - struct p2p_group_member *m; - - p2p_dbg(group->p2p, "* P2P Group Info"); - group_info = wpabuf_put(buf, 0); - wpabuf_put_u8(buf, P2P_ATTR_GROUP_INFO); - wpabuf_put_le16(buf, 0); /* Length to be filled */ - for (m = group->members; m; m = m->next) { - p2p_client_info(buf, m); - count++; - if (max_clients >= 0 && count >= max_clients) - break; - } - WPA_PUT_LE16(group_info + 1, - (u8 *) wpabuf_put(buf, 0) - group_info - 3); -} - - -void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf) -{ - p2p_buf_add_group_id(buf, group->p2p->cfg->dev_addr, group->cfg->ssid, - group->cfg->ssid_len); -} - - -static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) -{ - struct wpabuf *p2p_subelems, *ie; - - p2p_subelems = wpabuf_alloc(500); - if (p2p_subelems == NULL) - return NULL; - - p2p_group_add_common_ies(group, p2p_subelems); - p2p_group_add_noa(p2p_subelems, group->noa); - - /* P2P Device Info */ - p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL); - - /* P2P Group Info: Only when at least one P2P Client is connected */ - if (group->members) - p2p_buf_add_group_info(group, p2p_subelems, -1); - - ie = p2p_group_encaps_probe_resp(p2p_subelems); - wpabuf_free(p2p_subelems); - -#ifdef CONFIG_WIFI_DISPLAY - if (group->wfd_ie) { - struct wpabuf *wfd = wpabuf_dup(group->wfd_ie); - ie = wpabuf_concat(wfd, ie); - } -#endif /* CONFIG_WIFI_DISPLAY */ - - return ie; -} - - -void p2p_group_update_ies(struct p2p_group *group) -{ - struct wpabuf *beacon_ie; - struct wpabuf *probe_resp_ie; - -#ifdef CONFIG_WIFI_DISPLAY - wifi_display_group_update(group); -#endif /* CONFIG_WIFI_DISPLAY */ - - probe_resp_ie = p2p_group_build_probe_resp_ie(group); - if (probe_resp_ie == NULL) - return; - wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Probe Response P2P IE", - probe_resp_ie); - - if (group->beacon_update) { - beacon_ie = p2p_group_build_beacon_ie(group); - if (beacon_ie) - group->beacon_update = 0; - wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Beacon P2P IE", - beacon_ie); - } else - beacon_ie = NULL; - - group->cfg->ie_update(group->cfg->cb_ctx, beacon_ie, probe_resp_ie); -} - - -/** - * p2p_build_client_info - Build P2P Client Info Descriptor - * @addr: MAC address of the peer device - * @p2p_ie: P2P IE from (Re)Association Request - * @dev_capab: Buffer for returning Device Capability - * @dev_addr: Buffer for returning P2P Device Address - * Returns: P2P Client Info Descriptor or %NULL on failure - * - * This function builds P2P Client Info Descriptor based on the information - * available from (Re)Association Request frame. Group owner can use this to - * build the P2P Group Info attribute for Probe Response frames. - */ -static struct wpabuf * p2p_build_client_info(const u8 *addr, - struct wpabuf *p2p_ie, - u8 *dev_capab, u8 *dev_addr) -{ - const u8 *spos; - struct p2p_message msg; - u8 *len_pos; - struct wpabuf *buf; - - if (p2p_ie == NULL) - return NULL; - - os_memset(&msg, 0, sizeof(msg)); - if (p2p_parse_p2p_ie(p2p_ie, &msg) || - msg.capability == NULL || msg.p2p_device_info == NULL) - return NULL; - - buf = wpabuf_alloc(ETH_ALEN + 1 + 1 + msg.p2p_device_info_len); - if (buf == NULL) - return NULL; - - *dev_capab = msg.capability[0]; - os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN); - - spos = msg.p2p_device_info; /* P2P Device address */ - - /* P2P Client Info Descriptor */ - /* Length to be set */ - len_pos = wpabuf_put(buf, 1); - /* P2P Device address */ - wpabuf_put_data(buf, spos, ETH_ALEN); - /* P2P Interface address */ - wpabuf_put_data(buf, addr, ETH_ALEN); - /* Device Capability Bitmap */ - wpabuf_put_u8(buf, msg.capability[0]); - /* - * Config Methods, Primary Device Type, Number of Secondary Device - * Types, Secondary Device Type List, Device Name copied from - * Device Info - */ - wpabuf_put_data(buf, spos + ETH_ALEN, - msg.p2p_device_info_len - ETH_ALEN); - - *len_pos = wpabuf_len(buf) - 1; - - - return buf; -} - - -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) -{ - struct p2p_group_member *m; - - if (group == NULL) - return -1; - - p2p_add_device(group->p2p, addr, 0, NULL, 0, ie, len, 0); - - m = os_zalloc(sizeof(*m)); - if (m == NULL) - return -1; - os_memcpy(m->addr, addr, ETH_ALEN); - m->p2p_ie = ieee802_11_vendor_ie_concat(ie, len, P2P_IE_VENDOR_TYPE); - if (m->p2p_ie) { - m->client_info = p2p_build_client_info(addr, m->p2p_ie, - &m->dev_capab, - m->dev_addr); - } -#ifdef CONFIG_WIFI_DISPLAY - m->wfd_ie = ieee802_11_vendor_ie_concat(ie, len, WFD_IE_VENDOR_TYPE); -#endif /* CONFIG_WIFI_DISPLAY */ - - p2p_group_remove_member(group, addr); - - m->next = group->members; - group->members = m; - group->num_members++; - p2p_dbg(group->p2p, "Add client " MACSTR - " to group (p2p=%d wfd=%d client_info=%d); num_members=%u/%u", - MAC2STR(addr), m->p2p_ie ? 1 : 0, m->wfd_ie ? 1 : 0, - m->client_info ? 1 : 0, - group->num_members, group->cfg->max_clients); - if (group->num_members == group->cfg->max_clients) - group->beacon_update = 1; - p2p_group_update_ies(group); - if (group->num_members == 1) - group->cfg->idle_update(group->cfg->cb_ctx, 0); - - return 0; -} - - -struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) -{ - struct wpabuf *resp; - u8 *rlen; - size_t extra = 0; - -#ifdef CONFIG_WIFI_DISPLAY - if (group->wfd_ie) - extra = wpabuf_len(group->wfd_ie); -#endif /* CONFIG_WIFI_DISPLAY */ - - /* - * (Re)Association Response - P2P IE - * Status attribute (shall be present when association request is - * denied) - * Extended Listen Timing (may be present) - */ - resp = wpabuf_alloc(20 + extra); - if (resp == NULL) - return NULL; - -#ifdef CONFIG_WIFI_DISPLAY - if (group->wfd_ie) - wpabuf_put_buf(resp, group->wfd_ie); -#endif /* CONFIG_WIFI_DISPLAY */ - - rlen = p2p_buf_add_ie_hdr(resp); - if (status != P2P_SC_SUCCESS) - p2p_buf_add_status(resp, status); - p2p_buf_update_ie_hdr(resp, rlen); - - return resp; -} - - -void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr) -{ - if (p2p_group_remove_member(group, addr)) { - p2p_dbg(group->p2p, "Remove client " MACSTR - " from group; num_members=%u/%u", - MAC2STR(addr), group->num_members, - group->cfg->max_clients); - if (group->num_members == group->cfg->max_clients - 1) - group->beacon_update = 1; - p2p_group_update_ies(group); - if (group->num_members == 0) - group->cfg->idle_update(group->cfg->cb_ctx, 1); - } -} - - -/** - * p2p_match_dev_type_member - Match client device type with requested type - * @m: Group member - * @wps: WPS TLVs from Probe Request frame (concatenated WPS IEs) - * Returns: 1 on match, 0 on mismatch - * - * This function can be used to match the Requested Device Type attribute in - * WPS IE with the device types of a group member for deciding whether a GO - * should reply to a Probe Request frame. - */ -static int p2p_match_dev_type_member(struct p2p_group_member *m, - struct wpabuf *wps) -{ - const u8 *pos, *end; - struct wps_parse_attr attr; - u8 num_sec; - - if (m->client_info == NULL || wps == NULL) - return 0; - - pos = wpabuf_head(m->client_info); - end = pos + wpabuf_len(m->client_info); - - pos += 1 + 2 * ETH_ALEN + 1 + 2; - if (end - pos < WPS_DEV_TYPE_LEN + 1) - return 0; - - if (wps_parse_msg(wps, &attr)) - return 1; /* assume no Requested Device Type attributes */ - - if (attr.num_req_dev_type == 0) - return 1; /* no Requested Device Type attributes -> match */ - - if (dev_type_list_match(pos, attr.req_dev_type, attr.num_req_dev_type)) - return 1; /* Match with client Primary Device Type */ - - pos += WPS_DEV_TYPE_LEN; - num_sec = *pos++; - if (end - pos < num_sec * WPS_DEV_TYPE_LEN) - return 0; - while (num_sec > 0) { - num_sec--; - if (dev_type_list_match(pos, attr.req_dev_type, - attr.num_req_dev_type)) - return 1; /* Match with client Secondary Device Type */ - pos += WPS_DEV_TYPE_LEN; - } - - /* No matching device type found */ - return 0; -} - - -int p2p_group_match_dev_type(struct p2p_group *group, struct wpabuf *wps) -{ - struct p2p_group_member *m; - - if (p2p_match_dev_type(group->p2p, wps)) - return 1; /* Match with own device type */ - - for (m = group->members; m; m = m->next) { - if (p2p_match_dev_type_member(m, wps)) - return 1; /* Match with group client device type */ - } - - /* No match with Requested Device Type */ - return 0; -} - - -int p2p_group_match_dev_id(struct p2p_group *group, struct wpabuf *p2p) -{ - struct p2p_group_member *m; - struct p2p_message msg; - - os_memset(&msg, 0, sizeof(msg)); - if (p2p_parse_p2p_ie(p2p, &msg)) - return 1; /* Failed to parse - assume no filter on Device ID */ - - if (!msg.device_id) - return 1; /* No filter on Device ID */ - - if (os_memcmp(msg.device_id, group->p2p->cfg->dev_addr, ETH_ALEN) == 0) - return 1; /* Match with our P2P Device Address */ - - for (m = group->members; m; m = m->next) { - if (os_memcmp(msg.device_id, m->dev_addr, ETH_ALEN) == 0) - return 1; /* Match with group client P2P Device Address */ - } - - /* No match with Device ID */ - return 0; -} - - -void p2p_group_notif_formation_done(struct p2p_group *group) -{ - if (group == NULL) - return; - group->group_formation = 0; - group->beacon_update = 1; - p2p_group_update_ies(group); -} - - -int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa, - size_t noa_len) -{ - if (noa == NULL) { - wpabuf_free(group->noa); - group->noa = NULL; - } else { - if (group->noa) { - if (wpabuf_size(group->noa) >= noa_len) { - group->noa->used = 0; - wpabuf_put_data(group->noa, noa, noa_len); - } else { - wpabuf_free(group->noa); - group->noa = NULL; - } - } - - if (!group->noa) { - group->noa = wpabuf_alloc_copy(noa, noa_len); - if (group->noa == NULL) - return -1; - } - } - - group->beacon_update = 1; - p2p_group_update_ies(group); - return 0; -} - - -static struct p2p_group_member * p2p_group_get_client(struct p2p_group *group, - const u8 *dev_id) -{ - struct p2p_group_member *m; - - for (m = group->members; m; m = m->next) { - if (os_memcmp(dev_id, m->dev_addr, ETH_ALEN) == 0) - return m; - } - - return NULL; -} - - -static struct p2p_group_member * p2p_group_get_client_iface( - struct p2p_group *group, const u8 *interface_addr) -{ - struct p2p_group_member *m; - - for (m = group->members; m; m = m->next) { - if (os_memcmp(interface_addr, m->addr, ETH_ALEN) == 0) - return m; - } - - return NULL; -} - - -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 && !is_zero_ether_addr(m->dev_addr)) - return m->dev_addr; - return NULL; -} - - -static struct wpabuf * p2p_build_go_disc_req(void) -{ - struct wpabuf *buf; - - buf = wpabuf_alloc(100); - if (buf == NULL) - return NULL; - - p2p_buf_add_action_hdr(buf, P2P_GO_DISC_REQ, 0); - - return buf; -} - - -int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id, - const u8 *searching_dev, int rx_freq) -{ - struct p2p_group_member *m; - struct wpabuf *req; - struct p2p_data *p2p = group->p2p; - int freq; - - m = p2p_group_get_client(group, dev_id); - if (m == NULL || m->client_info == NULL) { - p2p_dbg(group->p2p, "Requested client was not in this group " - MACSTR, MAC2STR(group->cfg->interface_addr)); - return -1; - } - - if (!(m->dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { - p2p_dbg(group->p2p, "Requested client does not support client discoverability"); - return -1; - } - - p2p_dbg(group->p2p, "Schedule GO Discoverability Request to be sent to " - MACSTR, MAC2STR(dev_id)); - - req = p2p_build_go_disc_req(); - if (req == NULL) - return -1; - - /* TODO: Should really use group operating frequency here */ - freq = rx_freq; - - p2p->pending_action_state = P2P_PENDING_GO_DISC_REQ; - if (p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, m->addr, - group->cfg->interface_addr, - group->cfg->interface_addr, - wpabuf_head(req), wpabuf_len(req), 200) < 0) - { - p2p_dbg(p2p, "Failed to send Action frame"); - } - - wpabuf_free(req); - - return 0; -} - - -const u8 * p2p_group_get_interface_addr(struct p2p_group *group) -{ - return group->cfg->interface_addr; -} - - -u8 p2p_group_presence_req(struct p2p_group *group, - const u8 *client_interface_addr, - const u8 *noa, size_t noa_len) -{ - struct p2p_group_member *m; - u8 curr_noa[50]; - int curr_noa_len; - - m = p2p_group_get_client_iface(group, client_interface_addr); - if (m == NULL || m->client_info == NULL) { - p2p_dbg(group->p2p, "Client was not in this group"); - return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; - } - - wpa_hexdump(MSG_DEBUG, "P2P: Presence Request NoA", noa, noa_len); - - if (group->p2p->cfg->get_noa) - curr_noa_len = group->p2p->cfg->get_noa( - group->p2p->cfg->cb_ctx, group->cfg->interface_addr, - curr_noa, sizeof(curr_noa)); - else - curr_noa_len = -1; - if (curr_noa_len < 0) - p2p_dbg(group->p2p, "Failed to fetch current NoA"); - else if (curr_noa_len == 0) - p2p_dbg(group->p2p, "No NoA being advertized"); - else - wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa, - curr_noa_len); - - /* TODO: properly process request and store copy */ - if (curr_noa_len > 0 || curr_noa_len == -1) - return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; - - return P2P_SC_SUCCESS; -} - - -unsigned int p2p_get_group_num_members(struct p2p_group *group) -{ - return group->num_members; -} - - -const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next) -{ - struct p2p_group_member *iter = *next; - - if (!iter) - iter = group->members; - else - iter = iter->next; - - *next = iter; - - if (!iter) - return NULL; - - return iter->addr; -} - - -int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr) -{ - struct p2p_group_member *m; - - for (m = group->members; m; m = m->next) { - if (os_memcmp(m->dev_addr, dev_addr, ETH_ALEN) == 0) - return 1; - } - - return 0; -} - - -int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id, - size_t group_id_len) -{ - if (group_id_len != ETH_ALEN + group->cfg->ssid_len) - return 0; - if (os_memcmp(group_id, group->p2p->cfg->dev_addr, ETH_ALEN) != 0) - return 0; - return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid, - group->cfg->ssid_len) == 0; -} - - -void p2p_group_force_beacon_update_ies(struct p2p_group *group) -{ - group->beacon_update = 1; - p2p_group_update_ies(group); -} - - -int p2p_group_get_freq(struct p2p_group *group) -{ - return group->cfg->freq; -} diff --git a/contrib/hostapd/src/p2p/p2p_i.h b/contrib/hostapd/src/p2p/p2p_i.h deleted file mode 100644 index 6ebaa846d6..0000000000 --- a/contrib/hostapd/src/p2p/p2p_i.h +++ /dev/null @@ -1,759 +0,0 @@ -/* - * P2P - Internal definitions for P2P module - * Copyright (c) 2009-2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef P2P_I_H -#define P2P_I_H - -#include "utils/list.h" -#include "p2p.h" - -enum p2p_role_indication; - -enum p2p_go_state { - UNKNOWN_GO, - LOCAL_GO, - REMOTE_GO -}; - -/** - * struct p2p_device - P2P Device data (internal to P2P module) - */ -struct p2p_device { - struct dl_list list; - struct os_reltime last_seen; - int listen_freq; - int oob_go_neg_freq; - enum p2p_wps_method wps_method; - u16 oob_pw_id; - - struct p2p_peer_info info; - - /* - * If the peer was discovered based on an interface address (e.g., GO - * from Beacon/Probe Response), the interface address is stored here. - * p2p_device_addr must still be set in such a case to the unique - * identifier for the P2P Device. - */ - u8 interface_addr[ETH_ALEN]; - - /* - * P2P Device Address of the GO in whose group this P2P Device is a - * client. - */ - u8 member_in_go_dev[ETH_ALEN]; - - /* - * P2P Interface Address of the GO in whose group this P2P Device is a - * client. - */ - u8 member_in_go_iface[ETH_ALEN]; - - int go_neg_req_sent; - enum p2p_go_state go_state; - u8 dialog_token; - u8 tie_breaker; - u8 intended_addr[ETH_ALEN]; - - char country[3]; - struct p2p_channels channels; - int oper_freq; - u8 oper_ssid[32]; - size_t oper_ssid_len; - - /** - * 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) -#define P2P_DEV_SD_INFO BIT(3) -#define P2P_DEV_SD_SCHEDULE BIT(4) -#define P2P_DEV_PD_PEER_DISPLAY BIT(5) -#define P2P_DEV_PD_PEER_KEYPAD BIT(6) -#define P2P_DEV_USER_REJECTED BIT(7) -#define P2P_DEV_PEER_WAITING_RESPONSE BIT(8) -#define P2P_DEV_PREFER_PERSISTENT_GROUP BIT(9) -#define P2P_DEV_WAIT_GO_NEG_RESPONSE BIT(10) -#define P2P_DEV_WAIT_GO_NEG_CONFIRM BIT(11) -#define P2P_DEV_GROUP_CLIENT_ONLY BIT(12) -#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) -#define P2P_DEV_PD_BEFORE_GO_NEG BIT(17) -#define P2P_DEV_NO_PREF_CHAN BIT(18) - unsigned int flags; - - int status; /* enum p2p_status_code */ - unsigned int wait_count; - unsigned int connect_reqs; - unsigned int invitation_reqs; - - u16 ext_listen_period; - u16 ext_listen_interval; - - u8 go_timeout; - u8 client_timeout; -}; - -struct p2p_sd_query { - struct p2p_sd_query *next; - u8 peer[ETH_ALEN]; - int for_all_peers; - int wsd; /* Wi-Fi Display Service Discovery Request */ - struct wpabuf *tlvs; -}; - -struct p2p_pending_action_tx { - unsigned int freq; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - size_t len; - unsigned int wait_time; - /* Followed by len octets of the frame */ -}; - -/** - * struct p2p_data - P2P module data (internal to P2P module) - */ -struct p2p_data { - /** - * cfg - P2P module configuration - * - * This is included in the same memory allocation with the - * struct p2p_data and as such, must not be freed separately. - */ - struct p2p_config *cfg; - - /** - * state - The current P2P state - */ - enum p2p_state { - /** - * P2P_IDLE - Idle - */ - P2P_IDLE, - - /** - * P2P_SEARCH - Search (Device Discovery) - */ - P2P_SEARCH, - - /** - * P2P_CONNECT - Trying to start GO Negotiation - */ - P2P_CONNECT, - - /** - * P2P_CONNECT_LISTEN - Listen during GO Negotiation start - */ - P2P_CONNECT_LISTEN, - - /** - * P2P_GO_NEG - In GO Negotiation - */ - P2P_GO_NEG, - - /** - * P2P_LISTEN_ONLY - Listen only - */ - P2P_LISTEN_ONLY, - - /** - * P2P_WAIT_PEER_CONNECT - Waiting peer in List for GO Neg - */ - P2P_WAIT_PEER_CONNECT, - - /** - * P2P_WAIT_PEER_IDLE - Waiting peer idle for GO Neg - */ - P2P_WAIT_PEER_IDLE, - - /** - * P2P_SD_DURING_FIND - Service Discovery during find - */ - P2P_SD_DURING_FIND, - - /** - * P2P_PROVISIONING - Provisioning (during group formation) - */ - P2P_PROVISIONING, - - /** - * P2P_PD_DURING_FIND - Provision Discovery during find - */ - P2P_PD_DURING_FIND, - - /** - * P2P_INVITE - Trying to start Invite - */ - P2P_INVITE, - - /** - * P2P_INVITE_LISTEN - Listen during Invite - */ - P2P_INVITE_LISTEN, - } state; - - /** - * min_disc_int - minDiscoverableInterval - */ - int min_disc_int; - - /** - * max_disc_int - maxDiscoverableInterval - */ - int max_disc_int; - - /** - * max_disc_tu - Maximum number of TUs for discoverable interval - */ - int max_disc_tu; - - /** - * devices - List of known P2P Device peers - */ - struct dl_list devices; - - /** - * go_neg_peer - Pointer to GO Negotiation peer - */ - struct p2p_device *go_neg_peer; - - /** - * invite_peer - Pointer to Invite peer - */ - struct p2p_device *invite_peer; - - const u8 *invite_go_dev_addr; - u8 invite_go_dev_addr_buf[ETH_ALEN]; - int invite_dev_pw_id; - - /** - * sd_peer - Pointer to Service Discovery peer - */ - struct p2p_device *sd_peer; - - /** - * sd_query - Pointer to Service Discovery query - */ - struct p2p_sd_query *sd_query; - - /* GO Negotiation data */ - - /** - * intended_addr - Local Intended P2P Interface Address - * - * This address is used during group owner negotiation as the Intended - * P2P Interface Address and the group interface will be created with - * address as the local address in case of successfully completed - * negotiation. - */ - u8 intended_addr[ETH_ALEN]; - - /** - * go_intent - Local GO Intent to be used during GO Negotiation - */ - u8 go_intent; - - /** - * next_tie_breaker - Next tie-breaker value to use in GO Negotiation - */ - u8 next_tie_breaker; - - /** - * ssid - Selected SSID for GO Negotiation (if local end will be GO) - */ - u8 ssid[32]; - - /** - * ssid_len - ssid length in octets - */ - 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; - - /** - * op_channel - Own operational channel - */ - u8 op_channel; - - /** - * channels - Own supported regulatory classes and channels - * - * List of supposerted channels per regulatory class. The regulatory - * classes are defined in IEEE Std 802.11-2007 Annex J and the - * numbering of the clases depends on the configured country code. - */ - struct p2p_channels channels; - - struct wpa_freq_range_list no_go_freq; - - enum p2p_pending_action_state { - P2P_NO_PENDING_ACTION, - P2P_PENDING_GO_NEG_REQUEST, - P2P_PENDING_GO_NEG_RESPONSE, - P2P_PENDING_GO_NEG_RESPONSE_FAILURE, - P2P_PENDING_GO_NEG_CONFIRM, - P2P_PENDING_SD, - P2P_PENDING_PD, - P2P_PENDING_INVITATION_REQUEST, - P2P_PENDING_INVITATION_RESPONSE, - P2P_PENDING_DEV_DISC_REQUEST, - P2P_PENDING_DEV_DISC_RESPONSE, - P2P_PENDING_GO_DISC_REQ - } pending_action_state; - - unsigned int pending_listen_freq; - unsigned int pending_listen_sec; - unsigned int pending_listen_usec; - - u8 dev_capab; - - int in_listen; - int drv_in_listen; - - /** - * sd_queries - Pending service discovery queries - */ - struct p2p_sd_query *sd_queries; - - /** - * srv_update_indic - Service Update Indicator for local services - */ - u16 srv_update_indic; - - struct wpabuf *sd_resp; /* Fragmented SD response */ - u8 sd_resp_addr[ETH_ALEN]; - u8 sd_resp_dialog_token; - size_t sd_resp_pos; /* Offset in sd_resp */ - u8 sd_frag_id; - - struct wpabuf *sd_rx_resp; /* Reassembled SD response */ - u16 sd_rx_update_indic; - - /* P2P Invitation data */ - enum p2p_invite_role inv_role; - u8 inv_bssid[ETH_ALEN]; - int inv_bssid_set; - u8 inv_ssid[32]; - size_t inv_ssid_len; - u8 inv_sa[ETH_ALEN]; - u8 inv_group_bssid[ETH_ALEN]; - u8 *inv_group_bssid_ptr; - u8 inv_go_dev_addr[ETH_ALEN]; - u8 inv_status; - int inv_op_freq; - 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; - enum p2p_after_scan { - P2P_AFTER_SCAN_NOTHING, - P2P_AFTER_SCAN_LISTEN, - P2P_AFTER_SCAN_CONNECT - } start_after_scan; - u8 after_scan_peer[ETH_ALEN]; - struct p2p_pending_action_tx *after_scan_tx; - unsigned int after_scan_tx_in_progress:1; - - /* Requested device types for find/search */ - unsigned int num_req_dev_types; - u8 *req_dev_types; - u8 *find_dev_id; - u8 find_dev_id_buf[ETH_ALEN]; - - struct os_reltime find_start; /* time of last p2p_find start */ - - struct p2p_group **groups; - size_t num_groups; - - struct p2p_device *pending_client_disc_go; - u8 pending_client_disc_addr[ETH_ALEN]; - u8 pending_dev_disc_dialog_token; - u8 pending_dev_disc_addr[ETH_ALEN]; - int pending_dev_disc_freq; - unsigned int pending_client_disc_freq; - - int ext_listen_only; - unsigned int ext_listen_period; - unsigned int ext_listen_interval; - unsigned int ext_listen_interval_sec; - unsigned int ext_listen_interval_usec; - - u8 peer_filter[ETH_ALEN]; - - int cross_connect; - - int best_freq_24; - int best_freq_5; - int best_freq_overall; - int own_freq_preference; - - /** - * wps_vendor_ext - WPS Vendor Extensions to add - */ - struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT]; - - /* - * user_initiated_pd - Whether a PD request is user initiated or not. - */ - u8 user_initiated_pd; - - /* - * Keep track of which peer a given PD request was sent to. - * Used to raise a timeout alert in case there is no response. - */ - u8 pending_pd_devaddr[ETH_ALEN]; - - /* - * Retry counter for provision discovery requests when issued - * in IDLE state. - */ - int pd_retries; - - /** - * pd_force_freq - Forced frequency for PD retries or 0 to auto-select - * - * This is is used during PD retries for join-a-group case to use the - * correct operating frequency determined from a BSS entry for the GO. - */ - int pd_force_freq; - - u8 go_timeout; - u8 client_timeout; - - /* Extra delay in milliseconds between search iterations */ - unsigned int search_delay; - int in_search_delay; - -#ifdef CONFIG_WIFI_DISPLAY - struct wpabuf *wfd_ie_beacon; - struct wpabuf *wfd_ie_probe_req; - struct wpabuf *wfd_ie_probe_resp; - struct wpabuf *wfd_ie_assoc_req; - struct wpabuf *wfd_ie_invitation; - struct wpabuf *wfd_ie_prov_disc_req; - struct wpabuf *wfd_ie_prov_disc_resp; - struct wpabuf *wfd_ie_go_neg; - struct wpabuf *wfd_dev_info; - struct wpabuf *wfd_assoc_bssid; - struct wpabuf *wfd_coupled_sink_info; -#endif /* CONFIG_WIFI_DISPLAY */ - - u16 authorized_oob_dev_pw_id; -}; - -/** - * struct p2p_message - Parsed P2P message (or P2P IE) - */ -struct p2p_message { - struct wpabuf *p2p_attributes; - struct wpabuf *wps_attributes; - struct wpabuf *wfd_subelems; - - u8 dialog_token; - - const u8 *capability; - const u8 *go_intent; - const u8 *status; - const u8 *listen_channel; - const u8 *operating_channel; - const u8 *channel_list; - u8 channel_list_len; - const u8 *config_timeout; - const u8 *intended_addr; - const u8 *group_bssid; - const u8 *invitation_flags; - - const u8 *group_info; - size_t group_info_len; - - const u8 *group_id; - size_t group_id_len; - - const u8 *device_id; - - const u8 *manageability; - - const u8 *noa; - size_t noa_len; - - const u8 *ext_listen_timing; - - const u8 *minor_reason_code; - - const u8 *oob_go_neg_channel; - - /* P2P Device Info */ - const u8 *p2p_device_info; - size_t p2p_device_info_len; - const u8 *p2p_device_addr; - const u8 *pri_dev_type; - u8 num_sec_dev_types; - char device_name[33]; - u16 config_methods; - - /* WPS IE */ - u16 dev_password_id; - int dev_password_id_present; - u16 wps_config_methods; - const u8 *wps_pri_dev_type; - const u8 *wps_sec_dev_type_list; - size_t wps_sec_dev_type_list_len; - const u8 *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT]; - size_t wps_vendor_ext_len[P2P_MAX_WPS_VENDOR_EXT]; - const u8 *manufacturer; - size_t manufacturer_len; - const u8 *model_name; - size_t model_name_len; - const u8 *model_number; - size_t model_number_len; - const u8 *serial_number; - size_t serial_number_len; - const u8 *oob_dev_password; - size_t oob_dev_password_len; - - /* DS Parameter Set IE */ - const u8 *ds_params; - - /* SSID IE */ - const u8 *ssid; -}; - - -#define P2P_MAX_GROUP_ENTRIES 50 - -struct p2p_group_info { - unsigned int num_clients; - struct p2p_client_info { - const u8 *p2p_device_addr; - const u8 *p2p_interface_addr; - u8 dev_capab; - u16 config_methods; - const u8 *pri_dev_type; - u8 num_sec_dev_types; - const u8 *sec_dev_types; - const char *dev_name; - size_t dev_name_len; - } client[P2P_MAX_GROUP_ENTRIES]; -}; - - -/* p2p_utils.c */ -int p2p_random(char *buf, size_t len); -int p2p_channel_to_freq(int op_class, int channel); -int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel); -void p2p_channels_intersect(const struct p2p_channels *a, - const struct p2p_channels *b, - struct p2p_channels *res); -void p2p_channels_union(const struct p2p_channels *a, - const struct p2p_channels *b, - struct p2p_channels *res); -void p2p_channels_remove_freqs(struct p2p_channels *chan, - const struct wpa_freq_range_list *list); -int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class, - u8 channel); -void p2p_channels_dump(struct p2p_data *p2p, const char *title, - const struct p2p_channels *chan); -int p2p_channel_select(struct p2p_channels *chans, const int *classes, - u8 *op_class, u8 *op_channel); - -/* p2p_parse.c */ -int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg); -int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg); -int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg); -int p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p, - size_t p2p_len, struct p2p_message *msg); -void p2p_parse_free(struct p2p_message *msg); -int p2p_attr_text(struct wpabuf *data, char *buf, char *end); -int p2p_group_info_parse(const u8 *gi, size_t gi_len, - struct p2p_group_info *info); - -/* p2p_build.c */ - -struct p2p_noa_desc { - u8 count_type; - u32 duration; - u32 interval; - u32 start_time; -}; - -/* p2p_group.c */ -const u8 * p2p_group_get_interface_addr(struct p2p_group *group); -u8 p2p_group_presence_req(struct p2p_group *group, - const u8 *client_interface_addr, - const u8 *noa, size_t noa_len); -int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id, - size_t group_id_len); -void p2p_group_update_ies(struct p2p_group *group); -void p2p_group_force_beacon_update_ies(struct p2p_group *group); -struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g); -void p2p_buf_add_group_info(struct p2p_group *group, struct wpabuf *buf, - int max_clients); -void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf); -int p2p_group_get_freq(struct p2p_group *group); - - -void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token); -void p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype, - u8 dialog_token); -u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf); -void p2p_buf_add_status(struct wpabuf *buf, u8 status); -void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p, - struct p2p_device *peer); -void p2p_buf_add_device_id(struct wpabuf *buf, const u8 *dev_addr); -void p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len); -void p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab); -void p2p_buf_add_go_intent(struct wpabuf *buf, u8 go_intent); -void p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country, - u8 reg_class, u8 channel); -void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country, - u8 reg_class, u8 channel); -void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country, - struct p2p_channels *chan); -void p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout, - u8 client_timeout); -void p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr); -void p2p_buf_add_group_bssid(struct wpabuf *buf, const u8 *bssid); -void p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr, - const u8 *ssid, size_t ssid_len); -void p2p_buf_add_invitation_flags(struct wpabuf *buf, u8 flags); -void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow, - struct p2p_noa_desc *desc1, struct p2p_noa_desc *desc2); -void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period, - u16 interval); -void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p); -void p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country, - u8 oper_class, u8 channel, - enum p2p_role_indication role); -int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id, - int all_attr); - -/* p2p_sd.c */ -struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p, - struct p2p_device *dev); -void p2p_free_sd_queries(struct p2p_data *p2p); -void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq); -void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq); -void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq); -void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq); -int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev); - -/* p2p_go_neg.c */ -int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own, - struct p2p_device *dev, - const u8 *channel_list, size_t channel_list_len); -void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq); -void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq); -void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len); -int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev); -u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method); -void p2p_reselect_channel(struct p2p_data *p2p, - struct p2p_channels *intersection); - -/* p2p_pd.c */ -void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq); -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 force_freq); -void p2p_reset_pending_pd(struct p2p_data *p2p); - -/* p2p_invitation.c */ -void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq); -void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len); -int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev, - const u8 *go_dev_addr, int dev_pw_id); -void p2p_invitation_req_cb(struct p2p_data *p2p, int success); -void p2p_invitation_resp_cb(struct p2p_data *p2p, int success); - -/* p2p_dev_disc.c */ -void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq); -void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success); -int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev); -void p2p_dev_disc_resp_cb(struct p2p_data *p2p, int success); -void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len); -void p2p_go_disc_req_cb(struct p2p_data *p2p, int success); -void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa, - const u8 *data, size_t len, int rx_freq); - -/* p2p.c */ -void p2p_set_state(struct p2p_data *p2p, int new_state); -void p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, - unsigned int usec); -void p2p_clear_timeout(struct p2p_data *p2p); -void p2p_continue_find(struct p2p_data *p2p); -struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p, - const u8 *addr, - struct p2p_message *msg); -void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr, - struct p2p_device *dev, struct p2p_message *msg); -int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, - struct os_reltime *rx_time, int level, const u8 *ies, - size_t ies_len, int scan_res); -struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr); -struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p, - const u8 *addr); -void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer, - int status); -void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer); -int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps); -int dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[], - size_t num_req_dev_type); -struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p); -void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len); -int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst, - const u8 *src, const u8 *bssid, const u8 *buf, - size_t len, unsigned int wait_time); -void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq); -int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev, - unsigned int force_freq, unsigned int pref_freq, - int go); -void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...) -PRINTF_FORMAT(2, 3); -void p2p_info(struct p2p_data *p2p, const char *fmt, ...) -PRINTF_FORMAT(2, 3); -void p2p_err(struct p2p_data *p2p, const char *fmt, ...) -PRINTF_FORMAT(2, 3); - -#endif /* P2P_I_H */ diff --git a/contrib/hostapd/src/p2p/p2p_invitation.c b/contrib/hostapd/src/p2p/p2p_invitation.c deleted file mode 100644 index 98cfb3303c..0000000000 --- a/contrib/hostapd/src/p2p/p2p_invitation.c +++ /dev/null @@ -1,605 +0,0 @@ -/* - * Wi-Fi Direct - P2P Invitation procedure - * Copyright (c) 2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "common/ieee802_11_defs.h" -#include "p2p_i.h" -#include "p2p.h" - - -static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, - struct p2p_device *peer, - const u8 *go_dev_addr, - int dev_pw_id) -{ - struct wpabuf *buf; - u8 *len; - const u8 *dev_addr; - size_t extra = 0; - -#ifdef CONFIG_WIFI_DISPLAY - struct wpabuf *wfd_ie = p2p->wfd_ie_invitation; - if (wfd_ie && p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO) { - size_t i; - for (i = 0; i < p2p->num_groups; i++) { - struct p2p_group *g = p2p->groups[i]; - struct wpabuf *ie; - if (os_memcmp(p2p_group_get_interface_addr(g), - p2p->inv_bssid, ETH_ALEN) != 0) - continue; - ie = p2p_group_get_wfd_ie(g); - if (ie) { - wfd_ie = ie; - break; - } - } - } - if (wfd_ie) - extra = wpabuf_len(wfd_ie); -#endif /* CONFIG_WIFI_DISPLAY */ - - buf = wpabuf_alloc(1000 + extra); - if (buf == NULL) - return NULL; - - peer->dialog_token++; - if (peer->dialog_token == 0) - peer->dialog_token = 1; - p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_REQ, - peer->dialog_token); - - len = p2p_buf_add_ie_hdr(buf); - if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO || !p2p->inv_persistent) - p2p_buf_add_config_timeout(buf, 0, 0); - else - p2p_buf_add_config_timeout(buf, p2p->go_timeout, - p2p->client_timeout); - p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ? - P2P_INVITATION_FLAGS_TYPE : 0); - if (p2p->inv_role != P2P_INVITE_ROLE_CLIENT || - !(peer->flags & P2P_DEV_NO_PREF_CHAN)) - p2p_buf_add_operating_channel(buf, p2p->cfg->country, - p2p->op_reg_class, - p2p->op_channel); - if (p2p->inv_bssid_set) - p2p_buf_add_group_bssid(buf, p2p->inv_bssid); - p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels); - if (go_dev_addr) - dev_addr = go_dev_addr; - else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT) - dev_addr = peer->info.p2p_device_addr; - else - dev_addr = p2p->cfg->dev_addr; - 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); - -#ifdef CONFIG_WIFI_DISPLAY - if (wfd_ie) - wpabuf_put_buf(buf, wfd_ie); -#endif /* CONFIG_WIFI_DISPLAY */ - - if (dev_pw_id >= 0) { - /* WSC IE in Invitation Request for NFC static handover */ - p2p_build_wps_ie(p2p, buf, dev_pw_id, 0); - } - - return buf; -} - - -static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p, - struct p2p_device *peer, - u8 dialog_token, u8 status, - const u8 *group_bssid, - u8 reg_class, u8 channel, - struct p2p_channels *channels) -{ - struct wpabuf *buf; - u8 *len; - size_t extra = 0; - -#ifdef CONFIG_WIFI_DISPLAY - struct wpabuf *wfd_ie = p2p->wfd_ie_invitation; - if (wfd_ie && group_bssid) { - size_t i; - for (i = 0; i < p2p->num_groups; i++) { - struct p2p_group *g = p2p->groups[i]; - struct wpabuf *ie; - if (os_memcmp(p2p_group_get_interface_addr(g), - group_bssid, ETH_ALEN) != 0) - continue; - ie = p2p_group_get_wfd_ie(g); - if (ie) { - wfd_ie = ie; - break; - } - } - } - if (wfd_ie) - extra = wpabuf_len(wfd_ie); -#endif /* CONFIG_WIFI_DISPLAY */ - - buf = wpabuf_alloc(1000 + extra); - if (buf == NULL) - return NULL; - - p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_RESP, - dialog_token); - - len = p2p_buf_add_ie_hdr(buf); - p2p_buf_add_status(buf, status); - p2p_buf_add_config_timeout(buf, 0, 0); /* FIX */ - if (reg_class && channel) - p2p_buf_add_operating_channel(buf, p2p->cfg->country, - reg_class, channel); - if (group_bssid) - p2p_buf_add_group_bssid(buf, group_bssid); - if (channels) - p2p_buf_add_channel_list(buf, p2p->cfg->country, channels); - p2p_buf_update_ie_hdr(buf, len); - -#ifdef CONFIG_WIFI_DISPLAY - if (wfd_ie) - wpabuf_put_buf(buf, wfd_ie); -#endif /* CONFIG_WIFI_DISPLAY */ - - return buf; -} - - -void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) -{ - struct p2p_device *dev; - struct p2p_message msg; - struct wpabuf *resp = NULL; - u8 status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; - int freq; - int go = 0; - u8 group_bssid[ETH_ALEN], *bssid; - int op_freq = 0; - u8 reg_class = 0, channel = 0; - struct p2p_channels intersection, *channels = NULL; - int persistent; - - os_memset(group_bssid, 0, sizeof(group_bssid)); - - p2p_dbg(p2p, "Received Invitation Request from " MACSTR " (freq=%d)", - MAC2STR(sa), rx_freq); - - if (p2p_parse(data, len, &msg)) - return; - - dev = p2p_get_device(p2p, sa); - if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { - p2p_dbg(p2p, "Invitation Request from unknown peer " MACSTR, - MAC2STR(sa)); - - if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1, - 0)) { - p2p_dbg(p2p, "Invitation Request add device failed " - MACSTR, MAC2STR(sa)); - status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; - goto fail; - } - - dev = p2p_get_device(p2p, sa); - if (dev == NULL) { - p2p_dbg(p2p, "Reject Invitation Request from unknown peer " - MACSTR, MAC2STR(sa)); - status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; - goto fail; - } - } - - if (!msg.group_id || !msg.channel_list) { - p2p_dbg(p2p, "Mandatory attribute missing in Invitation Request from " - MACSTR, MAC2STR(sa)); - status = P2P_SC_FAIL_INVALID_PARAMS; - goto fail; - } - - if (msg.invitation_flags) - persistent = *msg.invitation_flags & P2P_INVITATION_FLAGS_TYPE; - else { - /* Invitation Flags is a mandatory attribute starting from P2P - * spec 1.06. As a backwards compatibility mechanism, assume - * the request was for a persistent group if the attribute is - * missing. - */ - p2p_dbg(p2p, "Mandatory Invitation Flags attribute missing from Invitation Request"); - persistent = 1; - } - - if (p2p_peer_channels_check(p2p, &p2p->cfg->channels, dev, - msg.channel_list, msg.channel_list_len) < - 0) { - p2p_dbg(p2p, "No common channels found"); - status = P2P_SC_FAIL_NO_COMMON_CHANNELS; - goto fail; - } - - p2p_channels_intersect(&p2p->cfg->channels, &dev->channels, - &intersection); - - if (p2p->cfg->invitation_process) { - status = p2p->cfg->invitation_process( - p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id, - msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN, - &go, group_bssid, &op_freq, persistent, &intersection, - msg.dev_password_id_present ? msg.dev_password_id : -1); - } - - if (op_freq) { - p2p_dbg(p2p, "Invitation processing forced frequency %d MHz", - op_freq); - if (p2p_freq_to_channel(op_freq, ®_class, &channel) < 0) { - p2p_dbg(p2p, "Unknown forced freq %d MHz from invitation_process()", - op_freq); - status = P2P_SC_FAIL_NO_COMMON_CHANNELS; - goto fail; - } - - if (!p2p_channels_includes(&intersection, reg_class, channel)) - { - p2p_dbg(p2p, "forced freq %d MHz not in the supported channels interaction", - op_freq); - status = P2P_SC_FAIL_NO_COMMON_CHANNELS; - goto fail; - } - - if (status == P2P_SC_SUCCESS) - channels = &intersection; - } else { - p2p_dbg(p2p, "No forced channel from invitation processing - figure out best one to use"); - - /* Default to own configuration as a starting point */ - p2p->op_reg_class = p2p->cfg->op_reg_class; - p2p->op_channel = p2p->cfg->op_channel; - p2p_dbg(p2p, "Own default op_class %d channel %d", - p2p->op_reg_class, p2p->op_channel); - - /* Use peer preference if specified and compatible */ - if (msg.operating_channel) { - int req_freq; - req_freq = p2p_channel_to_freq( - msg.operating_channel[3], - msg.operating_channel[4]); - p2p_dbg(p2p, "Peer operating channel preference: %d MHz", - req_freq); - if (req_freq > 0 && - p2p_channels_includes(&intersection, - msg.operating_channel[3], - msg.operating_channel[4])) { - p2p->op_reg_class = msg.operating_channel[3]; - p2p->op_channel = msg.operating_channel[4]; - p2p_dbg(p2p, "Use peer preference op_class %d channel %d", - p2p->op_reg_class, p2p->op_channel); - } else { - p2p_dbg(p2p, "Cannot use peer channel preference"); - } - } - - if (!p2p_channels_includes(&intersection, p2p->op_reg_class, - p2p->op_channel)) { - p2p_dbg(p2p, "Initially selected channel (op_class %d channel %d) not in channel intersection - try to reselect", - p2p->op_reg_class, p2p->op_channel); - p2p_reselect_channel(p2p, &intersection); - p2p_dbg(p2p, "Re-selection result: op_class %d channel %d", - p2p->op_reg_class, p2p->op_channel); - if (!p2p_channels_includes(&intersection, - p2p->op_reg_class, - p2p->op_channel)) { - p2p_dbg(p2p, "Peer does not support selected operating channel (reg_class=%u channel=%u)", - p2p->op_reg_class, p2p->op_channel); - status = P2P_SC_FAIL_NO_COMMON_CHANNELS; - goto fail; - } - } else if (!(dev->flags & P2P_DEV_FORCE_FREQ) && - !p2p->cfg->cfg_op_channel) { - p2p_dbg(p2p, "Try to reselect channel selection with peer information received; previously selected op_class %u channel %u", - p2p->op_reg_class, p2p->op_channel); - p2p_reselect_channel(p2p, &intersection); - } - - op_freq = p2p_channel_to_freq(p2p->op_reg_class, - p2p->op_channel); - if (op_freq < 0) { - p2p_dbg(p2p, "Unknown operational channel (country=%c%c reg_class=%u channel=%u)", - p2p->cfg->country[0], p2p->cfg->country[1], - p2p->op_reg_class, p2p->op_channel); - status = P2P_SC_FAIL_NO_COMMON_CHANNELS; - goto fail; - } - p2p_dbg(p2p, "Selected operating channel - %d MHz", op_freq); - - if (status == P2P_SC_SUCCESS) { - reg_class = p2p->op_reg_class; - channel = p2p->op_channel; - channels = &intersection; - } - } - -fail: - if (go && status == P2P_SC_SUCCESS && !is_zero_ether_addr(group_bssid)) - bssid = group_bssid; - else - bssid = NULL; - resp = p2p_build_invitation_resp(p2p, dev, msg.dialog_token, status, - bssid, reg_class, channel, channels); - - if (resp == NULL) - goto out; - - if (rx_freq > 0) - freq = rx_freq; - else - freq = p2p_channel_to_freq(p2p->cfg->reg_class, - p2p->cfg->channel); - if (freq < 0) { - p2p_dbg(p2p, "Unknown regulatory class/channel"); - goto out; - } - - /* - * Store copy of invitation data to be used when processing TX status - * callback for the Acton frame. - */ - os_memcpy(p2p->inv_sa, sa, ETH_ALEN); - if (msg.group_bssid) { - os_memcpy(p2p->inv_group_bssid, msg.group_bssid, ETH_ALEN); - p2p->inv_group_bssid_ptr = p2p->inv_group_bssid; - } else - p2p->inv_group_bssid_ptr = NULL; - if (msg.group_id_len - ETH_ALEN <= 32) { - os_memcpy(p2p->inv_ssid, msg.group_id + ETH_ALEN, - msg.group_id_len - ETH_ALEN); - p2p->inv_ssid_len = msg.group_id_len - ETH_ALEN; - } - os_memcpy(p2p->inv_go_dev_addr, msg.group_id, ETH_ALEN); - p2p->inv_status = status; - p2p->inv_op_freq = op_freq; - - p2p->pending_action_state = P2P_PENDING_INVITATION_RESPONSE; - if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, - p2p->cfg->dev_addr, - wpabuf_head(resp), wpabuf_len(resp), 200) < 0) { - p2p_dbg(p2p, "Failed to send Action frame"); - } - -out: - wpabuf_free(resp); - p2p_parse_free(&msg); -} - - -void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len) -{ - struct p2p_device *dev; - struct p2p_message msg; - struct p2p_channels intersection, *channels = NULL; - - p2p_dbg(p2p, "Received Invitation Response from " MACSTR, - MAC2STR(sa)); - - dev = p2p_get_device(p2p, sa); - if (dev == NULL) { - p2p_dbg(p2p, "Ignore Invitation Response from unknown peer " - MACSTR, MAC2STR(sa)); - return; - } - - if (dev != p2p->invite_peer) { - p2p_dbg(p2p, "Ignore unexpected Invitation Response from peer " - MACSTR, MAC2STR(sa)); - return; - } - - if (p2p_parse(data, len, &msg)) - return; - - if (!msg.status) { - p2p_dbg(p2p, "Mandatory Status attribute missing in Invitation Response from " - MACSTR, MAC2STR(sa)); - p2p_parse_free(&msg); - return; - } - - if (!msg.channel_list && *msg.status == P2P_SC_SUCCESS) { - p2p_dbg(p2p, "Mandatory Channel List attribute missing in Invitation Response from " - MACSTR, MAC2STR(sa)); -#ifdef CONFIG_P2P_STRICT - p2p_parse_free(&msg); - return; -#endif /* CONFIG_P2P_STRICT */ - /* Try to survive without peer channel list */ - channels = &p2p->channels; - } else if (!msg.channel_list) { - /* Non-success cases are not required to include Channel List */ - channels = &p2p->channels; - } else if (p2p_peer_channels_check(p2p, &p2p->channels, dev, - msg.channel_list, - msg.channel_list_len) < 0) { - p2p_dbg(p2p, "No common channels found"); - p2p_parse_free(&msg); - return; - } else { - p2p_channels_intersect(&p2p->channels, &dev->channels, - &intersection); - channels = &intersection; - } - - if (p2p->cfg->invitation_result) { - int freq = p2p_channel_to_freq(p2p->op_reg_class, - p2p->op_channel); - if (freq < 0) - freq = 0; - p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status, - msg.group_bssid, channels, sa, - freq); - } - - p2p_parse_free(&msg); - - p2p_clear_timeout(p2p); - p2p_set_state(p2p, P2P_IDLE); - p2p->invite_peer = NULL; -} - - -int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev, - const u8 *go_dev_addr, int dev_pw_id) -{ - struct wpabuf *req; - int freq; - - freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; - if (freq <= 0) - freq = dev->oob_go_neg_freq; - if (freq <= 0) { - p2p_dbg(p2p, "No Listen/Operating frequency known for the peer " - MACSTR " to send Invitation Request", - MAC2STR(dev->info.p2p_device_addr)); - return -1; - } - - req = p2p_build_invitation_req(p2p, dev, go_dev_addr, dev_pw_id); - if (req == NULL) - return -1; - if (p2p->state != P2P_IDLE) - p2p_stop_listen_for_freq(p2p, freq); - p2p_dbg(p2p, "Sending Invitation Request"); - p2p_set_state(p2p, P2P_INVITE); - p2p->pending_action_state = P2P_PENDING_INVITATION_REQUEST; - p2p->invite_peer = dev; - dev->invitation_reqs++; - if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, - p2p->cfg->dev_addr, dev->info.p2p_device_addr, - wpabuf_head(req), wpabuf_len(req), 500) < 0) { - p2p_dbg(p2p, "Failed to send Action frame"); - /* Use P2P find to recover and retry */ - p2p_set_timeout(p2p, 0, 0); - } - - wpabuf_free(req); - - return 0; -} - - -void p2p_invitation_req_cb(struct p2p_data *p2p, int success) -{ - p2p_dbg(p2p, "Invitation Request TX callback: success=%d", success); - - if (p2p->invite_peer == NULL) { - p2p_dbg(p2p, "No pending Invite"); - return; - } - - /* - * Use P2P find, if needed, to find the other device from its listen - * channel. - */ - p2p_set_state(p2p, P2P_INVITE); - p2p_set_timeout(p2p, 0, success ? 500000 : 100000); -} - - -void p2p_invitation_resp_cb(struct p2p_data *p2p, int success) -{ - p2p_dbg(p2p, "Invitation Response TX callback: success=%d", success); - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - - if (!success) - p2p_dbg(p2p, "Assume Invitation Response was actually received by the peer even though Ack was not reported"); - - if (p2p->cfg->invitation_received) { - p2p->cfg->invitation_received(p2p->cfg->cb_ctx, - p2p->inv_sa, - p2p->inv_group_bssid_ptr, - p2p->inv_ssid, p2p->inv_ssid_len, - p2p->inv_go_dev_addr, - p2p->inv_status, - p2p->inv_op_freq); - } -} - - -int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, - const u8 *bssid, const u8 *ssid, size_t ssid_len, - unsigned int force_freq, const u8 *go_dev_addr, - int persistent_group, unsigned int pref_freq, int dev_pw_id) -{ - struct p2p_device *dev; - - p2p_dbg(p2p, "Request to invite peer " MACSTR " role=%d persistent=%d " - "force_freq=%u", - MAC2STR(peer), role, persistent_group, force_freq); - if (bssid) - p2p_dbg(p2p, "Invitation for BSSID " MACSTR, MAC2STR(bssid)); - if (go_dev_addr) { - p2p_dbg(p2p, "Invitation for GO Device Address " MACSTR, - MAC2STR(go_dev_addr)); - os_memcpy(p2p->invite_go_dev_addr_buf, go_dev_addr, ETH_ALEN); - p2p->invite_go_dev_addr = p2p->invite_go_dev_addr_buf; - } else - p2p->invite_go_dev_addr = NULL; - wpa_hexdump_ascii(MSG_DEBUG, "Invitation for SSID", - ssid, ssid_len); - if (dev_pw_id >= 0) { - p2p_dbg(p2p, "Invitation to use Device Password ID %d", - dev_pw_id); - } - p2p->invite_dev_pw_id = dev_pw_id; - - dev = p2p_get_device(p2p, peer); - if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0 && - dev->oob_go_neg_freq <= 0)) { - p2p_dbg(p2p, "Cannot invite unknown P2P Device " MACSTR, - MAC2STR(peer)); - return -1; - } - - if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq, - role != P2P_INVITE_ROLE_CLIENT) < 0) - return -1; - - if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq && - !pref_freq) - dev->flags |= P2P_DEV_NO_PREF_CHAN; - else - dev->flags &= ~P2P_DEV_NO_PREF_CHAN; - - if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) { - if (!(dev->info.dev_capab & - P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { - p2p_dbg(p2p, "Cannot invite a P2P Device " MACSTR - " that is in a group and is not discoverable", - MAC2STR(peer)); - } - /* TODO: use device discoverability request through GO */ - } - - dev->invitation_reqs = 0; - - if (p2p->state != P2P_IDLE) - p2p_stop_find(p2p); - - p2p->inv_role = role; - p2p->inv_bssid_set = bssid != NULL; - if (bssid) - os_memcpy(p2p->inv_bssid, bssid, ETH_ALEN); - os_memcpy(p2p->inv_ssid, ssid, ssid_len); - p2p->inv_ssid_len = ssid_len; - p2p->inv_persistent = persistent_group; - return p2p_invite_send(p2p, dev, go_dev_addr, dev_pw_id); -} diff --git a/contrib/hostapd/src/p2p/p2p_parse.c b/contrib/hostapd/src/p2p/p2p_parse.c deleted file mode 100644 index d6144a0ebc..0000000000 --- a/contrib/hostapd/src/p2p/p2p_parse.c +++ /dev/null @@ -1,767 +0,0 @@ -/* - * P2P - IE parser - * Copyright (c) 2009-2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "wps/wps_i.h" -#include "p2p_i.h" - - -static int p2p_parse_attribute(u8 id, const u8 *data, u16 len, - struct p2p_message *msg) -{ - const u8 *pos; - size_t i, nlen; - char devtype[WPS_DEV_TYPE_BUFSIZE]; - - switch (id) { - case P2P_ATTR_CAPABILITY: - if (len < 2) { - wpa_printf(MSG_DEBUG, "P2P: Too short Capability " - "attribute (length %d)", len); - return -1; - } - msg->capability = data; - wpa_printf(MSG_DEBUG, "P2P: * Device Capability %02x " - "Group Capability %02x", - data[0], data[1]); - break; - case P2P_ATTR_DEVICE_ID: - if (len < ETH_ALEN) { - wpa_printf(MSG_DEBUG, "P2P: Too short Device ID " - "attribute (length %d)", len); - return -1; - } - msg->device_id = data; - wpa_printf(MSG_DEBUG, "P2P: * Device ID " MACSTR, - MAC2STR(msg->device_id)); - break; - case P2P_ATTR_GROUP_OWNER_INTENT: - if (len < 1) { - wpa_printf(MSG_DEBUG, "P2P: Too short GO Intent " - "attribute (length %d)", len); - return -1; - } - msg->go_intent = data; - wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u " - "Tie breaker %u", data[0] >> 1, data[0] & 0x01); - break; - case P2P_ATTR_STATUS: - if (len < 1) { - wpa_printf(MSG_DEBUG, "P2P: Too short Status " - "attribute (length %d)", len); - return -1; - } - msg->status = data; - wpa_printf(MSG_DEBUG, "P2P: * Status: %d", data[0]); - break; - case P2P_ATTR_LISTEN_CHANNEL: - if (len == 0) { - wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Ignore " - "null channel"); - break; - } - if (len < 5) { - wpa_printf(MSG_DEBUG, "P2P: Too short Listen Channel " - "attribute (length %d)", len); - return -1; - } - msg->listen_channel = data; - wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: " - "Country %c%c(0x%02x) Regulatory " - "Class %d Channel Number %d", data[0], data[1], - data[2], data[3], data[4]); - break; - case P2P_ATTR_OPERATING_CHANNEL: - if (len == 0) { - wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: " - "Ignore null channel"); - break; - } - if (len < 5) { - wpa_printf(MSG_DEBUG, "P2P: Too short Operating " - "Channel attribute (length %d)", len); - return -1; - } - msg->operating_channel = data; - wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: " - "Country %c%c(0x%02x) Regulatory " - "Class %d Channel Number %d", data[0], data[1], - data[2], data[3], data[4]); - break; - case P2P_ATTR_CHANNEL_LIST: - if (len < 3) { - wpa_printf(MSG_DEBUG, "P2P: Too short Channel List " - "attribute (length %d)", len); - return -1; - } - msg->channel_list = data; - msg->channel_list_len = len; - wpa_printf(MSG_DEBUG, "P2P: * Channel List: Country String " - "'%c%c(0x%02x)'", data[0], data[1], data[2]); - wpa_hexdump(MSG_MSGDUMP, "P2P: Channel List", - msg->channel_list, msg->channel_list_len); - break; - case P2P_ATTR_GROUP_INFO: - msg->group_info = data; - msg->group_info_len = len; - wpa_printf(MSG_DEBUG, "P2P: * Group Info"); - break; - case P2P_ATTR_DEVICE_INFO: - if (len < ETH_ALEN + 2 + 8 + 1) { - wpa_printf(MSG_DEBUG, "P2P: Too short Device Info " - "attribute (length %d)", len); - return -1; - } - msg->p2p_device_info = data; - msg->p2p_device_info_len = len; - pos = data; - msg->p2p_device_addr = pos; - pos += ETH_ALEN; - msg->config_methods = WPA_GET_BE16(pos); - pos += 2; - msg->pri_dev_type = pos; - pos += 8; - msg->num_sec_dev_types = *pos++; - if (msg->num_sec_dev_types * 8 > data + len - pos) { - wpa_printf(MSG_DEBUG, "P2P: Device Info underflow"); - return -1; - } - pos += msg->num_sec_dev_types * 8; - if (data + len - pos < 4) { - wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name " - "length %d", (int) (data + len - pos)); - return -1; - } - if (WPA_GET_BE16(pos) != ATTR_DEV_NAME) { - wpa_hexdump(MSG_DEBUG, "P2P: Unexpected Device Name " - "header", pos, 4); - return -1; - } - pos += 2; - nlen = WPA_GET_BE16(pos); - pos += 2; - if (data + len - pos < (int) nlen || nlen > 32) { - wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name " - "length %d (buf len %d)", (int) nlen, - (int) (data + len - pos)); - return -1; - } - os_memcpy(msg->device_name, pos, nlen); - msg->device_name[nlen] = '\0'; - for (i = 0; i < nlen; i++) { - if (msg->device_name[i] == '\0') - break; - if (msg->device_name[i] > 0 && - msg->device_name[i] < 32) - msg->device_name[i] = '_'; - } - wpa_printf(MSG_DEBUG, "P2P: * Device Info: addr " MACSTR - " primary device type %s device name '%s' " - "config methods 0x%x", - MAC2STR(msg->p2p_device_addr), - wps_dev_type_bin2str(msg->pri_dev_type, devtype, - sizeof(devtype)), - msg->device_name, msg->config_methods); - break; - case P2P_ATTR_CONFIGURATION_TIMEOUT: - if (len < 2) { - wpa_printf(MSG_DEBUG, "P2P: Too short Configuration " - "Timeout attribute (length %d)", len); - return -1; - } - msg->config_timeout = data; - wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout"); - break; - case P2P_ATTR_INTENDED_INTERFACE_ADDR: - if (len < ETH_ALEN) { - wpa_printf(MSG_DEBUG, "P2P: Too short Intended P2P " - "Interface Address attribute (length %d)", - len); - return -1; - } - msg->intended_addr = data; - wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address: " - MACSTR, MAC2STR(msg->intended_addr)); - break; - case P2P_ATTR_GROUP_BSSID: - if (len < ETH_ALEN) { - wpa_printf(MSG_DEBUG, "P2P: Too short P2P Group BSSID " - "attribute (length %d)", len); - return -1; - } - msg->group_bssid = data; - wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID: " MACSTR, - MAC2STR(msg->group_bssid)); - break; - case P2P_ATTR_GROUP_ID: - if (len < ETH_ALEN || len > ETH_ALEN + 32) { - wpa_printf(MSG_DEBUG, "P2P: Invalid P2P Group ID " - "attribute length %d", len); - return -1; - } - msg->group_id = data; - msg->group_id_len = len; - wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID: Device Address " - MACSTR, MAC2STR(msg->group_id)); - wpa_hexdump_ascii(MSG_DEBUG, "P2P: * P2P Group ID: SSID", - msg->group_id + ETH_ALEN, - msg->group_id_len - ETH_ALEN); - break; - case P2P_ATTR_INVITATION_FLAGS: - if (len < 1) { - wpa_printf(MSG_DEBUG, "P2P: Too short Invitation " - "Flag attribute (length %d)", len); - return -1; - } - msg->invitation_flags = data; - wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", - data[0]); - break; - case P2P_ATTR_MANAGEABILITY: - if (len < 1) { - wpa_printf(MSG_DEBUG, "P2P: Too short Manageability " - "attribute (length %d)", len); - return -1; - } - msg->manageability = data; - wpa_printf(MSG_DEBUG, "P2P: * Manageability: bitmap 0x%x", - data[0]); - break; - case P2P_ATTR_NOTICE_OF_ABSENCE: - if (len < 2) { - wpa_printf(MSG_DEBUG, "P2P: Too short Notice of " - "Absence attribute (length %d)", len); - return -1; - } - msg->noa = data; - msg->noa_len = len; - wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence"); - break; - case P2P_ATTR_EXT_LISTEN_TIMING: - if (len < 4) { - wpa_printf(MSG_DEBUG, "P2P: Too short Extended Listen " - "Timing attribute (length %d)", len); - return -1; - } - msg->ext_listen_timing = data; - wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing " - "(period %u msec interval %u msec)", - WPA_GET_LE16(msg->ext_listen_timing), - WPA_GET_LE16(msg->ext_listen_timing + 2)); - break; - case P2P_ATTR_MINOR_REASON_CODE: - if (len < 1) { - wpa_printf(MSG_DEBUG, "P2P: Too short Minor Reason " - "Code attribute (length %d)", len); - return -1; - } - msg->minor_reason_code = data; - wpa_printf(MSG_DEBUG, "P2P: * Minor Reason Code: %u", - *msg->minor_reason_code); - break; - case P2P_ATTR_OOB_GO_NEG_CHANNEL: - if (len < 6) { - wpa_printf(MSG_DEBUG, "P2P: Too short OOB GO Neg " - "Channel attribute (length %d)", len); - return -1; - } - msg->oob_go_neg_channel = data; - wpa_printf(MSG_DEBUG, "P2P: * OOB GO Neg Channel: " - "Country %c%c(0x%02x) Operating Class %d " - "Channel Number %d Role %d", - data[0], data[1], data[2], data[3], data[4], - data[5]); - break; - default: - wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d " - "(length %d)", id, len); - break; - } - - return 0; -} - - -/** - * p2p_parse_p2p_ie - Parse P2P IE - * @buf: Concatenated P2P IE(s) payload - * @msg: Buffer for returning parsed attributes - * Returns: 0 on success, -1 on failure - * - * Note: Caller is responsible for clearing the msg data structure before - * calling this function. - */ -int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg) -{ - const u8 *pos = wpabuf_head_u8(buf); - const u8 *end = pos + wpabuf_len(buf); - - wpa_printf(MSG_DEBUG, "P2P: Parsing P2P IE"); - - while (pos < end) { - u16 attr_len; - if (pos + 2 >= end) { - wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute"); - return -1; - } - attr_len = WPA_GET_LE16(pos + 1); - wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u", - pos[0], attr_len); - if (pos + 3 + attr_len > end) { - wpa_printf(MSG_DEBUG, "P2P: Attribute underflow " - "(len=%u left=%d)", - attr_len, (int) (end - pos - 3)); - wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos); - return -1; - } - if (p2p_parse_attribute(pos[0], pos + 3, attr_len, msg)) - return -1; - pos += 3 + attr_len; - } - - return 0; -} - - -static int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg) -{ - struct wps_parse_attr attr; - int i; - - wpa_printf(MSG_DEBUG, "P2P: Parsing WPS IE"); - if (wps_parse_msg(buf, &attr)) - return -1; - if (attr.dev_name && attr.dev_name_len < sizeof(msg->device_name) && - !msg->device_name[0]) - os_memcpy(msg->device_name, attr.dev_name, attr.dev_name_len); - if (attr.config_methods) { - msg->wps_config_methods = - WPA_GET_BE16(attr.config_methods); - wpa_printf(MSG_DEBUG, "P2P: Config Methods (WPS): 0x%x", - msg->wps_config_methods); - } - if (attr.dev_password_id) { - msg->dev_password_id = WPA_GET_BE16(attr.dev_password_id); - wpa_printf(MSG_DEBUG, "P2P: Device Password ID: %d", - msg->dev_password_id); - msg->dev_password_id_present = 1; - } - if (attr.primary_dev_type) { - char devtype[WPS_DEV_TYPE_BUFSIZE]; - msg->wps_pri_dev_type = attr.primary_dev_type; - wpa_printf(MSG_DEBUG, "P2P: Primary Device Type (WPS): %s", - wps_dev_type_bin2str(msg->wps_pri_dev_type, devtype, - sizeof(devtype))); - } - if (attr.sec_dev_type_list) { - msg->wps_sec_dev_type_list = attr.sec_dev_type_list; - msg->wps_sec_dev_type_list_len = attr.sec_dev_type_list_len; - } - - for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { - msg->wps_vendor_ext[i] = attr.vendor_ext[i]; - msg->wps_vendor_ext_len[i] = attr.vendor_ext_len[i]; - } - - msg->manufacturer = attr.manufacturer; - msg->manufacturer_len = attr.manufacturer_len; - msg->model_name = attr.model_name; - msg->model_name_len = attr.model_name_len; - msg->model_number = attr.model_number; - msg->model_number_len = attr.model_number_len; - msg->serial_number = attr.serial_number; - msg->serial_number_len = attr.serial_number_len; - - msg->oob_dev_password = attr.oob_dev_password; - msg->oob_dev_password_len = attr.oob_dev_password_len; - - return 0; -} - - -/** - * p2p_parse_ies - Parse P2P message IEs (both WPS and P2P IE) - * @data: IEs from the message - * @len: Length of data buffer in octets - * @msg: Buffer for returning parsed attributes - * Returns: 0 on success, -1 on failure - * - * Note: Caller is responsible for clearing the msg data structure before - * calling this function. - * - * Note: Caller must free temporary memory allocations by calling - * p2p_parse_free() when the parsed data is not needed anymore. - */ -int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg) -{ - struct ieee802_11_elems elems; - - ieee802_11_parse_elems(data, len, &elems, 0); - if (elems.ds_params && elems.ds_params_len >= 1) - msg->ds_params = elems.ds_params; - if (elems.ssid) - msg->ssid = elems.ssid - 2; - - msg->wps_attributes = ieee802_11_vendor_ie_concat(data, len, - WPS_DEV_OUI_WFA); - if (msg->wps_attributes && - p2p_parse_wps_ie(msg->wps_attributes, msg)) { - p2p_parse_free(msg); - return -1; - } - - msg->p2p_attributes = ieee802_11_vendor_ie_concat(data, len, - P2P_IE_VENDOR_TYPE); - if (msg->p2p_attributes && - p2p_parse_p2p_ie(msg->p2p_attributes, msg)) { - wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data"); - if (msg->p2p_attributes) - wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data", - msg->p2p_attributes); - p2p_parse_free(msg); - return -1; - } - -#ifdef CONFIG_WIFI_DISPLAY - if (elems.wfd) { - msg->wfd_subelems = ieee802_11_vendor_ie_concat( - data, len, WFD_IE_VENDOR_TYPE); - } -#endif /* CONFIG_WIFI_DISPLAY */ - - return 0; -} - - -/** - * p2p_parse - Parse a P2P Action frame contents - * @data: Action frame payload after Category and Code fields - * @len: Length of data buffer in octets - * @msg: Buffer for returning parsed attributes - * Returns: 0 on success, -1 on failure - * - * Note: Caller must free temporary memory allocations by calling - * p2p_parse_free() when the parsed data is not needed anymore. - */ -int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg) -{ - os_memset(msg, 0, sizeof(*msg)); - wpa_printf(MSG_DEBUG, "P2P: Parsing the received message"); - if (len < 1) { - wpa_printf(MSG_DEBUG, "P2P: No Dialog Token in the message"); - return -1; - } - msg->dialog_token = data[0]; - wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", msg->dialog_token); - - return p2p_parse_ies(data + 1, len - 1, msg); -} - - -int p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p, - size_t p2p_len, struct p2p_message *msg) -{ - os_memset(msg, 0, sizeof(*msg)); - - msg->wps_attributes = wpabuf_alloc_copy(wsc, wsc_len); - if (msg->wps_attributes && - p2p_parse_wps_ie(msg->wps_attributes, msg)) { - p2p_parse_free(msg); - return -1; - } - - msg->p2p_attributes = wpabuf_alloc_copy(p2p, p2p_len); - if (msg->p2p_attributes && - p2p_parse_p2p_ie(msg->p2p_attributes, msg)) { - wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data"); - if (msg->p2p_attributes) - wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data", - msg->p2p_attributes); - p2p_parse_free(msg); - return -1; - } - - return 0; -} - - -/** - * p2p_parse_free - Free temporary data from P2P parsing - * @msg: Parsed attributes - */ -void p2p_parse_free(struct p2p_message *msg) -{ - wpabuf_free(msg->p2p_attributes); - msg->p2p_attributes = NULL; - wpabuf_free(msg->wps_attributes); - msg->wps_attributes = NULL; -#ifdef CONFIG_WIFI_DISPLAY - wpabuf_free(msg->wfd_subelems); - msg->wfd_subelems = NULL; -#endif /* CONFIG_WIFI_DISPLAY */ -} - - -int p2p_group_info_parse(const u8 *gi, size_t gi_len, - struct p2p_group_info *info) -{ - const u8 *g, *gend; - - os_memset(info, 0, sizeof(*info)); - if (gi == NULL) - return 0; - - g = gi; - gend = gi + gi_len; - while (g < gend) { - struct p2p_client_info *cli; - const u8 *t, *cend; - int count; - - cli = &info->client[info->num_clients]; - cend = g + 1 + g[0]; - if (cend > gend) - return -1; /* invalid data */ - /* g at start of P2P Client Info Descriptor */ - /* t at Device Capability Bitmap */ - t = g + 1 + 2 * ETH_ALEN; - if (t > cend) - return -1; /* invalid data */ - cli->p2p_device_addr = g + 1; - cli->p2p_interface_addr = g + 1 + ETH_ALEN; - cli->dev_capab = t[0]; - - if (t + 1 + 2 + 8 + 1 > cend) - return -1; /* invalid data */ - - cli->config_methods = WPA_GET_BE16(&t[1]); - cli->pri_dev_type = &t[3]; - - t += 1 + 2 + 8; - /* t at Number of Secondary Device Types */ - cli->num_sec_dev_types = *t++; - if (t + 8 * cli->num_sec_dev_types > cend) - return -1; /* invalid data */ - cli->sec_dev_types = t; - t += 8 * cli->num_sec_dev_types; - - /* t at Device Name in WPS TLV format */ - if (t + 2 + 2 > cend) - return -1; /* invalid data */ - if (WPA_GET_BE16(t) != ATTR_DEV_NAME) - return -1; /* invalid Device Name TLV */ - t += 2; - count = WPA_GET_BE16(t); - t += 2; - if (count > cend - t) - return -1; /* invalid Device Name TLV */ - if (count >= 32) - count = 32; - cli->dev_name = (const char *) t; - cli->dev_name_len = count; - - g = cend; - - info->num_clients++; - if (info->num_clients == P2P_MAX_GROUP_ENTRIES) - return -1; - } - - return 0; -} - - -static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf, - char *end) -{ - char *pos = buf; - int ret; - struct p2p_group_info info; - unsigned int i; - - if (p2p_group_info_parse(gi, gi_len, &info) < 0) - return 0; - - for (i = 0; i < info.num_clients; i++) { - struct p2p_client_info *cli; - char name[33]; - char devtype[WPS_DEV_TYPE_BUFSIZE]; - u8 s; - int count; - - cli = &info.client[i]; - ret = os_snprintf(pos, end - pos, "p2p_group_client: " - "dev=" MACSTR " iface=" MACSTR, - MAC2STR(cli->p2p_device_addr), - MAC2STR(cli->p2p_interface_addr)); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - ret = os_snprintf(pos, end - pos, - " dev_capab=0x%x config_methods=0x%x " - "dev_type=%s", - cli->dev_capab, cli->config_methods, - wps_dev_type_bin2str(cli->pri_dev_type, - devtype, - sizeof(devtype))); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - for (s = 0; s < cli->num_sec_dev_types; s++) { - ret = os_snprintf(pos, end - pos, " dev_type=%s", - wps_dev_type_bin2str( - &cli->sec_dev_types[s * 8], - devtype, sizeof(devtype))); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - - os_memcpy(name, cli->dev_name, cli->dev_name_len); - name[cli->dev_name_len] = '\0'; - count = (int) cli->dev_name_len - 1; - while (count >= 0) { - if (name[count] > 0 && name[count] < 32) - name[count] = '_'; - count--; - } - - ret = os_snprintf(pos, end - pos, " dev_name='%s'\n", name); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - - return pos - buf; -} - - -/** - * p2p_attr_text - Build text format description of P2P IE attributes - * @data: P2P IE contents - * @buf: Buffer for returning text - * @end: Pointer to the end of the buf area - * Returns: Number of octets written to the buffer or -1 on faikure - * - * This function can be used to parse P2P IE contents into text format - * field=value lines. - */ -int p2p_attr_text(struct wpabuf *data, char *buf, char *end) -{ - struct p2p_message msg; - char *pos = buf; - int ret; - - os_memset(&msg, 0, sizeof(msg)); - if (p2p_parse_p2p_ie(data, &msg)) - return -1; - - if (msg.capability) { - ret = os_snprintf(pos, end - pos, - "p2p_dev_capab=0x%x\n" - "p2p_group_capab=0x%x\n", - msg.capability[0], msg.capability[1]); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - - if (msg.pri_dev_type) { - char devtype[WPS_DEV_TYPE_BUFSIZE]; - ret = os_snprintf(pos, end - pos, - "p2p_primary_device_type=%s\n", - wps_dev_type_bin2str(msg.pri_dev_type, - devtype, - sizeof(devtype))); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - - ret = os_snprintf(pos, end - pos, "p2p_device_name=%s\n", - msg.device_name); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - if (msg.p2p_device_addr) { - ret = os_snprintf(pos, end - pos, "p2p_device_addr=" MACSTR - "\n", - MAC2STR(msg.p2p_device_addr)); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - - ret = os_snprintf(pos, end - pos, "p2p_config_methods=0x%x\n", - msg.config_methods); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - ret = p2p_group_info_text(msg.group_info, msg.group_info_len, - pos, end); - if (ret < 0) - return pos - buf; - pos += ret; - - return pos - buf; -} - - -int p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie) -{ - struct p2p_message msg; - - os_memset(&msg, 0, sizeof(msg)); - if (p2p_parse_p2p_ie(p2p_ie, &msg)) - return 0; - - if (!msg.manageability) - return 0; - - return !(msg.manageability[0] & P2P_MAN_CROSS_CONNECTION_PERMITTED); -} - - -u8 p2p_get_group_capab(const struct wpabuf *p2p_ie) -{ - struct p2p_message msg; - - os_memset(&msg, 0, sizeof(msg)); - if (p2p_parse_p2p_ie(p2p_ie, &msg)) - return 0; - - if (!msg.capability) - return 0; - - return msg.capability[1]; -} - - -const u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie) -{ - struct p2p_message msg; - - os_memset(&msg, 0, sizeof(msg)); - if (p2p_parse_p2p_ie(p2p_ie, &msg)) - return NULL; - - if (msg.p2p_device_addr) - return msg.p2p_device_addr; - if (msg.device_id) - return msg.device_id; - - return NULL; -} diff --git a/contrib/hostapd/src/p2p/p2p_pd.c b/contrib/hostapd/src/p2p/p2p_pd.c deleted file mode 100644 index 409405fb26..0000000000 --- a/contrib/hostapd/src/p2p/p2p_pd.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Wi-Fi Direct - P2P provision discovery - * Copyright (c) 2009-2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "common/ieee802_11_defs.h" -#include "wps/wps_defs.h" -#include "p2p_i.h" -#include "p2p.h" - - -/* - * Number of retries to attempt for provision discovery requests - * in case the peer is not listening. - */ -#define MAX_PROV_DISC_REQ_RETRIES 120 - - -static void p2p_build_wps_ie_config_methods(struct wpabuf *buf, - u16 config_methods) -{ - u8 *len; - wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); - len = wpabuf_put(buf, 1); - wpabuf_put_be32(buf, WPS_DEV_OUI_WFA); - - /* Config Methods */ - wpabuf_put_be16(buf, ATTR_CONFIG_METHODS); - wpabuf_put_be16(buf, 2); - wpabuf_put_be16(buf, config_methods); - - p2p_buf_update_ie_hdr(buf, len); -} - - -static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, - u8 dialog_token, - u16 config_methods, - struct p2p_device *go) -{ - struct wpabuf *buf; - u8 *len; - size_t extra = 0; - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p->wfd_ie_prov_disc_req) - extra = wpabuf_len(p2p->wfd_ie_prov_disc_req); -#endif /* CONFIG_WIFI_DISPLAY */ - - buf = wpabuf_alloc(1000 + extra); - if (buf == NULL) - return NULL; - - p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token); - - len = p2p_buf_add_ie_hdr(buf); - p2p_buf_add_capability(buf, p2p->dev_capab & - ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0); - p2p_buf_add_device_info(buf, p2p, NULL); - if (go) { - p2p_buf_add_group_id(buf, go->info.p2p_device_addr, - go->oper_ssid, go->oper_ssid_len); - } - p2p_buf_update_ie_hdr(buf, len); - - /* WPS IE with Config Methods attribute */ - p2p_build_wps_ie_config_methods(buf, config_methods); - -#ifdef CONFIG_WIFI_DISPLAY - if (p2p->wfd_ie_prov_disc_req) - wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req); -#endif /* CONFIG_WIFI_DISPLAY */ - - return buf; -} - - -static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p, - u8 dialog_token, - u16 config_methods, - const u8 *group_id, - size_t group_id_len) -{ - struct wpabuf *buf; - size_t extra = 0; - -#ifdef CONFIG_WIFI_DISPLAY - struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp; - if (wfd_ie && group_id) { - size_t i; - for (i = 0; i < p2p->num_groups; i++) { - struct p2p_group *g = p2p->groups[i]; - struct wpabuf *ie; - if (!p2p_group_is_group_id_match(g, group_id, - group_id_len)) - continue; - ie = p2p_group_get_wfd_ie(g); - if (ie) { - wfd_ie = ie; - break; - } - } - } - if (wfd_ie) - extra = wpabuf_len(wfd_ie); -#endif /* CONFIG_WIFI_DISPLAY */ - - buf = wpabuf_alloc(100 + extra); - if (buf == NULL) - return NULL; - - p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token); - - /* WPS IE with Config Methods attribute */ - p2p_build_wps_ie_config_methods(buf, config_methods); - -#ifdef CONFIG_WIFI_DISPLAY - if (wfd_ie) - wpabuf_put_buf(buf, wfd_ie); -#endif /* CONFIG_WIFI_DISPLAY */ - - return buf; -} - - -void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) -{ - struct p2p_message msg; - struct p2p_device *dev; - int freq; - int reject = 1; - struct wpabuf *resp; - - if (p2p_parse(data, len, &msg)) - return; - - p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR - " with config methods 0x%x (freq=%d)", - MAC2STR(sa), msg.wps_config_methods, rx_freq); - - dev = p2p_get_device(p2p, sa); - if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { - p2p_dbg(p2p, "Provision Discovery Request from unknown peer " - MACSTR, MAC2STR(sa)); - - if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1, - 0)) { - p2p_dbg(p2p, "Provision Discovery Request add device failed " - MACSTR, MAC2STR(sa)); - } - } else if (msg.wfd_subelems) { - wpabuf_free(dev->info.wfd_subelems); - dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); - } - - if (!(msg.wps_config_methods & - (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | - WPS_CONFIG_PUSHBUTTON))) { - p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request"); - goto out; - } - - if (msg.group_id) { - size_t i; - for (i = 0; i < p2p->num_groups; i++) { - if (p2p_group_is_group_id_match(p2p->groups[i], - msg.group_id, - msg.group_id_len)) - break; - } - if (i == p2p->num_groups) { - p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject"); - goto out; - } - } - - if (dev) - dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY | - P2P_DEV_PD_PEER_KEYPAD); - if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) { - p2p_dbg(p2p, "Peer " MACSTR - " requested us to show a PIN on display", MAC2STR(sa)); - if (dev) - dev->flags |= P2P_DEV_PD_PEER_KEYPAD; - } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { - p2p_dbg(p2p, "Peer " MACSTR - " requested us to write its PIN using keypad", - MAC2STR(sa)); - if (dev) - dev->flags |= P2P_DEV_PD_PEER_DISPLAY; - } - - reject = 0; - -out: - resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token, - reject ? 0 : msg.wps_config_methods, - msg.group_id, msg.group_id_len); - if (resp == NULL) { - p2p_parse_free(&msg); - return; - } - p2p_dbg(p2p, "Sending Provision Discovery Response"); - if (rx_freq > 0) - freq = rx_freq; - else - freq = p2p_channel_to_freq(p2p->cfg->reg_class, - p2p->cfg->channel); - if (freq < 0) { - p2p_dbg(p2p, "Unknown regulatory class/channel"); - wpabuf_free(resp); - p2p_parse_free(&msg); - return; - } - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, - p2p->cfg->dev_addr, - wpabuf_head(resp), wpabuf_len(resp), 200) < 0) { - p2p_dbg(p2p, "Failed to send Action frame"); - } - - wpabuf_free(resp); - - if (!reject && p2p->cfg->prov_disc_req) { - const u8 *dev_addr = sa; - if (msg.p2p_device_addr) - dev_addr = msg.p2p_device_addr; - p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa, - msg.wps_config_methods, - dev_addr, msg.pri_dev_type, - msg.device_name, msg.config_methods, - msg.capability ? msg.capability[0] : 0, - msg.capability ? msg.capability[1] : - 0, - msg.group_id, msg.group_id_len); - } - p2p_parse_free(&msg); -} - - -void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len) -{ - struct p2p_message msg; - struct p2p_device *dev; - u16 report_config_methods = 0, req_config_methods; - int success = 0; - - if (p2p_parse(data, len, &msg)) - return; - - p2p_dbg(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) { - p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR - " with no pending request", MAC2STR(sa)); - p2p_parse_free(&msg); - return; - } - - if (dev->dialog_token != msg.dialog_token) { - p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)", - msg.dialog_token, dev->dialog_token); - p2p_parse_free(&msg); - return; - } - - if (p2p->pending_action_state == P2P_PENDING_PD) { - os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN); - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - } - - /* - * Use a local copy of the requested config methods since - * p2p_reset_pending_pd() can clear this in the peer entry. - */ - req_config_methods = dev->req_config_methods; - - /* - * If the response is from the peer to whom a user initiated request - * was sent earlier, we reset that state info here. - */ - if (p2p->user_initiated_pd && - os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0) - p2p_reset_pending_pd(p2p); - - if (msg.wps_config_methods != req_config_methods) { - p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x", - msg.wps_config_methods, req_config_methods); - if (p2p->cfg->prov_disc_fail) - p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, - P2P_PROV_DISC_REJECTED); - p2p_parse_free(&msg); - goto out; - } - - report_config_methods = req_config_methods; - dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY | - P2P_DEV_PD_PEER_KEYPAD); - if (req_config_methods & WPS_CONFIG_DISPLAY) { - p2p_dbg(p2p, "Peer " MACSTR - " accepted to show a PIN on display", MAC2STR(sa)); - dev->flags |= P2P_DEV_PD_PEER_DISPLAY; - } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { - p2p_dbg(p2p, "Peer " MACSTR - " accepted to write our PIN using keypad", - 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); - success = 1; - -out: - dev->req_config_methods = 0; - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) { - p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with " - MACSTR, MAC2STR(dev->info.p2p_device_addr)); - dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG; - p2p_connect_send(p2p, dev); - return; - } - if (success && p2p->cfg->prov_disc_resp) - p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa, - report_config_methods); - - if (p2p->state == P2P_PD_DURING_FIND) { - p2p_clear_timeout(p2p); - p2p_continue_find(p2p); - } -} - - -int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, - int join, int force_freq) -{ - struct wpabuf *req; - int freq; - - if (force_freq > 0) - freq = force_freq; - else - freq = dev->listen_freq > 0 ? dev->listen_freq : - dev->oper_freq; - if (freq <= 0) { - p2p_dbg(p2p, "No Listen/Operating frequency known for the peer " - MACSTR " to send Provision Discovery Request", - MAC2STR(dev->info.p2p_device_addr)); - return -1; - } - - if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) { - if (!(dev->info.dev_capab & - P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { - p2p_dbg(p2p, "Cannot use PD with P2P Device " MACSTR - " that is in a group and is not discoverable", - MAC2STR(dev->info.p2p_device_addr)); - return -1; - } - /* TODO: use device discoverability request through GO */ - } - - req = p2p_build_prov_disc_req(p2p, dev->dialog_token, - dev->req_config_methods, - join ? dev : NULL); - if (req == NULL) - return -1; - - if (p2p->state != P2P_IDLE) - p2p_stop_listen_for_freq(p2p, freq); - p2p->pending_action_state = P2P_PENDING_PD; - if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, - p2p->cfg->dev_addr, dev->info.p2p_device_addr, - wpabuf_head(req), wpabuf_len(req), 200) < 0) { - p2p_dbg(p2p, "Failed to send Action frame"); - wpabuf_free(req); - return -1; - } - - os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN); - - wpabuf_free(req); - return 0; -} - - -int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, - u16 config_methods, int join, int force_freq, - int user_initiated_pd) -{ - struct p2p_device *dev; - - dev = p2p_get_device(p2p, peer_addr); - if (dev == NULL) - dev = p2p_get_device_interface(p2p, peer_addr); - if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { - p2p_dbg(p2p, "Provision Discovery Request destination " MACSTR - " not yet known", MAC2STR(peer_addr)); - return -1; - } - - p2p_dbg(p2p, "Provision Discovery Request with " MACSTR - " (config methods 0x%x)", - MAC2STR(peer_addr), config_methods); - 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; - else - dev->flags &= ~P2P_DEV_PD_FOR_JOIN; - - if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH && - p2p->state != P2P_LISTEN_ONLY) { - p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with " - MACSTR " (config methods 0x%x)", - MAC2STR(peer_addr), config_methods); - return 0; - } - - p2p->user_initiated_pd = user_initiated_pd; - p2p->pd_force_freq = force_freq; - - if (p2p->user_initiated_pd) - p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES; - - /* - * Assign dialog token here to use the same value in each retry within - * the same PD exchange. - */ - dev->dialog_token++; - if (dev->dialog_token == 0) - dev->dialog_token = 1; - - 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; - p2p->pd_force_freq = 0; -} diff --git a/contrib/hostapd/src/p2p/p2p_sd.c b/contrib/hostapd/src/p2p/p2p_sd.c deleted file mode 100644 index 0e0c7f121e..0000000000 --- a/contrib/hostapd/src/p2p/p2p_sd.c +++ /dev/null @@ -1,879 +0,0 @@ -/* - * Wi-Fi Direct - P2P service discovery - * Copyright (c) 2009, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "common/ieee802_11_defs.h" -#include "common/gas.h" -#include "p2p_i.h" -#include "p2p.h" - - -#ifdef CONFIG_WIFI_DISPLAY -static int wfd_wsd_supported(struct wpabuf *wfd) -{ - const u8 *pos, *end; - u8 subelem; - u16 len; - - if (wfd == NULL) - return 0; - - pos = wpabuf_head(wfd); - end = pos + wpabuf_len(wfd); - - while (pos + 3 <= end) { - subelem = *pos++; - len = WPA_GET_BE16(pos); - pos += 2; - if (pos + len > end) - break; - - if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) { - u16 info = WPA_GET_BE16(pos); - return !!(info & 0x0040); - } - - pos += len; - } - - return 0; -} -#endif /* CONFIG_WIFI_DISPLAY */ - -struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p, - struct p2p_device *dev) -{ - struct p2p_sd_query *q; - int wsd = 0; - - if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY)) - return NULL; /* peer does not support SD */ -#ifdef CONFIG_WIFI_DISPLAY - if (wfd_wsd_supported(dev->info.wfd_subelems)) - wsd = 1; -#endif /* CONFIG_WIFI_DISPLAY */ - - for (q = p2p->sd_queries; q; q = q->next) { - /* Use WSD only if the peer indicates support or it */ - if (q->wsd && !wsd) - continue; - if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO)) - return q; - if (!q->for_all_peers && - os_memcmp(q->peer, dev->info.p2p_device_addr, ETH_ALEN) == - 0) - return q; - } - - return NULL; -} - - -static int p2p_unlink_sd_query(struct p2p_data *p2p, - struct p2p_sd_query *query) -{ - struct p2p_sd_query *q, *prev; - q = p2p->sd_queries; - prev = NULL; - while (q) { - if (q == query) { - if (prev) - prev->next = q->next; - else - p2p->sd_queries = q->next; - if (p2p->sd_query == query) - p2p->sd_query = NULL; - return 1; - } - prev = q; - q = q->next; - } - return 0; -} - - -static void p2p_free_sd_query(struct p2p_sd_query *q) -{ - if (q == NULL) - return; - wpabuf_free(q->tlvs); - os_free(q); -} - - -void p2p_free_sd_queries(struct p2p_data *p2p) -{ - struct p2p_sd_query *q, *prev; - q = p2p->sd_queries; - p2p->sd_queries = NULL; - while (q) { - prev = q; - q = q->next; - p2p_free_sd_query(prev); - } -} - - -static struct wpabuf * p2p_build_sd_query(u16 update_indic, - struct wpabuf *tlvs) -{ - struct wpabuf *buf; - u8 *len_pos; - - buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs)); - if (buf == NULL) - return NULL; - - /* 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); - - gas_anqp_set_len(buf); - - return buf; -} - - -static void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst, - u8 dialog_token, int freq) -{ - struct wpabuf *req; - - req = gas_build_comeback_req(dialog_token); - if (req == NULL) - return; - - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, dst, - wpabuf_head(req), wpabuf_len(req), 200) < 0) - p2p_dbg(p2p, "Failed to send Action frame"); - - wpabuf_free(req); -} - - -static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code, - u16 comeback_delay, - u16 update_indic, - const struct wpabuf *tlvs) -{ - struct wpabuf *buf; - u8 *len_pos; - - buf = gas_anqp_build_initial_resp(dialog_token, status_code, - comeback_delay, - 100 + (tlvs ? wpabuf_len(tlvs) : 0)); - if (buf == NULL) - return NULL; - - if (tlvs) { - /* 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); - gas_anqp_set_element_len(buf, len_pos); - } - - gas_anqp_set_len(buf); - - return buf; -} - - -static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token, - u16 status_code, - u16 update_indic, - const u8 *data, size_t len, - u8 frag_id, u8 more, - u16 total_len) -{ - struct wpabuf *buf; - - buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id, - more, 0, 100 + len); - if (buf == NULL) - return NULL; - - if (frag_id == 0) { - /* 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); - /* Service Update Indicator */ - wpabuf_put_le16(buf, update_indic); - } - - wpabuf_put_data(buf, data, len); - gas_anqp_set_len(buf); - - return buf; -} - - -int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev) -{ - struct wpabuf *req; - int ret = 0; - struct p2p_sd_query *query; - int freq; - - freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; - if (freq <= 0) { - p2p_dbg(p2p, "No Listen/Operating frequency known for the peer " - MACSTR " to send SD Request", - MAC2STR(dev->info.p2p_device_addr)); - return -1; - } - - query = p2p_pending_sd_req(p2p, dev); - if (query == NULL) - return -1; - - p2p_dbg(p2p, "Start Service Discovery with " MACSTR, - MAC2STR(dev->info.p2p_device_addr)); - - req = p2p_build_sd_query(p2p->srv_update_indic, query->tlvs); - if (req == NULL) - return -1; - - p2p->sd_peer = dev; - p2p->sd_query = query; - p2p->pending_action_state = P2P_PENDING_SD; - - if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, - p2p->cfg->dev_addr, dev->info.p2p_device_addr, - wpabuf_head(req), wpabuf_len(req), 5000) < 0) { - p2p_dbg(p2p, "Failed to send Action frame"); - ret = -1; - } - - wpabuf_free(req); - - return ret; -} - - -void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) -{ - const u8 *pos = data; - const u8 *end = data + len; - const u8 *next; - u8 dialog_token; - u16 slen; - int freq; - u16 update_indic; - - - if (p2p->cfg->sd_request == NULL) - return; - - if (rx_freq > 0) - freq = rx_freq; - else - freq = p2p_channel_to_freq(p2p->cfg->reg_class, - p2p->cfg->channel); - if (freq < 0) - return; - - if (len < 1 + 2) - return; - - dialog_token = *pos++; - p2p_dbg(p2p, "GAS Initial Request from " MACSTR - " (dialog token %u, freq %d)", - MAC2STR(sa), dialog_token, rx_freq); - - if (*pos != WLAN_EID_ADV_PROTO) { - p2p_dbg(p2p, "Unexpected IE in GAS Initial Request: %u", *pos); - return; - } - pos++; - - slen = *pos++; - next = pos + slen; - if (next > end || slen < 2) { - p2p_dbg(p2p, "Invalid IE in GAS Initial Request"); - return; - } - pos++; /* skip QueryRespLenLimit and PAME-BI */ - - if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { - p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u", - *pos); - return; - } - - pos = next; - /* Query Request */ - if (pos + 2 > end) - return; - slen = WPA_GET_LE16(pos); - pos += 2; - if (pos + slen > end) - return; - end = pos + slen; - - /* ANQP Query Request */ - if (pos + 4 > end) - return; - if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { - p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); - return; - } - pos += 2; - - slen = WPA_GET_LE16(pos); - pos += 2; - if (pos + slen > end || slen < 3 + 1) { - p2p_dbg(p2p, "Invalid ANQP Query Request length"); - return; - } - - if (WPA_GET_BE24(pos) != OUI_WFA) { - p2p_dbg(p2p, "Unsupported ANQP OUI %06x", WPA_GET_BE24(pos)); - return; - } - pos += 3; - - if (*pos != P2P_OUI_TYPE) { - p2p_dbg(p2p, "Unsupported ANQP vendor type %u", *pos); - return; - } - pos++; - - if (pos + 2 > end) - return; - update_indic = WPA_GET_LE16(pos); - p2p_dbg(p2p, "Service Update Indicator: %u", update_indic); - pos += 2; - - p2p->cfg->sd_request(p2p->cfg->cb_ctx, freq, sa, dialog_token, - update_indic, pos, end - pos); - /* the response will be indicated with a call to p2p_sd_response() */ -} - - -void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst, - u8 dialog_token, const struct wpabuf *resp_tlvs) -{ - struct wpabuf *resp; - - /* TODO: fix the length limit to match with the maximum frame length */ - if (wpabuf_len(resp_tlvs) > 1400) { - p2p_dbg(p2p, "SD response long enough to require fragmentation"); - if (p2p->sd_resp) { - /* - * TODO: Could consider storing the fragmented response - * separately for each peer to avoid having to drop old - * one if there is more than one pending SD query. - * Though, that would eat more memory, so there are - * also benefits to just using a single buffer. - */ - p2p_dbg(p2p, "Drop previous SD response"); - wpabuf_free(p2p->sd_resp); - } - p2p->sd_resp = wpabuf_dup(resp_tlvs); - if (p2p->sd_resp == NULL) { - p2p_err(p2p, "Failed to allocate SD response fragmentation area"); - return; - } - os_memcpy(p2p->sd_resp_addr, dst, ETH_ALEN); - p2p->sd_resp_dialog_token = dialog_token; - p2p->sd_resp_pos = 0; - p2p->sd_frag_id = 0; - resp = p2p_build_sd_response(dialog_token, WLAN_STATUS_SUCCESS, - 1, p2p->srv_update_indic, NULL); - } else { - p2p_dbg(p2p, "SD response fits in initial response"); - resp = p2p_build_sd_response(dialog_token, - WLAN_STATUS_SUCCESS, 0, - p2p->srv_update_indic, resp_tlvs); - } - if (resp == NULL) - return; - - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, - p2p->cfg->dev_addr, - wpabuf_head(resp), wpabuf_len(resp), 200) < 0) - p2p_dbg(p2p, "Failed to send Action frame"); - - wpabuf_free(resp); -} - - -void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) -{ - const u8 *pos = data; - const u8 *end = data + len; - const u8 *next; - u8 dialog_token; - u16 status_code; - u16 comeback_delay; - u16 slen; - u16 update_indic; - - if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL || - os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) { - p2p_dbg(p2p, "Ignore unexpected GAS Initial Response from " - MACSTR, MAC2STR(sa)); - return; - } - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - p2p_clear_timeout(p2p); - - p2p_dbg(p2p, "Received GAS Initial Response from " MACSTR " (len=%d)", - MAC2STR(sa), (int) len); - - if (len < 5 + 2) { - p2p_dbg(p2p, "Too short GAS Initial Response frame"); - return; - } - - dialog_token = *pos++; - /* TODO: check dialog_token match */ - status_code = WPA_GET_LE16(pos); - pos += 2; - comeback_delay = WPA_GET_LE16(pos); - pos += 2; - p2p_dbg(p2p, "dialog_token=%u status_code=%u comeback_delay=%u", - dialog_token, status_code, comeback_delay); - if (status_code) { - p2p_dbg(p2p, "Service Discovery failed: status code %u", - status_code); - return; - } - - if (*pos != WLAN_EID_ADV_PROTO) { - p2p_dbg(p2p, "Unexpected IE in GAS Initial Response: %u", *pos); - return; - } - pos++; - - slen = *pos++; - next = pos + slen; - if (next > end || slen < 2) { - p2p_dbg(p2p, "Invalid IE in GAS Initial Response"); - return; - } - pos++; /* skip QueryRespLenLimit and PAME-BI */ - - if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { - p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u", - *pos); - return; - } - - pos = next; - /* Query Response */ - if (pos + 2 > end) { - p2p_dbg(p2p, "Too short Query Response"); - return; - } - slen = WPA_GET_LE16(pos); - pos += 2; - p2p_dbg(p2p, "Query Response Length: %d", slen); - if (pos + slen > end) { - p2p_dbg(p2p, "Not enough Query Response data"); - return; - } - end = pos + slen; - - if (comeback_delay) { - p2p_dbg(p2p, "Fragmented response - request fragments"); - if (p2p->sd_rx_resp) { - p2p_dbg(p2p, "Drop old SD reassembly buffer"); - wpabuf_free(p2p->sd_rx_resp); - p2p->sd_rx_resp = NULL; - } - p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq); - return; - } - - /* ANQP Query Response */ - if (pos + 4 > end) - return; - if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { - p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); - return; - } - pos += 2; - - slen = WPA_GET_LE16(pos); - pos += 2; - if (pos + slen > end || slen < 3 + 1) { - p2p_dbg(p2p, "Invalid ANQP Query Response length"); - return; - } - - if (WPA_GET_BE24(pos) != OUI_WFA) { - p2p_dbg(p2p, "Unsupported ANQP OUI %06x", WPA_GET_BE24(pos)); - return; - } - pos += 3; - - if (*pos != P2P_OUI_TYPE) { - p2p_dbg(p2p, "Unsupported ANQP vendor type %u", *pos); - return; - } - pos++; - - if (pos + 2 > end) - return; - update_indic = WPA_GET_LE16(pos); - p2p_dbg(p2p, "Service Update Indicator: %u", update_indic); - pos += 2; - - p2p->sd_peer->flags |= P2P_DEV_SD_INFO; - p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE; - p2p->sd_peer = NULL; - - if (p2p->sd_query) { - if (!p2p->sd_query->for_all_peers) { - struct p2p_sd_query *q; - p2p_dbg(p2p, "Remove completed SD query %p", - p2p->sd_query); - q = p2p->sd_query; - p2p_unlink_sd_query(p2p, p2p->sd_query); - p2p_free_sd_query(q); - } - p2p->sd_query = NULL; - } - - if (p2p->cfg->sd_response) - p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, update_indic, - pos, end - pos); - p2p_continue_find(p2p); -} - - -void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) -{ - struct wpabuf *resp; - u8 dialog_token; - size_t frag_len; - int more = 0; - - wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Request", data, len); - if (len < 1) - return; - dialog_token = *data; - p2p_dbg(p2p, "Dialog Token: %u", dialog_token); - if (dialog_token != p2p->sd_resp_dialog_token) { - p2p_dbg(p2p, "No pending SD response fragment for dialog token %u", - dialog_token); - return; - } - - if (p2p->sd_resp == NULL) { - p2p_dbg(p2p, "No pending SD response fragment available"); - return; - } - if (os_memcmp(sa, p2p->sd_resp_addr, ETH_ALEN) != 0) { - p2p_dbg(p2p, "No pending SD response fragment for " MACSTR, - MAC2STR(sa)); - return; - } - - frag_len = wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos; - if (frag_len > 1400) { - frag_len = 1400; - more = 1; - } - resp = p2p_build_gas_comeback_resp(dialog_token, WLAN_STATUS_SUCCESS, - p2p->srv_update_indic, - wpabuf_head_u8(p2p->sd_resp) + - p2p->sd_resp_pos, frag_len, - p2p->sd_frag_id, more, - wpabuf_len(p2p->sd_resp)); - if (resp == NULL) - return; - p2p_dbg(p2p, "Send GAS Comeback Response (frag_id %d more=%d frag_len=%d)", - p2p->sd_frag_id, more, (int) frag_len); - p2p->sd_frag_id++; - p2p->sd_resp_pos += frag_len; - - if (more) { - p2p_dbg(p2p, "%d more bytes remain to be sent", - (int) (wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos)); - } else { - p2p_dbg(p2p, "All fragments of SD response sent"); - wpabuf_free(p2p->sd_resp); - p2p->sd_resp = NULL; - } - - p2p->pending_action_state = P2P_NO_PENDING_ACTION; - if (p2p_send_action(p2p, rx_freq, sa, p2p->cfg->dev_addr, - p2p->cfg->dev_addr, - wpabuf_head(resp), wpabuf_len(resp), 200) < 0) - p2p_dbg(p2p, "Failed to send Action frame"); - - wpabuf_free(resp); -} - - -void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) -{ - const u8 *pos = data; - const u8 *end = data + len; - const u8 *next; - u8 dialog_token; - u16 status_code; - u8 frag_id; - u8 more_frags; - u16 comeback_delay; - u16 slen; - - wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len); - - if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL || - os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) { - p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from " - MACSTR, MAC2STR(sa)); - return; - } - p2p->cfg->send_action_done(p2p->cfg->cb_ctx); - p2p_clear_timeout(p2p); - - p2p_dbg(p2p, "Received GAS Comeback Response from " MACSTR " (len=%d)", - MAC2STR(sa), (int) len); - - if (len < 6 + 2) { - p2p_dbg(p2p, "Too short GAS Comeback Response frame"); - return; - } - - dialog_token = *pos++; - /* TODO: check dialog_token match */ - status_code = WPA_GET_LE16(pos); - pos += 2; - frag_id = *pos & 0x7f; - more_frags = (*pos & 0x80) >> 7; - pos++; - comeback_delay = WPA_GET_LE16(pos); - pos += 2; - p2p_dbg(p2p, "dialog_token=%u status_code=%u frag_id=%d more_frags=%d " - "comeback_delay=%u", - dialog_token, status_code, frag_id, more_frags, - comeback_delay); - /* TODO: check frag_id match */ - if (status_code) { - p2p_dbg(p2p, "Service Discovery failed: status code %u", - status_code); - return; - } - - if (*pos != WLAN_EID_ADV_PROTO) { - p2p_dbg(p2p, "Unexpected IE in GAS Comeback Response: %u", - *pos); - return; - } - pos++; - - slen = *pos++; - next = pos + slen; - if (next > end || slen < 2) { - p2p_dbg(p2p, "Invalid IE in GAS Comeback Response"); - return; - } - pos++; /* skip QueryRespLenLimit and PAME-BI */ - - if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { - p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u", - *pos); - return; - } - - pos = next; - /* Query Response */ - if (pos + 2 > end) { - p2p_dbg(p2p, "Too short Query Response"); - return; - } - slen = WPA_GET_LE16(pos); - pos += 2; - p2p_dbg(p2p, "Query Response Length: %d", slen); - if (pos + slen > end) { - p2p_dbg(p2p, "Not enough Query Response data"); - return; - } - if (slen == 0) { - p2p_dbg(p2p, "No Query Response data"); - return; - } - end = pos + slen; - - if (p2p->sd_rx_resp) { - /* - * ANQP header is only included in the first fragment; rest of - * the fragments start with continue TLVs. - */ - goto skip_nqp_header; - } - - /* ANQP Query Response */ - if (pos + 4 > end) - return; - if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { - p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); - return; - } - pos += 2; - - slen = WPA_GET_LE16(pos); - pos += 2; - p2p_dbg(p2p, "ANQP Query Response length: %u", slen); - if (slen < 3 + 1) { - p2p_dbg(p2p, "Invalid ANQP Query Response length"); - return; - } - if (pos + 4 > end) - return; - - if (WPA_GET_BE24(pos) != OUI_WFA) { - p2p_dbg(p2p, "Unsupported ANQP OUI %06x", WPA_GET_BE24(pos)); - return; - } - pos += 3; - - if (*pos != P2P_OUI_TYPE) { - p2p_dbg(p2p, "Unsupported ANQP vendor type %u", *pos); - return; - } - pos++; - - if (pos + 2 > end) - return; - p2p->sd_rx_update_indic = WPA_GET_LE16(pos); - p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic); - pos += 2; - -skip_nqp_header: - if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0) - return; - wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos); - p2p_dbg(p2p, "Current SD reassembly buffer length: %u", - (unsigned int) wpabuf_len(p2p->sd_rx_resp)); - - if (more_frags) { - p2p_dbg(p2p, "More fragments remains"); - /* TODO: what would be a good size limit? */ - if (wpabuf_len(p2p->sd_rx_resp) > 64000) { - wpabuf_free(p2p->sd_rx_resp); - p2p->sd_rx_resp = NULL; - p2p_dbg(p2p, "Too long SD response - drop it"); - return; - } - p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq); - return; - } - - p2p->sd_peer->flags |= P2P_DEV_SD_INFO; - p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE; - p2p->sd_peer = NULL; - - if (p2p->sd_query) { - if (!p2p->sd_query->for_all_peers) { - struct p2p_sd_query *q; - p2p_dbg(p2p, "Remove completed SD query %p", - p2p->sd_query); - q = p2p->sd_query; - p2p_unlink_sd_query(p2p, p2p->sd_query); - p2p_free_sd_query(q); - } - p2p->sd_query = NULL; - } - - if (p2p->cfg->sd_response) - p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, - p2p->sd_rx_update_indic, - wpabuf_head(p2p->sd_rx_resp), - wpabuf_len(p2p->sd_rx_resp)); - wpabuf_free(p2p->sd_rx_resp); - p2p->sd_rx_resp = NULL; - - p2p_continue_find(p2p); -} - - -void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst, - const struct wpabuf *tlvs) -{ - struct p2p_sd_query *q; - - q = os_zalloc(sizeof(*q)); - if (q == NULL) - return NULL; - - if (dst) - os_memcpy(q->peer, dst, ETH_ALEN); - else - q->for_all_peers = 1; - - q->tlvs = wpabuf_dup(tlvs); - if (q->tlvs == NULL) { - p2p_free_sd_query(q); - return NULL; - } - - q->next = p2p->sd_queries; - p2p->sd_queries = q; - p2p_dbg(p2p, "Added SD Query %p", q); - - if (dst == NULL) { - struct p2p_device *dev; - dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) - dev->flags &= ~P2P_DEV_SD_INFO; - } - - return q; -} - - -#ifdef CONFIG_WIFI_DISPLAY -void * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst, - const struct wpabuf *tlvs) -{ - struct p2p_sd_query *q; - q = p2p_sd_request(p2p, dst, tlvs); - if (q) - q->wsd = 1; - return q; -} -#endif /* CONFIG_WIFI_DISPLAY */ - - -void p2p_sd_service_update(struct p2p_data *p2p) -{ - p2p->srv_update_indic++; -} - - -int p2p_sd_cancel_request(struct p2p_data *p2p, void *req) -{ - if (p2p_unlink_sd_query(p2p, req)) { - p2p_dbg(p2p, "Cancel pending SD query %p", req); - p2p_free_sd_query(req); - return 0; - } - return -1; -} diff --git a/contrib/hostapd/src/p2p/p2p_utils.c b/contrib/hostapd/src/p2p/p2p_utils.c deleted file mode 100644 index 161a402ef3..0000000000 --- a/contrib/hostapd/src/p2p/p2p_utils.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - * P2P - generic helper functions - * Copyright (c) 2009, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "p2p_i.h" - - -/** - * p2p_random - Generate random string for SSID and passphrase - * @buf: Buffer for returning the result - * @len: Number of octets to write to the buffer - * Returns: 0 on success, -1 on failure - * - * This function generates a random string using the following character set: - * 'A'-'Z', 'a'-'z', '0'-'9'. - */ -int p2p_random(char *buf, size_t len) -{ - u8 val; - size_t i; - u8 letters = 'Z' - 'A' + 1; - u8 numbers = 10; - - if (os_get_random((unsigned char *) buf, len)) - return -1; - /* Character set: 'A'-'Z', 'a'-'z', '0'-'9' */ - for (i = 0; i < len; i++) { - val = buf[i]; - val %= 2 * letters + numbers; - if (val < letters) - buf[i] = 'A' + val; - else if (val < 2 * letters) - buf[i] = 'a' + (val - letters); - else - buf[i] = '0' + (val - 2 * letters); - } - - return 0; -} - - -/** - * p2p_channel_to_freq - Convert channel info to frequency - * @op_class: Operating class - * @channel: Channel number - * Returns: Frequency in MHz or -1 if the specified channel is unknown - */ -int p2p_channel_to_freq(int op_class, int channel) -{ - /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */ - /* TODO: more operating classes */ - switch (op_class) { - case 81: - /* channels 1..13 */ - if (channel < 1 || channel > 13) - return -1; - return 2407 + 5 * channel; - case 82: - /* channel 14 */ - if (channel != 14) - return -1; - return 2414 + 5 * channel; - case 83: /* channels 1..9; 40 MHz */ - case 84: /* channels 5..13; 40 MHz */ - if (channel < 1 || channel > 13) - return -1; - return 2407 + 5 * channel; - case 115: /* channels 36,40,44,48; indoor only */ - case 118: /* channels 52,56,60,64; dfs */ - if (channel < 36 || channel > 64) - return -1; - return 5000 + 5 * channel; - case 124: /* channels 149,153,157,161 */ - case 125: /* channels 149,153,157,161,165,169 */ - if (channel < 149 || channel > 161) - return -1; - return 5000 + 5 * channel; - case 116: /* channels 36,44; 40 MHz; indoor only */ - case 117: /* channels 40,48; 40 MHz; indoor only */ - case 119: /* channels 52,60; 40 MHz; dfs */ - case 120: /* channels 56,64; 40 MHz; dfs */ - if (channel < 36 || channel > 64) - return -1; - return 5000 + 5 * channel; - case 126: /* channels 149,157; 40 MHz */ - case 127: /* channels 153,161; 40 MHz */ - if (channel < 149 || channel > 161) - return -1; - return 5000 + 5 * channel; - case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */ - if (channel < 36 || channel > 161) - return -1; - return 5000 + 5 * channel; - } - return -1; -} - - -/** - * p2p_freq_to_channel - Convert frequency into channel info - * @op_class: Buffer for returning operating class - * @channel: Buffer for returning channel number - * Returns: 0 on success, -1 if the specified frequency is unknown - */ -int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel) -{ - /* TODO: more operating classes */ - if (freq >= 2412 && freq <= 2472) { - if ((freq - 2407) % 5) - return -1; - - *op_class = 81; /* 2.407 GHz, channels 1..13 */ - *channel = (freq - 2407) / 5; - return 0; - } - - if (freq == 2484) { - *op_class = 82; /* channel 14 */ - *channel = 14; - return 0; - } - - if (freq >= 5180 && freq <= 5240) { - if ((freq - 5000) % 5) - return -1; - - *op_class = 115; /* 5 GHz, channels 36..48 */ - *channel = (freq - 5000) / 5; - return 0; - } - - if (freq >= 5745 && freq <= 5805) { - if ((freq - 5000) % 5) - return -1; - - *op_class = 124; /* 5 GHz, channels 149..161 */ - *channel = (freq - 5000) / 5; - return 0; - } - - return -1; -} - - -static void p2p_reg_class_intersect(const struct p2p_reg_class *a, - const struct p2p_reg_class *b, - struct p2p_reg_class *res) -{ - size_t i, j; - - res->reg_class = a->reg_class; - - for (i = 0; i < a->channels; i++) { - for (j = 0; j < b->channels; j++) { - if (a->channel[i] != b->channel[j]) - continue; - res->channel[res->channels] = a->channel[i]; - res->channels++; - if (res->channels == P2P_MAX_REG_CLASS_CHANNELS) - return; - } - } -} - - -/** - * p2p_channels_intersect - Intersection of supported channel lists - * @a: First set of supported channels - * @b: Second set of supported channels - * @res: Data structure for returning the intersection of support channels - * - * This function can be used to find a common set of supported channels. Both - * input channels sets are assumed to use the same country code. If different - * country codes are used, the regulatory class numbers may not be matched - * correctly and results are undefined. - */ -void p2p_channels_intersect(const struct p2p_channels *a, - const struct p2p_channels *b, - struct p2p_channels *res) -{ - size_t i, j; - - os_memset(res, 0, sizeof(*res)); - - for (i = 0; i < a->reg_classes; i++) { - const struct p2p_reg_class *a_reg = &a->reg_class[i]; - for (j = 0; j < b->reg_classes; j++) { - const struct p2p_reg_class *b_reg = &b->reg_class[j]; - if (a_reg->reg_class != b_reg->reg_class) - continue; - p2p_reg_class_intersect( - a_reg, b_reg, - &res->reg_class[res->reg_classes]); - if (res->reg_class[res->reg_classes].channels) { - res->reg_classes++; - if (res->reg_classes == P2P_MAX_REG_CLASSES) - return; - } - } - } -} - - -static void p2p_op_class_union(struct p2p_reg_class *cl, - const struct p2p_reg_class *b_cl) -{ - size_t i, j; - - for (i = 0; i < b_cl->channels; i++) { - for (j = 0; j < cl->channels; j++) { - if (b_cl->channel[i] == cl->channel[j]) - break; - } - if (j == cl->channels) { - if (cl->channels == P2P_MAX_REG_CLASS_CHANNELS) - return; - cl->channel[cl->channels++] = b_cl->channel[i]; - } - } -} - - -/** - * p2p_channels_union - Union of channel lists - * @a: First set of channels - * @b: Second set of channels - * @res: Data structure for returning the union of channels - */ -void p2p_channels_union(const struct p2p_channels *a, - const struct p2p_channels *b, - struct p2p_channels *res) -{ - size_t i, j; - - if (a != res) - os_memcpy(res, a, sizeof(*res)); - - for (i = 0; i < res->reg_classes; i++) { - struct p2p_reg_class *cl = &res->reg_class[i]; - for (j = 0; j < b->reg_classes; j++) { - const struct p2p_reg_class *b_cl = &b->reg_class[j]; - if (cl->reg_class != b_cl->reg_class) - continue; - p2p_op_class_union(cl, b_cl); - } - } - - for (j = 0; j < b->reg_classes; j++) { - const struct p2p_reg_class *b_cl = &b->reg_class[j]; - - for (i = 0; i < res->reg_classes; i++) { - struct p2p_reg_class *cl = &res->reg_class[i]; - if (cl->reg_class == b_cl->reg_class) - break; - } - - if (i == res->reg_classes) { - if (res->reg_classes == P2P_MAX_REG_CLASSES) - return; - os_memcpy(&res->reg_class[res->reg_classes++], - b_cl, sizeof(struct p2p_reg_class)); - } - } -} - - -void p2p_channels_remove_freqs(struct p2p_channels *chan, - const struct wpa_freq_range_list *list) -{ - size_t o, c; - - if (list == NULL) - return; - - o = 0; - while (o < chan->reg_classes) { - struct p2p_reg_class *op = &chan->reg_class[o]; - - c = 0; - while (c < op->channels) { - int freq = p2p_channel_to_freq(op->reg_class, - op->channel[c]); - if (freq > 0 && freq_range_list_includes(list, freq)) { - op->channels--; - os_memmove(&op->channel[c], - &op->channel[c + 1], - op->channels - c); - } else - c++; - } - - if (op->channels == 0) { - chan->reg_classes--; - os_memmove(&chan->reg_class[o], &chan->reg_class[o + 1], - (chan->reg_classes - o) * - sizeof(struct p2p_reg_class)); - } else - o++; - } -} - - -/** - * p2p_channels_includes - Check whether a channel is included in the list - * @channels: List of supported channels - * @reg_class: Regulatory class of the channel to search - * @channel: Channel number of the channel to search - * Returns: 1 if channel was found or 0 if not - */ -int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class, - u8 channel) -{ - size_t i, j; - for (i = 0; i < channels->reg_classes; i++) { - const struct p2p_reg_class *reg = &channels->reg_class[i]; - if (reg->reg_class != reg_class) - continue; - for (j = 0; j < reg->channels; j++) { - if (reg->channel[j] == channel) - return 1; - } - } - return 0; -} - - -int p2p_channels_includes_freq(const struct p2p_channels *channels, - unsigned int freq) -{ - size_t i, j; - for (i = 0; i < channels->reg_classes; i++) { - const struct p2p_reg_class *reg = &channels->reg_class[i]; - for (j = 0; j < reg->channels; j++) { - if (p2p_channel_to_freq(reg->reg_class, - reg->channel[j]) == (int) freq) - return 1; - } - } - return 0; -} - - -int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq) -{ - u8 op_reg_class, op_channel; - if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0) - return 0; - return p2p_channels_includes(&p2p->cfg->channels, op_reg_class, - op_channel); -} - - -int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq) -{ - u8 op_reg_class, op_channel; - if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0) - return 0; - return p2p_channels_includes(&p2p->cfg->channels, op_reg_class, - op_channel) && - !freq_range_list_includes(&p2p->no_go_freq, freq); -} - - -int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq) -{ - u8 op_reg_class, op_channel; - if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0) - return 0; - return p2p_channels_includes(&p2p->cfg->channels, op_reg_class, - op_channel) || - p2p_channels_includes(&p2p->cfg->cli_channels, op_reg_class, - op_channel); -} - - -unsigned int p2p_get_pref_freq(struct p2p_data *p2p, - const struct p2p_channels *channels) -{ - unsigned int i; - int freq = 0; - - if (channels == NULL) { - if (p2p->cfg->num_pref_chan) { - freq = p2p_channel_to_freq( - p2p->cfg->pref_chan[0].op_class, - p2p->cfg->pref_chan[0].chan); - if (freq < 0) - freq = 0; - } - return freq; - } - - for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) { - freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class, - p2p->cfg->pref_chan[i].chan); - if (p2p_channels_includes_freq(channels, freq)) - return freq; - } - - return 0; -} - - -void p2p_channels_dump(struct p2p_data *p2p, const char *title, - const struct p2p_channels *chan) -{ - char buf[500], *pos, *end; - size_t i, j; - int ret; - - pos = buf; - end = pos + sizeof(buf); - - for (i = 0; i < chan->reg_classes; i++) { - const struct p2p_reg_class *c; - c = &chan->reg_class[i]; - ret = os_snprintf(pos, end - pos, " %u:", c->reg_class); - if (ret < 0 || ret >= end - pos) - break; - pos += ret; - - for (j = 0; j < c->channels; j++) { - ret = os_snprintf(pos, end - pos, "%s%u", - j == 0 ? "" : ",", - c->channel[j]); - if (ret < 0 || ret >= end - pos) - break; - pos += ret; - } - } - *pos = '\0'; - - p2p_dbg(p2p, "%s:%s", title, buf); -} - - -int p2p_channel_select(struct p2p_channels *chans, const int *classes, - u8 *op_class, u8 *op_channel) -{ - unsigned int i, j, r; - - for (j = 0; classes[j]; j++) { - for (i = 0; i < chans->reg_classes; i++) { - struct p2p_reg_class *c = &chans->reg_class[i]; - - if (c->channels == 0) - continue; - - if (c->reg_class == classes[j]) { - /* - * Pick one of the available channels in the - * operating class at random. - */ - os_get_random((u8 *) &r, sizeof(r)); - r %= c->channels; - *op_class = c->reg_class; - *op_channel = c->channel[r]; - return 0; - } - } - } - - return -1; -} diff --git a/contrib/hostapd/src/radius/radius.c b/contrib/hostapd/src/radius/radius.c deleted file mode 100644 index 494f92d19e..0000000000 --- a/contrib/hostapd/src/radius/radius.c +++ /dev/null @@ -1,1578 +0,0 @@ -/* - * RADIUS message processing - * Copyright (c) 2002-2009, 2011-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/wpabuf.h" -#include "crypto/md5.h" -#include "crypto/crypto.h" -#include "radius.h" - - -/** - * struct radius_msg - RADIUS message structure for new and parsed messages - */ -struct radius_msg { - /** - * buf - Allocated buffer for RADIUS message - */ - struct wpabuf *buf; - - /** - * hdr - Pointer to the RADIUS header in buf - */ - struct radius_hdr *hdr; - - /** - * attr_pos - Array of indexes to attributes - * - * The values are number of bytes from buf to the beginning of - * struct radius_attr_hdr. - */ - size_t *attr_pos; - - /** - * attr_size - Total size of the attribute pointer array - */ - size_t attr_size; - - /** - * attr_used - Total number of attributes in the array - */ - size_t attr_used; -}; - - -struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg) -{ - return msg->hdr; -} - - -struct wpabuf * radius_msg_get_buf(struct radius_msg *msg) -{ - return msg->buf; -} - - -static struct radius_attr_hdr * -radius_get_attr_hdr(struct radius_msg *msg, int idx) -{ - return (struct radius_attr_hdr *) - (wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]); -} - - -static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier) -{ - msg->hdr->code = code; - msg->hdr->identifier = identifier; -} - - -static int radius_msg_initialize(struct radius_msg *msg) -{ - msg->attr_pos = os_calloc(RADIUS_DEFAULT_ATTR_COUNT, - sizeof(*msg->attr_pos)); - if (msg->attr_pos == NULL) - return -1; - - msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT; - msg->attr_used = 0; - - return 0; -} - - -/** - * radius_msg_new - Create a new RADIUS message - * @code: Code for RADIUS header - * @identifier: Identifier for RADIUS header - * Returns: Context for RADIUS message or %NULL on failure - * - * The caller is responsible for freeing the returned data with - * radius_msg_free(). - */ -struct radius_msg * radius_msg_new(u8 code, u8 identifier) -{ - struct radius_msg *msg; - - msg = os_zalloc(sizeof(*msg)); - if (msg == NULL) - return NULL; - - msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE); - if (msg->buf == NULL || radius_msg_initialize(msg)) { - radius_msg_free(msg); - return NULL; - } - msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr)); - - radius_msg_set_hdr(msg, code, identifier); - - return msg; -} - - -/** - * radius_msg_free - Free a RADIUS message - * @msg: RADIUS message from radius_msg_new() or radius_msg_parse() - */ -void radius_msg_free(struct radius_msg *msg) -{ - if (msg == NULL) - return; - - wpabuf_free(msg->buf); - os_free(msg->attr_pos); - os_free(msg); -} - - -static const char *radius_code_string(u8 code) -{ - switch (code) { - case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request"; - case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept"; - case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject"; - case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request"; - case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response"; - case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge"; - case RADIUS_CODE_STATUS_SERVER: return "Status-Server"; - case RADIUS_CODE_STATUS_CLIENT: return "Status-Client"; - case RADIUS_CODE_RESERVED: return "Reserved"; - case RADIUS_CODE_DISCONNECT_REQUEST: return "Disconnect-Request"; - case RADIUS_CODE_DISCONNECT_ACK: return "Disconnect-ACK"; - case RADIUS_CODE_DISCONNECT_NAK: return "Disconnect-NAK"; - case RADIUS_CODE_COA_REQUEST: return "CoA-Request"; - case RADIUS_CODE_COA_ACK: return "CoA-ACK"; - case RADIUS_CODE_COA_NAK: return "CoA-NAK"; - default: return "?Unknown?"; - } -} - - -struct radius_attr_type { - u8 type; - char *name; - enum { - RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP, - RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6 - } data_type; -}; - -static struct radius_attr_type radius_attrs[] = -{ - { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT }, - { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST }, - { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP }, - { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT }, - { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST }, - { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST }, - { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST }, - { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action", - RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id", - RADIUS_ATTR_TEXT }, - { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id", - RADIUS_ATTR_TEXT }, - { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT }, - { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST }, - { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type", - RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets", - RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets", - RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT }, - { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time", - RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets", - RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets", - RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause", - RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id", - RADIUS_ATTR_TEXT }, - { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", - RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords", - RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp", - RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 }, - { 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", - RADIUS_ATTR_UNDIST }, - { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id", - RADIUS_ATTR_HEXDUMP }, - { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval", - RADIUS_ATTR_INT32 }, - { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity", - RADIUS_ATTR_TEXT }, - { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 }, - { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 } -}; -#define RADIUS_ATTRS ARRAY_SIZE(radius_attrs) - - -static struct radius_attr_type *radius_get_attr_type(u8 type) -{ - size_t i; - - for (i = 0; i < RADIUS_ATTRS; i++) { - if (type == radius_attrs[i].type) - return &radius_attrs[i]; - } - - return NULL; -} - - -static void print_char(char c) -{ - if (c >= 32 && c < 127) - printf("%c", c); - else - printf("<%02x>", c); -} - - -static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) -{ - struct radius_attr_type *attr; - int i, len; - unsigned char *pos; - - attr = radius_get_attr_type(hdr->type); - - printf(" Attribute %d (%s) length=%d\n", - hdr->type, attr ? attr->name : "?Unknown?", hdr->length); - - if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr)) - return; - - len = hdr->length - sizeof(struct radius_attr_hdr); - pos = (unsigned char *) (hdr + 1); - - switch (attr->data_type) { - case RADIUS_ATTR_TEXT: - printf(" Value: '"); - for (i = 0; i < len; i++) - print_char(pos[i]); - printf("'\n"); - break; - - case RADIUS_ATTR_IP: - if (len == 4) { - struct in_addr addr; - os_memcpy(&addr, pos, 4); - printf(" Value: %s\n", inet_ntoa(addr)); - } else - printf(" Invalid IP address length %d\n", len); - break; - -#ifdef CONFIG_IPV6 - case RADIUS_ATTR_IPV6: - if (len == 16) { - char buf[128]; - const char *atxt; - struct in6_addr *addr = (struct in6_addr *) pos; - atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf)); - printf(" Value: %s\n", atxt ? atxt : "?"); - } else - printf(" Invalid IPv6 address length %d\n", len); - break; -#endif /* CONFIG_IPV6 */ - - case RADIUS_ATTR_HEXDUMP: - case RADIUS_ATTR_UNDIST: - printf(" Value:"); - for (i = 0; i < len; i++) - printf(" %02x", pos[i]); - printf("\n"); - break; - - case RADIUS_ATTR_INT32: - if (len == 4) - printf(" Value: %u\n", WPA_GET_BE32(pos)); - else - printf(" Invalid INT32 length %d\n", len); - break; - - default: - break; - } -} - - -void radius_msg_dump(struct radius_msg *msg) -{ - size_t i; - - printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n", - msg->hdr->code, radius_code_string(msg->hdr->code), - msg->hdr->identifier, be_to_host16(msg->hdr->length)); - - for (i = 0; i < msg->attr_used; i++) { - struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); - radius_msg_dump_attr(attr); - } -} - - -int radius_msg_finish(struct radius_msg *msg, const u8 *secret, - size_t secret_len) -{ - if (secret) { - u8 auth[MD5_MAC_LEN]; - struct radius_attr_hdr *attr; - - os_memset(auth, 0, MD5_MAC_LEN); - attr = radius_msg_add_attr(msg, - RADIUS_ATTR_MESSAGE_AUTHENTICATOR, - auth, MD5_MAC_LEN); - if (attr == NULL) { - wpa_printf(MSG_WARNING, "RADIUS: Could not add " - "Message-Authenticator"); - return -1; - } - msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); - hmac_md5(secret, secret_len, wpabuf_head(msg->buf), - wpabuf_len(msg->buf), (u8 *) (attr + 1)); - } else - msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); - - if (wpabuf_len(msg->buf) > 0xffff) { - wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", - (unsigned long) wpabuf_len(msg->buf)); - return -1; - } - return 0; -} - - -int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, - size_t secret_len, const u8 *req_authenticator) -{ - u8 auth[MD5_MAC_LEN]; - struct radius_attr_hdr *attr; - const u8 *addr[4]; - size_t len[4]; - - os_memset(auth, 0, MD5_MAC_LEN); - attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, - auth, MD5_MAC_LEN); - if (attr == NULL) { - printf("WARNING: Could not add Message-Authenticator\n"); - return -1; - } - msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); - os_memcpy(msg->hdr->authenticator, req_authenticator, - sizeof(msg->hdr->authenticator)); - hmac_md5(secret, secret_len, wpabuf_head(msg->buf), - wpabuf_len(msg->buf), (u8 *) (attr + 1)); - - /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ - addr[0] = (u8 *) msg->hdr; - len[0] = 1 + 1 + 2; - addr[1] = req_authenticator; - len[1] = MD5_MAC_LEN; - addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); - len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); - addr[3] = secret; - len[3] = secret_len; - md5_vector(4, addr, len, msg->hdr->authenticator); - - if (wpabuf_len(msg->buf) > 0xffff) { - wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", - (unsigned long) wpabuf_len(msg->buf)); - return -1; - } - return 0; -} - - -int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret, - size_t secret_len, - const struct radius_hdr *req_hdr) -{ - const u8 *addr[2]; - size_t len[2]; - u8 auth[MD5_MAC_LEN]; - struct radius_attr_hdr *attr; - - os_memset(auth, 0, MD5_MAC_LEN); - attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, - auth, MD5_MAC_LEN); - if (attr == NULL) { - wpa_printf(MSG_WARNING, "Could not add Message-Authenticator"); - return -1; - } - - msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); - os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16); - hmac_md5(secret, secret_len, wpabuf_head(msg->buf), - wpabuf_len(msg->buf), (u8 *) (attr + 1)); - - /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ - addr[0] = wpabuf_head_u8(msg->buf); - len[0] = wpabuf_len(msg->buf); - addr[1] = secret; - len[1] = secret_len; - if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) - return -1; - - if (wpabuf_len(msg->buf) > 0xffff) { - wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", - (unsigned long) wpabuf_len(msg->buf)); - return -1; - } - return 0; -} - - -void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, - size_t secret_len) -{ - const u8 *addr[2]; - size_t len[2]; - - msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); - os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); - addr[0] = wpabuf_head(msg->buf); - len[0] = wpabuf_len(msg->buf); - addr[1] = secret; - len[1] = secret_len; - md5_vector(2, addr, len, msg->hdr->authenticator); - - if (wpabuf_len(msg->buf) > 0xffff) { - wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", - (unsigned long) wpabuf_len(msg->buf)); - } -} - - -int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret, - size_t secret_len) -{ - const u8 *addr[4]; - size_t len[4]; - u8 zero[MD5_MAC_LEN]; - u8 hash[MD5_MAC_LEN]; - - os_memset(zero, 0, sizeof(zero)); - addr[0] = (u8 *) msg->hdr; - len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; - addr[1] = zero; - len[1] = MD5_MAC_LEN; - addr[2] = (u8 *) (msg->hdr + 1); - len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); - addr[3] = secret; - len[3] = secret_len; - md5_vector(4, addr, len, hash); - return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0; -} - - -int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, - size_t secret_len) -{ - const u8 *addr[4]; - size_t len[4]; - u8 zero[MD5_MAC_LEN]; - u8 hash[MD5_MAC_LEN]; - u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; - u8 orig_authenticator[16]; - - struct radius_attr_hdr *attr = NULL, *tmp; - size_t i; - - os_memset(zero, 0, sizeof(zero)); - addr[0] = (u8 *) msg->hdr; - len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; - addr[1] = zero; - len[1] = MD5_MAC_LEN; - addr[2] = (u8 *) (msg->hdr + 1); - len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); - addr[3] = secret; - len[3] = secret_len; - md5_vector(4, addr, len, hash); - if (os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0) - return 1; - - for (i = 0; i < msg->attr_used; i++) { - tmp = radius_get_attr_hdr(msg, i); - if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { - if (attr != NULL) { - wpa_printf(MSG_WARNING, "Multiple " - "Message-Authenticator attributes " - "in RADIUS message"); - return 1; - } - attr = tmp; - } - } - - if (attr == NULL) { - /* Message-Authenticator is MAY; not required */ - return 0; - } - - os_memcpy(orig, attr + 1, MD5_MAC_LEN); - os_memset(attr + 1, 0, MD5_MAC_LEN); - os_memcpy(orig_authenticator, msg->hdr->authenticator, - sizeof(orig_authenticator)); - os_memset(msg->hdr->authenticator, 0, - sizeof(msg->hdr->authenticator)); - hmac_md5(secret, secret_len, wpabuf_head(msg->buf), - wpabuf_len(msg->buf), auth); - os_memcpy(attr + 1, orig, MD5_MAC_LEN); - os_memcpy(msg->hdr->authenticator, orig_authenticator, - sizeof(orig_authenticator)); - - return os_memcmp(orig, auth, MD5_MAC_LEN) != 0; -} - - -static int radius_msg_add_attr_to_array(struct radius_msg *msg, - struct radius_attr_hdr *attr) -{ - if (msg->attr_used >= msg->attr_size) { - size_t *nattr_pos; - int nlen = msg->attr_size * 2; - - nattr_pos = os_realloc_array(msg->attr_pos, nlen, - sizeof(*msg->attr_pos)); - if (nattr_pos == NULL) - return -1; - - msg->attr_pos = nattr_pos; - msg->attr_size = nlen; - } - - msg->attr_pos[msg->attr_used++] = - (unsigned char *) attr - wpabuf_head_u8(msg->buf); - - return 0; -} - - -struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, - const u8 *data, size_t data_len) -{ - size_t buf_needed; - struct radius_attr_hdr *attr; - - if (data_len > RADIUS_MAX_ATTR_LEN) { - printf("radius_msg_add_attr: too long attribute (%lu bytes)\n", - (unsigned long) data_len); - return NULL; - } - - buf_needed = sizeof(*attr) + data_len; - - if (wpabuf_tailroom(msg->buf) < buf_needed) { - /* allocate more space for message buffer */ - if (wpabuf_resize(&msg->buf, buf_needed) < 0) - return NULL; - msg->hdr = wpabuf_mhead(msg->buf); - } - - attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); - attr->type = type; - attr->length = sizeof(*attr) + data_len; - wpabuf_put_data(msg->buf, data, data_len); - - if (radius_msg_add_attr_to_array(msg, attr)) - return NULL; - - return attr; -} - - -/** - * radius_msg_parse - Parse a RADIUS message - * @data: RADIUS message to be parsed - * @len: Length of data buffer in octets - * Returns: Parsed RADIUS message or %NULL on failure - * - * This parses a RADIUS message and makes a copy of its data. The caller is - * responsible for freeing the returned data with radius_msg_free(). - */ -struct radius_msg * radius_msg_parse(const u8 *data, size_t len) -{ - struct radius_msg *msg; - struct radius_hdr *hdr; - struct radius_attr_hdr *attr; - size_t msg_len; - unsigned char *pos, *end; - - if (data == NULL || len < sizeof(*hdr)) - return NULL; - - hdr = (struct radius_hdr *) data; - - msg_len = be_to_host16(hdr->length); - if (msg_len < sizeof(*hdr) || msg_len > len) { - wpa_printf(MSG_INFO, "RADIUS: Invalid message length"); - return NULL; - } - - if (msg_len < len) { - wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after " - "RADIUS message", (unsigned long) len - msg_len); - } - - msg = os_zalloc(sizeof(*msg)); - if (msg == NULL) - return NULL; - - msg->buf = wpabuf_alloc_copy(data, msg_len); - if (msg->buf == NULL || radius_msg_initialize(msg)) { - radius_msg_free(msg); - return NULL; - } - msg->hdr = wpabuf_mhead(msg->buf); - - /* parse attributes */ - pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr); - end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf); - while (pos < end) { - if ((size_t) (end - pos) < sizeof(*attr)) - goto fail; - - attr = (struct radius_attr_hdr *) pos; - - if (pos + attr->length > end || attr->length < sizeof(*attr)) - goto fail; - - /* TODO: check that attr->length is suitable for attr->type */ - - if (radius_msg_add_attr_to_array(msg, attr)) - goto fail; - - pos += attr->length; - } - - return msg; - - fail: - radius_msg_free(msg); - return NULL; -} - - -int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) -{ - const u8 *pos = data; - size_t left = data_len; - - while (left > 0) { - int len; - if (left > RADIUS_MAX_ATTR_LEN) - len = RADIUS_MAX_ATTR_LEN; - else - len = left; - - if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE, - pos, len)) - return 0; - - pos += len; - left -= len; - } - - return 1; -} - - -struct wpabuf * radius_msg_get_eap(struct radius_msg *msg) -{ - struct wpabuf *eap; - size_t len, i; - struct radius_attr_hdr *attr; - - if (msg == NULL) - return NULL; - - len = 0; - for (i = 0; i < msg->attr_used; i++) { - attr = radius_get_attr_hdr(msg, i); - if (attr->type == RADIUS_ATTR_EAP_MESSAGE && - attr->length > sizeof(struct radius_attr_hdr)) - len += attr->length - sizeof(struct radius_attr_hdr); - } - - if (len == 0) - return NULL; - - eap = wpabuf_alloc(len); - if (eap == NULL) - return NULL; - - for (i = 0; i < msg->attr_used; i++) { - attr = radius_get_attr_hdr(msg, i); - if (attr->type == RADIUS_ATTR_EAP_MESSAGE && - attr->length > sizeof(struct radius_attr_hdr)) { - int flen = attr->length - sizeof(*attr); - wpabuf_put_data(eap, attr + 1, flen); - } - } - - return eap; -} - - -int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, - size_t secret_len, const u8 *req_auth) -{ - u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; - u8 orig_authenticator[16]; - struct radius_attr_hdr *attr = NULL, *tmp; - size_t i; - - for (i = 0; i < msg->attr_used; i++) { - tmp = radius_get_attr_hdr(msg, i); - if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { - if (attr != NULL) { - printf("Multiple Message-Authenticator " - "attributes in RADIUS message\n"); - return 1; - } - attr = tmp; - } - } - - if (attr == NULL) { - printf("No Message-Authenticator attribute found\n"); - return 1; - } - - os_memcpy(orig, attr + 1, MD5_MAC_LEN); - os_memset(attr + 1, 0, MD5_MAC_LEN); - if (req_auth) { - os_memcpy(orig_authenticator, msg->hdr->authenticator, - sizeof(orig_authenticator)); - os_memcpy(msg->hdr->authenticator, req_auth, - sizeof(msg->hdr->authenticator)); - } - hmac_md5(secret, secret_len, wpabuf_head(msg->buf), - wpabuf_len(msg->buf), auth); - os_memcpy(attr + 1, orig, MD5_MAC_LEN); - if (req_auth) { - os_memcpy(msg->hdr->authenticator, orig_authenticator, - sizeof(orig_authenticator)); - } - - if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) { - printf("Invalid Message-Authenticator!\n"); - return 1; - } - - return 0; -} - - -int radius_msg_verify(struct radius_msg *msg, const u8 *secret, - size_t secret_len, struct radius_msg *sent_msg, int auth) -{ - const u8 *addr[4]; - size_t len[4]; - u8 hash[MD5_MAC_LEN]; - - if (sent_msg == NULL) { - printf("No matching Access-Request message found\n"); - return 1; - } - - if (auth && - radius_msg_verify_msg_auth(msg, secret, secret_len, - sent_msg->hdr->authenticator)) { - return 1; - } - - /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ - addr[0] = (u8 *) msg->hdr; - len[0] = 1 + 1 + 2; - addr[1] = sent_msg->hdr->authenticator; - len[1] = MD5_MAC_LEN; - addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); - len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); - addr[3] = secret; - len[3] = secret_len; - md5_vector(4, addr, len, hash); - if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { - printf("Response Authenticator invalid!\n"); - return 1; - } - - return 0; -} - - -int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, - u8 type) -{ - struct radius_attr_hdr *attr; - size_t i; - int count = 0; - - for (i = 0; i < src->attr_used; i++) { - attr = radius_get_attr_hdr(src, i); - if (attr->type == type && attr->length >= sizeof(*attr)) { - if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1), - attr->length - sizeof(*attr))) - return -1; - count++; - } - } - - return count; -} - - -/* Create Request Authenticator. The value should be unique over the lifetime - * of the shared secret between authenticator and authentication server. - * Use one-way MD5 hash calculated from current timestamp and some data given - * by the caller. */ -void radius_msg_make_authenticator(struct radius_msg *msg, - const u8 *data, size_t len) -{ - struct os_time tv; - long int l; - const u8 *addr[3]; - size_t elen[3]; - - os_get_time(&tv); - l = os_random(); - addr[0] = (u8 *) &tv; - elen[0] = sizeof(tv); - addr[1] = data; - elen[1] = len; - addr[2] = (u8 *) &l; - elen[2] = sizeof(l); - md5_vector(3, addr, elen, msg->hdr->authenticator); -} - - -/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message. - * Returns the Attribute payload and sets alen to indicate the length of the - * payload if a vendor attribute with subtype is found, otherwise returns NULL. - * The returned payload is allocated with os_malloc() and caller must free it - * by calling os_free(). - */ -static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor, - u8 subtype, size_t *alen) -{ - u8 *data, *pos; - size_t i, len; - - if (msg == NULL) - return NULL; - - for (i = 0; i < msg->attr_used; i++) { - struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); - size_t left; - u32 vendor_id; - struct radius_attr_vendor *vhdr; - - if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC || - attr->length < sizeof(*attr)) - continue; - - left = attr->length - sizeof(*attr); - if (left < 4) - continue; - - pos = (u8 *) (attr + 1); - - os_memcpy(&vendor_id, pos, 4); - pos += 4; - left -= 4; - - if (ntohl(vendor_id) != vendor) - continue; - - while (left >= sizeof(*vhdr)) { - vhdr = (struct radius_attr_vendor *) pos; - if (vhdr->vendor_length > left || - vhdr->vendor_length < sizeof(*vhdr)) { - left = 0; - break; - } - if (vhdr->vendor_type != subtype) { - pos += vhdr->vendor_length; - left -= vhdr->vendor_length; - continue; - } - - len = vhdr->vendor_length - sizeof(*vhdr); - data = os_malloc(len); - if (data == NULL) - return NULL; - os_memcpy(data, pos + sizeof(*vhdr), len); - if (alen) - *alen = len; - return data; - } - } - - return NULL; -} - - -static u8 * decrypt_ms_key(const u8 *key, size_t len, - const u8 *req_authenticator, - const u8 *secret, size_t secret_len, size_t *reslen) -{ - u8 *plain, *ppos, *res; - const u8 *pos; - size_t left, plen; - u8 hash[MD5_MAC_LEN]; - int i, first = 1; - const u8 *addr[3]; - size_t elen[3]; - - /* key: 16-bit salt followed by encrypted key info */ - - if (len < 2 + 16) - return NULL; - - pos = key + 2; - left = len - 2; - if (left % 16) { - printf("Invalid ms key len %lu\n", (unsigned long) left); - return NULL; - } - - plen = left; - ppos = plain = os_malloc(plen); - if (plain == NULL) - return NULL; - plain[0] = 0; - - while (left > 0) { - /* b(1) = MD5(Secret + Request-Authenticator + Salt) - * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ - - addr[0] = secret; - elen[0] = secret_len; - if (first) { - addr[1] = req_authenticator; - elen[1] = MD5_MAC_LEN; - addr[2] = key; - elen[2] = 2; /* Salt */ - } else { - addr[1] = pos - MD5_MAC_LEN; - elen[1] = MD5_MAC_LEN; - } - md5_vector(first ? 3 : 2, addr, elen, hash); - first = 0; - - for (i = 0; i < MD5_MAC_LEN; i++) - *ppos++ = *pos++ ^ hash[i]; - left -= MD5_MAC_LEN; - } - - if (plain[0] == 0 || plain[0] > plen - 1) { - printf("Failed to decrypt MPPE key\n"); - os_free(plain); - return NULL; - } - - res = os_malloc(plain[0]); - if (res == NULL) { - os_free(plain); - return NULL; - } - os_memcpy(res, plain + 1, plain[0]); - if (reslen) - *reslen = plain[0]; - os_free(plain); - return res; -} - - -static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, - const u8 *req_authenticator, - const u8 *secret, size_t secret_len, - u8 *ebuf, size_t *elen) -{ - int i, len, first = 1; - u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; - const u8 *addr[3]; - size_t _len[3]; - - WPA_PUT_BE16(saltbuf, salt); - - len = 1 + key_len; - if (len & 0x0f) { - len = (len & 0xf0) + 16; - } - os_memset(ebuf, 0, len); - ebuf[0] = key_len; - os_memcpy(ebuf + 1, key, key_len); - - *elen = len; - - pos = ebuf; - while (len > 0) { - /* b(1) = MD5(Secret + Request-Authenticator + Salt) - * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ - addr[0] = secret; - _len[0] = secret_len; - if (first) { - addr[1] = req_authenticator; - _len[1] = MD5_MAC_LEN; - addr[2] = saltbuf; - _len[2] = sizeof(saltbuf); - } else { - addr[1] = pos - MD5_MAC_LEN; - _len[1] = MD5_MAC_LEN; - } - md5_vector(first ? 3 : 2, addr, _len, hash); - first = 0; - - for (i = 0; i < MD5_MAC_LEN; i++) - *pos++ ^= hash[i]; - - len -= MD5_MAC_LEN; - } -} - - -struct radius_ms_mppe_keys * -radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, - const u8 *secret, size_t secret_len) -{ - u8 *key; - size_t keylen; - struct radius_ms_mppe_keys *keys; - - if (msg == NULL || sent_msg == NULL) - return NULL; - - keys = os_zalloc(sizeof(*keys)); - if (keys == NULL) - return NULL; - - key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, - RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY, - &keylen); - if (key) { - keys->send = decrypt_ms_key(key, keylen, - sent_msg->hdr->authenticator, - secret, secret_len, - &keys->send_len); - os_free(key); - } - - key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, - RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY, - &keylen); - if (key) { - keys->recv = decrypt_ms_key(key, keylen, - sent_msg->hdr->authenticator, - secret, secret_len, - &keys->recv_len); - os_free(key); - } - - return keys; -} - - -struct radius_ms_mppe_keys * -radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, - const u8 *secret, size_t secret_len) -{ - u8 *key; - size_t keylen; - struct radius_ms_mppe_keys *keys; - - if (msg == NULL || sent_msg == NULL) - return NULL; - - keys = os_zalloc(sizeof(*keys)); - if (keys == NULL) - return NULL; - - key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO, - RADIUS_CISCO_AV_PAIR, &keylen); - if (key && keylen == 51 && - os_memcmp(key, "leap:session-key=", 17) == 0) { - keys->recv = decrypt_ms_key(key + 17, keylen - 17, - sent_msg->hdr->authenticator, - secret, secret_len, - &keys->recv_len); - } - os_free(key); - - return keys; -} - - -int radius_msg_add_mppe_keys(struct radius_msg *msg, - const u8 *req_authenticator, - const u8 *secret, size_t secret_len, - const u8 *send_key, size_t send_key_len, - const u8 *recv_key, size_t recv_key_len) -{ - struct radius_attr_hdr *attr; - u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT); - u8 *buf; - struct radius_attr_vendor *vhdr; - u8 *pos; - size_t elen; - int hlen; - u16 salt; - - hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2; - - /* MS-MPPE-Send-Key */ - buf = os_malloc(hlen + send_key_len + 16); - if (buf == NULL) { - return 0; - } - pos = buf; - os_memcpy(pos, &vendor_id, sizeof(vendor_id)); - pos += sizeof(vendor_id); - vhdr = (struct radius_attr_vendor *) pos; - vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY; - pos = (u8 *) (vhdr + 1); - salt = os_random() | 0x8000; - WPA_PUT_BE16(pos, salt); - pos += 2; - encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret, - secret_len, pos, &elen); - vhdr->vendor_length = hlen + elen - sizeof(vendor_id); - - attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, - buf, hlen + elen); - os_free(buf); - if (attr == NULL) { - return 0; - } - - /* MS-MPPE-Recv-Key */ - buf = os_malloc(hlen + send_key_len + 16); - if (buf == NULL) { - return 0; - } - pos = buf; - os_memcpy(pos, &vendor_id, sizeof(vendor_id)); - pos += sizeof(vendor_id); - vhdr = (struct radius_attr_vendor *) pos; - vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY; - pos = (u8 *) (vhdr + 1); - salt ^= 1; - WPA_PUT_BE16(pos, salt); - pos += 2; - encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret, - secret_len, pos, &elen); - vhdr->vendor_length = hlen + elen - sizeof(vendor_id); - - attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, - buf, hlen + elen); - os_free(buf); - if (attr == NULL) { - return 0; - } - - return 1; -} - - -/* Add User-Password attribute to a RADIUS message and encrypt it as specified - * in RFC 2865, Chap. 5.2 */ -struct radius_attr_hdr * -radius_msg_add_attr_user_password(struct radius_msg *msg, - const u8 *data, size_t data_len, - const u8 *secret, size_t secret_len) -{ - u8 buf[128]; - size_t padlen, i, buf_len, pos; - const u8 *addr[2]; - size_t len[2]; - u8 hash[16]; - - if (data_len > 128) - return NULL; - - os_memcpy(buf, data, data_len); - buf_len = data_len; - - padlen = data_len % 16; - if (padlen && data_len < sizeof(buf)) { - padlen = 16 - padlen; - os_memset(buf + data_len, 0, padlen); - buf_len += padlen; - } - - addr[0] = secret; - len[0] = secret_len; - addr[1] = msg->hdr->authenticator; - len[1] = 16; - md5_vector(2, addr, len, hash); - - for (i = 0; i < 16; i++) - buf[i] ^= hash[i]; - pos = 16; - - while (pos < buf_len) { - addr[0] = secret; - len[0] = secret_len; - addr[1] = &buf[pos - 16]; - len[1] = 16; - md5_vector(2, addr, len, hash); - - for (i = 0; i < 16; i++) - buf[pos + i] ^= hash[i]; - - pos += 16; - } - - return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, - buf, buf_len); -} - - -int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len) -{ - struct radius_attr_hdr *attr = NULL, *tmp; - size_t i, dlen; - - for (i = 0; i < msg->attr_used; i++) { - tmp = radius_get_attr_hdr(msg, i); - if (tmp->type == type) { - attr = tmp; - break; - } - } - - if (!attr || attr->length < sizeof(*attr)) - return -1; - - dlen = attr->length - sizeof(*attr); - if (buf) - os_memcpy(buf, (attr + 1), dlen > len ? len : dlen); - return dlen; -} - - -int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, - size_t *len, const u8 *start) -{ - size_t i; - struct radius_attr_hdr *attr = NULL, *tmp; - - for (i = 0; i < msg->attr_used; i++) { - tmp = radius_get_attr_hdr(msg, i); - if (tmp->type == type && - (start == NULL || (u8 *) tmp > start)) { - attr = tmp; - break; - } - } - - if (!attr || attr->length < sizeof(*attr)) - return -1; - - *buf = (u8 *) (attr + 1); - *len = attr->length - sizeof(*attr); - return 0; -} - - -int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len) -{ - size_t i; - int count; - - for (count = 0, i = 0; i < msg->attr_used; i++) { - struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); - if (attr->type == type && - attr->length >= sizeof(struct radius_attr_hdr) + min_len) - count++; - } - - return count; -} - - -struct radius_tunnel_attrs { - int tag_used; - int type; /* Tunnel-Type */ - int medium_type; /* Tunnel-Medium-Type */ - int vlanid; -}; - - -/** - * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information - * @msg: RADIUS message - * Returns: VLAN ID for the first tunnel configuration of -1 if none is found - */ -int radius_msg_get_vlanid(struct radius_msg *msg) -{ - struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun; - size_t i; - struct radius_attr_hdr *attr = NULL; - const u8 *data; - char buf[10]; - size_t dlen; - - os_memset(&tunnel, 0, sizeof(tunnel)); - - for (i = 0; i < msg->attr_used; i++) { - attr = radius_get_attr_hdr(msg, i); - if (attr->length < sizeof(*attr)) - return -1; - data = (const u8 *) (attr + 1); - dlen = attr->length - sizeof(*attr); - if (attr->length < 3) - continue; - if (data[0] >= RADIUS_TUNNEL_TAGS) - tun = &tunnel[0]; - else - tun = &tunnel[data[0]]; - - switch (attr->type) { - case RADIUS_ATTR_TUNNEL_TYPE: - if (attr->length != 6) - break; - tun->tag_used++; - tun->type = WPA_GET_BE24(data + 1); - break; - case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE: - if (attr->length != 6) - break; - tun->tag_used++; - tun->medium_type = WPA_GET_BE24(data + 1); - break; - case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID: - if (data[0] < RADIUS_TUNNEL_TAGS) { - data++; - dlen--; - } - if (dlen >= sizeof(buf)) - break; - os_memcpy(buf, data, dlen); - buf[dlen] = '\0'; - tun->tag_used++; - tun->vlanid = atoi(buf); - break; - } - } - - for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) { - tun = &tunnel[i]; - if (tun->tag_used && - tun->type == RADIUS_TUNNEL_TYPE_VLAN && - tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 && - tun->vlanid > 0) - return tun->vlanid; - } - - return -1; -} - - -/** - * 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 - * @n: Number of password attribute to return (starting with 0) - * Returns: Pointer to n-th 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, size_t n) -{ - 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, j = 0; - 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 n-th valid Tunnel-Password attribute */ - 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; - j++; - if (j <= n) - continue; - - fdata = data; - fdlen = dlen; - break; - } - 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; - if (c == NULL) - return; - for (i = 0; i < c->count; i++) - os_free(c->attr[i].data); - os_free(c->attr); - c->attr = NULL; - c->count = 0; -} - - -int radius_copy_class(struct radius_class_data *dst, - const struct radius_class_data *src) -{ - size_t i; - - if (src->attr == NULL) - return 0; - - dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data)); - if (dst->attr == NULL) - return -1; - - dst->count = 0; - - for (i = 0; i < src->count; i++) { - dst->attr[i].data = os_malloc(src->attr[i].len); - if (dst->attr[i].data == NULL) - break; - dst->count++; - os_memcpy(dst->attr[i].data, src->attr[i].data, - src->attr[i].len); - dst->attr[i].len = src->attr[i].len; - } - - return 0; -} - - -u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs) -{ - size_t i, j; - struct radius_attr_hdr *attr; - - for (i = 0; i < msg->attr_used; i++) { - attr = radius_get_attr_hdr(msg, i); - - for (j = 0; attrs[j]; j++) { - if (attr->type == attrs[j]) - break; - } - - if (attrs[j] == 0) - return attr->type; /* unlisted attr */ - } - - return 0; -} diff --git a/contrib/hostapd/src/radius/radius.h b/contrib/hostapd/src/radius/radius.h deleted file mode 100644 index 2031054b1d..0000000000 --- a/contrib/hostapd/src/radius/radius.h +++ /dev/null @@ -1,287 +0,0 @@ -/* - * RADIUS message processing - * Copyright (c) 2002-2009, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef RADIUS_H -#define RADIUS_H - -/* RFC 2865 - RADIUS */ - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct radius_hdr { - u8 code; - u8 identifier; - be16 length; /* including this header */ - u8 authenticator[16]; - /* followed by length-20 octets of attributes */ -} STRUCT_PACKED; - -enum { RADIUS_CODE_ACCESS_REQUEST = 1, - RADIUS_CODE_ACCESS_ACCEPT = 2, - RADIUS_CODE_ACCESS_REJECT = 3, - RADIUS_CODE_ACCOUNTING_REQUEST = 4, - RADIUS_CODE_ACCOUNTING_RESPONSE = 5, - RADIUS_CODE_ACCESS_CHALLENGE = 11, - RADIUS_CODE_STATUS_SERVER = 12, - RADIUS_CODE_STATUS_CLIENT = 13, - RADIUS_CODE_DISCONNECT_REQUEST = 40, - RADIUS_CODE_DISCONNECT_ACK = 41, - RADIUS_CODE_DISCONNECT_NAK = 42, - RADIUS_CODE_COA_REQUEST = 43, - RADIUS_CODE_COA_ACK = 44, - RADIUS_CODE_COA_NAK = 45, - RADIUS_CODE_RESERVED = 255 -}; - -struct radius_attr_hdr { - u8 type; - u8 length; /* including this header */ - /* followed by length-2 octets of attribute value */ -} STRUCT_PACKED; - -#define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr)) - -enum { RADIUS_ATTR_USER_NAME = 1, - RADIUS_ATTR_USER_PASSWORD = 2, - RADIUS_ATTR_NAS_IP_ADDRESS = 4, - RADIUS_ATTR_NAS_PORT = 5, - RADIUS_ATTR_FRAMED_MTU = 12, - RADIUS_ATTR_REPLY_MESSAGE = 18, - RADIUS_ATTR_STATE = 24, - RADIUS_ATTR_CLASS = 25, - RADIUS_ATTR_VENDOR_SPECIFIC = 26, - RADIUS_ATTR_SESSION_TIMEOUT = 27, - RADIUS_ATTR_IDLE_TIMEOUT = 28, - RADIUS_ATTR_TERMINATION_ACTION = 29, - RADIUS_ATTR_CALLED_STATION_ID = 30, - RADIUS_ATTR_CALLING_STATION_ID = 31, - RADIUS_ATTR_NAS_IDENTIFIER = 32, - RADIUS_ATTR_PROXY_STATE = 33, - RADIUS_ATTR_ACCT_STATUS_TYPE = 40, - RADIUS_ATTR_ACCT_DELAY_TIME = 41, - RADIUS_ATTR_ACCT_INPUT_OCTETS = 42, - RADIUS_ATTR_ACCT_OUTPUT_OCTETS = 43, - RADIUS_ATTR_ACCT_SESSION_ID = 44, - RADIUS_ATTR_ACCT_AUTHENTIC = 45, - RADIUS_ATTR_ACCT_SESSION_TIME = 46, - RADIUS_ATTR_ACCT_INPUT_PACKETS = 47, - RADIUS_ATTR_ACCT_OUTPUT_PACKETS = 48, - RADIUS_ATTR_ACCT_TERMINATE_CAUSE = 49, - RADIUS_ATTR_ACCT_MULTI_SESSION_ID = 50, - RADIUS_ATTR_ACCT_LINK_COUNT = 51, - RADIUS_ATTR_ACCT_INPUT_GIGAWORDS = 52, - RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53, - RADIUS_ATTR_EVENT_TIMESTAMP = 55, - 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, - RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID = 81, - RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85, - RADIUS_ATTR_CHARGEABLE_USER_IDENTITY = 89, - RADIUS_ATTR_NAS_IPV6_ADDRESS = 95, - RADIUS_ATTR_ERROR_CAUSE = 101 -}; - - -/* Termination-Action */ -#define RADIUS_TERMINATION_ACTION_DEFAULT 0 -#define RADIUS_TERMINATION_ACTION_RADIUS_REQUEST 1 - -/* NAS-Port-Type */ -#define RADIUS_NAS_PORT_TYPE_IEEE_802_11 19 - -/* Acct-Status-Type */ -#define RADIUS_ACCT_STATUS_TYPE_START 1 -#define RADIUS_ACCT_STATUS_TYPE_STOP 2 -#define RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE 3 -#define RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON 7 -#define RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF 8 - -/* Acct-Authentic */ -#define RADIUS_ACCT_AUTHENTIC_RADIUS 1 -#define RADIUS_ACCT_AUTHENTIC_LOCAL 2 -#define RADIUS_ACCT_AUTHENTIC_REMOTE 3 - -/* Acct-Terminate-Cause */ -#define RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST 1 -#define RADIUS_ACCT_TERMINATE_CAUSE_LOST_CARRIER 2 -#define RADIUS_ACCT_TERMINATE_CAUSE_LOST_SERVICE 3 -#define RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT 4 -#define RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT 5 -#define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET 6 -#define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT 7 -#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_ERROR 8 -#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_ERROR 9 -#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_REQUEST 10 -#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT 11 -#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_UNNEEDED 12 -#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_PREEMPTED 13 -#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_SUSPENDED 14 -#define RADIUS_ACCT_TERMINATE_CAUSE_SERVICE_UNAVAILABLE 15 -#define RADIUS_ACCT_TERMINATE_CAUSE_CALLBACK 16 -#define RADIUS_ACCT_TERMINATE_CAUSE_USER_ERROR 17 -#define RADIUS_ACCT_TERMINATE_CAUSE_HOST_REQUEST 18 - -#define RADIUS_TUNNEL_TAGS 32 - -/* Tunnel-Type */ -#define RADIUS_TUNNEL_TYPE_PPTP 1 -#define RADIUS_TUNNEL_TYPE_L2TP 3 -#define RADIUS_TUNNEL_TYPE_IPIP 7 -#define RADIUS_TUNNEL_TYPE_GRE 10 -#define RADIUS_TUNNEL_TYPE_VLAN 13 - -/* Tunnel-Medium-Type */ -#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV4 1 -#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV6 2 -#define RADIUS_TUNNEL_MEDIUM_TYPE_802 6 - - -struct radius_attr_vendor { - u8 vendor_type; - u8 vendor_length; -} STRUCT_PACKED; - -#define RADIUS_VENDOR_ID_CISCO 9 -#define RADIUS_CISCO_AV_PAIR 1 - -/* RFC 2548 - Microsoft Vendor-specific RADIUS Attributes */ -#define RADIUS_VENDOR_ID_MICROSOFT 311 - -enum { RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY = 16, - RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17 -}; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - -struct radius_ms_mppe_keys { - u8 *send; - size_t send_len; - u8 *recv; - size_t recv_len; -}; - - -struct radius_msg; - -/* Default size to be allocated for new RADIUS messages */ -#define RADIUS_DEFAULT_MSG_SIZE 1024 - -/* Default size to be allocated for attribute array */ -#define RADIUS_DEFAULT_ATTR_COUNT 16 - - -/* MAC address ASCII format for IEEE 802.1X use - * (draft-congdon-radius-8021x-20.txt) */ -#define RADIUS_802_1X_ADDR_FORMAT "%02X-%02X-%02X-%02X-%02X-%02X" -/* MAC address ASCII format for non-802.1X use */ -#define RADIUS_ADDR_FORMAT "%02x%02x%02x%02x%02x%02x" - -struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg); -struct wpabuf * radius_msg_get_buf(struct radius_msg *msg); -struct radius_msg * radius_msg_new(u8 code, u8 identifier); -void radius_msg_free(struct radius_msg *msg); -void radius_msg_dump(struct radius_msg *msg); -int radius_msg_finish(struct radius_msg *msg, const u8 *secret, - size_t secret_len); -int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, - size_t secret_len, const u8 *req_authenticator); -int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret, - size_t secret_len, - const struct radius_hdr *req_hdr); -void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, - size_t secret_len); -int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret, - size_t secret_len); -int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, - size_t secret_len); -struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type, - const u8 *data, size_t data_len); -struct radius_msg * radius_msg_parse(const u8 *data, size_t len); -int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, - size_t data_len); -struct wpabuf * radius_msg_get_eap(struct radius_msg *msg); -int radius_msg_verify(struct radius_msg *msg, const u8 *secret, - size_t secret_len, struct radius_msg *sent_msg, - int auth); -int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, - size_t secret_len, const u8 *req_auth); -int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, - u8 type); -void radius_msg_make_authenticator(struct radius_msg *msg, - const u8 *data, size_t len); -struct radius_ms_mppe_keys * -radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, - const u8 *secret, size_t secret_len); -struct radius_ms_mppe_keys * -radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, - const u8 *secret, size_t secret_len); -int radius_msg_add_mppe_keys(struct radius_msg *msg, - const u8 *req_authenticator, - const u8 *secret, size_t secret_len, - const u8 *send_key, size_t send_key_len, - const u8 *recv_key, size_t recv_key_len); -struct radius_attr_hdr * -radius_msg_add_attr_user_password(struct radius_msg *msg, - const u8 *data, size_t data_len, - 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, size_t n); - -static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type, - u32 value) -{ - u32 val = htonl(value); - return radius_msg_add_attr(msg, type, (u8 *) &val, 4) != NULL; -} - -static inline int radius_msg_get_attr_int32(struct radius_msg *msg, u8 type, - u32 *value) -{ - u32 val; - int res; - res = radius_msg_get_attr(msg, type, (u8 *) &val, 4); - if (res != 4) - return -1; - - *value = ntohl(val); - return 0; -} -int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, - size_t *len, const u8 *start); -int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len); - - -struct radius_attr_data { - u8 *data; - size_t len; -}; - -struct radius_class_data { - struct radius_attr_data *attr; - size_t count; -}; - -void radius_free_class(struct radius_class_data *c); -int radius_copy_class(struct radius_class_data *dst, - const struct radius_class_data *src); - -u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs); - -#endif /* RADIUS_H */ diff --git a/contrib/hostapd/src/radius/radius_client.c b/contrib/hostapd/src/radius/radius_client.c deleted file mode 100644 index 762599668f..0000000000 --- a/contrib/hostapd/src/radius/radius_client.c +++ /dev/null @@ -1,1491 +0,0 @@ -/* - * RADIUS client - * Copyright (c) 2002-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "radius.h" -#include "radius_client.h" -#include "eloop.h" - -/* Defaults for RADIUS retransmit values (exponential backoff) */ - -/** - * RADIUS_CLIENT_FIRST_WAIT - RADIUS client timeout for first retry in seconds - */ -#define RADIUS_CLIENT_FIRST_WAIT 3 - -/** - * RADIUS_CLIENT_MAX_WAIT - RADIUS client maximum retry timeout in seconds - */ -#define RADIUS_CLIENT_MAX_WAIT 120 - -/** - * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries - * - * Maximum number of retransmit attempts before the entry is removed from - * retransmit list. - */ -#define RADIUS_CLIENT_MAX_RETRIES 10 - -/** - * RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages - * - * Maximum number of entries in retransmit list (oldest entries will be - * removed, if this limit is exceeded). - */ -#define RADIUS_CLIENT_MAX_ENTRIES 30 - -/** - * RADIUS_CLIENT_NUM_FAILOVER - RADIUS client failover point - * - * The number of failed retry attempts after which the RADIUS server will be - * changed (if one of more backup servers are configured). - */ -#define RADIUS_CLIENT_NUM_FAILOVER 4 - - -/** - * struct radius_rx_handler - RADIUS client RX handler - * - * This data structure is used internally inside the RADIUS client module to - * store registered RX handlers. These handlers are registered by calls to - * radius_client_register() and unregistered when the RADIUS client is - * deinitialized with a call to radius_client_deinit(). - */ -struct radius_rx_handler { - /** - * handler - Received RADIUS message handler - */ - RadiusRxResult (*handler)(struct radius_msg *msg, - struct radius_msg *req, - const u8 *shared_secret, - size_t shared_secret_len, - void *data); - - /** - * data - Context data for the handler - */ - void *data; -}; - - -/** - * struct radius_msg_list - RADIUS client message retransmit list - * - * This data structure is used internally inside the RADIUS client module to - * store pending RADIUS requests that may still need to be retransmitted. - */ -struct radius_msg_list { - /** - * addr - STA/client address - * - * This is used to find RADIUS messages for the same STA. - */ - u8 addr[ETH_ALEN]; - - /** - * msg - RADIUS message - */ - struct radius_msg *msg; - - /** - * msg_type - Message type - */ - RadiusType msg_type; - - /** - * first_try - Time of the first transmission attempt - */ - os_time_t first_try; - - /** - * next_try - Time for the next transmission attempt - */ - os_time_t next_try; - - /** - * attempts - Number of transmission attempts - */ - int attempts; - - /** - * next_wait - Next retransmission wait time in seconds - */ - int next_wait; - - /** - * last_attempt - Time of the last transmission attempt - */ - struct os_reltime last_attempt; - - /** - * shared_secret - Shared secret with the target RADIUS server - */ - const u8 *shared_secret; - - /** - * shared_secret_len - shared_secret length in octets - */ - size_t shared_secret_len; - - /* TODO: server config with failover to backup server(s) */ - - /** - * next - Next message in the list - */ - struct radius_msg_list *next; -}; - - -/** - * struct radius_client_data - Internal RADIUS client data - * - * This data structure is used internally inside the RADIUS client module. - * External users allocate this by calling radius_client_init() and free it by - * calling radius_client_deinit(). The pointer to this opaque data is used in - * calls to other functions as an identifier for the RADIUS client instance. - */ -struct radius_client_data { - /** - * ctx - Context pointer for hostapd_logger() callbacks - */ - void *ctx; - - /** - * conf - RADIUS client configuration (list of RADIUS servers to use) - */ - struct hostapd_radius_servers *conf; - - /** - * auth_serv_sock - IPv4 socket for RADIUS authentication messages - */ - int auth_serv_sock; - - /** - * acct_serv_sock - IPv4 socket for RADIUS accounting messages - */ - int acct_serv_sock; - - /** - * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages - */ - int auth_serv_sock6; - - /** - * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages - */ - int acct_serv_sock6; - - /** - * auth_sock - Currently used socket for RADIUS authentication server - */ - int auth_sock; - - /** - * acct_sock - Currently used socket for RADIUS accounting server - */ - int acct_sock; - - /** - * auth_handlers - Authentication message handlers - */ - struct radius_rx_handler *auth_handlers; - - /** - * num_auth_handlers - Number of handlers in auth_handlers - */ - size_t num_auth_handlers; - - /** - * acct_handlers - Accounting message handlers - */ - struct radius_rx_handler *acct_handlers; - - /** - * num_acct_handlers - Number of handlers in acct_handlers - */ - size_t num_acct_handlers; - - /** - * msgs - Pending outgoing RADIUS messages - */ - struct radius_msg_list *msgs; - - /** - * num_msgs - Number of pending messages in the msgs list - */ - size_t num_msgs; - - /** - * next_radius_identifier - Next RADIUS message identifier to use - */ - u8 next_radius_identifier; -}; - - -static int -radius_change_server(struct radius_client_data *radius, - struct hostapd_radius_server *nserv, - struct hostapd_radius_server *oserv, - int sock, int sock6, int auth); -static int radius_client_init_acct(struct radius_client_data *radius); -static int radius_client_init_auth(struct radius_client_data *radius); - - -static void radius_client_msg_free(struct radius_msg_list *req) -{ - radius_msg_free(req->msg); - os_free(req); -} - - -/** - * radius_client_register - Register a RADIUS client RX handler - * @radius: RADIUS client context from radius_client_init() - * @msg_type: RADIUS client type (RADIUS_AUTH or RADIUS_ACCT) - * @handler: Handler for received RADIUS messages - * @data: Context pointer for handler callbacks - * Returns: 0 on success, -1 on failure - * - * This function is used to register a handler for processing received RADIUS - * authentication and accounting messages. The handler() callback function will - * be called whenever a RADIUS message is received from the active server. - * - * There can be multiple registered RADIUS message handlers. The handlers will - * be called in order until one of them indicates that it has processed or - * queued the message. - */ -int radius_client_register(struct radius_client_data *radius, - RadiusType msg_type, - RadiusRxResult (*handler)(struct radius_msg *msg, - struct radius_msg *req, - const u8 *shared_secret, - size_t shared_secret_len, - void *data), - void *data) -{ - struct radius_rx_handler **handlers, *newh; - size_t *num; - - if (msg_type == RADIUS_ACCT) { - handlers = &radius->acct_handlers; - num = &radius->num_acct_handlers; - } else { - handlers = &radius->auth_handlers; - num = &radius->num_auth_handlers; - } - - newh = os_realloc_array(*handlers, *num + 1, - sizeof(struct radius_rx_handler)); - if (newh == NULL) - return -1; - - newh[*num].handler = handler; - newh[*num].data = data; - (*num)++; - *handlers = newh; - - return 0; -} - - -static void radius_client_handle_send_error(struct radius_client_data *radius, - int s, RadiusType msg_type) -{ -#ifndef CONFIG_NATIVE_WINDOWS - int _errno = errno; - wpa_printf(MSG_INFO, "send[RADIUS]: %s", strerror(errno)); - if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL || - _errno == EBADF) { - hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_INFO, - "Send failed - maybe interface status changed -" - " try to connect again"); - eloop_unregister_read_sock(s); - close(s); - if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) - radius_client_init_acct(radius); - else - radius_client_init_auth(radius); - } -#endif /* CONFIG_NATIVE_WINDOWS */ -} - - -static int radius_client_retransmit(struct radius_client_data *radius, - struct radius_msg_list *entry, - os_time_t now) -{ - struct hostapd_radius_servers *conf = radius->conf; - int s; - struct wpabuf *buf; - - if (entry->msg_type == RADIUS_ACCT || - entry->msg_type == RADIUS_ACCT_INTERIM) { - s = radius->acct_sock; - if (entry->attempts == 0) - conf->acct_server->requests++; - else { - conf->acct_server->timeouts++; - conf->acct_server->retransmissions++; - } - } else { - s = radius->auth_sock; - if (entry->attempts == 0) - conf->auth_server->requests++; - else { - conf->auth_server->timeouts++; - conf->auth_server->retransmissions++; - } - } - - /* retransmit; remove entry if too many attempts */ - entry->attempts++; - hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)", - radius_msg_get_hdr(entry->msg)->identifier); - - os_get_reltime(&entry->last_attempt); - buf = radius_msg_get_buf(entry->msg); - if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) - radius_client_handle_send_error(radius, s, entry->msg_type); - - entry->next_try = now + entry->next_wait; - entry->next_wait *= 2; - if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT) - entry->next_wait = RADIUS_CLIENT_MAX_WAIT; - if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) { - wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts"); - return 1; - } - - return 0; -} - - -static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) -{ - struct radius_client_data *radius = eloop_ctx; - struct hostapd_radius_servers *conf = radius->conf; - struct os_reltime now; - os_time_t first; - struct radius_msg_list *entry, *prev, *tmp; - int auth_failover = 0, acct_failover = 0; - char abuf[50]; - - entry = radius->msgs; - if (!entry) - return; - - os_get_reltime(&now); - first = 0; - - prev = NULL; - while (entry) { - if (now.sec >= entry->next_try && - radius_client_retransmit(radius, entry, now.sec)) { - if (prev) - prev->next = entry->next; - else - radius->msgs = entry->next; - - tmp = entry; - entry = entry->next; - radius_client_msg_free(tmp); - radius->num_msgs--; - continue; - } - - if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) { - if (entry->msg_type == RADIUS_ACCT || - entry->msg_type == RADIUS_ACCT_INTERIM) - acct_failover++; - else - auth_failover++; - } - - if (first == 0 || entry->next_try < first) - first = entry->next_try; - - prev = entry; - entry = entry->next; - } - - if (radius->msgs) { - if (first < now.sec) - first = now.sec; - eloop_register_timeout(first - now.sec, 0, - radius_client_timer, radius, NULL); - hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, "Next RADIUS client " - "retransmit in %ld seconds", - (long int) (first - now.sec)); - } - - if (auth_failover && conf->num_auth_servers > 1) { - struct hostapd_radius_server *next, *old; - old = conf->auth_server; - hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_NOTICE, - "No response from Authentication server " - "%s:%d - failover", - hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), - old->port); - - for (entry = radius->msgs; entry; entry = entry->next) { - if (entry->msg_type == RADIUS_AUTH) - old->timeouts++; - } - - next = old + 1; - if (next > &(conf->auth_servers[conf->num_auth_servers - 1])) - next = conf->auth_servers; - conf->auth_server = next; - radius_change_server(radius, next, old, - radius->auth_serv_sock, - radius->auth_serv_sock6, 1); - } - - if (acct_failover && conf->num_acct_servers > 1) { - struct hostapd_radius_server *next, *old; - old = conf->acct_server; - hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_NOTICE, - "No response from Accounting server " - "%s:%d - failover", - hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), - old->port); - - for (entry = radius->msgs; entry; entry = entry->next) { - if (entry->msg_type == RADIUS_ACCT || - entry->msg_type == RADIUS_ACCT_INTERIM) - old->timeouts++; - } - - next = old + 1; - if (next > &conf->acct_servers[conf->num_acct_servers - 1]) - next = conf->acct_servers; - conf->acct_server = next; - radius_change_server(radius, next, old, - radius->acct_serv_sock, - radius->acct_serv_sock6, 0); - } -} - - -static void radius_client_update_timeout(struct radius_client_data *radius) -{ - struct os_reltime now; - os_time_t first; - struct radius_msg_list *entry; - - eloop_cancel_timeout(radius_client_timer, radius, NULL); - - if (radius->msgs == NULL) { - return; - } - - first = 0; - for (entry = radius->msgs; entry; entry = entry->next) { - if (first == 0 || entry->next_try < first) - first = entry->next_try; - } - - os_get_reltime(&now); - if (first < now.sec) - first = now.sec; - eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius, - NULL); - hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in" - " %ld seconds", (long int) (first - now.sec)); -} - - -static void radius_client_list_add(struct radius_client_data *radius, - struct radius_msg *msg, - RadiusType msg_type, - const u8 *shared_secret, - size_t shared_secret_len, const u8 *addr) -{ - struct radius_msg_list *entry, *prev; - - if (eloop_terminated()) { - /* No point in adding entries to retransmit queue since event - * loop has already been terminated. */ - radius_msg_free(msg); - return; - } - - entry = os_zalloc(sizeof(*entry)); - if (entry == NULL) { - wpa_printf(MSG_INFO, "RADIUS: Failed to add packet into retransmit list"); - radius_msg_free(msg); - return; - } - - if (addr) - os_memcpy(entry->addr, addr, ETH_ALEN); - entry->msg = msg; - entry->msg_type = msg_type; - entry->shared_secret = shared_secret; - entry->shared_secret_len = shared_secret_len; - os_get_reltime(&entry->last_attempt); - entry->first_try = entry->last_attempt.sec; - entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; - entry->attempts = 1; - entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; - entry->next = radius->msgs; - radius->msgs = entry; - radius_client_update_timeout(radius); - - if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) { - wpa_printf(MSG_INFO, "RADIUS: Removing the oldest un-ACKed packet due to retransmit list limits"); - prev = NULL; - while (entry->next) { - prev = entry; - entry = entry->next; - } - if (prev) { - prev->next = NULL; - radius_client_msg_free(entry); - } - } else - radius->num_msgs++; -} - - -static void radius_client_list_del(struct radius_client_data *radius, - RadiusType msg_type, const u8 *addr) -{ - struct radius_msg_list *entry, *prev, *tmp; - - if (addr == NULL) - return; - - entry = radius->msgs; - prev = NULL; - while (entry) { - if (entry->msg_type == msg_type && - os_memcmp(entry->addr, addr, ETH_ALEN) == 0) { - if (prev) - prev->next = entry->next; - else - radius->msgs = entry->next; - tmp = entry; - entry = entry->next; - hostapd_logger(radius->ctx, addr, - HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, - "Removing matching RADIUS message"); - radius_client_msg_free(tmp); - radius->num_msgs--; - continue; - } - prev = entry; - entry = entry->next; - } -} - - -/** - * radius_client_send - Send a RADIUS request - * @radius: RADIUS client context from radius_client_init() - * @msg: RADIUS message to be sent - * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM) - * @addr: MAC address of the device related to this message or %NULL - * Returns: 0 on success, -1 on failure - * - * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or - * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference - * between accounting and interim accounting messages is that the interim - * message will override any pending interim accounting updates while a new - * accounting message does not remove any pending messages. - * - * The message is added on the retransmission queue and will be retransmitted - * automatically until a response is received or maximum number of retries - * (RADIUS_CLIENT_MAX_RETRIES) is reached. - * - * The related device MAC address can be used to identify pending messages that - * can be removed with radius_client_flush_auth() or with interim accounting - * updates. - */ -int radius_client_send(struct radius_client_data *radius, - struct radius_msg *msg, RadiusType msg_type, - const u8 *addr) -{ - struct hostapd_radius_servers *conf = radius->conf; - const u8 *shared_secret; - size_t shared_secret_len; - char *name; - int s, res; - struct wpabuf *buf; - - if (msg_type == RADIUS_ACCT_INTERIM) { - /* Remove any pending interim acct update for the same STA. */ - radius_client_list_del(radius, msg_type, addr); - } - - if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) { - if (conf->acct_server == NULL) { - hostapd_logger(radius->ctx, NULL, - HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_INFO, - "No accounting server configured"); - return -1; - } - shared_secret = conf->acct_server->shared_secret; - shared_secret_len = conf->acct_server->shared_secret_len; - radius_msg_finish_acct(msg, shared_secret, shared_secret_len); - name = "accounting"; - s = radius->acct_sock; - conf->acct_server->requests++; - } else { - if (conf->auth_server == NULL) { - hostapd_logger(radius->ctx, NULL, - HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_INFO, - "No authentication server configured"); - return -1; - } - shared_secret = conf->auth_server->shared_secret; - shared_secret_len = conf->auth_server->shared_secret_len; - radius_msg_finish(msg, shared_secret, shared_secret_len); - name = "authentication"; - s = radius->auth_sock; - conf->auth_server->requests++; - } - - hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s " - "server", name); - if (conf->msg_dumps) - radius_msg_dump(msg); - - buf = radius_msg_get_buf(msg); - res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0); - if (res < 0) - radius_client_handle_send_error(radius, s, msg_type); - - radius_client_list_add(radius, msg, msg_type, shared_secret, - shared_secret_len, addr); - - return 0; -} - - -static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct radius_client_data *radius = eloop_ctx; - struct hostapd_radius_servers *conf = radius->conf; - RadiusType msg_type = (RadiusType) sock_ctx; - int len, roundtrip; - unsigned char buf[3000]; - struct radius_msg *msg; - struct radius_hdr *hdr; - struct radius_rx_handler *handlers; - size_t num_handlers, i; - struct radius_msg_list *req, *prev_req; - struct os_reltime now; - struct hostapd_radius_server *rconf; - int invalid_authenticator = 0; - - if (msg_type == RADIUS_ACCT) { - handlers = radius->acct_handlers; - num_handlers = radius->num_acct_handlers; - rconf = conf->acct_server; - } else { - handlers = radius->auth_handlers; - num_handlers = radius->num_auth_handlers; - rconf = conf->auth_server; - } - - len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT); - if (len < 0) { - wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno)); - return; - } - hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS " - "server", len); - if (len == sizeof(buf)) { - wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it"); - return; - } - - msg = radius_msg_parse(buf, len); - if (msg == NULL) { - wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed"); - rconf->malformed_responses++; - return; - } - hdr = radius_msg_get_hdr(msg); - - hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, "Received RADIUS message"); - if (conf->msg_dumps) - radius_msg_dump(msg); - - switch (hdr->code) { - case RADIUS_CODE_ACCESS_ACCEPT: - rconf->access_accepts++; - break; - case RADIUS_CODE_ACCESS_REJECT: - rconf->access_rejects++; - break; - case RADIUS_CODE_ACCESS_CHALLENGE: - rconf->access_challenges++; - break; - case RADIUS_CODE_ACCOUNTING_RESPONSE: - rconf->responses++; - break; - } - - prev_req = NULL; - req = radius->msgs; - while (req) { - /* TODO: also match by src addr:port of the packet when using - * alternative RADIUS servers (?) */ - if ((req->msg_type == msg_type || - (req->msg_type == RADIUS_ACCT_INTERIM && - msg_type == RADIUS_ACCT)) && - radius_msg_get_hdr(req->msg)->identifier == - hdr->identifier) - break; - - prev_req = req; - req = req->next; - } - - if (req == NULL) { - hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, - "No matching RADIUS request found (type=%d " - "id=%d) - dropping packet", - msg_type, hdr->identifier); - goto fail; - } - - os_get_reltime(&now); - roundtrip = (now.sec - req->last_attempt.sec) * 100 + - (now.usec - req->last_attempt.usec) / 10000; - hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, - "Received RADIUS packet matched with a pending " - "request, round trip time %d.%02d sec", - roundtrip / 100, roundtrip % 100); - rconf->round_trip_time = roundtrip; - - /* Remove ACKed RADIUS packet from retransmit list */ - if (prev_req) - prev_req->next = req->next; - else - radius->msgs = req->next; - radius->num_msgs--; - - for (i = 0; i < num_handlers; i++) { - RadiusRxResult res; - res = handlers[i].handler(msg, req->msg, req->shared_secret, - req->shared_secret_len, - handlers[i].data); - switch (res) { - case RADIUS_RX_PROCESSED: - radius_msg_free(msg); - /* continue */ - case RADIUS_RX_QUEUED: - radius_client_msg_free(req); - return; - case RADIUS_RX_INVALID_AUTHENTICATOR: - invalid_authenticator++; - /* continue */ - case RADIUS_RX_UNKNOWN: - /* continue with next handler */ - break; - } - } - - if (invalid_authenticator) - rconf->bad_authenticators++; - else - rconf->unknown_types++; - hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found " - "(type=%d code=%d id=%d)%s - dropping packet", - msg_type, hdr->code, hdr->identifier, - invalid_authenticator ? " [INVALID AUTHENTICATOR]" : - ""); - radius_client_msg_free(req); - - fail: - radius_msg_free(msg); -} - - -/** - * radius_client_get_id - Get an identifier for a new RADIUS message - * @radius: RADIUS client context from radius_client_init() - * Returns: Allocated identifier - * - * This function is used to fetch a unique (among pending requests) identifier - * for a new RADIUS message. - */ -u8 radius_client_get_id(struct radius_client_data *radius) -{ - struct radius_msg_list *entry, *prev, *_remove; - u8 id = radius->next_radius_identifier++; - - /* remove entries with matching id from retransmit list to avoid - * using new reply from the RADIUS server with an old request */ - entry = radius->msgs; - prev = NULL; - while (entry) { - if (radius_msg_get_hdr(entry->msg)->identifier == id) { - hostapd_logger(radius->ctx, entry->addr, - HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, - "Removing pending RADIUS message, " - "since its id (%d) is reused", id); - if (prev) - prev->next = entry->next; - else - radius->msgs = entry->next; - _remove = entry; - } else { - _remove = NULL; - prev = entry; - } - entry = entry->next; - - if (_remove) - radius_client_msg_free(_remove); - } - - return id; -} - - -/** - * radius_client_flush - Flush all pending RADIUS client messages - * @radius: RADIUS client context from radius_client_init() - * @only_auth: Whether only authentication messages are removed - */ -void radius_client_flush(struct radius_client_data *radius, int only_auth) -{ - struct radius_msg_list *entry, *prev, *tmp; - - if (!radius) - return; - - prev = NULL; - entry = radius->msgs; - - while (entry) { - if (!only_auth || entry->msg_type == RADIUS_AUTH) { - if (prev) - prev->next = entry->next; - else - radius->msgs = entry->next; - - tmp = entry; - entry = entry->next; - radius_client_msg_free(tmp); - radius->num_msgs--; - } else { - prev = entry; - entry = entry->next; - } - } - - if (radius->msgs == NULL) - eloop_cancel_timeout(radius_client_timer, radius, NULL); -} - - -static void radius_client_update_acct_msgs(struct radius_client_data *radius, - const u8 *shared_secret, - size_t shared_secret_len) -{ - struct radius_msg_list *entry; - - if (!radius) - return; - - for (entry = radius->msgs; entry; entry = entry->next) { - if (entry->msg_type == RADIUS_ACCT) { - entry->shared_secret = shared_secret; - entry->shared_secret_len = shared_secret_len; - radius_msg_finish_acct(entry->msg, shared_secret, - shared_secret_len); - } - } -} - - -static int -radius_change_server(struct radius_client_data *radius, - struct hostapd_radius_server *nserv, - struct hostapd_radius_server *oserv, - int sock, int sock6, int auth) -{ - struct sockaddr_in serv, claddr; -#ifdef CONFIG_IPV6 - struct sockaddr_in6 serv6, claddr6; -#endif /* CONFIG_IPV6 */ - struct sockaddr *addr, *cl_addr; - socklen_t addrlen, claddrlen; - char abuf[50]; - int sel_sock; - struct radius_msg_list *entry; - struct hostapd_radius_servers *conf = radius->conf; - - hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_INFO, - "%s server %s:%d", - auth ? "Authentication" : "Accounting", - hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)), - nserv->port); - - if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len || - os_memcmp(nserv->shared_secret, oserv->shared_secret, - nserv->shared_secret_len) != 0) { - /* Pending RADIUS packets used different shared secret, so - * they need to be modified. Update accounting message - * authenticators here. Authentication messages are removed - * since they would require more changes and the new RADIUS - * server may not be prepared to receive them anyway due to - * missing state information. Client will likely retry - * authentication, so this should not be an issue. */ - if (auth) - radius_client_flush(radius, 1); - else { - radius_client_update_acct_msgs( - radius, nserv->shared_secret, - nserv->shared_secret_len); - } - } - - /* Reset retry counters for the new server */ - for (entry = radius->msgs; entry; entry = entry->next) { - if ((auth && entry->msg_type != RADIUS_AUTH) || - (!auth && entry->msg_type != RADIUS_ACCT)) - continue; - entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; - entry->attempts = 0; - entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; - } - - if (radius->msgs) { - eloop_cancel_timeout(radius_client_timer, radius, NULL); - eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0, - radius_client_timer, radius, NULL); - } - - switch (nserv->addr.af) { - case AF_INET: - os_memset(&serv, 0, sizeof(serv)); - serv.sin_family = AF_INET; - serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr; - serv.sin_port = htons(nserv->port); - addr = (struct sockaddr *) &serv; - addrlen = sizeof(serv); - sel_sock = sock; - break; -#ifdef CONFIG_IPV6 - case AF_INET6: - os_memset(&serv6, 0, sizeof(serv6)); - serv6.sin6_family = AF_INET6; - os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6, - sizeof(struct in6_addr)); - serv6.sin6_port = htons(nserv->port); - addr = (struct sockaddr *) &serv6; - addrlen = sizeof(serv6); - sel_sock = sock6; - break; -#endif /* CONFIG_IPV6 */ - default: - return -1; - } - - if (conf->force_client_addr) { - switch (conf->client_addr.af) { - case AF_INET: - os_memset(&claddr, 0, sizeof(claddr)); - claddr.sin_family = AF_INET; - claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr; - claddr.sin_port = htons(0); - cl_addr = (struct sockaddr *) &claddr; - claddrlen = sizeof(claddr); - break; -#ifdef CONFIG_IPV6 - case AF_INET6: - os_memset(&claddr6, 0, sizeof(claddr6)); - claddr6.sin6_family = AF_INET6; - os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6, - sizeof(struct in6_addr)); - claddr6.sin6_port = htons(0); - cl_addr = (struct sockaddr *) &claddr6; - claddrlen = sizeof(claddr6); - break; -#endif /* CONFIG_IPV6 */ - default: - return -1; - } - - if (bind(sel_sock, cl_addr, claddrlen) < 0) { - wpa_printf(MSG_INFO, "bind[radius]: %s", - strerror(errno)); - return -1; - } - } - - if (connect(sel_sock, addr, addrlen) < 0) { - wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno)); - return -1; - } - -#ifndef CONFIG_NATIVE_WINDOWS - switch (nserv->addr.af) { - case AF_INET: - claddrlen = sizeof(claddr); - getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen); - wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", - inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port)); - break; -#ifdef CONFIG_IPV6 - case AF_INET6: { - claddrlen = sizeof(claddr6); - getsockname(sel_sock, (struct sockaddr *) &claddr6, - &claddrlen); - wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", - inet_ntop(AF_INET6, &claddr6.sin6_addr, - abuf, sizeof(abuf)), - ntohs(claddr6.sin6_port)); - break; - } -#endif /* CONFIG_IPV6 */ - } -#endif /* CONFIG_NATIVE_WINDOWS */ - - if (auth) - radius->auth_sock = sel_sock; - else - radius->acct_sock = sel_sock; - - return 0; -} - - -static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx) -{ - struct radius_client_data *radius = eloop_ctx; - struct hostapd_radius_servers *conf = radius->conf; - struct hostapd_radius_server *oserv; - - if (radius->auth_sock >= 0 && conf->auth_servers && - conf->auth_server != conf->auth_servers) { - oserv = conf->auth_server; - conf->auth_server = conf->auth_servers; - radius_change_server(radius, conf->auth_server, oserv, - radius->auth_serv_sock, - radius->auth_serv_sock6, 1); - } - - if (radius->acct_sock >= 0 && conf->acct_servers && - conf->acct_server != conf->acct_servers) { - oserv = conf->acct_server; - conf->acct_server = conf->acct_servers; - radius_change_server(radius, conf->acct_server, oserv, - radius->acct_serv_sock, - radius->acct_serv_sock6, 0); - } - - if (conf->retry_primary_interval) - eloop_register_timeout(conf->retry_primary_interval, 0, - radius_retry_primary_timer, radius, - NULL); -} - - -static int radius_client_disable_pmtu_discovery(int s) -{ - int r = -1; -#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) - /* Turn off Path MTU discovery on IPv4/UDP sockets. */ - int action = IP_PMTUDISC_DONT; - r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, - sizeof(action)); - if (r == -1) - wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s", - strerror(errno)); -#endif - return r; -} - - -static int radius_client_init_auth(struct radius_client_data *radius) -{ - struct hostapd_radius_servers *conf = radius->conf; - int ok = 0; - - radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (radius->auth_serv_sock < 0) - wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s", - strerror(errno)); - else { - radius_client_disable_pmtu_discovery(radius->auth_serv_sock); - ok++; - } - -#ifdef CONFIG_IPV6 - radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0); - if (radius->auth_serv_sock6 < 0) - wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s", - strerror(errno)); - else - ok++; -#endif /* CONFIG_IPV6 */ - - if (ok == 0) - return -1; - - radius_change_server(radius, conf->auth_server, NULL, - radius->auth_serv_sock, radius->auth_serv_sock6, - 1); - - if (radius->auth_serv_sock >= 0 && - eloop_register_read_sock(radius->auth_serv_sock, - radius_client_receive, radius, - (void *) RADIUS_AUTH)) { - wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server"); - return -1; - } - -#ifdef CONFIG_IPV6 - if (radius->auth_serv_sock6 >= 0 && - eloop_register_read_sock(radius->auth_serv_sock6, - radius_client_receive, radius, - (void *) RADIUS_AUTH)) { - wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server"); - return -1; - } -#endif /* CONFIG_IPV6 */ - - return 0; -} - - -static int radius_client_init_acct(struct radius_client_data *radius) -{ - struct hostapd_radius_servers *conf = radius->conf; - int ok = 0; - - radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (radius->acct_serv_sock < 0) - wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s", - strerror(errno)); - else { - radius_client_disable_pmtu_discovery(radius->acct_serv_sock); - ok++; - } - -#ifdef CONFIG_IPV6 - radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0); - if (radius->acct_serv_sock6 < 0) - wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s", - strerror(errno)); - else - ok++; -#endif /* CONFIG_IPV6 */ - - if (ok == 0) - return -1; - - radius_change_server(radius, conf->acct_server, NULL, - radius->acct_serv_sock, radius->acct_serv_sock6, - 0); - - if (radius->acct_serv_sock >= 0 && - eloop_register_read_sock(radius->acct_serv_sock, - radius_client_receive, radius, - (void *) RADIUS_ACCT)) { - wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server"); - return -1; - } - -#ifdef CONFIG_IPV6 - if (radius->acct_serv_sock6 >= 0 && - eloop_register_read_sock(radius->acct_serv_sock6, - radius_client_receive, radius, - (void *) RADIUS_ACCT)) { - wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server"); - return -1; - } -#endif /* CONFIG_IPV6 */ - - return 0; -} - - -/** - * radius_client_init - Initialize RADIUS client - * @ctx: Callback context to be used in hostapd_logger() calls - * @conf: RADIUS client configuration (RADIUS servers) - * Returns: Pointer to private RADIUS client context or %NULL on failure - * - * The caller is responsible for keeping the configuration data available for - * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is - * called for the returned context pointer. - */ -struct radius_client_data * -radius_client_init(void *ctx, struct hostapd_radius_servers *conf) -{ - struct radius_client_data *radius; - - radius = os_zalloc(sizeof(struct radius_client_data)); - if (radius == NULL) - return NULL; - - radius->ctx = ctx; - radius->conf = conf; - radius->auth_serv_sock = radius->acct_serv_sock = - radius->auth_serv_sock6 = radius->acct_serv_sock6 = - radius->auth_sock = radius->acct_sock = -1; - - if (conf->auth_server && radius_client_init_auth(radius)) { - radius_client_deinit(radius); - return NULL; - } - - if (conf->acct_server && radius_client_init_acct(radius)) { - radius_client_deinit(radius); - return NULL; - } - - if (conf->retry_primary_interval) - eloop_register_timeout(conf->retry_primary_interval, 0, - radius_retry_primary_timer, radius, - NULL); - - return radius; -} - - -/** - * radius_client_deinit - Deinitialize RADIUS client - * @radius: RADIUS client context from radius_client_init() - */ -void radius_client_deinit(struct radius_client_data *radius) -{ - if (!radius) - return; - - if (radius->auth_serv_sock >= 0) - eloop_unregister_read_sock(radius->auth_serv_sock); - if (radius->acct_serv_sock >= 0) - eloop_unregister_read_sock(radius->acct_serv_sock); -#ifdef CONFIG_IPV6 - if (radius->auth_serv_sock6 >= 0) - eloop_unregister_read_sock(radius->auth_serv_sock6); - if (radius->acct_serv_sock6 >= 0) - eloop_unregister_read_sock(radius->acct_serv_sock6); -#endif /* CONFIG_IPV6 */ - - eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL); - - radius_client_flush(radius, 0); - os_free(radius->auth_handlers); - os_free(radius->acct_handlers); - os_free(radius); -} - - -/** - * radius_client_flush_auth - Flush pending RADIUS messages for an address - * @radius: RADIUS client context from radius_client_init() - * @addr: MAC address of the related device - * - * This function can be used to remove pending RADIUS authentication messages - * that are related to a specific device. The addr parameter is matched with - * the one used in radius_client_send() call that was used to transmit the - * authentication request. - */ -void radius_client_flush_auth(struct radius_client_data *radius, - const u8 *addr) -{ - struct radius_msg_list *entry, *prev, *tmp; - - prev = NULL; - entry = radius->msgs; - while (entry) { - if (entry->msg_type == RADIUS_AUTH && - os_memcmp(entry->addr, addr, ETH_ALEN) == 0) { - hostapd_logger(radius->ctx, addr, - HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, - "Removing pending RADIUS authentication" - " message for removed client"); - - if (prev) - prev->next = entry->next; - else - radius->msgs = entry->next; - - tmp = entry; - entry = entry->next; - radius_client_msg_free(tmp); - radius->num_msgs--; - continue; - } - - prev = entry; - entry = entry->next; - } -} - - -static int radius_client_dump_auth_server(char *buf, size_t buflen, - struct hostapd_radius_server *serv, - struct radius_client_data *cli) -{ - int pending = 0; - struct radius_msg_list *msg; - char abuf[50]; - - if (cli) { - for (msg = cli->msgs; msg; msg = msg->next) { - if (msg->msg_type == RADIUS_AUTH) - pending++; - } - } - - return os_snprintf(buf, buflen, - "radiusAuthServerIndex=%d\n" - "radiusAuthServerAddress=%s\n" - "radiusAuthClientServerPortNumber=%d\n" - "radiusAuthClientRoundTripTime=%d\n" - "radiusAuthClientAccessRequests=%u\n" - "radiusAuthClientAccessRetransmissions=%u\n" - "radiusAuthClientAccessAccepts=%u\n" - "radiusAuthClientAccessRejects=%u\n" - "radiusAuthClientAccessChallenges=%u\n" - "radiusAuthClientMalformedAccessResponses=%u\n" - "radiusAuthClientBadAuthenticators=%u\n" - "radiusAuthClientPendingRequests=%u\n" - "radiusAuthClientTimeouts=%u\n" - "radiusAuthClientUnknownTypes=%u\n" - "radiusAuthClientPacketsDropped=%u\n", - serv->index, - hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)), - serv->port, - serv->round_trip_time, - serv->requests, - serv->retransmissions, - serv->access_accepts, - serv->access_rejects, - serv->access_challenges, - serv->malformed_responses, - serv->bad_authenticators, - pending, - serv->timeouts, - serv->unknown_types, - serv->packets_dropped); -} - - -static int radius_client_dump_acct_server(char *buf, size_t buflen, - struct hostapd_radius_server *serv, - struct radius_client_data *cli) -{ - int pending = 0; - struct radius_msg_list *msg; - char abuf[50]; - - if (cli) { - for (msg = cli->msgs; msg; msg = msg->next) { - if (msg->msg_type == RADIUS_ACCT || - msg->msg_type == RADIUS_ACCT_INTERIM) - pending++; - } - } - - return os_snprintf(buf, buflen, - "radiusAccServerIndex=%d\n" - "radiusAccServerAddress=%s\n" - "radiusAccClientServerPortNumber=%d\n" - "radiusAccClientRoundTripTime=%d\n" - "radiusAccClientRequests=%u\n" - "radiusAccClientRetransmissions=%u\n" - "radiusAccClientResponses=%u\n" - "radiusAccClientMalformedResponses=%u\n" - "radiusAccClientBadAuthenticators=%u\n" - "radiusAccClientPendingRequests=%u\n" - "radiusAccClientTimeouts=%u\n" - "radiusAccClientUnknownTypes=%u\n" - "radiusAccClientPacketsDropped=%u\n", - serv->index, - hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)), - serv->port, - serv->round_trip_time, - serv->requests, - serv->retransmissions, - serv->responses, - serv->malformed_responses, - serv->bad_authenticators, - pending, - serv->timeouts, - serv->unknown_types, - serv->packets_dropped); -} - - -/** - * radius_client_get_mib - Get RADIUS client MIB information - * @radius: RADIUS client context from radius_client_init() - * @buf: Buffer for returning MIB data in text format - * @buflen: Maximum buf length in octets - * Returns: Number of octets written into the buffer - */ -int radius_client_get_mib(struct radius_client_data *radius, char *buf, - size_t buflen) -{ - struct hostapd_radius_servers *conf = radius->conf; - int i; - struct hostapd_radius_server *serv; - int count = 0; - - if (conf->auth_servers) { - for (i = 0; i < conf->num_auth_servers; i++) { - serv = &conf->auth_servers[i]; - count += radius_client_dump_auth_server( - buf + count, buflen - count, serv, - serv == conf->auth_server ? - radius : NULL); - } - } - - if (conf->acct_servers) { - for (i = 0; i < conf->num_acct_servers; i++) { - serv = &conf->acct_servers[i]; - count += radius_client_dump_acct_server( - buf + count, buflen - count, serv, - serv == conf->acct_server ? - radius : NULL); - } - } - - return count; -} - - -void radius_client_reconfig(struct radius_client_data *radius, - struct hostapd_radius_servers *conf) -{ - if (radius) - radius->conf = conf; -} diff --git a/contrib/hostapd/src/radius/radius_client.h b/contrib/hostapd/src/radius/radius_client.h deleted file mode 100644 index 3db16aa282..0000000000 --- a/contrib/hostapd/src/radius/radius_client.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * RADIUS client - * Copyright (c) 2002-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef RADIUS_CLIENT_H -#define RADIUS_CLIENT_H - -#include "ip_addr.h" - -struct radius_msg; - -/** - * struct hostapd_radius_server - RADIUS server information for RADIUS client - * - * This structure contains information about a RADIUS server. The values are - * mainly for MIB information. The MIB variable prefix (radiusAuth or - * radiusAcc) depends on whether this is an authentication or accounting - * server. - * - * radiusAuthClientPendingRequests (or radiusAccClientPendingRequests) is the - * number struct radius_client_data::msgs for matching msg_type. - */ -struct hostapd_radius_server { - /** - * addr - radiusAuthServerAddress or radiusAccServerAddress - */ - struct hostapd_ip_addr addr; - - /** - * port - radiusAuthClientServerPortNumber or radiusAccClientServerPortNumber - */ - int port; - - /** - * shared_secret - Shared secret for authenticating RADIUS messages - */ - u8 *shared_secret; - - /** - * shared_secret_len - Length of shared_secret in octets - */ - size_t shared_secret_len; - - /* Dynamic (not from configuration file) MIB data */ - - /** - * index - radiusAuthServerIndex or radiusAccServerIndex - */ - int index; - - /** - * round_trip_time - radiusAuthClientRoundTripTime or radiusAccClientRoundTripTime - * Round-trip time in hundredths of a second. - */ - int round_trip_time; - - /** - * requests - radiusAuthClientAccessRequests or radiusAccClientRequests - */ - u32 requests; - - /** - * retransmissions - radiusAuthClientAccessRetransmissions or radiusAccClientRetransmissions - */ - u32 retransmissions; - - /** - * access_accepts - radiusAuthClientAccessAccepts - */ - u32 access_accepts; - - /** - * access_rejects - radiusAuthClientAccessRejects - */ - u32 access_rejects; - - /** - * access_challenges - radiusAuthClientAccessChallenges - */ - u32 access_challenges; - - /** - * responses - radiusAccClientResponses - */ - u32 responses; - - /** - * malformed_responses - radiusAuthClientMalformedAccessResponses or radiusAccClientMalformedResponses - */ - u32 malformed_responses; - - /** - * bad_authenticators - radiusAuthClientBadAuthenticators or radiusAccClientBadAuthenticators - */ - u32 bad_authenticators; - - /** - * timeouts - radiusAuthClientTimeouts or radiusAccClientTimeouts - */ - u32 timeouts; - - /** - * unknown_types - radiusAuthClientUnknownTypes or radiusAccClientUnknownTypes - */ - u32 unknown_types; - - /** - * packets_dropped - radiusAuthClientPacketsDropped or radiusAccClientPacketsDropped - */ - u32 packets_dropped; -}; - -/** - * struct hostapd_radius_servers - RADIUS servers for RADIUS client - */ -struct hostapd_radius_servers { - /** - * auth_servers - RADIUS Authentication servers in priority order - */ - struct hostapd_radius_server *auth_servers; - - /** - * num_auth_servers - Number of auth_servers entries - */ - int num_auth_servers; - - /** - * auth_server - The current Authentication server - */ - struct hostapd_radius_server *auth_server; - - /** - * acct_servers - RADIUS Accounting servers in priority order - */ - struct hostapd_radius_server *acct_servers; - - /** - * num_acct_servers - Number of acct_servers entries - */ - int num_acct_servers; - - /** - * acct_server - The current Accounting server - */ - struct hostapd_radius_server *acct_server; - - /** - * retry_primary_interval - Retry interval for trying primary server - * - * This specifies a retry interval in sexconds for trying to return to - * the primary RADIUS server. RADIUS client code will automatically try - * to use the next server when the current server is not replying to - * requests. If this interval is set (non-zero), the primary server - * will be retried after the specified number of seconds has passed - * even if the current used secondary server is still working. - */ - int retry_primary_interval; - - /** - * msg_dumps - Whether RADIUS message details are shown in stdout - */ - int msg_dumps; - - /** - * client_addr - Client (local) address to use if force_client_addr - */ - struct hostapd_ip_addr client_addr; - - /** - * force_client_addr - Whether to force client (local) address - */ - int force_client_addr; -}; - - -/** - * RadiusType - RADIUS server type for RADIUS client - */ -typedef enum { - /** - * RADIUS authentication - */ - RADIUS_AUTH, - - /** - * RADIUS_ACCT - RADIUS accounting - */ - RADIUS_ACCT, - - /** - * RADIUS_ACCT_INTERIM - RADIUS interim accounting message - * - * Used only with radius_client_send(). This behaves just like - * RADIUS_ACCT, but removes any pending interim RADIUS Accounting - * messages for the same STA before sending the new interim update. - */ - RADIUS_ACCT_INTERIM -} RadiusType; - -/** - * RadiusRxResult - RADIUS client RX handler result - */ -typedef enum { - /** - * RADIUS_RX_PROCESSED - Message processed - * - * This stops handler calls and frees the message. - */ - RADIUS_RX_PROCESSED, - - /** - * RADIUS_RX_QUEUED - Message has been queued - * - * This stops handler calls, but does not free the message; the handler - * that returned this is responsible for eventually freeing the - * message. - */ - RADIUS_RX_QUEUED, - - /** - * RADIUS_RX_UNKNOWN - Message is not for this handler - */ - RADIUS_RX_UNKNOWN, - - /** - * RADIUS_RX_INVALID_AUTHENTICATOR - Message has invalid Authenticator - */ - RADIUS_RX_INVALID_AUTHENTICATOR -} RadiusRxResult; - -struct radius_client_data; - -int radius_client_register(struct radius_client_data *radius, - RadiusType msg_type, - RadiusRxResult (*handler) - (struct radius_msg *msg, struct radius_msg *req, - const u8 *shared_secret, size_t shared_secret_len, - void *data), - void *data); -int radius_client_send(struct radius_client_data *radius, - struct radius_msg *msg, - RadiusType msg_type, const u8 *addr); -u8 radius_client_get_id(struct radius_client_data *radius); -void radius_client_flush(struct radius_client_data *radius, int only_auth); -struct radius_client_data * -radius_client_init(void *ctx, struct hostapd_radius_servers *conf); -void radius_client_deinit(struct radius_client_data *radius); -void radius_client_flush_auth(struct radius_client_data *radius, - const u8 *addr); -int radius_client_get_mib(struct radius_client_data *radius, char *buf, - size_t buflen); -void radius_client_reconfig(struct radius_client_data *radius, - struct hostapd_radius_servers *conf); - -#endif /* RADIUS_CLIENT_H */ diff --git a/contrib/hostapd/src/radius/radius_das.c b/contrib/hostapd/src/radius/radius_das.c deleted file mode 100644 index b2a27735b3..0000000000 --- a/contrib/hostapd/src/radius/radius_das.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * RADIUS Dynamic Authorization Server (DAS) (RFC 5176) - * Copyright (c) 2012-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "utils/common.h" -#include "utils/eloop.h" -#include "utils/ip_addr.h" -#include "radius.h" -#include "radius_das.h" - - -struct radius_das_data { - int sock; - u8 *shared_secret; - size_t shared_secret_len; - struct hostapd_ip_addr client_addr; - unsigned int time_window; - int require_event_timestamp; - void *ctx; - enum radius_das_res (*disconnect)(void *ctx, - struct radius_das_attrs *attr); -}; - - -static struct radius_msg * radius_das_disconnect(struct radius_das_data *das, - struct radius_msg *msg, - const char *abuf, - int from_port) -{ - struct radius_hdr *hdr; - struct radius_msg *reply; - u8 allowed[] = { - RADIUS_ATTR_USER_NAME, - RADIUS_ATTR_CALLING_STATION_ID, - RADIUS_ATTR_ACCT_SESSION_ID, - RADIUS_ATTR_EVENT_TIMESTAMP, - RADIUS_ATTR_MESSAGE_AUTHENTICATOR, - RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, - 0 - }; - int error = 405; - u8 attr; - enum radius_das_res res; - struct radius_das_attrs attrs; - u8 *buf; - size_t len; - char tmp[100]; - u8 sta_addr[ETH_ALEN]; - - hdr = radius_msg_get_hdr(msg); - - attr = radius_msg_find_unlisted_attr(msg, allowed); - if (attr) { - wpa_printf(MSG_INFO, "DAS: Unsupported attribute %u in " - "Disconnect-Request from %s:%d", attr, - abuf, from_port); - error = 401; - goto fail; - } - - os_memset(&attrs, 0, sizeof(attrs)); - - if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID, - &buf, &len, NULL) == 0) { - if (len >= sizeof(tmp)) - len = sizeof(tmp) - 1; - os_memcpy(tmp, buf, len); - tmp[len] = '\0'; - if (hwaddr_aton2(tmp, sta_addr) < 0) { - wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id " - "'%s' from %s:%d", tmp, abuf, from_port); - error = 407; - goto fail; - } - attrs.sta_addr = sta_addr; - } - - if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, - &buf, &len, NULL) == 0) { - attrs.user_name = buf; - attrs.user_name_len = len; - } - - if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID, - &buf, &len, NULL) == 0) { - attrs.acct_session_id = buf; - attrs.acct_session_id_len = len; - } - - if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, - &buf, &len, NULL) == 0) { - attrs.cui = buf; - attrs.cui_len = len; - } - - res = das->disconnect(das->ctx, &attrs); - switch (res) { - case RADIUS_DAS_NAS_MISMATCH: - wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d", - abuf, from_port); - error = 403; - break; - case RADIUS_DAS_SESSION_NOT_FOUND: - wpa_printf(MSG_INFO, "DAS: Session not found for request from " - "%s:%d", abuf, from_port); - error = 503; - break; - case RADIUS_DAS_SUCCESS: - error = 0; - break; - } - -fail: - reply = radius_msg_new(error ? RADIUS_CODE_DISCONNECT_NAK : - RADIUS_CODE_DISCONNECT_ACK, hdr->identifier); - if (reply == NULL) - return NULL; - - if (error) { - if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, - error)) { - radius_msg_free(reply); - return NULL; - } - } - - return reply; -} - - -static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct radius_das_data *das = eloop_ctx; - u8 buf[1500]; - union { - struct sockaddr_storage ss; - struct sockaddr_in sin; -#ifdef CONFIG_IPV6 - struct sockaddr_in6 sin6; -#endif /* CONFIG_IPV6 */ - } from; - char abuf[50]; - int from_port = 0; - socklen_t fromlen; - int len; - struct radius_msg *msg, *reply = NULL; - struct radius_hdr *hdr; - struct wpabuf *rbuf; - u32 val; - int res; - struct os_time now; - - fromlen = sizeof(from); - len = recvfrom(sock, buf, sizeof(buf), 0, - (struct sockaddr *) &from.ss, &fromlen); - if (len < 0) { - wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno)); - return; - } - - os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); - from_port = ntohs(from.sin.sin_port); - - wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d", - len, abuf, from_port); - if (das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) { - wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client"); - return; - } - - msg = radius_msg_parse(buf, len); - if (msg == NULL) { - wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet " - "from %s:%d failed", abuf, from_port); - return; - } - - if (wpa_debug_level <= MSG_MSGDUMP) - radius_msg_dump(msg); - - if (radius_msg_verify_das_req(msg, das->shared_secret, - das->shared_secret_len)) { - wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet " - "from %s:%d - drop", abuf, from_port); - goto fail; - } - - os_get_time(&now); - res = radius_msg_get_attr(msg, RADIUS_ATTR_EVENT_TIMESTAMP, - (u8 *) &val, 4); - if (res == 4) { - u32 timestamp = ntohl(val); - if ((unsigned int) abs(now.sec - timestamp) > - das->time_window) { - wpa_printf(MSG_DEBUG, "DAS: Unacceptable " - "Event-Timestamp (%u; local time %u) in " - "packet from %s:%d - drop", - timestamp, (unsigned int) now.sec, - abuf, from_port); - goto fail; - } - } else if (das->require_event_timestamp) { - wpa_printf(MSG_DEBUG, "DAS: Missing Event-Timestamp in packet " - "from %s:%d - drop", abuf, from_port); - goto fail; - } - - hdr = radius_msg_get_hdr(msg); - - switch (hdr->code) { - case RADIUS_CODE_DISCONNECT_REQUEST: - reply = radius_das_disconnect(das, msg, abuf, from_port); - break; - case RADIUS_CODE_COA_REQUEST: - /* TODO */ - reply = radius_msg_new(RADIUS_CODE_COA_NAK, - hdr->identifier); - if (reply == NULL) - break; - - /* Unsupported Service */ - if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, - 405)) { - radius_msg_free(reply); - reply = NULL; - break; - } - break; - default: - wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in " - "packet from %s:%d", - hdr->code, abuf, from_port); - } - - if (reply) { - wpa_printf(MSG_DEBUG, "DAS: Reply to %s:%d", abuf, from_port); - - if (!radius_msg_add_attr_int32(reply, - RADIUS_ATTR_EVENT_TIMESTAMP, - now.sec)) { - wpa_printf(MSG_DEBUG, "DAS: Failed to add " - "Event-Timestamp attribute"); - } - - if (radius_msg_finish_das_resp(reply, das->shared_secret, - das->shared_secret_len, hdr) < - 0) { - wpa_printf(MSG_DEBUG, "DAS: Failed to add " - "Message-Authenticator attribute"); - } - - if (wpa_debug_level <= MSG_MSGDUMP) - radius_msg_dump(reply); - - rbuf = radius_msg_get_buf(reply); - res = sendto(das->sock, wpabuf_head(rbuf), - wpabuf_len(rbuf), 0, - (struct sockaddr *) &from.ss, fromlen); - if (res < 0) { - wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s", - abuf, from_port, strerror(errno)); - } - } - -fail: - radius_msg_free(msg); - radius_msg_free(reply); -} - - -static int radius_das_open_socket(int port) -{ - int s; - struct sockaddr_in addr; - - s = socket(PF_INET, SOCK_DGRAM, 0); - if (s < 0) { - wpa_printf(MSG_INFO, "RADIUS DAS: socket: %s", strerror(errno)); - return -1; - } - - os_memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - wpa_printf(MSG_INFO, "RADIUS DAS: bind: %s", strerror(errno)); - close(s); - return -1; - } - - return s; -} - - -struct radius_das_data * -radius_das_init(struct radius_das_conf *conf) -{ - struct radius_das_data *das; - - if (conf->port == 0 || conf->shared_secret == NULL || - conf->client_addr == NULL) - return NULL; - - das = os_zalloc(sizeof(*das)); - if (das == NULL) - return NULL; - - das->time_window = conf->time_window; - das->require_event_timestamp = conf->require_event_timestamp; - das->ctx = conf->ctx; - das->disconnect = conf->disconnect; - - os_memcpy(&das->client_addr, conf->client_addr, - sizeof(das->client_addr)); - - das->shared_secret = os_malloc(conf->shared_secret_len); - if (das->shared_secret == NULL) { - radius_das_deinit(das); - return NULL; - } - os_memcpy(das->shared_secret, conf->shared_secret, - conf->shared_secret_len); - das->shared_secret_len = conf->shared_secret_len; - - das->sock = radius_das_open_socket(conf->port); - if (das->sock < 0) { - wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS " - "DAS"); - radius_das_deinit(das); - return NULL; - } - - if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL)) - { - radius_das_deinit(das); - return NULL; - } - - return das; -} - - -void radius_das_deinit(struct radius_das_data *das) -{ - if (das == NULL) - return; - - if (das->sock >= 0) { - eloop_unregister_read_sock(das->sock); - close(das->sock); - } - - os_free(das->shared_secret); - os_free(das); -} diff --git a/contrib/hostapd/src/radius/radius_das.h b/contrib/hostapd/src/radius/radius_das.h deleted file mode 100644 index 738b18b059..0000000000 --- a/contrib/hostapd/src/radius/radius_das.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * RADIUS Dynamic Authorization Server (DAS) - * Copyright (c) 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef RADIUS_DAS_H -#define RADIUS_DAS_H - -struct radius_das_data; - -enum radius_das_res { - RADIUS_DAS_SUCCESS, - RADIUS_DAS_NAS_MISMATCH, - RADIUS_DAS_SESSION_NOT_FOUND -}; - -struct radius_das_attrs { - const u8 *sta_addr; - const u8 *user_name; - size_t user_name_len; - const u8 *acct_session_id; - size_t acct_session_id_len; - const u8 *cui; - size_t cui_len; -}; - -struct radius_das_conf { - int port; - const u8 *shared_secret; - size_t shared_secret_len; - const struct hostapd_ip_addr *client_addr; - unsigned int time_window; - int require_event_timestamp; - void *ctx; - enum radius_das_res (*disconnect)(void *ctx, - struct radius_das_attrs *attr); -}; - -struct radius_das_data * -radius_das_init(struct radius_das_conf *conf); - -void radius_das_deinit(struct radius_das_data *data); - -#endif /* RADIUS_DAS_H */ diff --git a/contrib/hostapd/src/radius/radius_server.c b/contrib/hostapd/src/radius/radius_server.c deleted file mode 100644 index 1063d65ace..0000000000 --- a/contrib/hostapd/src/radius/radius_server.c +++ /dev/null @@ -1,1555 +0,0 @@ -/* - * RADIUS authentication server - * Copyright (c) 2005-2009, 2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "radius.h" -#include "eloop.h" -#include "eap_server/eap.h" -#include "radius_server.h" - -/** - * RADIUS_SESSION_TIMEOUT - Session timeout in seconds - */ -#define RADIUS_SESSION_TIMEOUT 60 - -/** - * RADIUS_MAX_SESSION - Maximum number of active sessions - */ -#define RADIUS_MAX_SESSION 100 - -/** - * RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages - */ -#define RADIUS_MAX_MSG_LEN 3000 - -static struct eapol_callbacks radius_server_eapol_cb; - -struct radius_client; -struct radius_server_data; - -/** - * struct radius_server_counters - RADIUS server statistics counters - */ -struct radius_server_counters { - u32 access_requests; - u32 invalid_requests; - u32 dup_access_requests; - u32 access_accepts; - u32 access_rejects; - u32 access_challenges; - u32 malformed_access_requests; - u32 bad_authenticators; - u32 packets_dropped; - u32 unknown_types; -}; - -/** - * struct radius_session - Internal RADIUS server data for a session - */ -struct radius_session { - struct radius_session *next; - struct radius_client *client; - struct radius_server_data *server; - unsigned int sess_id; - struct eap_sm *eap; - struct eap_eapol_interface *eap_if; - - struct radius_msg *last_msg; - char *last_from_addr; - int last_from_port; - struct sockaddr_storage last_from; - socklen_t last_fromlen; - u8 last_identifier; - struct radius_msg *last_reply; - u8 last_authenticator[16]; -}; - -/** - * struct radius_client - Internal RADIUS server data for a client - */ -struct radius_client { - struct radius_client *next; - struct in_addr addr; - struct in_addr mask; -#ifdef CONFIG_IPV6 - struct in6_addr addr6; - struct in6_addr mask6; -#endif /* CONFIG_IPV6 */ - char *shared_secret; - int shared_secret_len; - struct radius_session *sessions; - struct radius_server_counters counters; -}; - -/** - * struct radius_server_data - Internal RADIUS server data - */ -struct radius_server_data { - /** - * auth_sock - Socket for RADIUS authentication messages - */ - int auth_sock; - - /** - * clients - List of authorized RADIUS clients - */ - struct radius_client *clients; - - /** - * next_sess_id - Next session identifier - */ - unsigned int next_sess_id; - - /** - * conf_ctx - Context pointer for callbacks - * - * This is used as the ctx argument in get_eap_user() calls. - */ - void *conf_ctx; - - /** - * num_sess - Number of active sessions - */ - int num_sess; - - /** - * eap_sim_db_priv - EAP-SIM/AKA database context - * - * This is passed to the EAP-SIM/AKA server implementation as a - * callback context. - */ - void *eap_sim_db_priv; - - /** - * ssl_ctx - TLS context - * - * This is passed to the EAP server implementation as a callback - * context for TLS operations. - */ - void *ssl_ctx; - - /** - * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST - * - * This parameter is used to set a key for EAP-FAST to encrypt the - * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If - * set, must point to a 16-octet key. - */ - u8 *pac_opaque_encr_key; - - /** - * eap_fast_a_id - EAP-FAST authority identity (A-ID) - * - * If EAP-FAST is not used, this can be set to %NULL. In theory, this - * is a variable length field, but due to some existing implementations - * requiring A-ID to be 16 octets in length, it is recommended to use - * that length for the field to provide interoperability with deployed - * peer implementations. - */ - u8 *eap_fast_a_id; - - /** - * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets - */ - size_t eap_fast_a_id_len; - - /** - * eap_fast_a_id_info - EAP-FAST authority identifier information - * - * This A-ID-Info contains a user-friendly name for the A-ID. For - * example, this could be the enterprise and server names in - * human-readable format. This field is encoded as UTF-8. If EAP-FAST - * is not used, this can be set to %NULL. - */ - char *eap_fast_a_id_info; - - /** - * eap_fast_prov - EAP-FAST provisioning modes - * - * 0 = provisioning disabled, 1 = only anonymous provisioning allowed, - * 2 = only authenticated provisioning allowed, 3 = both provisioning - * modes allowed. - */ - int eap_fast_prov; - - /** - * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds - * - * This is the hard limit on how long a provisioned PAC-Key can be - * used. - */ - int pac_key_lifetime; - - /** - * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds - * - * This is a soft limit on the PAC-Key. The server will automatically - * generate a new PAC-Key when this number of seconds (or fewer) of the - * lifetime remains. - */ - int pac_key_refresh_time; - - /** - * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication - * - * This controls whether the protected success/failure indication - * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA. - */ - int eap_sim_aka_result_ind; - - /** - * tnc - Trusted Network Connect (TNC) - * - * This controls whether TNC is enabled and will be required before the - * peer is allowed to connect. Note: This is only used with EAP-TTLS - * and EAP-FAST. If any other EAP method is enabled, the peer will be - * allowed to connect without TNC. - */ - int tnc; - - /** - * pwd_group - The D-H group assigned for EAP-pwd - * - * If EAP-pwd is not used it can be set to zero. - */ - u16 pwd_group; - - /** - * server_id - Server identity - */ - const char *server_id; - - /** - * wps - Wi-Fi Protected Setup context - * - * If WPS is used with an external RADIUS server (which is quite - * unlikely configuration), this is used to provide a pointer to WPS - * context data. Normally, this can be set to %NULL. - */ - struct wps_context *wps; - - /** - * ipv6 - Whether to enable IPv6 support in the RADIUS server - */ - int ipv6; - - /** - * start_time - Timestamp of server start - */ - struct os_reltime start_time; - - /** - * counters - Statistics counters for server operations - * - * These counters are the sum over all clients. - */ - struct radius_server_counters counters; - - /** - * get_eap_user - Callback for fetching EAP user information - * @ctx: Context data from conf_ctx - * @identity: User identity - * @identity_len: identity buffer length in octets - * @phase2: Whether this is for Phase 2 identity - * @user: Data structure for filling in the user information - * Returns: 0 on success, -1 on failure - * - * This is used to fetch information from user database. The callback - * will fill in information about allowed EAP methods and the user - * password. The password field will be an allocated copy of the - * password data and RADIUS server will free it after use. - */ - int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, - int phase2, struct eap_user *user); - - /** - * eap_req_id_text - Optional data for EAP-Request/Identity - * - * This can be used to configure an optional, displayable message that - * will be sent in EAP-Request/Identity. This string can contain an - * ASCII-0 character (nul) to separate network infromation per RFC - * 4284. The actual string length is explicit provided in - * eap_req_id_text_len since nul character will not be used as a string - * terminator. - */ - char *eap_req_id_text; - - /** - * eap_req_id_text_len - Length of eap_req_id_text buffer in octets - */ - size_t eap_req_id_text_len; - - /* - * msg_ctx - Context data for wpa_msg() calls - */ - void *msg_ctx; - -#ifdef CONFIG_RADIUS_TEST - char *dump_msk_file; -#endif /* CONFIG_RADIUS_TEST */ -}; - - -#define RADIUS_DEBUG(args...) \ -wpa_printf(MSG_DEBUG, "RADIUS SRV: " args) -#define RADIUS_ERROR(args...) \ -wpa_printf(MSG_ERROR, "RADIUS SRV: " args) -#define RADIUS_DUMP(args...) \ -wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args) -#define RADIUS_DUMP_ASCII(args...) \ -wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args) - - -static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx); -static void radius_server_session_remove_timeout(void *eloop_ctx, - void *timeout_ctx); - - -static struct radius_client * -radius_server_get_client(struct radius_server_data *data, struct in_addr *addr, - int ipv6) -{ - struct radius_client *client = data->clients; - - while (client) { -#ifdef CONFIG_IPV6 - if (ipv6) { - struct in6_addr *addr6; - int i; - - addr6 = (struct in6_addr *) addr; - for (i = 0; i < 16; i++) { - if ((addr6->s6_addr[i] & - client->mask6.s6_addr[i]) != - (client->addr6.s6_addr[i] & - client->mask6.s6_addr[i])) { - i = 17; - break; - } - } - if (i == 16) { - break; - } - } -#endif /* CONFIG_IPV6 */ - if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) == - (addr->s_addr & client->mask.s_addr)) { - break; - } - - client = client->next; - } - - return client; -} - - -static struct radius_session * -radius_server_get_session(struct radius_client *client, unsigned int sess_id) -{ - struct radius_session *sess = client->sessions; - - while (sess) { - if (sess->sess_id == sess_id) { - break; - } - sess = sess->next; - } - - return sess; -} - - -static void radius_server_session_free(struct radius_server_data *data, - struct radius_session *sess) -{ - eloop_cancel_timeout(radius_server_session_timeout, data, sess); - eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess); - eap_server_sm_deinit(sess->eap); - radius_msg_free(sess->last_msg); - os_free(sess->last_from_addr); - radius_msg_free(sess->last_reply); - os_free(sess); - data->num_sess--; -} - - -static void radius_server_session_remove(struct radius_server_data *data, - struct radius_session *sess) -{ - struct radius_client *client = sess->client; - struct radius_session *session, *prev; - - eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess); - - prev = NULL; - session = client->sessions; - while (session) { - if (session == sess) { - if (prev == NULL) { - client->sessions = sess->next; - } else { - prev->next = sess->next; - } - radius_server_session_free(data, sess); - break; - } - prev = session; - session = session->next; - } -} - - -static void radius_server_session_remove_timeout(void *eloop_ctx, - void *timeout_ctx) -{ - struct radius_server_data *data = eloop_ctx; - struct radius_session *sess = timeout_ctx; - RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id); - radius_server_session_remove(data, sess); -} - - -static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct radius_server_data *data = eloop_ctx; - struct radius_session *sess = timeout_ctx; - - RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id); - radius_server_session_remove(data, sess); -} - - -static struct radius_session * -radius_server_new_session(struct radius_server_data *data, - struct radius_client *client) -{ - struct radius_session *sess; - - if (data->num_sess >= RADIUS_MAX_SESSION) { - RADIUS_DEBUG("Maximum number of existing session - no room " - "for a new session"); - return NULL; - } - - sess = os_zalloc(sizeof(*sess)); - if (sess == NULL) - return NULL; - - sess->server = data; - sess->client = client; - sess->sess_id = data->next_sess_id++; - sess->next = client->sessions; - client->sessions = sess; - eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0, - radius_server_session_timeout, data, sess); - data->num_sess++; - return sess; -} - - -static struct radius_session * -radius_server_get_new_session(struct radius_server_data *data, - struct radius_client *client, - struct radius_msg *msg) -{ - u8 *user; - size_t user_len; - int res; - struct radius_session *sess; - struct eap_config eap_conf; - - RADIUS_DEBUG("Creating a new session"); - - user = os_malloc(256); - if (user == NULL) { - return NULL; - } - res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256); - if (res < 0 || res > 256) { - RADIUS_DEBUG("Could not get User-Name"); - os_free(user); - return NULL; - } - user_len = res; - RADIUS_DUMP_ASCII("User-Name", user, user_len); - - res = data->get_eap_user(data->conf_ctx, user, user_len, 0, NULL); - os_free(user); - - if (res == 0) { - RADIUS_DEBUG("Matching user entry found"); - sess = radius_server_new_session(data, client); - if (sess == NULL) { - RADIUS_DEBUG("Failed to create a new session"); - return NULL; - } - } else { - RADIUS_DEBUG("User-Name not found from user database"); - return NULL; - } - - os_memset(&eap_conf, 0, sizeof(eap_conf)); - eap_conf.ssl_ctx = data->ssl_ctx; - eap_conf.msg_ctx = data->msg_ctx; - eap_conf.eap_sim_db_priv = data->eap_sim_db_priv; - eap_conf.backend_auth = TRUE; - eap_conf.eap_server = 1; - eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key; - eap_conf.eap_fast_a_id = data->eap_fast_a_id; - eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len; - eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info; - eap_conf.eap_fast_prov = data->eap_fast_prov; - eap_conf.pac_key_lifetime = data->pac_key_lifetime; - eap_conf.pac_key_refresh_time = data->pac_key_refresh_time; - eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind; - eap_conf.tnc = data->tnc; - eap_conf.wps = data->wps; - eap_conf.pwd_group = data->pwd_group; - eap_conf.server_id = (const u8 *) data->server_id; - eap_conf.server_id_len = os_strlen(data->server_id); - sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb, - &eap_conf); - if (sess->eap == NULL) { - RADIUS_DEBUG("Failed to initialize EAP state machine for the " - "new session"); - radius_server_session_free(data, sess); - return NULL; - } - sess->eap_if = eap_get_interface(sess->eap); - sess->eap_if->eapRestart = TRUE; - sess->eap_if->portEnabled = TRUE; - - RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id); - - return sess; -} - - -static struct radius_msg * -radius_server_encapsulate_eap(struct radius_server_data *data, - struct radius_client *client, - struct radius_session *sess, - struct radius_msg *request) -{ - struct radius_msg *msg; - int code; - unsigned int sess_id; - struct radius_hdr *hdr = radius_msg_get_hdr(request); - - if (sess->eap_if->eapFail) { - sess->eap_if->eapFail = FALSE; - code = RADIUS_CODE_ACCESS_REJECT; - } else if (sess->eap_if->eapSuccess) { - sess->eap_if->eapSuccess = FALSE; - code = RADIUS_CODE_ACCESS_ACCEPT; - } else { - sess->eap_if->eapReq = FALSE; - code = RADIUS_CODE_ACCESS_CHALLENGE; - } - - msg = radius_msg_new(code, hdr->identifier); - if (msg == NULL) { - RADIUS_DEBUG("Failed to allocate reply message"); - return NULL; - } - - sess_id = htonl(sess->sess_id); - if (code == RADIUS_CODE_ACCESS_CHALLENGE && - !radius_msg_add_attr(msg, RADIUS_ATTR_STATE, - (u8 *) &sess_id, sizeof(sess_id))) { - RADIUS_DEBUG("Failed to add State attribute"); - } - - if (sess->eap_if->eapReqData && - !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData), - wpabuf_len(sess->eap_if->eapReqData))) { - RADIUS_DEBUG("Failed to add EAP-Message attribute"); - } - - 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 { - len = sess->eap_if->eapKeyDataLen / 2; - } - if (!radius_msg_add_mppe_keys(msg, hdr->authenticator, - (u8 *) client->shared_secret, - client->shared_secret_len, - sess->eap_if->eapKeyData + len, - len, sess->eap_if->eapKeyData, - len)) { - RADIUS_DEBUG("Failed to add MPPE key attributes"); - } - } - - if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { - RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); - radius_msg_free(msg); - return NULL; - } - - if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, - client->shared_secret_len, - hdr->authenticator) < 0) { - RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); - } - - return msg; -} - - -static int radius_server_reject(struct radius_server_data *data, - struct radius_client *client, - struct radius_msg *request, - struct sockaddr *from, socklen_t fromlen, - const char *from_addr, int from_port) -{ - struct radius_msg *msg; - int ret = 0; - struct eap_hdr eapfail; - struct wpabuf *buf; - struct radius_hdr *hdr = radius_msg_get_hdr(request); - - RADIUS_DEBUG("Reject invalid request from %s:%d", - from_addr, from_port); - - msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT, hdr->identifier); - if (msg == NULL) { - return -1; - } - - os_memset(&eapfail, 0, sizeof(eapfail)); - eapfail.code = EAP_CODE_FAILURE; - eapfail.identifier = 0; - eapfail.length = host_to_be16(sizeof(eapfail)); - - if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) { - RADIUS_DEBUG("Failed to add EAP-Message attribute"); - } - - if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { - RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); - radius_msg_free(msg); - return -1; - } - - if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, - client->shared_secret_len, - hdr->authenticator) < - 0) { - RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); - } - - if (wpa_debug_level <= MSG_MSGDUMP) { - radius_msg_dump(msg); - } - - data->counters.access_rejects++; - client->counters.access_rejects++; - buf = radius_msg_get_buf(msg); - if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0, - (struct sockaddr *) from, sizeof(*from)) < 0) { - wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", strerror(errno)); - ret = -1; - } - - radius_msg_free(msg); - - return ret; -} - - -static int radius_server_request(struct radius_server_data *data, - struct radius_msg *msg, - struct sockaddr *from, socklen_t fromlen, - struct radius_client *client, - const char *from_addr, int from_port, - struct radius_session *force_sess) -{ - struct wpabuf *eap = NULL; - int res, state_included = 0; - u8 statebuf[4]; - unsigned int state; - struct radius_session *sess; - struct radius_msg *reply; - int is_complete = 0; - - if (force_sess) - sess = force_sess; - else { - res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf, - sizeof(statebuf)); - state_included = res >= 0; - if (res == sizeof(statebuf)) { - state = WPA_GET_BE32(statebuf); - sess = radius_server_get_session(client, state); - } else { - sess = NULL; - } - } - - if (sess) { - RADIUS_DEBUG("Request for session 0x%x", sess->sess_id); - } else if (state_included) { - RADIUS_DEBUG("State attribute included but no session found"); - radius_server_reject(data, client, msg, from, fromlen, - from_addr, from_port); - return -1; - } else { - sess = radius_server_get_new_session(data, client, msg); - if (sess == NULL) { - RADIUS_DEBUG("Could not create a new session"); - radius_server_reject(data, client, msg, from, fromlen, - from_addr, from_port); - return -1; - } - } - - if (sess->last_from_port == from_port && - sess->last_identifier == radius_msg_get_hdr(msg)->identifier && - os_memcmp(sess->last_authenticator, - radius_msg_get_hdr(msg)->authenticator, 16) == 0) { - RADIUS_DEBUG("Duplicate message from %s", from_addr); - data->counters.dup_access_requests++; - client->counters.dup_access_requests++; - - if (sess->last_reply) { - struct wpabuf *buf; - buf = radius_msg_get_buf(sess->last_reply); - res = sendto(data->auth_sock, wpabuf_head(buf), - wpabuf_len(buf), 0, - (struct sockaddr *) from, fromlen); - if (res < 0) { - wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", - strerror(errno)); - } - return 0; - } - - RADIUS_DEBUG("No previous reply available for duplicate " - "message"); - return -1; - } - - eap = radius_msg_get_eap(msg); - if (eap == NULL) { - RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s", - from_addr); - data->counters.packets_dropped++; - client->counters.packets_dropped++; - return -1; - } - - RADIUS_DUMP("Received EAP data", wpabuf_head(eap), wpabuf_len(eap)); - - /* FIX: if Code is Request, Success, or Failure, send Access-Reject; - * RFC3579 Sect. 2.6.2. - * Include EAP-Response/Nak with no preferred method if - * code == request. - * If code is not 1-4, discard the packet silently. - * Or is this already done by the EAP state machine? */ - - wpabuf_free(sess->eap_if->eapRespData); - sess->eap_if->eapRespData = eap; - sess->eap_if->eapResp = TRUE; - eap_server_sm_step(sess->eap); - - if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess || - sess->eap_if->eapFail) && sess->eap_if->eapReqData) { - RADIUS_DUMP("EAP data from the state machine", - wpabuf_head(sess->eap_if->eapReqData), - wpabuf_len(sess->eap_if->eapReqData)); - } else if (sess->eap_if->eapFail) { - RADIUS_DEBUG("No EAP data from the state machine, but eapFail " - "set"); - } else if (eap_sm_method_pending(sess->eap)) { - radius_msg_free(sess->last_msg); - sess->last_msg = msg; - sess->last_from_port = from_port; - os_free(sess->last_from_addr); - sess->last_from_addr = os_strdup(from_addr); - sess->last_fromlen = fromlen; - os_memcpy(&sess->last_from, from, fromlen); - return -2; - } else { - RADIUS_DEBUG("No EAP data from the state machine - ignore this" - " Access-Request silently (assuming it was a " - "duplicate)"); - data->counters.packets_dropped++; - client->counters.packets_dropped++; - return -1; - } - - if (sess->eap_if->eapSuccess || sess->eap_if->eapFail) - is_complete = 1; - - reply = radius_server_encapsulate_eap(data, client, sess, msg); - - if (reply) { - struct wpabuf *buf; - struct radius_hdr *hdr; - - RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port); - if (wpa_debug_level <= MSG_MSGDUMP) { - radius_msg_dump(reply); - } - - switch (radius_msg_get_hdr(reply)->code) { - case RADIUS_CODE_ACCESS_ACCEPT: - data->counters.access_accepts++; - client->counters.access_accepts++; - break; - case RADIUS_CODE_ACCESS_REJECT: - data->counters.access_rejects++; - client->counters.access_rejects++; - break; - case RADIUS_CODE_ACCESS_CHALLENGE: - data->counters.access_challenges++; - client->counters.access_challenges++; - break; - } - buf = radius_msg_get_buf(reply); - res = sendto(data->auth_sock, wpabuf_head(buf), - wpabuf_len(buf), 0, - (struct sockaddr *) from, fromlen); - if (res < 0) { - wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", - strerror(errno)); - } - radius_msg_free(sess->last_reply); - sess->last_reply = reply; - sess->last_from_port = from_port; - hdr = radius_msg_get_hdr(msg); - sess->last_identifier = hdr->identifier; - os_memcpy(sess->last_authenticator, hdr->authenticator, 16); - } else { - data->counters.packets_dropped++; - client->counters.packets_dropped++; - } - - if (is_complete) { - RADIUS_DEBUG("Removing completed session 0x%x after timeout", - sess->sess_id); - eloop_cancel_timeout(radius_server_session_remove_timeout, - data, sess); - eloop_register_timeout(10, 0, - radius_server_session_remove_timeout, - data, sess); - } - - return 0; -} - - -static void radius_server_receive_auth(int sock, void *eloop_ctx, - void *sock_ctx) -{ - struct radius_server_data *data = eloop_ctx; - u8 *buf = NULL; - union { - struct sockaddr_storage ss; - struct sockaddr_in sin; -#ifdef CONFIG_IPV6 - struct sockaddr_in6 sin6; -#endif /* CONFIG_IPV6 */ - } from; - socklen_t fromlen; - int len; - struct radius_client *client = NULL; - struct radius_msg *msg = NULL; - char abuf[50]; - int from_port = 0; - - buf = os_malloc(RADIUS_MAX_MSG_LEN); - if (buf == NULL) { - goto fail; - } - - fromlen = sizeof(from); - len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0, - (struct sockaddr *) &from.ss, &fromlen); - if (len < 0) { - wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s", - strerror(errno)); - goto fail; - } - -#ifdef CONFIG_IPV6 - if (data->ipv6) { - if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf, - sizeof(abuf)) == NULL) - abuf[0] = '\0'; - from_port = ntohs(from.sin6.sin6_port); - RADIUS_DEBUG("Received %d bytes from %s:%d", - len, abuf, from_port); - - client = radius_server_get_client(data, - (struct in_addr *) - &from.sin6.sin6_addr, 1); - } -#endif /* CONFIG_IPV6 */ - - if (!data->ipv6) { - os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); - from_port = ntohs(from.sin.sin_port); - RADIUS_DEBUG("Received %d bytes from %s:%d", - len, abuf, from_port); - - client = radius_server_get_client(data, &from.sin.sin_addr, 0); - } - - RADIUS_DUMP("Received data", buf, len); - - if (client == NULL) { - RADIUS_DEBUG("Unknown client %s - packet ignored", abuf); - data->counters.invalid_requests++; - goto fail; - } - - msg = radius_msg_parse(buf, len); - if (msg == NULL) { - RADIUS_DEBUG("Parsing incoming RADIUS frame failed"); - data->counters.malformed_access_requests++; - client->counters.malformed_access_requests++; - goto fail; - } - - os_free(buf); - buf = NULL; - - if (wpa_debug_level <= MSG_MSGDUMP) { - radius_msg_dump(msg); - } - - if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) { - RADIUS_DEBUG("Unexpected RADIUS code %d", - radius_msg_get_hdr(msg)->code); - data->counters.unknown_types++; - client->counters.unknown_types++; - goto fail; - } - - data->counters.access_requests++; - client->counters.access_requests++; - - if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret, - client->shared_secret_len, NULL)) { - RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf); - data->counters.bad_authenticators++; - client->counters.bad_authenticators++; - goto fail; - } - - if (radius_server_request(data, msg, (struct sockaddr *) &from, - fromlen, client, abuf, from_port, NULL) == - -2) - return; /* msg was stored with the session */ - -fail: - radius_msg_free(msg); - os_free(buf); -} - - -static int radius_server_disable_pmtu_discovery(int s) -{ - int r = -1; -#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) - /* Turn off Path MTU discovery on IPv4/UDP sockets. */ - int action = IP_PMTUDISC_DONT; - r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, - sizeof(action)); - if (r == -1) - wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: " - "%s", strerror(errno)); -#endif - return r; -} - - -static int radius_server_open_socket(int port) -{ - int s; - struct sockaddr_in addr; - - s = socket(PF_INET, SOCK_DGRAM, 0); - if (s < 0) { - wpa_printf(MSG_INFO, "RADIUS: socket: %s", strerror(errno)); - return -1; - } - - radius_server_disable_pmtu_discovery(s); - - os_memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno)); - close(s); - return -1; - } - - return s; -} - - -#ifdef CONFIG_IPV6 -static int radius_server_open_socket6(int port) -{ - int s; - struct sockaddr_in6 addr; - - s = socket(PF_INET6, SOCK_DGRAM, 0); - if (s < 0) { - wpa_printf(MSG_INFO, "RADIUS: socket[IPv6]: %s", - strerror(errno)); - return -1; - } - - os_memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any)); - addr.sin6_port = htons(port); - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno)); - close(s); - return -1; - } - - return s; -} -#endif /* CONFIG_IPV6 */ - - -static void radius_server_free_sessions(struct radius_server_data *data, - struct radius_session *sessions) -{ - struct radius_session *session, *prev; - - session = sessions; - while (session) { - prev = session; - session = session->next; - radius_server_session_free(data, prev); - } -} - - -static void radius_server_free_clients(struct radius_server_data *data, - struct radius_client *clients) -{ - struct radius_client *client, *prev; - - client = clients; - while (client) { - prev = client; - client = client->next; - - radius_server_free_sessions(data, prev->sessions); - os_free(prev->shared_secret); - os_free(prev); - } -} - - -static struct radius_client * -radius_server_read_clients(const char *client_file, int ipv6) -{ - FILE *f; - const int buf_size = 1024; - char *buf, *pos; - struct radius_client *clients, *tail, *entry; - int line = 0, mask, failed = 0, i; - struct in_addr addr; -#ifdef CONFIG_IPV6 - struct in6_addr addr6; -#endif /* CONFIG_IPV6 */ - unsigned int val; - - f = fopen(client_file, "r"); - if (f == NULL) { - RADIUS_ERROR("Could not open client file '%s'", client_file); - return NULL; - } - - buf = os_malloc(buf_size); - if (buf == NULL) { - fclose(f); - return NULL; - } - - clients = tail = NULL; - while (fgets(buf, buf_size, f)) { - /* Configuration file format: - * 192.168.1.0/24 secret - * 192.168.1.2 secret - * fe80::211:22ff:fe33:4455/64 secretipv6 - */ - line++; - buf[buf_size - 1] = '\0'; - pos = buf; - while (*pos != '\0' && *pos != '\n') - pos++; - if (*pos == '\n') - *pos = '\0'; - if (*buf == '\0' || *buf == '#') - continue; - - pos = buf; - while ((*pos >= '0' && *pos <= '9') || *pos == '.' || - (*pos >= 'a' && *pos <= 'f') || *pos == ':' || - (*pos >= 'A' && *pos <= 'F')) { - pos++; - } - - if (*pos == '\0') { - failed = 1; - break; - } - - if (*pos == '/') { - char *end; - *pos++ = '\0'; - mask = strtol(pos, &end, 10); - if ((pos == end) || - (mask < 0 || mask > (ipv6 ? 128 : 32))) { - failed = 1; - break; - } - pos = end; - } else { - mask = ipv6 ? 128 : 32; - *pos++ = '\0'; - } - - if (!ipv6 && inet_aton(buf, &addr) == 0) { - failed = 1; - break; - } -#ifdef CONFIG_IPV6 - if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) { - if (inet_pton(AF_INET, buf, &addr) <= 0) { - failed = 1; - break; - } - /* Convert IPv4 address to IPv6 */ - if (mask <= 32) - mask += (128 - 32); - os_memset(addr6.s6_addr, 0, 10); - addr6.s6_addr[10] = 0xff; - addr6.s6_addr[11] = 0xff; - os_memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr, - 4); - } -#endif /* CONFIG_IPV6 */ - - while (*pos == ' ' || *pos == '\t') { - pos++; - } - - if (*pos == '\0') { - failed = 1; - break; - } - - entry = os_zalloc(sizeof(*entry)); - if (entry == NULL) { - failed = 1; - break; - } - entry->shared_secret = os_strdup(pos); - if (entry->shared_secret == NULL) { - failed = 1; - os_free(entry); - break; - } - entry->shared_secret_len = os_strlen(entry->shared_secret); - entry->addr.s_addr = addr.s_addr; - if (!ipv6) { - val = 0; - for (i = 0; i < mask; i++) - val |= 1 << (31 - i); - entry->mask.s_addr = htonl(val); - } -#ifdef CONFIG_IPV6 - if (ipv6) { - int offset = mask / 8; - - os_memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16); - os_memset(entry->mask6.s6_addr, 0xff, offset); - val = 0; - for (i = 0; i < (mask % 8); i++) - val |= 1 << (7 - i); - if (offset < 16) - entry->mask6.s6_addr[offset] = val; - } -#endif /* CONFIG_IPV6 */ - - if (tail == NULL) { - clients = tail = entry; - } else { - tail->next = entry; - tail = entry; - } - } - - if (failed) { - RADIUS_ERROR("Invalid line %d in '%s'", line, client_file); - radius_server_free_clients(NULL, clients); - clients = NULL; - } - - os_free(buf); - fclose(f); - - return clients; -} - - -/** - * radius_server_init - Initialize RADIUS server - * @conf: Configuration for the RADIUS server - * Returns: Pointer to private RADIUS server context or %NULL on failure - * - * This initializes a RADIUS server instance and returns a context pointer that - * will be used in other calls to the RADIUS server module. The server can be - * deinitialize by calling radius_server_deinit(). - */ -struct radius_server_data * -radius_server_init(struct radius_server_conf *conf) -{ - struct radius_server_data *data; - -#ifndef CONFIG_IPV6 - if (conf->ipv6) { - wpa_printf(MSG_ERROR, "RADIUS server compiled without IPv6 support"); - return NULL; - } -#endif /* CONFIG_IPV6 */ - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - - os_get_reltime(&data->start_time); - data->conf_ctx = conf->conf_ctx; - data->eap_sim_db_priv = conf->eap_sim_db_priv; - data->ssl_ctx = conf->ssl_ctx; - data->msg_ctx = conf->msg_ctx; - data->ipv6 = conf->ipv6; - if (conf->pac_opaque_encr_key) { - data->pac_opaque_encr_key = os_malloc(16); - os_memcpy(data->pac_opaque_encr_key, conf->pac_opaque_encr_key, - 16); - } - if (conf->eap_fast_a_id) { - data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len); - if (data->eap_fast_a_id) { - os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id, - conf->eap_fast_a_id_len); - data->eap_fast_a_id_len = conf->eap_fast_a_id_len; - } - } - if (conf->eap_fast_a_id_info) - data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info); - data->eap_fast_prov = conf->eap_fast_prov; - data->pac_key_lifetime = conf->pac_key_lifetime; - data->pac_key_refresh_time = conf->pac_key_refresh_time; - data->get_eap_user = conf->get_eap_user; - data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; - data->tnc = conf->tnc; - data->wps = conf->wps; - data->pwd_group = conf->pwd_group; - data->server_id = conf->server_id; - if (conf->eap_req_id_text) { - data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len); - if (data->eap_req_id_text) { - os_memcpy(data->eap_req_id_text, conf->eap_req_id_text, - conf->eap_req_id_text_len); - data->eap_req_id_text_len = conf->eap_req_id_text_len; - } - } - -#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) { - wpa_printf(MSG_ERROR, "No RADIUS clients configured"); - radius_server_deinit(data); - return NULL; - } - -#ifdef CONFIG_IPV6 - if (conf->ipv6) - data->auth_sock = radius_server_open_socket6(conf->auth_port); - else -#endif /* CONFIG_IPV6 */ - data->auth_sock = radius_server_open_socket(conf->auth_port); - if (data->auth_sock < 0) { - wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS authentication server"); - radius_server_deinit(data); - return NULL; - } - if (eloop_register_read_sock(data->auth_sock, - radius_server_receive_auth, - data, NULL)) { - radius_server_deinit(data); - return NULL; - } - - return data; -} - - -/** - * radius_server_deinit - Deinitialize RADIUS server - * @data: RADIUS server context from radius_server_init() - */ -void radius_server_deinit(struct radius_server_data *data) -{ - if (data == NULL) - return; - - if (data->auth_sock >= 0) { - eloop_unregister_read_sock(data->auth_sock); - close(data->auth_sock); - } - - radius_server_free_clients(data, data->clients); - - os_free(data->pac_opaque_encr_key); - 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); -} - - -/** - * radius_server_get_mib - Get RADIUS server MIB information - * @data: RADIUS server context from radius_server_init() - * @buf: Buffer for returning the MIB data in text format - * @buflen: buf length in octets - * Returns: Number of octets written into buf - */ -int radius_server_get_mib(struct radius_server_data *data, char *buf, - size_t buflen) -{ - int ret, uptime; - unsigned int idx; - char *end, *pos; - struct os_reltime now; - struct radius_client *cli; - - /* RFC 2619 - RADIUS Authentication Server MIB */ - - if (data == NULL || buflen == 0) - return 0; - - pos = buf; - end = buf + buflen; - - os_get_reltime(&now); - uptime = (now.sec - data->start_time.sec) * 100 + - ((now.usec - data->start_time.usec) / 10000) % 100; - ret = os_snprintf(pos, end - pos, - "RADIUS-AUTH-SERVER-MIB\n" - "radiusAuthServIdent=hostapd\n" - "radiusAuthServUpTime=%d\n" - "radiusAuthServResetTime=0\n" - "radiusAuthServConfigReset=4\n", - uptime); - if (ret < 0 || ret >= end - pos) { - *pos = '\0'; - return pos - buf; - } - pos += ret; - - ret = os_snprintf(pos, end - pos, - "radiusAuthServTotalAccessRequests=%u\n" - "radiusAuthServTotalInvalidRequests=%u\n" - "radiusAuthServTotalDupAccessRequests=%u\n" - "radiusAuthServTotalAccessAccepts=%u\n" - "radiusAuthServTotalAccessRejects=%u\n" - "radiusAuthServTotalAccessChallenges=%u\n" - "radiusAuthServTotalMalformedAccessRequests=%u\n" - "radiusAuthServTotalBadAuthenticators=%u\n" - "radiusAuthServTotalPacketsDropped=%u\n" - "radiusAuthServTotalUnknownTypes=%u\n", - data->counters.access_requests, - data->counters.invalid_requests, - data->counters.dup_access_requests, - data->counters.access_accepts, - data->counters.access_rejects, - data->counters.access_challenges, - data->counters.malformed_access_requests, - data->counters.bad_authenticators, - data->counters.packets_dropped, - data->counters.unknown_types); - if (ret < 0 || ret >= end - pos) { - *pos = '\0'; - return pos - buf; - } - pos += ret; - - for (cli = data->clients, idx = 0; cli; cli = cli->next, idx++) { - char abuf[50], mbuf[50]; -#ifdef CONFIG_IPV6 - if (data->ipv6) { - if (inet_ntop(AF_INET6, &cli->addr6, abuf, - sizeof(abuf)) == NULL) - abuf[0] = '\0'; - if (inet_ntop(AF_INET6, &cli->mask6, abuf, - sizeof(mbuf)) == NULL) - mbuf[0] = '\0'; - } -#endif /* CONFIG_IPV6 */ - if (!data->ipv6) { - os_strlcpy(abuf, inet_ntoa(cli->addr), sizeof(abuf)); - os_strlcpy(mbuf, inet_ntoa(cli->mask), sizeof(mbuf)); - } - - ret = os_snprintf(pos, end - pos, - "radiusAuthClientIndex=%u\n" - "radiusAuthClientAddress=%s/%s\n" - "radiusAuthServAccessRequests=%u\n" - "radiusAuthServDupAccessRequests=%u\n" - "radiusAuthServAccessAccepts=%u\n" - "radiusAuthServAccessRejects=%u\n" - "radiusAuthServAccessChallenges=%u\n" - "radiusAuthServMalformedAccessRequests=%u\n" - "radiusAuthServBadAuthenticators=%u\n" - "radiusAuthServPacketsDropped=%u\n" - "radiusAuthServUnknownTypes=%u\n", - idx, - abuf, mbuf, - cli->counters.access_requests, - cli->counters.dup_access_requests, - cli->counters.access_accepts, - cli->counters.access_rejects, - cli->counters.access_challenges, - cli->counters.malformed_access_requests, - cli->counters.bad_authenticators, - cli->counters.packets_dropped, - cli->counters.unknown_types); - if (ret < 0 || ret >= end - pos) { - *pos = '\0'; - return pos - buf; - } - pos += ret; - } - - return pos - buf; -} - - -static int radius_server_get_eap_user(void *ctx, const u8 *identity, - size_t identity_len, int phase2, - struct eap_user *user) -{ - struct radius_session *sess = ctx; - struct radius_server_data *data = sess->server; - - return data->get_eap_user(data->conf_ctx, identity, identity_len, - phase2, user); -} - - -static const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len) -{ - struct radius_session *sess = ctx; - struct radius_server_data *data = sess->server; - *len = data->eap_req_id_text_len; - return data->eap_req_id_text; -} - - -static struct eapol_callbacks radius_server_eapol_cb = -{ - .get_eap_user = radius_server_get_eap_user, - .get_eap_req_id_text = radius_server_get_eap_req_id_text, -}; - - -/** - * radius_server_eap_pending_cb - Pending EAP data notification - * @data: RADIUS server context from radius_server_init() - * @ctx: Pending EAP context pointer - * - * This function is used to notify EAP server module that a pending operation - * has been completed and processing of the EAP session can proceed. - */ -void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx) -{ - struct radius_client *cli; - struct radius_session *s, *sess = NULL; - struct radius_msg *msg; - - if (data == NULL) - return; - - for (cli = data->clients; cli; cli = cli->next) { - for (s = cli->sessions; s; s = s->next) { - if (s->eap == ctx && s->last_msg) { - sess = s; - break; - } - if (sess) - break; - } - if (sess) - break; - } - - if (sess == NULL) { - RADIUS_DEBUG("No session matched callback ctx"); - return; - } - - msg = sess->last_msg; - sess->last_msg = NULL; - eap_sm_pending_cb(sess->eap); - if (radius_server_request(data, msg, - (struct sockaddr *) &sess->last_from, - sess->last_fromlen, cli, - sess->last_from_addr, - sess->last_from_port, sess) == -2) - return; /* msg was stored with the session */ - - radius_msg_free(msg); -} diff --git a/contrib/hostapd/src/radius/radius_server.h b/contrib/hostapd/src/radius/radius_server.h deleted file mode 100644 index 284bd59d72..0000000000 --- a/contrib/hostapd/src/radius/radius_server.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * RADIUS authentication server - * Copyright (c) 2005-2009, 2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef RADIUS_SERVER_H -#define RADIUS_SERVER_H - -struct radius_server_data; -struct eap_user; - -/** - * struct radius_server_conf - RADIUS server configuration - */ -struct radius_server_conf { - /** - * auth_port - UDP port to listen to as an authentication server - */ - int auth_port; - - /** - * client_file - RADIUS client configuration file - * - * This file contains the RADIUS clients and the shared secret to be - * used with them in a format where each client is on its own line. The - * first item on the line is the IPv4 or IPv6 address of the client - * with an optional address mask to allow full network to be specified - * (e.g., 192.168.1.2 or 192.168.1.0/24). This is followed by white - * space (space or tabulator) and the shared secret. Lines starting - * with '#' are skipped and can be used as comments. - */ - char *client_file; - - /** - * conf_ctx - Context pointer for callbacks - * - * This is used as the ctx argument in get_eap_user() calls. - */ - void *conf_ctx; - - /** - * eap_sim_db_priv - EAP-SIM/AKA database context - * - * This is passed to the EAP-SIM/AKA server implementation as a - * callback context. - */ - void *eap_sim_db_priv; - - /** - * ssl_ctx - TLS context - * - * This is passed to the EAP server implementation as a callback - * context for TLS operations. - */ - void *ssl_ctx; - - /** - * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST - * - * This parameter is used to set a key for EAP-FAST to encrypt the - * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If - * set, must point to a 16-octet key. - */ - u8 *pac_opaque_encr_key; - - /** - * eap_fast_a_id - EAP-FAST authority identity (A-ID) - * - * If EAP-FAST is not used, this can be set to %NULL. In theory, this - * is a variable length field, but due to some existing implementations - * requiring A-ID to be 16 octets in length, it is recommended to use - * that length for the field to provide interoperability with deployed - * peer implementations. - */ - u8 *eap_fast_a_id; - - /** - * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets - */ - size_t eap_fast_a_id_len; - - /** - * eap_fast_a_id_info - EAP-FAST authority identifier information - * - * This A-ID-Info contains a user-friendly name for the A-ID. For - * example, this could be the enterprise and server names in - * human-readable format. This field is encoded as UTF-8. If EAP-FAST - * is not used, this can be set to %NULL. - */ - char *eap_fast_a_id_info; - - /** - * eap_fast_prov - EAP-FAST provisioning modes - * - * 0 = provisioning disabled, 1 = only anonymous provisioning allowed, - * 2 = only authenticated provisioning allowed, 3 = both provisioning - * modes allowed. - */ - int eap_fast_prov; - - /** - * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds - * - * This is the hard limit on how long a provisioned PAC-Key can be - * used. - */ - int pac_key_lifetime; - - /** - * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds - * - * This is a soft limit on the PAC-Key. The server will automatically - * generate a new PAC-Key when this number of seconds (or fewer) of the - * lifetime remains. - */ - int pac_key_refresh_time; - - /** - * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication - * - * This controls whether the protected success/failure indication - * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA. - */ - int eap_sim_aka_result_ind; - - /** - * tnc - Trusted Network Connect (TNC) - * - * This controls whether TNC is enabled and will be required before the - * peer is allowed to connect. Note: This is only used with EAP-TTLS - * and EAP-FAST. If any other EAP method is enabled, the peer will be - * allowed to connect without TNC. - */ - int tnc; - - /** - * pwd_group - EAP-pwd D-H group - * - * This is used to select which D-H group to use with EAP-pwd. - */ - u16 pwd_group; - - /** - * server_id - Server identity - */ - const char *server_id; - - /** - * wps - Wi-Fi Protected Setup context - * - * If WPS is used with an external RADIUS server (which is quite - * unlikely configuration), this is used to provide a pointer to WPS - * context data. Normally, this can be set to %NULL. - */ - struct wps_context *wps; - - /** - * ipv6 - Whether to enable IPv6 support in the RADIUS server - */ - int ipv6; - - /** - * get_eap_user - Callback for fetching EAP user information - * @ctx: Context data from conf_ctx - * @identity: User identity - * @identity_len: identity buffer length in octets - * @phase2: Whether this is for Phase 2 identity - * @user: Data structure for filling in the user information - * Returns: 0 on success, -1 on failure - * - * This is used to fetch information from user database. The callback - * will fill in information about allowed EAP methods and the user - * password. The password field will be an allocated copy of the - * password data and RADIUS server will free it after use. - */ - int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, - int phase2, struct eap_user *user); - - /** - * eap_req_id_text - Optional data for EAP-Request/Identity - * - * This can be used to configure an optional, displayable message that - * will be sent in EAP-Request/Identity. This string can contain an - * ASCII-0 character (nul) to separate network infromation per RFC - * 4284. The actual string length is explicit provided in - * eap_req_id_text_len since nul character will not be used as a string - * terminator. - */ - const char *eap_req_id_text; - - /** - * eap_req_id_text_len - Length of eap_req_id_text buffer in octets - */ - size_t eap_req_id_text_len; - - /* - * msg_ctx - Context data for wpa_msg() calls - */ - void *msg_ctx; - -#ifdef CONFIG_RADIUS_TEST - const char *dump_msk_file; -#endif /* CONFIG_RADIUS_TEST */ -}; - - -struct radius_server_data * -radius_server_init(struct radius_server_conf *conf); - -void radius_server_deinit(struct radius_server_data *data); - -int radius_server_get_mib(struct radius_server_data *data, char *buf, - size_t buflen); - -void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx); - -#endif /* RADIUS_SERVER_H */ diff --git a/contrib/hostapd/src/rsn_supp/peerkey.c b/contrib/hostapd/src/rsn_supp/peerkey.c deleted file mode 100644 index cb86dfbcc4..0000000000 --- a/contrib/hostapd/src/rsn_supp/peerkey.c +++ /dev/null @@ -1,1157 +0,0 @@ -/* - * WPA Supplicant - PeerKey for Direct Link Setup (DLS) - * Copyright (c) 2006-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#ifdef CONFIG_PEERKEY - -#include "common.h" -#include "eloop.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "crypto/random.h" -#include "common/ieee802_11_defs.h" -#include "wpa.h" -#include "wpa_i.h" -#include "wpa_ie.h" -#include "peerkey.h" - - -static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len) -{ - os_memcpy(pos, ie, ie_len); - return pos + ie_len; -} - - -static u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len) -{ - *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = RSN_SELECTOR_LEN + data_len; - RSN_SELECTOR_PUT(pos, kde); - pos += RSN_SELECTOR_LEN; - os_memcpy(pos, data, data_len); - pos += data_len; - return pos; -} - - -static void wpa_supplicant_smk_timeout(void *eloop_ctx, void *timeout_ctx) -{ -#if 0 - struct wpa_sm *sm = eloop_ctx; - struct wpa_peerkey *peerkey = timeout_ctx; -#endif - /* TODO: time out SMK and any STK that was generated using this SMK */ -} - - -static void wpa_supplicant_peerkey_free(struct wpa_sm *sm, - struct wpa_peerkey *peerkey) -{ - eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey); - os_free(peerkey); -} - - -static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst, - const u8 *peer, - u16 mui, u16 error_type, int ver) -{ - size_t rlen; - struct wpa_eapol_key *err; - struct rsn_error_kde error; - u8 *rbuf, *pos; - size_t kde_len; - u16 key_info; - - kde_len = 2 + RSN_SELECTOR_LEN + sizeof(error); - if (peer) - kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN; - - rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, - NULL, sizeof(*err) + kde_len, &rlen, - (void *) &err); - if (rbuf == NULL) - return -1; - - err->type = EAPOL_KEY_TYPE_RSN; - key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | - WPA_KEY_INFO_SECURE | WPA_KEY_INFO_ERROR | - WPA_KEY_INFO_REQUEST; - WPA_PUT_BE16(err->key_info, key_info); - WPA_PUT_BE16(err->key_length, 0); - os_memcpy(err->replay_counter, sm->request_counter, - WPA_REPLAY_COUNTER_LEN); - inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); - - WPA_PUT_BE16(err->key_data_length, (u16) kde_len); - pos = (u8 *) (err + 1); - - if (peer) { - /* Peer MAC Address KDE */ - pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN); - } - - /* Error KDE */ - error.mui = host_to_be16(mui); - error.error_type = host_to_be16(error_type); - wpa_add_kde(pos, RSN_KEY_DATA_ERROR, (u8 *) &error, sizeof(error)); - - if (peer) { - wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error (peer " - MACSTR " mui %d error_type %d)", - MAC2STR(peer), mui, error_type); - } else { - wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error " - "(mui %d error_type %d)", mui, error_type); - } - - wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL, - rbuf, rlen, err->key_mic); - - return 0; -} - - -static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm, - const unsigned char *src_addr, - const struct wpa_eapol_key *key, - int ver, struct wpa_peerkey *peerkey) -{ - size_t rlen; - struct wpa_eapol_key *reply; - u8 *rbuf, *pos; - size_t kde_len; - u16 key_info; - - /* KDEs: Peer RSN IE, Initiator MAC Address, Initiator Nonce */ - kde_len = peerkey->rsnie_p_len + - 2 + RSN_SELECTOR_LEN + ETH_ALEN + - 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN; - - rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, - NULL, sizeof(*reply) + kde_len, &rlen, - (void *) &reply); - if (rbuf == NULL) - return -1; - - reply->type = EAPOL_KEY_TYPE_RSN; - key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | - WPA_KEY_INFO_SECURE; - WPA_PUT_BE16(reply->key_info, key_info); - WPA_PUT_BE16(reply->key_length, 0); - os_memcpy(reply->replay_counter, key->replay_counter, - WPA_REPLAY_COUNTER_LEN); - - os_memcpy(reply->key_nonce, peerkey->pnonce, WPA_NONCE_LEN); - - WPA_PUT_BE16(reply->key_data_length, (u16) kde_len); - pos = (u8 *) (reply + 1); - - /* Peer RSN IE */ - pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len); - - /* Initiator MAC Address KDE */ - pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peerkey->addr, ETH_ALEN); - - /* Initiator Nonce */ - wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN); - - wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3"); - wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL, - rbuf, rlen, reply->key_mic); - - return 0; -} - - -static int wpa_supplicant_process_smk_m2( - struct wpa_sm *sm, const unsigned char *src_addr, - const struct wpa_eapol_key *key, size_t extra_len, int ver) -{ - struct wpa_peerkey *peerkey; - struct wpa_eapol_ie_parse kde; - struct wpa_ie_data ie; - int cipher; - struct rsn_ie_hdr *hdr; - u8 *pos; - - wpa_printf(MSG_DEBUG, "RSN: Received SMK M2"); - - if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { - wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for " - "the current network"); - return -1; - } - - if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) < - 0) { - wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2"); - return -1; - } - - if (kde.rsn_ie == NULL || kde.mac_addr == NULL || - kde.mac_addr_len < ETH_ALEN) { - wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in " - "SMK M2"); - return -1; - } - - wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR, - MAC2STR(kde.mac_addr)); - - if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) { - wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK " - "M2"); - return -1; - } - - if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { - wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2"); - return -1; - } - - cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher & - sm->allowed_pairwise_cipher, 0); - if (cipher < 0) { - wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2"); - wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr, - STK_MUI_SMK, STK_ERR_CPHR_NS, - ver); - return -1; - } - wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey", - wpa_cipher_txt(cipher)); - - /* TODO: 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 - * same time? */ - peerkey = os_zalloc(sizeof(*peerkey)); - if (peerkey == NULL) - return -1; - os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN); - os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN); - os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len); - peerkey->rsnie_i_len = kde.rsn_ie_len; - peerkey->cipher = cipher; -#ifdef CONFIG_IEEE80211W - if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 | - WPA_KEY_MGMT_PSK_SHA256)) - peerkey->use_sha256 = 1; -#endif /* CONFIG_IEEE80211W */ - - if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Failed to get random data for PNonce"); - wpa_supplicant_peerkey_free(sm, peerkey); - return -1; - } - - hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p; - hdr->elem_id = WLAN_EID_RSN; - WPA_PUT_LE16(hdr->version, RSN_VERSION); - pos = (u8 *) (hdr + 1); - /* Group Suite can be anything for SMK RSN IE; receiver will just - * ignore it. */ - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); - pos += RSN_SELECTOR_LEN; - /* Include only the selected cipher in pairwise cipher suite */ - WPA_PUT_LE16(pos, 1); - pos += 2; - RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, cipher)); - pos += RSN_SELECTOR_LEN; - - hdr->len = (pos - peerkey->rsnie_p) - 2; - peerkey->rsnie_p_len = pos - peerkey->rsnie_p; - wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake", - peerkey->rsnie_p, peerkey->rsnie_p_len); - - wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey); - - peerkey->next = sm->peerkey; - sm->peerkey = peerkey; - - return 0; -} - - -/** - * rsn_smkid - Derive SMK identifier - * @smk: Station master key (32 bytes) - * @pnonce: Peer Nonce - * @mac_p: Peer MAC address - * @inonce: Initiator Nonce - * @mac_i: Initiator MAC address - * @use_sha256: Whether to use SHA256-based KDF - * - * 8.5.1.4 Station to station (STK) key hierarchy - * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I) - */ -static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p, - const u8 *inonce, const u8 *mac_i, u8 *smkid, - int use_sha256) -{ - char *title = "SMK Name"; - const u8 *addr[5]; - const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN, - ETH_ALEN }; - unsigned char hash[SHA256_MAC_LEN]; - - addr[0] = (u8 *) title; - addr[1] = pnonce; - addr[2] = mac_p; - addr[3] = inonce; - addr[4] = mac_i; - -#ifdef CONFIG_IEEE80211W - if (use_sha256) - hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash); - else -#endif /* CONFIG_IEEE80211W */ - hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash); - os_memcpy(smkid, hash, PMKID_LEN); -} - - -static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm, - struct wpa_peerkey *peerkey) -{ - size_t mlen; - struct wpa_eapol_key *msg; - u8 *mbuf; - size_t kde_len; - u16 key_info, ver; - - kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN; - - mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, - sizeof(*msg) + kde_len, &mlen, - (void *) &msg); - if (mbuf == NULL) - return; - - msg->type = EAPOL_KEY_TYPE_RSN; - - if (peerkey->cipher != WPA_CIPHER_TKIP) - ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; - else - ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; - - key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK; - WPA_PUT_BE16(msg->key_info, key_info); - - if (peerkey->cipher != WPA_CIPHER_TKIP) - WPA_PUT_BE16(msg->key_length, 16); - else - WPA_PUT_BE16(msg->key_length, 32); - - os_memcpy(msg->replay_counter, peerkey->replay_counter, - WPA_REPLAY_COUNTER_LEN); - inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN); - - WPA_PUT_BE16(msg->key_data_length, kde_len); - wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID, - peerkey->smkid, PMKID_LEN); - - if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "RSN: Failed to get random data for INonce (STK)"); - os_free(mbuf); - return; - } - wpa_hexdump(MSG_DEBUG, "RSN: INonce for STK 4-Way Handshake", - peerkey->inonce, WPA_NONCE_LEN); - os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN); - - wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR, - MAC2STR(peerkey->addr)); - wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL, - mbuf, mlen, NULL); -} - - -static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm, - struct wpa_peerkey *peerkey) -{ - size_t mlen; - struct wpa_eapol_key *msg; - u8 *mbuf, *pos; - size_t kde_len; - u16 key_info, ver; - be32 lifetime; - - kde_len = peerkey->rsnie_i_len + - 2 + RSN_SELECTOR_LEN + sizeof(lifetime); - - mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, - sizeof(*msg) + kde_len, &mlen, - (void *) &msg); - if (mbuf == NULL) - return; - - msg->type = EAPOL_KEY_TYPE_RSN; - - if (peerkey->cipher != WPA_CIPHER_TKIP) - ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; - else - ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; - - key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK | - WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE; - WPA_PUT_BE16(msg->key_info, key_info); - - if (peerkey->cipher != WPA_CIPHER_TKIP) - WPA_PUT_BE16(msg->key_length, 16); - else - WPA_PUT_BE16(msg->key_length, 32); - - os_memcpy(msg->replay_counter, peerkey->replay_counter, - WPA_REPLAY_COUNTER_LEN); - inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN); - - WPA_PUT_BE16(msg->key_data_length, kde_len); - pos = (u8 *) (msg + 1); - pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len); - lifetime = host_to_be32(peerkey->lifetime); - wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME, - (u8 *) &lifetime, sizeof(lifetime)); - - os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN); - - wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR, - MAC2STR(peerkey->addr)); - wpa_eapol_key_send(sm, peerkey->stk.kck, ver, peerkey->addr, - ETH_P_EAPOL, mbuf, mlen, msg->key_mic); -} - - -static int wpa_supplicant_process_smk_m4(struct wpa_peerkey *peerkey, - struct wpa_eapol_ie_parse *kde) -{ - wpa_printf(MSG_DEBUG, "RSN: Received SMK M4 (Initiator " MACSTR ")", - MAC2STR(kde->mac_addr)); - - if (os_memcmp(kde->smk + PMK_LEN, peerkey->pnonce, WPA_NONCE_LEN) != 0) - { - wpa_printf(MSG_INFO, "RSN: PNonce in SMK KDE does not " - "match with the one used in SMK M3"); - return -1; - } - - if (os_memcmp(kde->nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) { - wpa_printf(MSG_INFO, "RSN: INonce in SMK M4 did not " - "match with the one received in SMK M2"); - return -1; - } - - return 0; -} - - -static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm, - const unsigned char *src_addr, - const struct wpa_eapol_key *key, - int ver, - struct wpa_peerkey *peerkey, - struct wpa_eapol_ie_parse *kde) -{ - int cipher; - struct wpa_ie_data ie; - - wpa_printf(MSG_DEBUG, "RSN: Received SMK M5 (Peer " MACSTR ")", - MAC2STR(kde->mac_addr)); - if (kde->rsn_ie == NULL || kde->rsn_ie_len > PEERKEY_MAX_IE_LEN || - wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0) { - wpa_printf(MSG_INFO, "RSN: No RSN IE in SMK M5"); - /* TODO: abort negotiation */ - return -1; - } - - if (os_memcmp(key->key_nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) { - wpa_printf(MSG_INFO, "RSN: Key Nonce in SMK M5 does " - "not match with INonce used in SMK M1"); - return -1; - } - - if (os_memcmp(kde->smk + PMK_LEN, peerkey->inonce, WPA_NONCE_LEN) != 0) - { - wpa_printf(MSG_INFO, "RSN: INonce in SMK KDE does not " - "match with the one used in SMK M1"); - return -1; - } - - os_memcpy(peerkey->rsnie_p, kde->rsn_ie, kde->rsn_ie_len); - peerkey->rsnie_p_len = kde->rsn_ie_len; - os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN); - - cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher & - sm->allowed_pairwise_cipher, 0); - if (cipher < 0) { - wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR " selected " - "unacceptable cipher", MAC2STR(kde->mac_addr)); - wpa_supplicant_send_smk_error(sm, src_addr, kde->mac_addr, - STK_MUI_SMK, STK_ERR_CPHR_NS, - ver); - /* TODO: abort negotiation */ - return -1; - } - wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey", - wpa_cipher_txt(cipher)); - peerkey->cipher = cipher; - - return 0; -} - - -static int wpa_supplicant_process_smk_m45( - struct wpa_sm *sm, const unsigned char *src_addr, - const struct wpa_eapol_key *key, size_t extra_len, int ver) -{ - struct wpa_peerkey *peerkey; - struct wpa_eapol_ie_parse kde; - u32 lifetime; - - if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { - wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for " - "the current network"); - return -1; - } - - if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) < - 0) { - wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M4/M5"); - return -1; - } - - if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN || - kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN || - kde.smk == NULL || kde.smk_len < PMK_LEN + WPA_NONCE_LEN || - kde.lifetime == NULL || kde.lifetime_len < 4) { - wpa_printf(MSG_INFO, "RSN: No MAC Address, Nonce, SMK, or " - "Lifetime KDE in SMK M4/M5"); - return -1; - } - - for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) { - if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) == 0 && - os_memcmp(peerkey->initiator ? peerkey->inonce : - peerkey->pnonce, - key->key_nonce, WPA_NONCE_LEN) == 0) - break; - } - if (peerkey == NULL) { - wpa_printf(MSG_INFO, "RSN: No matching SMK handshake found " - "for SMK M4/M5: peer " MACSTR, - MAC2STR(kde.mac_addr)); - return -1; - } - - if (peerkey->initiator) { - if (wpa_supplicant_process_smk_m5(sm, src_addr, key, ver, - peerkey, &kde) < 0) - return -1; - } else { - if (wpa_supplicant_process_smk_m4(peerkey, &kde) < 0) - return -1; - } - - os_memcpy(peerkey->smk, kde.smk, PMK_LEN); - peerkey->smk_complete = 1; - wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", peerkey->smk, PMK_LEN); - lifetime = WPA_GET_BE32(kde.lifetime); - wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime); - if (lifetime > 1000000000) - lifetime = 1000000000; /* avoid overflowing eloop time */ - peerkey->lifetime = lifetime; - eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout, - sm, peerkey); - - if (peerkey->initiator) { - rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr, - peerkey->inonce, sm->own_addr, peerkey->smkid, - peerkey->use_sha256); - wpa_supplicant_send_stk_1_of_4(sm, peerkey); - } else { - rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr, - peerkey->inonce, peerkey->addr, peerkey->smkid, - peerkey->use_sha256); - } - wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN); - - return 0; -} - - -static int wpa_supplicant_process_smk_error( - struct wpa_sm *sm, const unsigned char *src_addr, - const struct wpa_eapol_key *key, size_t extra_len) -{ - struct wpa_eapol_ie_parse kde; - struct rsn_error_kde error; - u8 peer[ETH_ALEN]; - u16 error_type; - - wpa_printf(MSG_DEBUG, "RSN: Received SMK Error"); - - if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { - wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for " - "the current network"); - return -1; - } - - if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) < - 0) { - wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error"); - return -1; - } - - if (kde.error == NULL || kde.error_len < sizeof(error)) { - wpa_printf(MSG_INFO, "RSN: No Error KDE in SMK Error"); - return -1; - } - - if (kde.mac_addr && kde.mac_addr_len >= ETH_ALEN) - os_memcpy(peer, kde.mac_addr, ETH_ALEN); - else - os_memset(peer, 0, ETH_ALEN); - os_memcpy(&error, kde.error, sizeof(error)); - error_type = be_to_host16(error.error_type); - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "RSN: SMK Error KDE received: MUI %d error_type %d peer " - MACSTR, - be_to_host16(error.mui), error_type, - MAC2STR(peer)); - - if (kde.mac_addr && - (error_type == STK_ERR_STA_NR || error_type == STK_ERR_STA_NRSN || - error_type == STK_ERR_CPHR_NS)) { - struct wpa_peerkey *peerkey; - - for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) { - if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) == - 0) - break; - } - if (peerkey == NULL) { - wpa_printf(MSG_DEBUG, "RSN: No matching SMK handshake " - "found for SMK Error"); - return -1; - } - /* TODO: abort SMK/STK handshake and remove all related keys */ - } - - return 0; -} - - -static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm, - struct wpa_peerkey *peerkey, - const struct wpa_eapol_key *key, - u16 ver) -{ - struct wpa_eapol_ie_parse ie; - const u8 *kde; - size_t len, kde_buf_len; - struct wpa_ptk *stk; - u8 buf[8], *kde_buf, *pos; - be32 lifetime; - - wpa_printf(MSG_DEBUG, "RSN: RX message 1 of STK 4-Way Handshake from " - MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver); - - os_memset(&ie, 0, sizeof(ie)); - - /* RSN: msg 1/4 should contain SMKID for the selected SMK */ - kde = (const u8 *) (key + 1); - len = WPA_GET_BE16(key->key_data_length); - wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", kde, len); - if (wpa_supplicant_parse_ies(kde, len, &ie) < 0 || ie.pmkid == NULL) { - wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4"); - return; - } - if (os_memcmp(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) { - wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4", - ie.pmkid, PMKID_LEN); - return; - } - - if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "RSN: Failed to get random data for PNonce"); - return; - } - wpa_hexdump(MSG_DEBUG, "WPA: Renewed PNonce", - peerkey->pnonce, WPA_NONCE_LEN); - - /* Calculate STK which will be stored as a temporary STK until it has - * been verified when processing message 3/4. */ - stk = &peerkey->tstk; - wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion", - sm->own_addr, peerkey->addr, - peerkey->pnonce, key->key_nonce, - (u8 *) stk, sizeof(*stk), - peerkey->use_sha256); - /* Supplicant: swap tx/rx Mic keys */ - os_memcpy(buf, stk->u.auth.tx_mic_key, 8); - os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8); - os_memcpy(stk->u.auth.rx_mic_key, buf, 8); - peerkey->tstk_set = 1; - - kde_buf_len = peerkey->rsnie_p_len + - 2 + RSN_SELECTOR_LEN + sizeof(lifetime) + - 2 + RSN_SELECTOR_LEN + PMKID_LEN; - kde_buf = os_malloc(kde_buf_len); - if (kde_buf == NULL) - return; - pos = kde_buf; - pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len); - lifetime = host_to_be32(peerkey->lifetime); - pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME, - (u8 *) &lifetime, sizeof(lifetime)); - wpa_add_kde(pos, RSN_KEY_DATA_PMKID, peerkey->smkid, PMKID_LEN); - - if (wpa_supplicant_send_2_of_4(sm, peerkey->addr, key, ver, - peerkey->pnonce, kde_buf, kde_buf_len, - stk)) { - os_free(kde_buf); - return; - } - os_free(kde_buf); - - os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN); -} - - -static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm, - struct wpa_peerkey *peerkey, - struct wpa_eapol_ie_parse *kde) -{ - u32 lifetime; - - if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime)) - return; - - lifetime = WPA_GET_BE32(kde->lifetime); - - if (lifetime >= peerkey->lifetime) { - wpa_printf(MSG_DEBUG, "RSN: Peer used SMK lifetime %u seconds " - "which is larger than or equal to own value %u " - "seconds - ignored", lifetime, peerkey->lifetime); - return; - } - - wpa_printf(MSG_DEBUG, "RSN: Peer used shorter SMK lifetime %u seconds " - "(own was %u seconds) - updated", - lifetime, peerkey->lifetime); - peerkey->lifetime = lifetime; - - eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey); - eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout, - sm, peerkey); -} - - -static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm, - struct wpa_peerkey *peerkey, - const struct wpa_eapol_key *key, - u16 ver) -{ - struct wpa_eapol_ie_parse kde; - const u8 *keydata; - size_t len; - - wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from " - MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver); - - os_memset(&kde, 0, sizeof(kde)); - - /* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE - * from the peer. It may also include Lifetime KDE. */ - keydata = (const u8 *) (key + 1); - len = WPA_GET_BE16(key->key_data_length); - wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", keydata, len); - if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0 || - kde.pmkid == NULL || kde.rsn_ie == NULL) { - wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4"); - return; - } - - if (os_memcmp(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) { - wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4", - kde.pmkid, PMKID_LEN); - return; - } - - if (kde.rsn_ie_len != peerkey->rsnie_p_len || - os_memcmp(kde.rsn_ie, peerkey->rsnie_p, kde.rsn_ie_len) != 0) { - wpa_printf(MSG_INFO, "RSN: Peer RSN IE in SMK and STK " - "handshakes did not match"); - wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in SMK handshake", - peerkey->rsnie_p, peerkey->rsnie_p_len); - wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in STK handshake", - kde.rsn_ie, kde.rsn_ie_len); - return; - } - - wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde); - - wpa_supplicant_send_stk_3_of_4(sm, peerkey); - os_memcpy(peerkey->pnonce, key->key_nonce, WPA_NONCE_LEN); -} - - -static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm, - struct wpa_peerkey *peerkey, - const struct wpa_eapol_key *key, - u16 ver) -{ - struct wpa_eapol_ie_parse kde; - const u8 *keydata; - size_t len, key_len; - const u8 *_key; - u8 key_buf[32], rsc[6]; - - wpa_printf(MSG_DEBUG, "RSN: RX message 3 of STK 4-Way Handshake from " - MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver); - - os_memset(&kde, 0, sizeof(kde)); - - /* RSN: msg 3/4 should contain Initiator RSN IE. It may also include - * Lifetime KDE. */ - keydata = (const u8 *) (key + 1); - len = WPA_GET_BE16(key->key_data_length); - wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", keydata, len); - if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0) { - wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in " - "STK 3/4"); - return; - } - - if (kde.rsn_ie_len != peerkey->rsnie_i_len || - os_memcmp(kde.rsn_ie, peerkey->rsnie_i, kde.rsn_ie_len) != 0) { - wpa_printf(MSG_INFO, "RSN: Initiator RSN IE in SMK and STK " - "handshakes did not match"); - wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in SMK " - "handshake", - peerkey->rsnie_i, peerkey->rsnie_i_len); - wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in STK " - "handshake", - kde.rsn_ie, kde.rsn_ie_len); - return; - } - - if (os_memcmp(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN) != 0) { - wpa_printf(MSG_WARNING, "RSN: INonce from message 1 of STK " - "4-Way Handshake differs from 3 of STK 4-Way " - "Handshake - drop packet (src=" MACSTR ")", - MAC2STR(peerkey->addr)); - return; - } - - wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde); - - if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver, - WPA_GET_BE16(key->key_info), - NULL, 0, &peerkey->stk)) - return; - - _key = (u8 *) peerkey->stk.tk1; - if (peerkey->cipher == WPA_CIPHER_TKIP) { - /* Swap Tx/Rx keys for Michael MIC */ - os_memcpy(key_buf, _key, 16); - os_memcpy(key_buf + 16, peerkey->stk.u.auth.rx_mic_key, 8); - os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8); - _key = key_buf; - key_len = 32; - } else - key_len = 16; - - os_memset(rsc, 0, 6); - if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1, - rsc, sizeof(rsc), _key, key_len) < 0) { - wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the " - "driver."); - return; - } -} - - -static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm, - struct wpa_peerkey *peerkey, - const struct wpa_eapol_key *key, - u16 ver) -{ - u8 rsc[6]; - - wpa_printf(MSG_DEBUG, "RSN: RX message 4 of STK 4-Way Handshake from " - MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver); - - os_memset(rsc, 0, 6); - if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1, - rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1, - peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) { - wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the " - "driver."); - return; - } -} - - -/** - * peerkey_verify_eapol_key_mic - Verify PeerKey MIC - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @peerkey: Pointer to the PeerKey data for the peer - * @key: Pointer to the EAPOL-Key frame header - * @ver: Version bits from EAPOL-Key Key Info - * @buf: Pointer to the beginning of EAPOL-Key frame - * @len: Length of the EAPOL-Key frame - * Returns: 0 on success, -1 on failure - */ -int peerkey_verify_eapol_key_mic(struct wpa_sm *sm, - struct wpa_peerkey *peerkey, - struct wpa_eapol_key *key, u16 ver, - const u8 *buf, size_t len) -{ - u8 mic[16]; - int ok = 0; - - if (peerkey->initiator && !peerkey->stk_set) { - wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion", - sm->own_addr, peerkey->addr, - peerkey->inonce, key->key_nonce, - (u8 *) &peerkey->stk, sizeof(peerkey->stk), - peerkey->use_sha256); - peerkey->stk_set = 1; - } - - os_memcpy(mic, key->key_mic, 16); - if (peerkey->tstk_set) { - os_memset(key->key_mic, 0, 16); - wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len, - key->key_mic); - if (os_memcmp(mic, key->key_mic, 16) != 0) { - wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC " - "when using TSTK - ignoring TSTK"); - } else { - ok = 1; - peerkey->tstk_set = 0; - peerkey->stk_set = 1; - os_memcpy(&peerkey->stk, &peerkey->tstk, - sizeof(peerkey->stk)); - } - } - - if (!ok && peerkey->stk_set) { - os_memset(key->key_mic, 0, 16); - wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len, - key->key_mic); - if (os_memcmp(mic, key->key_mic, 16) != 0) { - wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC " - "- dropping packet"); - return -1; - } - ok = 1; - } - - if (!ok) { - wpa_printf(MSG_WARNING, "RSN: Could not verify EAPOL-Key MIC " - "- dropping packet"); - return -1; - } - - os_memcpy(peerkey->replay_counter, key->replay_counter, - WPA_REPLAY_COUNTER_LEN); - peerkey->replay_counter_set = 1; - return 0; -} - - -/** - * wpa_sm_stkstart - Send EAPOL-Key Request for STK handshake (STK M1) - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @peer: MAC address of the peer STA - * Returns: 0 on success, or -1 on failure - * - * Send an EAPOL-Key Request to the current authenticator to start STK - * handshake with the peer. - */ -int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) -{ - size_t rlen, kde_len; - struct wpa_eapol_key *req; - int key_info, ver; - u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos; - u16 count; - struct rsn_ie_hdr *hdr; - struct wpa_peerkey *peerkey; - struct wpa_ie_data ie; - - if (sm->proto != WPA_PROTO_RSN || !sm->ptk_set || !sm->peerkey_enabled) - return -1; - - if (sm->ap_rsn_ie && - wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &ie) == 0 && - !(ie.capabilities & WPA_CAPABILITY_PEERKEY_ENABLED)) { - wpa_printf(MSG_DEBUG, "RSN: Current AP does not support STK"); - return -1; - } - - if (sm->pairwise_cipher != WPA_CIPHER_TKIP) - ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; - else - ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; - - if (wpa_sm_get_bssid(sm, bssid) < 0) { - wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key " - "SMK M1"); - return -1; - } - - /* TODO: find existing entry and if found, use that instead of adding - * a new one */ - peerkey = os_zalloc(sizeof(*peerkey)); - if (peerkey == NULL) - return -1; - peerkey->initiator = 1; - os_memcpy(peerkey->addr, peer, ETH_ALEN); -#ifdef CONFIG_IEEE80211W - if (wpa_key_mgmt_sha256(sm->key_mgmt)) - peerkey->use_sha256 = 1; -#endif /* CONFIG_IEEE80211W */ - - /* SMK M1: - * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce, - * MIC=MIC, DataKDs=(RSNIE_I, MAC_P KDE)) - */ - - hdr = (struct rsn_ie_hdr *) peerkey->rsnie_i; - hdr->elem_id = WLAN_EID_RSN; - WPA_PUT_LE16(hdr->version, RSN_VERSION); - pos = (u8 *) (hdr + 1); - /* Group Suite can be anything for SMK RSN IE; receiver will just - * ignore it. */ - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); - pos += RSN_SELECTOR_LEN; - count_pos = pos; - pos += 2; - - count = rsn_cipher_put_suites(pos, sm->allowed_pairwise_cipher); - pos += count * RSN_SELECTOR_LEN; - WPA_PUT_LE16(count_pos, count); - - hdr->len = (pos - peerkey->rsnie_i) - 2; - peerkey->rsnie_i_len = pos - peerkey->rsnie_i; - wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake", - peerkey->rsnie_i, peerkey->rsnie_i_len); - - kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN; - - rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, - sizeof(*req) + kde_len, &rlen, - (void *) &req); - if (rbuf == NULL) { - wpa_supplicant_peerkey_free(sm, peerkey); - return -1; - } - - req->type = EAPOL_KEY_TYPE_RSN; - key_info = WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | - WPA_KEY_INFO_SECURE | WPA_KEY_INFO_REQUEST | ver; - WPA_PUT_BE16(req->key_info, key_info); - WPA_PUT_BE16(req->key_length, 0); - os_memcpy(req->replay_counter, sm->request_counter, - WPA_REPLAY_COUNTER_LEN); - inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); - - if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Failed to get random data for INonce"); - os_free(rbuf); - wpa_supplicant_peerkey_free(sm, peerkey); - return -1; - } - os_memcpy(req->key_nonce, peerkey->inonce, WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake", - req->key_nonce, WPA_NONCE_LEN); - - WPA_PUT_BE16(req->key_data_length, (u16) kde_len); - pos = (u8 *) (req + 1); - - /* Initiator RSN IE */ - pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len); - /* Peer MAC address KDE */ - wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN); - - wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer " - MACSTR ")", MAC2STR(peer)); - wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL, - rbuf, rlen, req->key_mic); - - peerkey->next = sm->peerkey; - sm->peerkey = peerkey; - - return 0; -} - - -/** - * peerkey_deinit - Free PeerKey values - * @sm: Pointer to WPA state machine data from wpa_sm_init() - */ -void peerkey_deinit(struct wpa_sm *sm) -{ - struct wpa_peerkey *prev, *peerkey = sm->peerkey; - while (peerkey) { - prev = peerkey; - peerkey = peerkey->next; - wpa_supplicant_peerkey_free(sm, prev); - } - sm->peerkey = NULL; -} - - -void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey, - struct wpa_eapol_key *key, u16 key_info, u16 ver) -{ - if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) == - (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) { - /* 3/4 STK 4-Way Handshake */ - wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver); - } else if (key_info & WPA_KEY_INFO_ACK) { - /* 1/4 STK 4-Way Handshake */ - wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver); - } else if (key_info & WPA_KEY_INFO_SECURE) { - /* 4/4 STK 4-Way Handshake */ - wpa_supplicant_process_stk_4_of_4(sm, peerkey, key, ver); - } else { - /* 2/4 STK 4-Way Handshake */ - wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver); - } -} - - -void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr, - struct wpa_eapol_key *key, size_t extra_len, - u16 key_info, u16 ver) -{ - if (key_info & WPA_KEY_INFO_ERROR) { - /* SMK Error */ - wpa_supplicant_process_smk_error(sm, src_addr, key, extra_len); - } else if (key_info & WPA_KEY_INFO_ACK) { - /* SMK M2 */ - wpa_supplicant_process_smk_m2(sm, src_addr, key, extra_len, - ver); - } else { - /* SMK M4 or M5 */ - wpa_supplicant_process_smk_m45(sm, src_addr, key, extra_len, - ver); - } -} - -#endif /* CONFIG_PEERKEY */ diff --git a/contrib/hostapd/src/rsn_supp/peerkey.h b/contrib/hostapd/src/rsn_supp/peerkey.h deleted file mode 100644 index f420691ac7..0000000000 --- a/contrib/hostapd/src/rsn_supp/peerkey.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * WPA Supplicant - PeerKey for Direct Link Setup (DLS) - * Copyright (c) 2006-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef PEERKEY_H -#define PEERKEY_H - -#define PEERKEY_MAX_IE_LEN 80 -struct wpa_peerkey { - struct wpa_peerkey *next; - int initiator; /* whether this end was initator for SMK handshake */ - u8 addr[ETH_ALEN]; /* other end MAC address */ - u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */ - u8 pnonce[WPA_NONCE_LEN]; /* Peer Nonce */ - u8 rsnie_i[PEERKEY_MAX_IE_LEN]; /* Initiator RSN IE */ - size_t rsnie_i_len; - u8 rsnie_p[PEERKEY_MAX_IE_LEN]; /* Peer RSN IE */ - size_t rsnie_p_len; - u8 smk[PMK_LEN]; - int smk_complete; - u8 smkid[PMKID_LEN]; - u32 lifetime; - int cipher; /* Selected cipher (WPA_CIPHER_*) */ - u8 replay_counter[WPA_REPLAY_COUNTER_LEN]; - int replay_counter_set; - int use_sha256; /* whether AKMP indicate SHA256-based derivations */ - - struct wpa_ptk stk, tstk; - int stk_set, tstk_set; -}; - - -#ifdef CONFIG_PEERKEY - -int peerkey_verify_eapol_key_mic(struct wpa_sm *sm, - struct wpa_peerkey *peerkey, - struct wpa_eapol_key *key, u16 ver, - const u8 *buf, size_t len); -void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey, - struct wpa_eapol_key *key, u16 key_info, u16 ver); -void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr, - struct wpa_eapol_key *key, size_t extra_len, - u16 key_info, u16 ver); -void peerkey_deinit(struct wpa_sm *sm); - -#else /* CONFIG_PEERKEY */ - -static inline int -peerkey_verify_eapol_key_mic(struct wpa_sm *sm, - struct wpa_peerkey *peerkey, - struct wpa_eapol_key *key, u16 ver, - const u8 *buf, size_t len) -{ - return -1; -} - -static inline void -peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey, - struct wpa_eapol_key *key, u16 key_info, u16 ver) -{ -} - -static inline void -peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr, - struct wpa_eapol_key *key, size_t extra_len, - u16 key_info, u16 ver) -{ -} - -static inline void peerkey_deinit(struct wpa_sm *sm) -{ -} - -#endif /* CONFIG_PEERKEY */ - -#endif /* PEERKEY_H */ diff --git a/contrib/hostapd/src/rsn_supp/pmksa_cache.c b/contrib/hostapd/src/rsn_supp/pmksa_cache.c deleted file mode 100644 index 09608153f1..0000000000 --- a/contrib/hostapd/src/rsn_supp/pmksa_cache.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - * WPA Supplicant - RSN PMKSA cache - * Copyright (c) 2004-2009, 2011-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eloop.h" -#include "eapol_supp/eapol_supp_sm.h" -#include "wpa.h" -#include "wpa_i.h" -#include "pmksa_cache.h" - -#ifdef IEEE8021X_EAPOL - -static const int pmksa_cache_max_entries = 32; - -struct rsn_pmksa_cache { - struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */ - int pmksa_count; /* number of entries in PMKSA cache */ - struct wpa_sm *sm; /* TODO: get rid of this reference(?) */ - - void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx, - enum pmksa_free_reason reason); - void *ctx; -}; - - -static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); - - -static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) -{ - os_free(entry); -} - - -static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, - struct rsn_pmksa_cache_entry *entry, - enum pmksa_free_reason reason) -{ - wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid); - pmksa->pmksa_count--; - pmksa->free_cb(entry, pmksa->ctx, reason); - _pmksa_cache_free_entry(entry); -} - - -static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) -{ - struct rsn_pmksa_cache *pmksa = eloop_ctx; - struct os_reltime now; - - os_get_reltime(&now); - while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { - struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; - pmksa->pmksa = entry->next; - wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " - MACSTR, MAC2STR(entry->aa)); - pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE); - } - - pmksa_cache_set_expiration(pmksa); -} - - -static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx) -{ - struct rsn_pmksa_cache *pmksa = eloop_ctx; - pmksa->sm->cur_pmksa = NULL; - eapol_sm_request_reauth(pmksa->sm->eapol); -} - - -static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) -{ - int sec; - struct rsn_pmksa_cache_entry *entry; - struct os_reltime now; - - eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); - eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL); - if (pmksa->pmksa == NULL) - return; - os_get_reltime(&now); - sec = pmksa->pmksa->expiration - now.sec; - if (sec < 0) - sec = 0; - eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL); - - entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa : - pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL); - if (entry) { - sec = pmksa->pmksa->reauth_time - now.sec; - if (sec < 0) - sec = 0; - eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa, - NULL); - } -} - - -/** - * pmksa_cache_add - Add a PMKSA cache entry - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() - * @pmk: The new pairwise master key - * @pmk_len: PMK length in bytes, usually PMK_LEN (32) - * @aa: Authenticator address - * @spa: Supplicant address - * @network_ctx: Network configuration context for this PMK - * @akmp: WPA_KEY_MGMT_* used in key derivation - * Returns: Pointer to the added PMKSA cache entry or %NULL on error - * - * This function create a PMKSA entry for a new PMK and adds it to the PMKSA - * cache. If an old entry is already in the cache for the same Authenticator, - * this entry will be replaced with the new entry. PMKID will be calculated - * based on the PMK and the driver interface is notified of the new PMKID. - */ -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) -{ - struct rsn_pmksa_cache_entry *entry, *pos, *prev; - struct os_reltime now; - - if (pmk_len > PMK_LEN) - return NULL; - - entry = os_zalloc(sizeof(*entry)); - if (entry == NULL) - return NULL; - os_memcpy(entry->pmk, pmk, pmk_len); - entry->pmk_len = pmk_len; - rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, - wpa_key_mgmt_sha256(akmp)); - os_get_reltime(&now); - entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime; - entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime * - pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100; - entry->akmp = akmp; - os_memcpy(entry->aa, aa, ETH_ALEN); - entry->network_ctx = network_ctx; - - /* Replace an old entry for the same Authenticator (if found) with the - * new entry */ - pos = pmksa->pmksa; - prev = NULL; - while (pos) { - if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) { - if (pos->pmk_len == pmk_len && - os_memcmp(pos->pmk, pmk, pmk_len) == 0 && - os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) == - 0) { - wpa_printf(MSG_DEBUG, "WPA: reusing previous " - "PMKSA entry"); - os_free(entry); - return pos; - } - if (prev == NULL) - pmksa->pmksa = pos->next; - else - prev->next = pos->next; - - /* - * 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. Only clear other entries if they have a - * matching PMK and this PMK has been used successfully - * with the current AP, i.e., if opportunistic flag has - * been cleared in wpa_supplicant_key_neg_complete(). - */ - wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for " - "the current AP and any PMKSA cache entry " - "that was based on the old PMK"); - if (!pos->opportunistic) - pmksa_cache_flush(pmksa, network_ctx, pos->pmk, - pos->pmk_len); - pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE); - break; - } - prev = pos; - pos = pos->next; - } - - if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) { - /* Remove the oldest entry to make room for the new entry */ - pos = pmksa->pmksa; - - if (pos == pmksa->sm->cur_pmksa) { - /* - * Never remove the current PMKSA cache entry, since - * it's in use, and removing it triggers a needless - * deauthentication. - */ - pos = pos->next; - pmksa->pmksa->next = pos ? pos->next : NULL; - } else - pmksa->pmksa = pos->next; - - if (pos) { - wpa_printf(MSG_DEBUG, "RSN: removed the oldest idle " - "PMKSA cache entry (for " MACSTR ") to " - "make room for new one", - MAC2STR(pos->aa)); - pmksa_cache_free_entry(pmksa, pos, PMKSA_FREE); - } - } - - /* Add the new entry; order by expiration time */ - pos = pmksa->pmksa; - prev = NULL; - while (pos) { - if (pos->expiration > entry->expiration) - break; - prev = pos; - pos = pos->next; - } - if (prev == NULL) { - entry->next = pmksa->pmksa; - pmksa->pmksa = entry; - pmksa_cache_set_expiration(pmksa); - } else { - entry->next = prev->next; - prev->next = entry; - } - pmksa->pmksa_count++; - wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR - " network_ctx=%p", MAC2STR(entry->aa), network_ctx); - wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid); - - return entry; -} - - -/** - * 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 - * @pmk: PMK to match for or %NYLL to match all PMKs - * @pmk_len: PMK length - */ -void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, - const u8 *pmk, size_t pmk_len) -{ - 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) && - (pmk == NULL || - (pmk_len == entry->pmk_len && - os_memcmp(pmk, entry->pmk, pmk_len) == 0))) { - 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, PMKSA_FREE); - 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() - */ -void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) -{ - struct rsn_pmksa_cache_entry *entry, *prev; - - if (pmksa == NULL) - return; - - entry = pmksa->pmksa; - pmksa->pmksa = NULL; - while (entry) { - prev = entry; - entry = entry->next; - os_free(prev); - } - pmksa_cache_set_expiration(pmksa); - os_free(pmksa); -} - - -/** - * pmksa_cache_get - Fetch a PMKSA cache entry - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() - * @aa: Authenticator address or %NULL to match any - * @pmkid: PMKID or %NULL to match any - * @network_ctx: Network context or %NULL to match any - * Returns: Pointer to PMKSA cache entry or %NULL if no match was found - */ -struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, - const u8 *aa, const u8 *pmkid, - const void *network_ctx) -{ - struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; - while (entry) { - if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) && - (pmkid == NULL || - os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) && - (network_ctx == NULL || network_ctx == entry->network_ctx)) - return entry; - entry = entry->next; - } - return NULL; -} - - -static struct rsn_pmksa_cache_entry * -pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, - const struct rsn_pmksa_cache_entry *old_entry, - const u8 *aa) -{ - struct rsn_pmksa_cache_entry *new_entry; - - new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, - aa, pmksa->sm->own_addr, - old_entry->network_ctx, old_entry->akmp); - if (new_entry == NULL) - return NULL; - - /* TODO: reorder entries based on expiration time? */ - new_entry->expiration = old_entry->expiration; - new_entry->opportunistic = 1; - - return new_entry; -} - - -/** - * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() - * @network_ctx: Network configuration context - * @aa: Authenticator address for the new AP - * Returns: Pointer to a new PMKSA cache entry or %NULL if not available - * - * Try to create a new PMKSA cache entry opportunistically by guessing that the - * new AP is sharing the same PMK as another AP that has the same SSID and has - * already an entry in PMKSA cache. - */ -struct rsn_pmksa_cache_entry * -pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, - const u8 *aa) -{ - 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) { - if (entry->network_ctx == network_ctx) { - entry = pmksa_cache_clone_entry(pmksa, entry, aa); - if (entry) { - wpa_printf(MSG_DEBUG, "RSN: added " - "opportunistic PMKSA cache entry " - "for " MACSTR, MAC2STR(aa)); - } - return entry; - } - entry = entry->next; - } - return NULL; -} - - -/** - * pmksa_cache_get_current - Get the current used PMKSA entry - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * Returns: Pointer to the current PMKSA cache entry or %NULL if not available - */ -struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm) -{ - if (sm == NULL) - return NULL; - return sm->cur_pmksa; -} - - -/** - * pmksa_cache_clear_current - Clear the current PMKSA entry selection - * @sm: Pointer to WPA state machine data from wpa_sm_init() - */ -void pmksa_cache_clear_current(struct wpa_sm *sm) -{ - if (sm == NULL) - return; - sm->cur_pmksa = NULL; -} - - -/** - * pmksa_cache_set_current - Set the current PMKSA entry selection - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @pmkid: PMKID for selecting PMKSA or %NULL if not used - * @bssid: BSSID for PMKSA or %NULL if not used - * @network_ctx: Network configuration context - * @try_opportunistic: Whether to allow opportunistic PMKSA caching - * Returns: 0 if PMKSA was found or -1 if no matching entry was found - */ -int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, - const u8 *bssid, void *network_ctx, - int try_opportunistic) -{ - struct rsn_pmksa_cache *pmksa = sm->pmksa; - wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p " - "try_opportunistic=%d", network_ctx, try_opportunistic); - if (pmkid) - wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID", - pmkid, PMKID_LEN); - if (bssid) - wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR, - MAC2STR(bssid)); - - sm->cur_pmksa = NULL; - if (pmkid) - sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid, - network_ctx); - if (sm->cur_pmksa == NULL && bssid) - sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL, - network_ctx); - if (sm->cur_pmksa == NULL && try_opportunistic && bssid) - sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, - network_ctx, - bssid); - if (sm->cur_pmksa) { - wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID", - sm->cur_pmksa->pmkid, PMKID_LEN); - return 0; - } - wpa_printf(MSG_DEBUG, "RSN: No PMKSA cache entry found"); - return -1; -} - - -/** - * pmksa_cache_list - Dump text list of entries in PMKSA cache - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() - * @buf: Buffer for the list - * @len: Length of the buffer - * Returns: number of bytes written to buffer - * - * This function is used to generate a text format representation of the - * current PMKSA cache contents for the ctrl_iface PMKSA command. - */ -int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) -{ - int i, ret; - char *pos = buf; - struct rsn_pmksa_cache_entry *entry; - struct os_reltime now; - - os_get_reltime(&now); - ret = os_snprintf(pos, buf + len - pos, - "Index / AA / PMKID / expiration (in seconds) / " - "opportunistic\n"); - if (ret < 0 || ret >= buf + len - pos) - return pos - buf; - pos += ret; - i = 0; - entry = pmksa->pmksa; - while (entry) { - i++; - ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ", - i, MAC2STR(entry->aa)); - if (ret < 0 || ret >= buf + len - pos) - return pos - buf; - pos += ret; - pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid, - PMKID_LEN); - ret = os_snprintf(pos, buf + len - pos, " %d %d\n", - (int) (entry->expiration - now.sec), - entry->opportunistic); - if (ret < 0 || ret >= buf + len - pos) - return pos - buf; - pos += ret; - entry = entry->next; - } - return pos - buf; -} - - -/** - * pmksa_cache_init - Initialize PMKSA cache - * @free_cb: Callback function to be called when a PMKSA cache entry is freed - * @ctx: Context pointer for free_cb function - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * Returns: Pointer to PMKSA cache data or %NULL on failure - */ -struct rsn_pmksa_cache * -pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, - void *ctx, enum pmksa_free_reason reason), - void *ctx, struct wpa_sm *sm) -{ - struct rsn_pmksa_cache *pmksa; - - pmksa = os_zalloc(sizeof(*pmksa)); - if (pmksa) { - pmksa->free_cb = free_cb; - pmksa->ctx = ctx; - pmksa->sm = sm; - } - - return pmksa; -} - -#endif /* IEEE8021X_EAPOL */ diff --git a/contrib/hostapd/src/rsn_supp/pmksa_cache.h b/contrib/hostapd/src/rsn_supp/pmksa_cache.h deleted file mode 100644 index 6cbf89aa43..0000000000 --- a/contrib/hostapd/src/rsn_supp/pmksa_cache.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * wpa_supplicant - WPA2/RSN PMKSA cache functions - * Copyright (c) 2003-2009, 2011-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef PMKSA_CACHE_H -#define PMKSA_CACHE_H - -/** - * struct rsn_pmksa_cache_entry - PMKSA cache entry - */ -struct rsn_pmksa_cache_entry { - struct rsn_pmksa_cache_entry *next; - u8 pmkid[PMKID_LEN]; - u8 pmk[PMK_LEN]; - size_t pmk_len; - os_time_t expiration; - int akmp; /* WPA_KEY_MGMT_* */ - u8 aa[ETH_ALEN]; - - os_time_t reauth_time; - - /** - * network_ctx - Network configuration context - * - * This field is only used to match PMKSA cache entries to a specific - * network configuration (e.g., a specific SSID and security policy). - * This can be a pointer to the configuration entry, but PMKSA caching - * code does not dereference the value and this could be any kind of - * identifier. - */ - void *network_ctx; - int opportunistic; -}; - -struct rsn_pmksa_cache; - -enum pmksa_free_reason { - PMKSA_FREE, - PMKSA_REPLACE, - PMKSA_EXPIRE, -}; - -#ifdef IEEE8021X_EAPOL - -struct rsn_pmksa_cache * -pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, - void *ctx, enum pmksa_free_reason reason), - void *ctx, struct wpa_sm *sm); -void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa); -struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, - const u8 *aa, const u8 *pmkid, - const void *network_ctx); -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); -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, - const u8 *bssid, void *network_ctx, - int try_opportunistic); -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, - const u8 *pmk, size_t pmk_len); - -#else /* IEEE8021X_EAPOL */ - -static inline struct rsn_pmksa_cache * -pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, - void *ctx, enum pmksa_free_reason reason), - void *ctx, struct wpa_sm *sm) -{ - return (void *) -1; -} - -static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) -{ -} - -static inline struct rsn_pmksa_cache_entry * -pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid, - const void *network_ctx) -{ - return NULL; -} - -static inline struct rsn_pmksa_cache_entry * -pmksa_cache_get_current(struct wpa_sm *sm) -{ - return NULL; -} - -static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, - size_t len) -{ - return -1; -} - -static inline 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) -{ - return NULL; -} - -static inline void pmksa_cache_clear_current(struct wpa_sm *sm) -{ -} - -static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, - const u8 *bssid, - void *network_ctx, - int try_opportunistic) -{ - return -1; -} - -static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, - void *network_ctx, - const u8 *pmk, size_t pmk_len) -{ -} - -#endif /* IEEE8021X_EAPOL */ - -#endif /* PMKSA_CACHE_H */ diff --git a/contrib/hostapd/src/rsn_supp/preauth.c b/contrib/hostapd/src/rsn_supp/preauth.c deleted file mode 100644 index 915f85e70e..0000000000 --- a/contrib/hostapd/src/rsn_supp/preauth.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * RSN pre-authentication (supplicant) - * Copyright (c) 2003-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "wpa.h" -#include "eloop.h" -#include "l2_packet/l2_packet.h" -#include "eapol_supp/eapol_supp_sm.h" -#include "preauth.h" -#include "pmksa_cache.h" -#include "wpa_i.h" - - -#ifdef IEEE8021X_EAPOL - -#define PMKID_CANDIDATE_PRIO_SCAN 1000 - - -struct rsn_pmksa_candidate { - struct dl_list list; - u8 bssid[ETH_ALEN]; - int priority; -}; - - -/** - * pmksa_candidate_free - Free all entries in PMKSA candidate list - * @sm: Pointer to WPA state machine data from wpa_sm_init() - */ -void pmksa_candidate_free(struct wpa_sm *sm) -{ - struct rsn_pmksa_candidate *entry, *n; - - if (sm == NULL) - return; - - dl_list_for_each_safe(entry, n, &sm->pmksa_candidates, - struct rsn_pmksa_candidate, list) { - dl_list_del(&entry->list); - os_free(entry); - } -} - - -static void rsn_preauth_receive(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len) -{ - struct wpa_sm *sm = ctx; - - wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(src_addr)); - wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len); - - if (sm->preauth_eapol == NULL || - is_zero_ether_addr(sm->preauth_bssid) || - os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) { - wpa_printf(MSG_WARNING, "RSN pre-auth frame received from " - "unexpected source " MACSTR " - dropped", - MAC2STR(src_addr)); - return; - } - - eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len); -} - - -static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, - enum eapol_supp_result result, - void *ctx) -{ - struct wpa_sm *sm = ctx; - u8 pmk[PMK_LEN]; - - if (result == EAPOL_SUPP_RESULT_SUCCESS) { - int res, pmk_len; - pmk_len = PMK_LEN; - res = eapol_sm_get_key(eapol, pmk, PMK_LEN); - if (res) { - /* - * EAP-LEAP is an exception from other EAP methods: it - * uses only 16-byte PMK. - */ - res = eapol_sm_get_key(eapol, pmk, 16); - pmk_len = 16; - } - if (res == 0) { - wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from pre-auth", - pmk, pmk_len); - sm->pmk_len = pmk_len; - pmksa_cache_add(sm->pmksa, pmk, pmk_len, - sm->preauth_bssid, sm->own_addr, - sm->network_ctx, - WPA_KEY_MGMT_IEEE8021X); - } else { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "RSN: failed to get master session key from " - "pre-auth EAPOL state machines"); - result = EAPOL_SUPP_RESULT_FAILURE; - } - } - - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with " - MACSTR " %s", MAC2STR(sm->preauth_bssid), - result == EAPOL_SUPP_RESULT_SUCCESS ? "completed successfully" : - "failed"); - - rsn_preauth_deinit(sm); - rsn_preauth_candidate_process(sm); -} - - -static void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_sm *sm = eloop_ctx; - - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with " - MACSTR " timed out", MAC2STR(sm->preauth_bssid)); - rsn_preauth_deinit(sm); - rsn_preauth_candidate_process(sm); -} - - -static int rsn_preauth_eapol_send(void *ctx, int type, const u8 *buf, - size_t len) -{ - struct wpa_sm *sm = ctx; - u8 *msg; - size_t msglen; - int res; - - /* TODO: could add l2_packet_sendmsg that allows fragments to avoid - * extra copy here */ - - if (sm->l2_preauth == NULL) - return -1; - - msg = wpa_sm_alloc_eapol(sm, type, buf, len, &msglen, NULL); - if (msg == NULL) - return -1; - - wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen); - res = l2_packet_send(sm->l2_preauth, sm->preauth_bssid, - ETH_P_RSN_PREAUTH, msg, msglen); - os_free(msg); - return res; -} - - -/** - * rsn_preauth_init - Start new RSN pre-authentication - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @dst: Authenticator address (BSSID) with which to preauthenticate - * @eap_conf: Current EAP configuration - * Returns: 0 on success, -1 on another pre-authentication is in progress, - * -2 on layer 2 packet initialization failure, -3 on EAPOL state machine - * initialization failure, -4 on memory allocation failure - * - * This function request an RSN pre-authentication with a given destination - * address. This is usually called for PMKSA candidates found from scan results - * or from driver reports. In addition, ctrl_iface PREAUTH command can trigger - * pre-authentication. - */ -int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, - struct eap_peer_config *eap_conf) -{ - struct eapol_config eapol_conf; - struct eapol_ctx *ctx; - - if (sm->preauth_eapol) - return -1; - - wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, - "RSN: starting pre-authentication with " MACSTR, MAC2STR(dst)); - - sm->l2_preauth = l2_packet_init(sm->ifname, sm->own_addr, - ETH_P_RSN_PREAUTH, - rsn_preauth_receive, sm, 0); - if (sm->l2_preauth == NULL) { - wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet " - "processing for pre-authentication"); - return -2; - } - - if (sm->bridge_ifname) { - sm->l2_preauth_br = l2_packet_init(sm->bridge_ifname, - sm->own_addr, - ETH_P_RSN_PREAUTH, - rsn_preauth_receive, sm, 0); - if (sm->l2_preauth_br == NULL) { - wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 " - "packet processing (bridge) for " - "pre-authentication"); - return -2; - } - } - - ctx = os_zalloc(sizeof(*ctx)); - if (ctx == NULL) { - wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context."); - return -4; - } - ctx->ctx = sm->ctx->ctx; - ctx->msg_ctx = sm->ctx->ctx; - ctx->preauth = 1; - ctx->cb = rsn_preauth_eapol_cb; - ctx->cb_ctx = sm; - ctx->scard_ctx = sm->scard_ctx; - ctx->eapol_send = rsn_preauth_eapol_send; - ctx->eapol_send_ctx = sm; - ctx->set_config_blob = sm->ctx->set_config_blob; - ctx->get_config_blob = sm->ctx->get_config_blob; - - sm->preauth_eapol = eapol_sm_init(ctx); - if (sm->preauth_eapol == NULL) { - os_free(ctx); - wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL " - "state machines for pre-authentication"); - return -3; - } - os_memset(&eapol_conf, 0, sizeof(eapol_conf)); - eapol_conf.accept_802_1x_keys = 0; - eapol_conf.required_keys = 0; - eapol_conf.fast_reauth = sm->fast_reauth; - eapol_conf.workaround = sm->eap_workaround; - eapol_sm_notify_config(sm->preauth_eapol, eap_conf, &eapol_conf); - /* - * Use a shorter startPeriod with preauthentication since the first - * preauth EAPOL-Start frame may end up being dropped due to race - * condition in the AP between the data receive and key configuration - * after the 4-Way Handshake. - */ - eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6); - os_memcpy(sm->preauth_bssid, dst, ETH_ALEN); - - eapol_sm_notify_portValid(sm->preauth_eapol, TRUE); - /* 802.1X::portControl = Auto */ - eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE); - - eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0, - rsn_preauth_timeout, sm, NULL); - - return 0; -} - - -/** - * rsn_preauth_deinit - Abort RSN pre-authentication - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * - * This function aborts the current RSN pre-authentication (if one is started) - * and frees resources allocated for it. - */ -void rsn_preauth_deinit(struct wpa_sm *sm) -{ - if (sm == NULL || !sm->preauth_eapol) - return; - - eloop_cancel_timeout(rsn_preauth_timeout, sm, NULL); - eapol_sm_deinit(sm->preauth_eapol); - sm->preauth_eapol = NULL; - os_memset(sm->preauth_bssid, 0, ETH_ALEN); - - l2_packet_deinit(sm->l2_preauth); - sm->l2_preauth = NULL; - if (sm->l2_preauth_br) { - l2_packet_deinit(sm->l2_preauth_br); - sm->l2_preauth_br = NULL; - } -} - - -/** - * rsn_preauth_candidate_process - Process PMKSA candidates - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * - * Go through the PMKSA candidates and start pre-authentication if a candidate - * without an existing PMKSA cache entry is found. Processed candidates will be - * removed from the list. - */ -void rsn_preauth_candidate_process(struct wpa_sm *sm) -{ - struct rsn_pmksa_candidate *candidate, *n; - - if (dl_list_empty(&sm->pmksa_candidates)) - return; - - /* TODO: drop priority for old candidate entries */ - - wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: processing PMKSA candidate " - "list"); - if (sm->preauth_eapol || - sm->proto != WPA_PROTO_RSN || - wpa_sm_get_state(sm) != WPA_COMPLETED || - (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X && - sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) { - wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable " - "state for new pre-authentication"); - return; /* invalid state for new pre-auth */ - } - - dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates, - struct rsn_pmksa_candidate, list) { - struct rsn_pmksa_cache_entry *p = NULL; - p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL, NULL); - if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 && - (p == NULL || p->opportunistic)) { - wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA " - "candidate " MACSTR - " selected for pre-authentication", - MAC2STR(candidate->bssid)); - dl_list_del(&candidate->list); - rsn_preauth_init(sm, candidate->bssid, - sm->eap_conf_ctx); - os_free(candidate); - return; - } - wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA candidate " - MACSTR " does not need pre-authentication anymore", - MAC2STR(candidate->bssid)); - /* Some drivers (e.g., NDIS) expect to get notified about the - * PMKIDs again, so report the existing data now. */ - if (p) { - wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid); - } - - dl_list_del(&candidate->list); - os_free(candidate); - } - wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: no more pending PMKSA " - "candidates"); -} - - -/** - * pmksa_candidate_add - Add a new PMKSA candidate - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @bssid: BSSID (authenticator address) of the candidate - * @prio: Priority (the smaller number, the higher priority) - * @preauth: Whether the candidate AP advertises support for pre-authentication - * - * This function is used to add PMKSA candidates for RSN pre-authentication. It - * is called from scan result processing and from driver events for PMKSA - * candidates, i.e., EVENT_PMKID_CANDIDATE events to wpa_supplicant_event(). - */ -void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid, - int prio, int preauth) -{ - struct rsn_pmksa_candidate *cand, *pos; - - if (sm->network_ctx && sm->proactive_key_caching) - pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx, - bssid); - - if (!preauth) { - wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without " - "preauth flag"); - return; - } - - /* If BSSID already on candidate list, update the priority of the old - * entry. Do not override priority based on normal scan results. */ - cand = NULL; - dl_list_for_each(pos, &sm->pmksa_candidates, - struct rsn_pmksa_candidate, list) { - if (os_memcmp(pos->bssid, bssid, ETH_ALEN) == 0) { - cand = pos; - break; - } - } - - if (cand) { - dl_list_del(&cand->list); - if (prio < PMKID_CANDIDATE_PRIO_SCAN) - cand->priority = prio; - } else { - cand = os_zalloc(sizeof(*cand)); - if (cand == NULL) - return; - os_memcpy(cand->bssid, bssid, ETH_ALEN); - cand->priority = prio; - } - - /* Add candidate to the list; order by increasing priority value. i.e., - * highest priority (smallest value) first. */ - dl_list_for_each(pos, &sm->pmksa_candidates, - struct rsn_pmksa_candidate, list) { - if (cand->priority <= pos->priority) { - dl_list_add(pos->list.prev, &cand->list); - cand = NULL; - break; - } - } - if (cand) - dl_list_add_tail(&sm->pmksa_candidates, &cand->list); - - wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: added PMKSA cache " - "candidate " MACSTR " prio %d", MAC2STR(bssid), prio); - rsn_preauth_candidate_process(sm); -} - - -/* TODO: schedule periodic scans if current AP supports preauth */ - -/** - * rsn_preauth_scan_results - Start processing scan results for canditates - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * Returns: 0 if ready to process results or -1 to skip processing - * - * This functions is used to notify RSN code about start of new scan results - * processing. The actual scan results will be provided by calling - * rsn_preauth_scan_result() for each BSS if this function returned 0. - */ -int rsn_preauth_scan_results(struct wpa_sm *sm) -{ - if (sm->ssid_len == 0) - return -1; - - /* - * TODO: is it ok to free all candidates? What about the entries - * received from EVENT_PMKID_CANDIDATE? - */ - pmksa_candidate_free(sm); - - return 0; -} - - -/** - * rsn_preauth_scan_result - Processing scan result for PMKSA canditates - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * - * Add all suitable APs (Authenticators) from scan results into PMKSA - * candidate list. - */ -void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid, - const u8 *ssid, const u8 *rsn) -{ - struct wpa_ie_data ie; - struct rsn_pmksa_cache_entry *pmksa; - - if (ssid[1] != sm->ssid_len || - os_memcmp(ssid + 2, sm->ssid, sm->ssid_len) != 0) - return; /* Not for the current SSID */ - - if (os_memcmp(bssid, sm->bssid, ETH_ALEN) == 0) - return; /* Ignore current AP */ - - if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie)) - return; - - pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL); - if (pmksa && (!pmksa->opportunistic || - !(ie.capabilities & WPA_CAPABILITY_PREAUTH))) - return; - - /* Give less priority to candidates found from normal scan results. */ - pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN, - ie.capabilities & WPA_CAPABILITY_PREAUTH); -} - - -#ifdef CONFIG_CTRL_IFACE -/** - * rsn_preauth_get_status - Get pre-authentication status - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @buf: Buffer for status information - * @buflen: Maximum buffer length - * @verbose: Whether to include verbose status information - * Returns: Number of bytes written to buf. - * - * Query WPA2 pre-authentication for status information. This function fills in - * a text area with current status information. If the buffer (buf) is not - * large enough, status information will be truncated to fit the buffer. - */ -int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen, - int verbose) -{ - char *pos = buf, *end = buf + buflen; - int res, ret; - - if (sm->preauth_eapol) { - ret = os_snprintf(pos, end - pos, "Pre-authentication " - "EAPOL state machines:\n"); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - res = eapol_sm_get_status(sm->preauth_eapol, - pos, end - pos, verbose); - if (res >= 0) - pos += res; - } - - return pos - buf; -} -#endif /* CONFIG_CTRL_IFACE */ - - -/** - * rsn_preauth_in_progress - Verify whether pre-authentication is in progress - * @sm: Pointer to WPA state machine data from wpa_sm_init() - */ -int rsn_preauth_in_progress(struct wpa_sm *sm) -{ - return sm->preauth_eapol != NULL; -} - -#endif /* IEEE8021X_EAPOL */ diff --git a/contrib/hostapd/src/rsn_supp/preauth.h b/contrib/hostapd/src/rsn_supp/preauth.h deleted file mode 100644 index 277f0663b0..0000000000 --- a/contrib/hostapd/src/rsn_supp/preauth.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * wpa_supplicant - WPA2/RSN pre-authentication functions - * Copyright (c) 2003-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef PREAUTH_H -#define PREAUTH_H - -struct wpa_scan_results; - -#ifdef IEEE8021X_EAPOL - -void pmksa_candidate_free(struct wpa_sm *sm); -int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, - struct eap_peer_config *eap_conf); -void rsn_preauth_deinit(struct wpa_sm *sm); -int rsn_preauth_scan_results(struct wpa_sm *sm); -void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid, - const u8 *ssid, const u8 *rsn); -void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid, - int prio, int preauth); -void rsn_preauth_candidate_process(struct wpa_sm *sm); -int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen, - int verbose); -int rsn_preauth_in_progress(struct wpa_sm *sm); - -#else /* IEEE8021X_EAPOL */ - -static inline void pmksa_candidate_free(struct wpa_sm *sm) -{ -} - -static inline void rsn_preauth_candidate_process(struct wpa_sm *sm) -{ -} - -static inline int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, - struct eap_peer_config *eap_conf) -{ - return -1; -} - -static inline void rsn_preauth_deinit(struct wpa_sm *sm) -{ -} - -static inline int rsn_preauth_scan_results(struct wpa_sm *sm) -{ - return -1; -} - -static inline void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid, - const u8 *ssid, const u8 *rsn) -{ -} - -static inline void pmksa_candidate_add(struct wpa_sm *sm, - const u8 *bssid, - int prio, int preauth) -{ -} - -static inline int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, - size_t buflen, int verbose) -{ - return 0; -} - -static inline int rsn_preauth_in_progress(struct wpa_sm *sm) -{ - return 0; -} - -#endif /* IEEE8021X_EAPOL */ - -#endif /* PREAUTH_H */ diff --git a/contrib/hostapd/src/rsn_supp/tdls.c b/contrib/hostapd/src/rsn_supp/tdls.c deleted file mode 100644 index 8a978f7475..0000000000 --- a/contrib/hostapd/src/rsn_supp/tdls.c +++ /dev/null @@ -1,2638 +0,0 @@ -/* - * wpa_supplicant - TDLS - * Copyright (c) 2010-2011, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "utils/os.h" -#include "common/ieee802_11_defs.h" -#include "crypto/sha256.h" -#include "crypto/crypto.h" -#include "crypto/aes_wrap.h" -#include "rsn_supp/wpa.h" -#include "rsn_supp/wpa_ie.h" -#include "rsn_supp/wpa_i.h" -#include "drivers/driver.h" -#include "l2_packet/l2_packet.h" - -#ifdef CONFIG_TDLS_TESTING -#define TDLS_TESTING_LONG_FRAME BIT(0) -#define TDLS_TESTING_ALT_RSN_IE BIT(1) -#define TDLS_TESTING_DIFF_BSSID BIT(2) -#define TDLS_TESTING_SHORT_LIFETIME BIT(3) -#define TDLS_TESTING_WRONG_LIFETIME_RESP BIT(4) -#define TDLS_TESTING_WRONG_LIFETIME_CONF BIT(5) -#define TDLS_TESTING_LONG_LIFETIME BIT(6) -#define TDLS_TESTING_CONCURRENT_INIT BIT(7) -#define TDLS_TESTING_NO_TPK_EXPIRATION BIT(8) -#define TDLS_TESTING_DECLINE_RESP BIT(9) -#define TDLS_TESTING_IGNORE_AP_PROHIBIT BIT(10) -unsigned int tdls_testing = 0; -#endif /* CONFIG_TDLS_TESTING */ - -#define TPK_LIFETIME 43200 /* 12 hours */ -#define TPK_M1_RETRY_COUNT 3 -#define TPK_M1_TIMEOUT 5000 /* in milliseconds */ -#define TPK_M2_RETRY_COUNT 10 -#define TPK_M2_TIMEOUT 500 /* in milliseconds */ - -#define TDLS_MIC_LEN 16 - -#define TDLS_TIMEOUT_LEN 4 - -struct wpa_tdls_ftie { - u8 ie_type; /* FTIE */ - u8 ie_len; - u8 mic_ctrl[2]; - u8 mic[TDLS_MIC_LEN]; - u8 Anonce[WPA_NONCE_LEN]; /* Responder Nonce in TDLS */ - u8 Snonce[WPA_NONCE_LEN]; /* Initiator Nonce in TDLS */ - /* followed by optional elements */ -} STRUCT_PACKED; - -struct wpa_tdls_timeoutie { - u8 ie_type; /* Timeout IE */ - u8 ie_len; - u8 interval_type; - u8 value[TDLS_TIMEOUT_LEN]; -} STRUCT_PACKED; - -struct wpa_tdls_lnkid { - u8 ie_type; /* Link Identifier IE */ - u8 ie_len; - u8 bssid[ETH_ALEN]; - u8 init_sta[ETH_ALEN]; - u8 resp_sta[ETH_ALEN]; -} STRUCT_PACKED; - -/* TDLS frame headers as per IEEE Std 802.11z-2010 */ -struct wpa_tdls_frame { - u8 payloadtype; /* IEEE80211_TDLS_RFTYPE */ - u8 category; /* Category */ - u8 action; /* Action (enum tdls_frame_type) */ -} STRUCT_PACKED; - -static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs); -static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx); -static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer); -static void wpa_tdls_disable_peer_link(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; - unsigned int reconfig_key:1; - int initiator; /* whether this end was initiator for TDLS setup */ - u8 addr[ETH_ALEN]; /* other end MAC address */ - u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */ - u8 rnonce[WPA_NONCE_LEN]; /* Responder Nonce */ - u8 rsnie_i[TDLS_MAX_IE_LEN]; /* Initiator RSN IE */ - size_t rsnie_i_len; - u8 rsnie_p[TDLS_MAX_IE_LEN]; /* Peer RSN IE */ - size_t rsnie_p_len; - u32 lifetime; - int cipher; /* Selected cipher (WPA_CIPHER_*) */ - u8 dtoken; - - struct tpk { - u8 kck[16]; /* TPK-KCK */ - u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */ - } tpk; - int tpk_set; - int tpk_success; - int tpk_in_progress; - - struct tpk_timer { - u8 dest[ETH_ALEN]; - int count; /* Retry Count */ - int timer; /* Timeout in milliseconds */ - u8 action_code; /* TDLS frame type */ - u8 dialog_token; - u16 status_code; - 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; - - struct ieee80211_ht_capabilities *ht_capabilities; - struct ieee80211_vht_capabilities *vht_capabilities; - - u8 qos_info; - - u16 aid; - - u8 *ext_capab; - size_t ext_capab_len; - - u8 *supp_channels; - size_t supp_channels_len; - - u8 *supp_oper_classes; - size_t supp_oper_classes_len; -}; - - -static int wpa_tdls_get_privacy(struct wpa_sm *sm) -{ - /* - * Get info needed from supplicant to check if the current BSS supports - * security. Other than OPEN mode, rest are considered secured - * WEP/WPA/WPA2 hence TDLS frames are processed for TPK handshake. - */ - return sm->pairwise_cipher != WPA_CIPHER_NONE; -} - - -static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len) -{ - os_memcpy(pos, ie, ie_len); - return pos + ie_len; -} - - -static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) -{ - if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr, - 0, 0, NULL, 0, NULL, 0) < 0) { - wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from " - "the driver"); - return -1; - } - - return 0; -} - - -static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) -{ - u8 key_len; - u8 rsc[6]; - enum wpa_alg alg; - - os_memset(rsc, 0, 6); - - switch (peer->cipher) { - case WPA_CIPHER_CCMP: - alg = WPA_ALG_CCMP; - key_len = 16; - break; - case WPA_CIPHER_NONE: - wpa_printf(MSG_DEBUG, "TDLS: Pairwise Cipher Suite: " - "NONE - do not use pairwise keys"); - return -1; - default: - wpa_printf(MSG_WARNING, "TDLS: Unsupported pairwise cipher %d", - sm->pairwise_cipher); - return -1; - } - - if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1, - rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) { - wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the " - "driver"); - return -1; - } - return 0; -} - - -static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst, - u8 action_code, u8 dialog_token, - u16 status_code, const u8 *buf, size_t len) -{ - return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token, - status_code, buf, len); -} - - -static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, - u8 dialog_token, u16 status_code, - const u8 *msg, size_t msg_len) -{ - struct wpa_tdls_peer *peer; - - wpa_printf(MSG_DEBUG, "TDLS: TPK send dest=" MACSTR " action_code=%u " - "dialog_token=%u status_code=%u msg_len=%u", - MAC2STR(dest), action_code, dialog_token, status_code, - (unsigned int) msg_len); - - if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token, - status_code, msg, msg_len)) { - wpa_printf(MSG_INFO, "TDLS: Failed to send message " - "(action_code=%u)", action_code); - return -1; - } - - if (action_code == WLAN_TDLS_SETUP_CONFIRM || - 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) { - if (os_memcmp(peer->addr, dest, ETH_ALEN) == 0) - break; - } - - if (peer == NULL) { - wpa_printf(MSG_INFO, "TDLS: No matching entry found for " - "retry " MACSTR, MAC2STR(dest)); - return 0; - } - - eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); - - if (action_code == WLAN_TDLS_SETUP_RESPONSE) { - peer->sm_tmr.count = TPK_M2_RETRY_COUNT; - peer->sm_tmr.timer = TPK_M2_TIMEOUT; - } else { - peer->sm_tmr.count = TPK_M1_RETRY_COUNT; - peer->sm_tmr.timer = TPK_M1_TIMEOUT; - } - - /* Copy message to resend on timeout */ - os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN); - peer->sm_tmr.action_code = action_code; - peer->sm_tmr.dialog_token = dialog_token; - peer->sm_tmr.status_code = status_code; - peer->sm_tmr.buf_len = msg_len; - os_free(peer->sm_tmr.buf); - peer->sm_tmr.buf = os_malloc(msg_len); - if (peer->sm_tmr.buf == NULL) - return -1; - os_memcpy(peer->sm_tmr.buf, msg, msg_len); - - wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered " - "(action_code=%u)", action_code); - eloop_register_timeout(peer->sm_tmr.timer / 1000, - (peer->sm_tmr.timer % 1000) * 1000, - wpa_tdls_tpk_retry_timeout, sm, peer); - return 0; -} - - -static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer, - u16 reason_code) -{ - int ret; - - ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code); - /* disable the link after teardown was sent */ - wpa_tdls_disable_peer_link(sm, peer); - - return ret; -} - - -static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx) -{ - - struct wpa_sm *sm = eloop_ctx; - struct wpa_tdls_peer *peer = timeout_ctx; - - if (peer->sm_tmr.count) { - peer->sm_tmr.count--; - - wpa_printf(MSG_INFO, "TDLS: Retrying sending of message " - "(action_code=%u)", - peer->sm_tmr.action_code); - - if (peer->sm_tmr.buf == NULL) { - wpa_printf(MSG_INFO, "TDLS: No retry buffer available " - "for action_code=%u", - peer->sm_tmr.action_code); - eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, - peer); - return; - } - - /* resend TPK Handshake Message to Peer */ - if (wpa_tdls_send_tpk_msg(sm, peer->sm_tmr.dest, - peer->sm_tmr.action_code, - peer->sm_tmr.dialog_token, - peer->sm_tmr.status_code, - peer->sm_tmr.buf, - peer->sm_tmr.buf_len)) { - wpa_printf(MSG_INFO, "TDLS: Failed to retry " - "transmission"); - } - - eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); - eloop_register_timeout(peer->sm_tmr.timer / 1000, - (peer->sm_tmr.timer % 1000) * 1000, - wpa_tdls_tpk_retry_timeout, sm, peer); - } else { - eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); - - wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request"); - wpa_tdls_do_teardown(sm, peer, - WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); - } -} - - -static void wpa_tdls_tpk_retry_timeout_cancel(struct wpa_sm *sm, - struct wpa_tdls_peer *peer, - u8 action_code) -{ - if (action_code == peer->sm_tmr.action_code) { - wpa_printf(MSG_DEBUG, "TDLS: Retry timeout cancelled for " - "action_code=%u", action_code); - - /* Cancel Timeout registered */ - eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); - - /* free all resources meant for retry */ - os_free(peer->sm_tmr.buf); - peer->sm_tmr.buf = NULL; - - peer->sm_tmr.count = 0; - peer->sm_tmr.timer = 0; - peer->sm_tmr.buf_len = 0; - peer->sm_tmr.action_code = 0xff; - } else { - wpa_printf(MSG_INFO, "TDLS: Error in cancelling retry timeout " - "(Unknown action_code=%u)", action_code); - } -} - - -static void wpa_tdls_generate_tpk(struct wpa_tdls_peer *peer, - const u8 *own_addr, const u8 *bssid) -{ - u8 key_input[SHA256_MAC_LEN]; - const u8 *nonce[2]; - size_t len[2]; - u8 data[3 * ETH_ALEN]; - - /* IEEE Std 802.11z-2010 8.5.9.1: - * TPK-Key-Input = SHA-256(min(SNonce, ANonce) || max(SNonce, ANonce)) - */ - len[0] = WPA_NONCE_LEN; - len[1] = WPA_NONCE_LEN; - if (os_memcmp(peer->inonce, peer->rnonce, WPA_NONCE_LEN) < 0) { - nonce[0] = peer->inonce; - nonce[1] = peer->rnonce; - } else { - nonce[0] = peer->rnonce; - nonce[1] = peer->inonce; - } - wpa_hexdump(MSG_DEBUG, "TDLS: min(Nonce)", nonce[0], WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, "TDLS: max(Nonce)", nonce[1], WPA_NONCE_LEN); - sha256_vector(2, nonce, len, key_input); - wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-Key-Input", - key_input, SHA256_MAC_LEN); - - /* - * TPK-Key-Data = KDF-N_KEY(TPK-Key-Input, "TDLS PMK", - * min(MAC_I, MAC_R) || max(MAC_I, MAC_R) || BSSID || N_KEY) - * TODO: is N_KEY really included in KDF Context and if so, in which - * presentation format (little endian 16-bit?) is it used? It gets - * added by the KDF anyway.. - */ - - if (os_memcmp(own_addr, peer->addr, ETH_ALEN) < 0) { - os_memcpy(data, own_addr, ETH_ALEN); - os_memcpy(data + ETH_ALEN, peer->addr, ETH_ALEN); - } else { - os_memcpy(data, peer->addr, ETH_ALEN); - os_memcpy(data + ETH_ALEN, own_addr, ETH_ALEN); - } - os_memcpy(data + 2 * ETH_ALEN, bssid, ETH_ALEN); - wpa_hexdump(MSG_DEBUG, "TDLS: KDF Context", data, sizeof(data)); - - sha256_prf(key_input, SHA256_MAC_LEN, "TDLS PMK", data, sizeof(data), - (u8 *) &peer->tpk, sizeof(peer->tpk)); - wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-KCK", - peer->tpk.kck, sizeof(peer->tpk.kck)); - wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-TK", - peer->tpk.tk, sizeof(peer->tpk.tk)); - peer->tpk_set = 1; -} - - -/** - * wpa_tdls_ftie_mic - Calculate TDLS FTIE MIC - * @kck: TPK-KCK - * @lnkid: Pointer to the beginning of Link Identifier IE - * @rsnie: Pointer to the beginning of RSN IE used for handshake - * @timeoutie: Pointer to the beginning of Timeout IE used for handshake - * @ftie: Pointer to the beginning of FT IE - * @mic: Pointer for writing MIC - * - * Calculate MIC for TDLS frame. - */ -static int wpa_tdls_ftie_mic(const u8 *kck, u8 trans_seq, const u8 *lnkid, - const u8 *rsnie, const u8 *timeoutie, - const u8 *ftie, u8 *mic) -{ - u8 *buf, *pos; - struct wpa_tdls_ftie *_ftie; - const struct wpa_tdls_lnkid *_lnkid; - int ret; - int len = 2 * ETH_ALEN + 1 + 2 + lnkid[1] + 2 + rsnie[1] + - 2 + timeoutie[1] + 2 + ftie[1]; - buf = os_zalloc(len); - if (!buf) { - wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation"); - return -1; - } - - pos = buf; - _lnkid = (const struct wpa_tdls_lnkid *) lnkid; - /* 1) TDLS initiator STA MAC address */ - os_memcpy(pos, _lnkid->init_sta, ETH_ALEN); - pos += ETH_ALEN; - /* 2) TDLS responder STA MAC address */ - os_memcpy(pos, _lnkid->resp_sta, ETH_ALEN); - pos += ETH_ALEN; - /* 3) Transaction Sequence number */ - *pos++ = trans_seq; - /* 4) Link Identifier IE */ - os_memcpy(pos, lnkid, 2 + lnkid[1]); - pos += 2 + lnkid[1]; - /* 5) RSN IE */ - os_memcpy(pos, rsnie, 2 + rsnie[1]); - pos += 2 + rsnie[1]; - /* 6) Timeout Interval IE */ - os_memcpy(pos, timeoutie, 2 + timeoutie[1]); - pos += 2 + timeoutie[1]; - /* 7) FTIE, with the MIC field of the FTIE set to 0 */ - os_memcpy(pos, ftie, 2 + ftie[1]); - _ftie = (struct wpa_tdls_ftie *) pos; - os_memset(_ftie->mic, 0, TDLS_MIC_LEN); - pos += 2 + ftie[1]; - - wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); - wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); - ret = omac1_aes_128(kck, buf, pos - buf, mic); - os_free(buf); - wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); - return ret; -} - - -/** - * wpa_tdls_key_mic_teardown - Calculate TDLS FTIE MIC for Teardown frame - * @kck: TPK-KCK - * @trans_seq: Transaction Sequence Number (4 - Teardown) - * @rcode: Reason code for Teardown - * @dtoken: Dialog Token used for that particular link - * @lnkid: Pointer to the beginning of Link Identifier IE - * @ftie: Pointer to the beginning of FT IE - * @mic: Pointer for writing MIC - * - * Calculate MIC for TDLS frame. - */ -static int wpa_tdls_key_mic_teardown(const u8 *kck, u8 trans_seq, u16 rcode, - u8 dtoken, const u8 *lnkid, - const u8 *ftie, u8 *mic) -{ - u8 *buf, *pos; - struct wpa_tdls_ftie *_ftie; - int ret; - int len; - - if (lnkid == NULL) - return -1; - - len = 2 + lnkid[1] + sizeof(rcode) + sizeof(dtoken) + - sizeof(trans_seq) + 2 + ftie[1]; - - buf = os_zalloc(len); - if (!buf) { - wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation"); - return -1; - } - - pos = buf; - /* 1) Link Identifier IE */ - os_memcpy(pos, lnkid, 2 + lnkid[1]); - pos += 2 + lnkid[1]; - /* 2) Reason Code */ - WPA_PUT_LE16(pos, rcode); - pos += sizeof(rcode); - /* 3) Dialog token */ - *pos++ = dtoken; - /* 4) Transaction Sequence number */ - *pos++ = trans_seq; - /* 7) FTIE, with the MIC field of the FTIE set to 0 */ - os_memcpy(pos, ftie, 2 + ftie[1]); - _ftie = (struct wpa_tdls_ftie *) pos; - os_memset(_ftie->mic, 0, TDLS_MIC_LEN); - pos += 2 + ftie[1]; - - wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); - wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); - ret = omac1_aes_128(kck, buf, pos - buf, mic); - os_free(buf); - wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); - return ret; -} - - -static int wpa_supplicant_verify_tdls_mic(u8 trans_seq, - struct wpa_tdls_peer *peer, - const u8 *lnkid, const u8 *timeoutie, - const struct wpa_tdls_ftie *ftie) -{ - u8 mic[16]; - - if (peer->tpk_set) { - wpa_tdls_ftie_mic(peer->tpk.kck, trans_seq, lnkid, - peer->rsnie_p, timeoutie, (u8 *) ftie, - mic); - if (os_memcmp(mic, ftie->mic, 16) != 0) { - wpa_printf(MSG_INFO, "TDLS: Invalid MIC in FTIE - " - "dropping packet"); - wpa_hexdump(MSG_DEBUG, "TDLS: Received MIC", - ftie->mic, 16); - wpa_hexdump(MSG_DEBUG, "TDLS: Calculated MIC", - mic, 16); - return -1; - } - } else { - wpa_printf(MSG_WARNING, "TDLS: Could not verify TDLS MIC, " - "TPK not set - dropping packet"); - return -1; - } - return 0; -} - - -static int wpa_supplicant_verify_tdls_mic_teardown( - u8 trans_seq, u16 rcode, u8 dtoken, struct wpa_tdls_peer *peer, - const u8 *lnkid, const struct wpa_tdls_ftie *ftie) -{ - u8 mic[16]; - - if (peer->tpk_set) { - wpa_tdls_key_mic_teardown(peer->tpk.kck, trans_seq, rcode, - dtoken, lnkid, (u8 *) ftie, mic); - if (os_memcmp(mic, ftie->mic, 16) != 0) { - wpa_printf(MSG_INFO, "TDLS: Invalid MIC in Teardown - " - "dropping packet"); - return -1; - } - } else { - wpa_printf(MSG_INFO, "TDLS: Could not verify TDLS Teardown " - "MIC, TPK not set - dropping packet"); - return -1; - } - return 0; -} - - -static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_sm *sm = eloop_ctx; - struct wpa_tdls_peer *peer = timeout_ctx; - - /* - * On TPK lifetime expiration, we have an option of either tearing down - * the direct link or trying to re-initiate it. The selection of what - * to do is not strictly speaking controlled by our role in the expired - * link, but for now, use that to select whether to renew or tear down - * the link. - */ - - if (peer->initiator) { - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR - " - try to renew", MAC2STR(peer->addr)); - wpa_tdls_start(sm, peer->addr); - } else { - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR - " - tear down", MAC2STR(peer->addr)); - wpa_tdls_do_teardown(sm, peer, - WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); - } -} - - -static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer) -{ - wpa_printf(MSG_DEBUG, "TDLS: Clear state for peer " MACSTR, - MAC2STR(peer->addr)); - eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); - eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); - peer->reconfig_key = 0; - peer->initiator = 0; - peer->tpk_in_progress = 0; - os_free(peer->sm_tmr.buf); - peer->sm_tmr.buf = NULL; - os_free(peer->ht_capabilities); - peer->ht_capabilities = NULL; - os_free(peer->vht_capabilities); - peer->vht_capabilities = NULL; - os_free(peer->ext_capab); - peer->ext_capab = NULL; - os_free(peer->supp_channels); - peer->supp_channels = NULL; - os_free(peer->supp_oper_classes); - peer->supp_oper_classes = NULL; - peer->rsnie_i_len = peer->rsnie_p_len = 0; - peer->cipher = 0; - peer->tpk_set = peer->tpk_success = 0; - os_memset(&peer->tpk, 0, sizeof(peer->tpk)); - os_memset(peer->inonce, 0, WPA_NONCE_LEN); - os_memset(peer->rnonce, 0, WPA_NONCE_LEN); -} - - -static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer, - struct wpa_tdls_lnkid *lnkid) -{ - lnkid->ie_type = WLAN_EID_LINK_ID; - lnkid->ie_len = 3 * ETH_ALEN; - os_memcpy(lnkid->bssid, sm->bssid, ETH_ALEN); - if (peer->initiator) { - os_memcpy(lnkid->init_sta, sm->own_addr, ETH_ALEN); - os_memcpy(lnkid->resp_sta, peer->addr, ETH_ALEN); - } else { - os_memcpy(lnkid->init_sta, peer->addr, ETH_ALEN); - os_memcpy(lnkid->resp_sta, sm->own_addr, ETH_ALEN); - } -} - - -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; - struct wpa_tdls_lnkid lnkid; - u8 dialog_token; - u8 *rbuf, *pos; - int ielen; - - if (sm->tdls_disabled || !sm->tdls_supported) - return -1; - - /* Find the node and free from the list */ - for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) - break; - } - - if (peer == NULL) { - wpa_printf(MSG_INFO, "TDLS: No matching entry found for " - "Teardown " MACSTR, MAC2STR(addr)); - return 0; - } - - dialog_token = peer->dtoken; - - wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR, - MAC2STR(addr)); - - ielen = 0; - if (wpa_tdls_get_privacy(sm) && peer->tpk_set && peer->tpk_success) { - /* To add FTIE for Teardown request and compute MIC */ - ielen += sizeof(*ftie); -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) - ielen += 170; -#endif /* CONFIG_TDLS_TESTING */ - } - - rbuf = os_zalloc(ielen + 1); - if (rbuf == NULL) - return -1; - pos = rbuf; - - if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) - goto skip_ies; - - ftie = (struct wpa_tdls_ftie *) pos; - ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; - /* Using the recent nonce which should be for CONFIRM frame */ - os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); - os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); - ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; - pos = (u8 *) (ftie + 1); -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " - "FTIE"); - 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, pos - (u8 *) ftie); - - /* compute MIC before sending */ - wpa_tdls_linkid(sm, peer, &lnkid); - wpa_tdls_key_mic_teardown(peer->tpk.kck, 4, reason_code, - dialog_token, (u8 *) &lnkid, (u8 *) ftie, - ftie->mic); - -skip_ies: - /* TODO: register for a Timeout handler, if Teardown is not received at - * the other end, then try again another time */ - - /* request driver to send Teardown using this FTIE */ - wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0, - reason_code, rbuf, pos - rbuf); - os_free(rbuf); - - /* clear the Peerkey statemachine */ - wpa_tdls_peer_free(sm, peer); - - return 0; -} - - -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); -} - - -static void wpa_tdls_disable_peer_link(struct wpa_sm *sm, - struct wpa_tdls_peer *peer) -{ - wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); - wpa_tdls_peer_free(sm, peer); -} - - -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_tdls_disable_peer_link(sm, peer); -} - - -const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr) -{ - struct wpa_tdls_peer *peer; - - if (sm->tdls_disabled || !sm->tdls_supported) - return "disabled"; - - for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) - break; - } - - if (peer == NULL) - return "peer does not exist"; - - if (!peer->tpk_success) - return "peer not connected"; - - return "connected"; -} - - -static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len) -{ - struct wpa_tdls_peer *peer = NULL; - struct wpa_tdls_ftie *ftie; - struct wpa_tdls_lnkid *lnkid; - struct wpa_eapol_ie_parse kde; - u16 reason_code; - const u8 *pos; - int ielen; - - /* Find the node and free from the list */ - 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 " - "Teardown " MACSTR, MAC2STR(src_addr)); - return 0; - } - - pos = buf; - pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; - - reason_code = WPA_GET_LE16(pos); - pos += 2; - - wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown Request from " MACSTR - " (reason code %u)", MAC2STR(src_addr), reason_code); - - ielen = len - (pos - buf); /* start of IE in buf */ - if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) { - wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in Teardown"); - return -1; - } - - if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { - wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TDLS " - "Teardown"); - return -1; - } - lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; - - if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) - goto skip_ftie; - - if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_INFO, "TDLS: No FTIE in TDLS Teardown"); - return -1; - } - - ftie = (struct wpa_tdls_ftie *) kde.ftie; - - /* Process MIC check to see if TDLS Teardown is right */ - if (wpa_supplicant_verify_tdls_mic_teardown(4, reason_code, - peer->dtoken, peer, - (u8 *) lnkid, ftie) < 0) { - wpa_printf(MSG_DEBUG, "TDLS: MIC failure for TDLS " - "Teardown Request from " MACSTR, MAC2STR(src_addr)); - return -1; - } - -skip_ftie: - /* - * Request the driver to disable the direct link and clear associated - * keys. - */ - wpa_tdls_disable_peer_link(sm, peer); - return 0; -} - - -/** - * wpa_tdls_send_error - To send suitable TDLS status response with - * appropriate status code mentioning reason for error/failure. - * @dst - MAC addr of Peer station - * @tdls_action - TDLS frame type for which error code is sent - * @status - status code mentioning reason - */ - -static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst, - u8 tdls_action, u8 dialog_token, u16 status) -{ - wpa_printf(MSG_DEBUG, "TDLS: Sending error to " MACSTR - " (action=%u status=%u)", - MAC2STR(dst), tdls_action, status); - return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status, - NULL, 0); -} - - -static struct wpa_tdls_peer * -wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr, int *existing) -{ - struct wpa_tdls_peer *peer; - - if (existing) - *existing = 0; - for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) { - if (existing) - *existing = 1; - return peer; /* re-use existing entry */ - } - } - - 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) -{ - size_t buf_len; - struct wpa_tdls_timeoutie timeoutie; - u16 rsn_capab; - struct wpa_tdls_ftie *ftie; - u8 *rbuf, *pos, *count_pos; - u16 count; - struct rsn_ie_hdr *hdr; - int status; - - if (!wpa_tdls_get_privacy(sm)) { - wpa_printf(MSG_DEBUG, "TDLS: No security used on the link"); - peer->rsnie_i_len = 0; - goto skip_rsnie; - } - - /* - * TPK Handshake Message 1: - * FTIE: ANonce=0, SNonce=initiator nonce MIC=0, DataKDs=(RSNIE_I, - * Timeout Interval IE)) - */ - - /* Filling RSN IE */ - hdr = (struct rsn_ie_hdr *) peer->rsnie_i; - hdr->elem_id = WLAN_EID_RSN; - WPA_PUT_LE16(hdr->version, RSN_VERSION); - - pos = (u8 *) (hdr + 1); - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); - pos += RSN_SELECTOR_LEN; - count_pos = pos; - pos += 2; - - count = 0; - - /* - * AES-CCMP is the default Encryption preferred for TDLS, so - * RSN IE is filled only with CCMP CIPHER - * Note: TKIP is not used to encrypt TDLS link. - * - * Regardless of the cipher used on the AP connection, select CCMP - * here. - */ - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); - pos += RSN_SELECTOR_LEN; - count++; - - WPA_PUT_LE16(count_pos, count); - - WPA_PUT_LE16(pos, 1); - pos += 2; - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE); - pos += RSN_SELECTOR_LEN; - - rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; - rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) { - wpa_printf(MSG_DEBUG, "TDLS: Use alternative RSN IE for " - "testing"); - rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; - } -#endif /* CONFIG_TDLS_TESTING */ - WPA_PUT_LE16(pos, rsn_capab); - pos += 2; -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) { - /* Number of PMKIDs */ - *pos++ = 0x00; - *pos++ = 0x00; - } -#endif /* CONFIG_TDLS_TESTING */ - - hdr->len = (pos - peer->rsnie_i) - 2; - peer->rsnie_i_len = pos - peer->rsnie_i; - wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake", - peer->rsnie_i, peer->rsnie_i_len); - -skip_rsnie: - buf_len = 0; - if (wpa_tdls_get_privacy(sm)) - buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + - sizeof(struct wpa_tdls_timeoutie); -#ifdef CONFIG_TDLS_TESTING - if (wpa_tdls_get_privacy(sm) && - (tdls_testing & TDLS_TESTING_LONG_FRAME)) - buf_len += 170; - if (tdls_testing & TDLS_TESTING_DIFF_BSSID) - buf_len += sizeof(struct wpa_tdls_lnkid); -#endif /* CONFIG_TDLS_TESTING */ - rbuf = os_zalloc(buf_len + 1); - if (rbuf == NULL) { - wpa_tdls_peer_free(sm, peer); - return -1; - } - pos = rbuf; - - if (!wpa_tdls_get_privacy(sm)) - goto skip_ies; - - /* Initiator RSN IE */ - pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len); - - ftie = (struct wpa_tdls_ftie *) pos; - ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; - ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; - - if (os_get_random(peer->inonce, WPA_NONCE_LEN)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "TDLS: Failed to get random data for initiator Nonce"); - os_free(rbuf); - wpa_tdls_peer_free(sm, peer); - return -1; - } - wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake", - peer->inonce, WPA_NONCE_LEN); - os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); - - wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK Handshake M1", - (u8 *) ftie, sizeof(struct wpa_tdls_ftie)); - - pos = (u8 *) (ftie + 1); - -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " - "FTIE"); - ftie->ie_len += 170; - *pos++ = 255; /* FTIE subelem */ - *pos++ = 168; /* FTIE subelem length */ - pos += 168; - } -#endif /* CONFIG_TDLS_TESTING */ - - /* Lifetime */ - peer->lifetime = TPK_LIFETIME; -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_SHORT_LIFETIME) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - use short TPK " - "lifetime"); - peer->lifetime = 301; - } - if (tdls_testing & TDLS_TESTING_LONG_LIFETIME) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - use long TPK " - "lifetime"); - peer->lifetime = 0xffffffff; - } -#endif /* CONFIG_TDLS_TESTING */ - pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, - sizeof(timeoutie), peer->lifetime); - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime); - -skip_ies: - -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_DIFF_BSSID) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - use incorrect BSSID in " - "Link Identifier"); - struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos; - wpa_tdls_linkid(sm, peer, l); - l->bssid[5] ^= 0x01; - pos += sizeof(*l); - } -#endif /* CONFIG_TDLS_TESTING */ - - wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Request / TPK " - "Handshake Message 1 (peer " MACSTR ")", - MAC2STR(peer->addr)); - - status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, - 1, 0, rbuf, pos - rbuf); - os_free(rbuf); - - return status; -} - - -static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm, - const unsigned char *src_addr, u8 dtoken, - struct wpa_tdls_lnkid *lnkid, - const struct wpa_tdls_peer *peer) -{ - u8 *rbuf, *pos; - size_t buf_len; - u32 lifetime; - struct wpa_tdls_timeoutie timeoutie; - struct wpa_tdls_ftie *ftie; - int status; - - buf_len = 0; - if (wpa_tdls_get_privacy(sm)) { - /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce), - * Lifetime */ - buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + - sizeof(struct wpa_tdls_timeoutie); -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) - buf_len += 170; -#endif /* CONFIG_TDLS_TESTING */ - } - - rbuf = os_zalloc(buf_len + 1); - if (rbuf == NULL) - return -1; - pos = rbuf; - - if (!wpa_tdls_get_privacy(sm)) - goto skip_ies; - - /* Peer RSN IE */ - pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len); - - ftie = (struct wpa_tdls_ftie *) pos; - ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; - /* TODO: ftie->mic_control to set 2-RESPONSE */ - os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); - os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); - ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; - wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK M2", - (u8 *) ftie, sizeof(*ftie)); - - pos = (u8 *) (ftie + 1); - -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " - "FTIE"); - ftie->ie_len += 170; - *pos++ = 255; /* FTIE subelem */ - *pos++ = 168; /* FTIE subelem length */ - pos += 168; - } -#endif /* CONFIG_TDLS_TESTING */ - - /* Lifetime */ - lifetime = peer->lifetime; -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_RESP) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK " - "lifetime in response"); - lifetime++; - } -#endif /* CONFIG_TDLS_TESTING */ - pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, - sizeof(timeoutie), lifetime); - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds from initiator", - lifetime); - - /* compute MIC before sending */ - wpa_tdls_ftie_mic(peer->tpk.kck, 2, (u8 *) lnkid, peer->rsnie_p, - (u8 *) &timeoutie, (u8 *) ftie, ftie->mic); - -skip_ies: - status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, - dtoken, 0, rbuf, pos - rbuf); - os_free(rbuf); - - return status; -} - - -static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm, - const unsigned char *src_addr, u8 dtoken, - struct wpa_tdls_lnkid *lnkid, - const struct wpa_tdls_peer *peer) -{ - u8 *rbuf, *pos; - size_t buf_len; - struct wpa_tdls_ftie *ftie; - struct wpa_tdls_timeoutie timeoutie; - u32 lifetime; - int status; - - buf_len = 0; - if (wpa_tdls_get_privacy(sm)) { - /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce), - * Lifetime */ - buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + - sizeof(struct wpa_tdls_timeoutie); -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) - buf_len += 170; -#endif /* CONFIG_TDLS_TESTING */ - } - - rbuf = os_zalloc(buf_len + 1); - if (rbuf == NULL) - return -1; - pos = rbuf; - - if (!wpa_tdls_get_privacy(sm)) - goto skip_ies; - - /* Peer RSN IE */ - pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len); - - ftie = (struct wpa_tdls_ftie *) pos; - ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; - /*TODO: ftie->mic_control to set 3-CONFIRM */ - os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); - os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); - ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; - - pos = (u8 *) (ftie + 1); - -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " - "FTIE"); - ftie->ie_len += 170; - *pos++ = 255; /* FTIE subelem */ - *pos++ = 168; /* FTIE subelem length */ - pos += 168; - } -#endif /* CONFIG_TDLS_TESTING */ - - /* Lifetime */ - lifetime = peer->lifetime; -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_CONF) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK " - "lifetime in confirm"); - lifetime++; - } -#endif /* CONFIG_TDLS_TESTING */ - pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, - sizeof(timeoutie), lifetime); - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", - lifetime); - - /* compute MIC before sending */ - wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p, - (u8 *) &timeoutie, (u8 *) ftie, ftie->mic); - -skip_ies: - status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, - dtoken, 0, rbuf, pos - rbuf); - os_free(rbuf); - - return status; -} - - -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, NULL); - 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 = merge_byte_arrays( - peer->supp_rates, sizeof(peer->supp_rates), - kde->supp_rates + 2, kde->supp_rates_len - 2, - kde->ext_supp_rates ? kde->ext_supp_rates + 2 : NULL, - kde->ext_supp_rates_len - 2); - return 0; -} - - -static int copy_peer_ht_capab(const struct wpa_eapol_ie_parse *kde, - struct wpa_tdls_peer *peer) -{ - if (!kde->ht_capabilities || - kde->ht_capabilities_len < - sizeof(struct ieee80211_ht_capabilities) ) { - wpa_printf(MSG_DEBUG, "TDLS: No supported ht capabilities " - "received"); - return 0; - } - - if (!peer->ht_capabilities) { - peer->ht_capabilities = - os_zalloc(sizeof(struct ieee80211_ht_capabilities)); - if (peer->ht_capabilities == NULL) - return -1; - } - - os_memcpy(peer->ht_capabilities, kde->ht_capabilities, - sizeof(struct ieee80211_ht_capabilities)); - wpa_hexdump(MSG_DEBUG, "TDLS: Peer HT capabilities", - (u8 *) peer->ht_capabilities, - sizeof(struct ieee80211_ht_capabilities)); - - return 0; -} - - -static int copy_peer_vht_capab(const struct wpa_eapol_ie_parse *kde, - struct wpa_tdls_peer *peer) -{ - if (!kde->vht_capabilities || - kde->vht_capabilities_len < - sizeof(struct ieee80211_vht_capabilities) ) { - wpa_printf(MSG_DEBUG, "TDLS: No supported vht capabilities " - "received"); - return 0; - } - - if (!peer->vht_capabilities) { - peer->vht_capabilities = - os_zalloc(sizeof(struct ieee80211_vht_capabilities)); - if (peer->vht_capabilities == NULL) - return -1; - } - - os_memcpy(peer->vht_capabilities, kde->vht_capabilities, - sizeof(struct ieee80211_vht_capabilities)); - wpa_hexdump(MSG_DEBUG, "TDLS: Peer VHT capabilities", - (u8 *) peer->vht_capabilities, - sizeof(struct ieee80211_vht_capabilities)); - - return 0; -} - - -static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde, - struct wpa_tdls_peer *peer) -{ - if (!kde->ext_capab) { - wpa_printf(MSG_DEBUG, "TDLS: No extended capabilities " - "received"); - return 0; - } - - if (!peer->ext_capab || peer->ext_capab_len < kde->ext_capab_len - 2) { - /* Need to allocate buffer to fit the new information */ - os_free(peer->ext_capab); - peer->ext_capab = os_zalloc(kde->ext_capab_len - 2); - if (peer->ext_capab == NULL) - return -1; - } - - peer->ext_capab_len = kde->ext_capab_len - 2; - os_memcpy(peer->ext_capab, kde->ext_capab + 2, peer->ext_capab_len); - - return 0; -} - - -static int copy_peer_supp_channels(const struct wpa_eapol_ie_parse *kde, - struct wpa_tdls_peer *peer) -{ - if (!kde->supp_channels) { - wpa_printf(MSG_DEBUG, "TDLS: No supported channels received"); - return 0; - } - - if (!peer->supp_channels || - peer->supp_channels_len < kde->supp_channels_len) { - os_free(peer->supp_channels); - peer->supp_channels = os_zalloc(kde->supp_channels_len); - if (peer->supp_channels == NULL) - return -1; - } - - peer->supp_channels_len = kde->supp_channels_len; - - os_memcpy(peer->supp_channels, kde->supp_channels, - peer->supp_channels_len); - wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Channels", - (u8 *) peer->supp_channels, peer->supp_channels_len); - return 0; -} - - -static int copy_peer_supp_oper_classes(const struct wpa_eapol_ie_parse *kde, - struct wpa_tdls_peer *peer) -{ - if (!kde->supp_oper_classes) { - wpa_printf(MSG_DEBUG, "TDLS: No supported operating classes received"); - return 0; - } - - if (!peer->supp_oper_classes || - peer->supp_oper_classes_len < kde->supp_oper_classes_len) { - os_free(peer->supp_oper_classes); - peer->supp_oper_classes = os_zalloc(kde->supp_oper_classes_len); - if (peer->supp_oper_classes == NULL) - return -1; - } - - peer->supp_oper_classes_len = kde->supp_oper_classes_len; - os_memcpy(peer->supp_oper_classes, kde->supp_oper_classes, - peer->supp_oper_classes_len); - wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Operating Classes", - (u8 *) peer->supp_oper_classes, - peer->supp_oper_classes_len); - return 0; -} - - -static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len) -{ - struct wpa_tdls_peer *peer; - struct wpa_eapol_ie_parse kde; - struct wpa_ie_data ie; - int cipher; - const u8 *cpos; - struct wpa_tdls_ftie *ftie = NULL; - struct wpa_tdls_timeoutie *timeoutie; - struct wpa_tdls_lnkid *lnkid; - u32 lifetime = 0; -#if 0 - struct rsn_ie_hdr *hdr; - u8 *pos; - u16 rsn_capab; - u16 rsn_ver; -#endif - u8 dtoken; - u16 ielen; - u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE; - int tdls_prohibited = sm->tdls_prohibited; - int existing_peer = 0; - - if (len < 3 + 3) - return -1; - - cpos = buf; - cpos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; - - /* driver had already verified the frame format */ - dtoken = *cpos++; /* dialog token */ - - wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken); - - peer = wpa_tdls_add_peer(sm, src_addr, &existing_peer); - if (peer == NULL) - goto error; - - /* If found, use existing entry instead of adding a new one; - * how to handle the case where both ends initiate at the - * same time? */ - if (existing_peer) { - if (peer->tpk_success) { - wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while " - "direct link is enabled - tear down the " - "old link first"); - wpa_tdls_disable_peer_link(sm, peer); - } - - /* - * An entry is already present, so check if we already sent a - * TDLS Setup Request. If so, compare MAC addresses and let the - * STA with the lower MAC address continue as the initiator. - * The other negotiation is terminated. - */ - if (peer->initiator) { - if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) { - wpa_printf(MSG_DEBUG, "TDLS: Discard request " - "from peer with higher address " - MACSTR, MAC2STR(src_addr)); - return -1; - } else { - wpa_printf(MSG_DEBUG, "TDLS: Accept request " - "from peer with lower address " - MACSTR " (terminate previously " - "initiated negotiation", - MAC2STR(src_addr)); - wpa_tdls_disable_peer_link(sm, peer); - } - } - } - - /* 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) { - wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M1"); - goto error; - } - - if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { - wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in " - "TPK M1"); - goto error; - } - wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M1", - kde.lnkid, kde.lnkid_len); - lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; - if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS"); - status = WLAN_STATUS_NOT_IN_SAME_BSS; - goto error; - } - - wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR, - MAC2STR(src_addr)); - - if (copy_supp_rates(&kde, peer) < 0) - goto error; - - if (copy_peer_ht_capab(&kde, peer) < 0) - goto error; - - if (copy_peer_vht_capab(&kde, peer) < 0) - goto error; - - if (copy_peer_ext_capab(&kde, peer) < 0) - goto error; - - if (copy_peer_supp_channels(&kde, peer) < 0) - goto error; - - if (copy_peer_supp_oper_classes(&kde, peer) < 0) - goto error; - - peer->qos_info = kde.qosinfo; - - peer->aid = kde.aid; - -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) { - peer = wpa_tdls_add_peer(sm, src_addr, NULL); - if (peer == NULL) - goto error; - wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of " - "TDLS setup - send own request"); - peer->initiator = 1; - wpa_tdls_send_tpk_m1(sm, peer); - } - - if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) && - tdls_prohibited) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition " - "on TDLS"); - tdls_prohibited = 0; - } -#endif /* CONFIG_TDLS_TESTING */ - - if (tdls_prohibited) { - wpa_printf(MSG_INFO, "TDLS: TDLS prohibited in this BSS"); - status = WLAN_STATUS_REQUEST_DECLINED; - goto error; - } - - if (!wpa_tdls_get_privacy(sm)) { - if (kde.rsn_ie) { - wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M1 while " - "security is disabled"); - status = WLAN_STATUS_SECURITY_DISABLED; - goto error; - } - goto skip_rsn; - } - - if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) || - kde.rsn_ie == NULL) { - wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M1"); - status = WLAN_STATUS_INVALID_PARAMETERS; - goto error; - } - - if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) { - wpa_printf(MSG_INFO, "TDLS: Too long Initiator RSN IE in " - "TPK M1"); - status = WLAN_STATUS_INVALID_RSNIE; - goto error; - } - - if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { - wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M1"); - status = WLAN_STATUS_INVALID_RSNIE; - goto error; - } - - cipher = ie.pairwise_cipher; - if (cipher & WPA_CIPHER_CCMP) { - wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link"); - cipher = WPA_CIPHER_CCMP; - } else { - wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M1"); - status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; - goto error; - } - - if ((ie.capabilities & - (WPA_CAPABILITY_NO_PAIRWISE | WPA_CAPABILITY_PEERKEY_ENABLED)) != - WPA_CAPABILITY_PEERKEY_ENABLED) { - wpa_printf(MSG_INFO, "TDLS: Invalid RSN Capabilities in " - "TPK M1"); - status = WLAN_STATUS_INVALID_RSN_IE_CAPAB; - goto error; - } - - /* Lifetime */ - if (kde.key_lifetime == NULL) { - wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M1"); - status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; - goto error; - } - timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; - lifetime = WPA_GET_LE32(timeoutie->value); - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", lifetime); - if (lifetime < 300) { - wpa_printf(MSG_INFO, "TDLS: Too short TPK lifetime"); - status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; - goto error; - } - -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; - - if (!wpa_tdls_get_privacy(sm)) { - peer->rsnie_i_len = 0; - peer->rsnie_p_len = 0; - peer->cipher = WPA_CIPHER_NONE; - goto skip_rsn_check; - } - - ftie = (struct wpa_tdls_ftie *) kde.ftie; - os_memcpy(peer->rsnie_i, kde.rsn_ie, kde.rsn_ie_len); - peer->rsnie_i_len = kde.rsn_ie_len; - peer->cipher = cipher; - - if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) { - /* - * There is no point in updating the RNonce for every obtained - * TPK M1 frame (e.g., retransmission due to timeout) with the - * same INonce (SNonce in FTIE). However, if the TPK M1 is - * retransmitted with a different INonce, update the RNonce - * since this is for a new TDLS session. - */ - wpa_printf(MSG_DEBUG, - "TDLS: New TPK M1 INonce - generate new RNonce"); - os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN); - if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) { - wpa_msg(sm->ctx->ctx, MSG_WARNING, - "TDLS: Failed to get random data for responder nonce"); - wpa_tdls_peer_free(sm, peer); - goto error; - } - } - -#if 0 - /* get version info from RSNIE received from Peer */ - hdr = (struct rsn_ie_hdr *) kde.rsn_ie; - rsn_ver = WPA_GET_LE16(hdr->version); - - /* use min(peer's version, out version) */ - if (rsn_ver > RSN_VERSION) - rsn_ver = RSN_VERSION; - - hdr = (struct rsn_ie_hdr *) peer->rsnie_p; - - hdr->elem_id = WLAN_EID_RSN; - WPA_PUT_LE16(hdr->version, rsn_ver); - pos = (u8 *) (hdr + 1); - - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); - pos += RSN_SELECTOR_LEN; - /* Include only the selected cipher in pairwise cipher suite */ - WPA_PUT_LE16(pos, 1); - pos += 2; - if (cipher == WPA_CIPHER_CCMP) - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); - pos += RSN_SELECTOR_LEN; - - WPA_PUT_LE16(pos, 1); - pos += 2; - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE); - pos += RSN_SELECTOR_LEN; - - rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; - rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; - WPA_PUT_LE16(pos, rsn_capab); - pos += 2; - - hdr->len = (pos - peer->rsnie_p) - 2; - peer->rsnie_p_len = pos - peer->rsnie_p; -#endif - - /* temp fix: validation of RSNIE later */ - os_memcpy(peer->rsnie_p, peer->rsnie_i, peer->rsnie_i_len); - peer->rsnie_p_len = peer->rsnie_i_len; - - wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake", - peer->rsnie_p, peer->rsnie_p_len); - - peer->lifetime = lifetime; - - 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, 0, NULL, 0, NULL, NULL, 0, - NULL, 0, NULL, 0, NULL, 0); - peer->tpk_in_progress = 1; - - wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2"); - if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) { - wpa_tdls_disable_peer_link(sm, peer); - goto error; - } - - return 0; - -error: - wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, - status); - return -1; -} - - -static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer) -{ - peer->tpk_success = 1; - peer->tpk_in_progress = 0; - eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); - if (wpa_tdls_get_privacy(sm)) { - u32 lifetime = peer->lifetime; - /* - * Start the initiator process a bit earlier to avoid race - * condition with the responder sending teardown request. - */ - if (lifetime > 3 && peer->initiator) - lifetime -= 3; - eloop_register_timeout(lifetime, 0, wpa_tdls_tpk_timeout, - sm, peer); -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - disable TPK " - "expiration"); - eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); - } -#endif /* CONFIG_TDLS_TESTING */ - } - - /* add supported rates, capabilities, and qos_info to the TDLS peer */ - if (wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->aid, - peer->capability, - peer->supp_rates, peer->supp_rates_len, - peer->ht_capabilities, - peer->vht_capabilities, - peer->qos_info, peer->ext_capab, - peer->ext_capab_len, - peer->supp_channels, - peer->supp_channels_len, - peer->supp_oper_classes, - peer->supp_oper_classes_len) < 0) - return -1; - - if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) { - wpa_printf(MSG_INFO, "TDLS: Could not configure key to the " - "driver"); - return -1; - } - peer->reconfig_key = 0; - - return wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr); -} - - -static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len) -{ - struct wpa_tdls_peer *peer; - struct wpa_eapol_ie_parse kde; - struct wpa_ie_data ie; - int cipher; - struct wpa_tdls_ftie *ftie; - struct wpa_tdls_timeoutie *timeoutie; - struct wpa_tdls_lnkid *lnkid; - u32 lifetime; - u8 dtoken; - int ielen; - u16 status; - const u8 *pos; - int ret = 0; - - wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 " - "(Peer " MACSTR ")", MAC2STR(src_addr)); - 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 peer found for " - "TPK M2: " MACSTR, MAC2STR(src_addr)); - return -1; - } - if (!peer->initiator) { - /* - * This may happen if both devices try to initiate TDLS at the - * same time and we accept the TPK M1 from the peer in - * wpa_tdls_process_tpk_m1() and clear our previous state. - */ - wpa_printf(MSG_INFO, "TDLS: We were not the initiator, so " - "ignore TPK M2 from " MACSTR, MAC2STR(src_addr)); - return -1; - } - wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST); - - if (len < 3 + 2 + 1) { - wpa_tdls_disable_peer_link(sm, peer); - return -1; - } - - pos = buf; - pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; - status = WPA_GET_LE16(pos); - pos += 2 /* status code */; - - if (status != WLAN_STATUS_SUCCESS) { - wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u", - status); - wpa_tdls_disable_peer_link(sm, peer); - return -1; - } - - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - - /* TODO: need to verify dialog token matches here or in kernel */ - dtoken = *pos++; /* dialog token */ - - wpa_printf(MSG_DEBUG, "TDLS: Dialog Token in TPK M2 %d", dtoken); - - if (len < 3 + 2 + 1 + 2) { - wpa_tdls_disable_peer_link(sm, peer); - return -1; - } - - /* 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) { - wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M2"); - goto error; - } - -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_DECLINE_RESP) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - decline response"); - status = WLAN_STATUS_REQUEST_DECLINED; - goto error; - } -#endif /* CONFIG_TDLS_TESTING */ - - if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { - wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in " - "TPK M2"); - goto error; - } - wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M2", - kde.lnkid, kde.lnkid_len); - lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; - - if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_INFO, "TDLS: TPK M2 from different BSS"); - status = WLAN_STATUS_NOT_IN_SAME_BSS; - goto error; - } - - if (copy_supp_rates(&kde, peer) < 0) - goto error; - - if (copy_peer_ht_capab(&kde, peer) < 0) - goto error; - - if (copy_peer_vht_capab(&kde, peer) < 0) - goto error; - - if (copy_peer_ext_capab(&kde, peer) < 0) - goto error; - - if (copy_peer_supp_channels(&kde, peer) < 0) - goto error; - - if (copy_peer_supp_oper_classes(&kde, peer) < 0) - goto error; - - peer->qos_info = kde.qosinfo; - - peer->aid = kde.aid; - - if (!wpa_tdls_get_privacy(sm)) { - peer->rsnie_p_len = 0; - peer->cipher = WPA_CIPHER_NONE; - goto skip_rsn; - } - - if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) || - kde.rsn_ie == NULL) { - wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M2"); - status = WLAN_STATUS_INVALID_PARAMETERS; - goto error; - } - wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2", - kde.rsn_ie, kde.rsn_ie_len); - - /* - * FIX: bitwise comparison of RSN IE is not the correct way of - * validation this. It can be different, but certain fields must - * match. Since we list only a single pairwise cipher in TPK M1, the - * memcmp is likely to work in most cases, though. - */ - if (kde.rsn_ie_len != peer->rsnie_i_len || - os_memcmp(peer->rsnie_i, kde.rsn_ie, peer->rsnie_i_len) != 0) { - wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M2 does " - "not match with RSN IE used in TPK M1"); - wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Sent in TPK M1", - peer->rsnie_i, peer->rsnie_i_len); - wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2", - kde.rsn_ie, kde.rsn_ie_len); - status = WLAN_STATUS_INVALID_RSNIE; - goto error; - } - - if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { - wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M2"); - status = WLAN_STATUS_INVALID_RSNIE; - goto error; - } - - cipher = ie.pairwise_cipher; - if (cipher == WPA_CIPHER_CCMP) { - wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link"); - cipher = WPA_CIPHER_CCMP; - } else { - wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M2"); - status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; - goto error; - } - - wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M2", - kde.ftie, sizeof(*ftie)); - ftie = (struct wpa_tdls_ftie *) kde.ftie; - - if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) { - wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M2 does " - "not match with FTIE SNonce used in TPK M1"); - /* Silently discard the frame */ - return -1; - } - - /* Responder Nonce and RSN IE */ - os_memcpy(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN); - os_memcpy(peer->rsnie_p, kde.rsn_ie, kde.rsn_ie_len); - peer->rsnie_p_len = kde.rsn_ie_len; - peer->cipher = cipher; - - /* Lifetime */ - if (kde.key_lifetime == NULL) { - wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M2"); - status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; - goto error; - } - timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; - lifetime = WPA_GET_LE32(timeoutie->value); - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M2", - lifetime); - if (lifetime != peer->lifetime) { - wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in " - "TPK M2 (expected %u)", lifetime, peer->lifetime); - status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; - goto error; - } - - wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); - - /* Process MIC check to see if TPK M2 is right */ - if (wpa_supplicant_verify_tdls_mic(2, peer, (u8 *) lnkid, - (u8 *) timeoutie, ftie) < 0) { - /* Discard the frame */ - wpa_tdls_del_key(sm, peer); - wpa_tdls_disable_peer_link(sm, peer); - return -1; - } - - if (wpa_tdls_set_key(sm, peer) < 0) { - /* - * Some drivers may not be able to config the key prior to full - * STA entry having been configured. - */ - wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after " - "STA entry is complete"); - peer->reconfig_key = 1; - } - -skip_rsn: - peer->dtoken = dtoken; - - wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / " - "TPK Handshake Message 3"); - if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0) { - wpa_tdls_disable_peer_link(sm, peer); - return -1; - } - - if (!peer->tpk_success) { - /* - * Enable Link only when tpk_success is 0, signifying that this - * processing of TPK M2 frame is not because of a retransmission - * during TDLS setup handshake. - */ - ret = wpa_tdls_enable_link(sm, peer); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "TDLS: Could not enable link"); - wpa_tdls_do_teardown( - sm, peer, - WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); - } - } - return ret; - -error: - wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, - status); - wpa_tdls_disable_peer_link(sm, peer); - return -1; -} - - -static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len) -{ - struct wpa_tdls_peer *peer; - struct wpa_eapol_ie_parse kde; - struct wpa_tdls_ftie *ftie; - struct wpa_tdls_timeoutie *timeoutie; - struct wpa_tdls_lnkid *lnkid; - int ielen; - u16 status; - const u8 *pos; - u32 lifetime; - int ret = 0; - - wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 " - "(Peer " MACSTR ")", MAC2STR(src_addr)); - 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 peer found for " - "TPK M3: " MACSTR, MAC2STR(src_addr)); - return -1; - } - wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE); - - if (len < 3 + 3) - goto error; - pos = buf; - pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; - - status = WPA_GET_LE16(pos); - - if (status != 0) { - wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u", - status); - goto error; - } - pos += 2 /* status code */ + 1 /* dialog token */; - - ielen = len - (pos - buf); /* start of IE in buf */ - if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) { - wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M3"); - goto error; - } - - if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { - wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TPK M3"); - goto error; - } - wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3", - (u8 *) kde.lnkid, kde.lnkid_len); - lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; - - if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_INFO, "TDLS: TPK M3 from diff BSS"); - goto error; - } - - if (!wpa_tdls_get_privacy(sm)) - goto skip_rsn; - - if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M3"); - goto error; - } - wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3", - kde.ftie, sizeof(*ftie)); - ftie = (struct wpa_tdls_ftie *) kde.ftie; - - if (kde.rsn_ie == NULL) { - wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M3"); - goto error; - } - wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M3", - kde.rsn_ie, kde.rsn_ie_len); - if (kde.rsn_ie_len != peer->rsnie_p_len || - os_memcmp(kde.rsn_ie, peer->rsnie_p, peer->rsnie_p_len) != 0) { - wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M3 does not match " - "with the one sent in TPK M2"); - goto error; - } - - if (!os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) { - wpa_printf(MSG_INFO, "TDLS: FTIE ANonce in TPK M3 does " - "not match with FTIE ANonce used in TPK M2"); - goto error; - } - - if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) { - wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M3 does not " - "match with FTIE SNonce used in TPK M1"); - goto error; - } - - if (kde.key_lifetime == NULL) { - wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M3"); - goto error; - } - timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; - wpa_hexdump(MSG_DEBUG, "TDLS: Timeout IE Received from TPK M3", - (u8 *) timeoutie, sizeof(*timeoutie)); - lifetime = WPA_GET_LE32(timeoutie->value); - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M3", - lifetime); - if (lifetime != peer->lifetime) { - wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in " - "TPK M3 (expected %u)", lifetime, peer->lifetime); - goto error; - } - - if (wpa_supplicant_verify_tdls_mic(3, peer, (u8 *) lnkid, - (u8 *) timeoutie, ftie) < 0) { - wpa_tdls_del_key(sm, peer); - goto error; - } - - if (wpa_tdls_set_key(sm, peer) < 0) { - /* - * Some drivers may not be able to config the key prior to full - * STA entry having been configured. - */ - wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after " - "STA entry is complete"); - peer->reconfig_key = 1; - } - -skip_rsn: - if (!peer->tpk_success) { - /* - * Enable Link only when tpk_success is 0, signifying that this - * processing of TPK M3 frame is not because of a retransmission - * during TDLS setup handshake. - */ - ret = wpa_tdls_enable_link(sm, peer); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "TDLS: Could not enable link"); - wpa_tdls_do_teardown( - sm, peer, - WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); - } - } - return ret; -error: - wpa_tdls_disable_peer_link(sm, peer); - return -1; -} - - -static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs) -{ - struct wpa_tdls_timeoutie *lifetime = (struct wpa_tdls_timeoutie *) ie; - - os_memset(lifetime, 0, ie_len); - lifetime->ie_type = WLAN_EID_TIMEOUT_INTERVAL; - lifetime->ie_len = sizeof(struct wpa_tdls_timeoutie) - 2; - lifetime->interval_type = WLAN_TIMEOUT_KEY_LIFETIME; - WPA_PUT_LE32(lifetime->value, tsecs); - os_memcpy(pos, ie, ie_len); - return pos + ie_len; -} - - -/** - * wpa_tdls_start - Initiate TDLS handshake (send TPK Handshake Message 1) - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @peer: MAC address of the peer STA - * Returns: 0 on success, or -1 on failure - * - * Send TPK Handshake Message 1 info to driver to start TDLS - * handshake with the peer. - */ -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 || !sm->tdls_supported) - return -1; - -#ifdef CONFIG_TDLS_TESTING - if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) && - tdls_prohibited) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition " - "on TDLS"); - tdls_prohibited = 0; - } -#endif /* CONFIG_TDLS_TESTING */ - - if (tdls_prohibited) { - wpa_printf(MSG_DEBUG, "TDLS: TDLS is prohibited in this BSS - " - "reject request to start setup"); - return -1; - } - - peer = wpa_tdls_add_peer(sm, addr, NULL); - if (peer == NULL) - return -1; - - if (peer->tpk_in_progress) { - wpa_printf(MSG_DEBUG, "TDLS: Setup is already in progress with the peer"); - return 0; - } - - peer->initiator = 1; - - /* add the peer to the driver as a "setup in progress" peer */ - wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, - NULL, 0, NULL, 0, NULL, 0); - - peer->tpk_in_progress = 1; - - if (wpa_tdls_send_tpk_m1(sm, peer) < 0) { - wpa_tdls_disable_peer_link(sm, peer); - return -1; - } - - return 0; -} - - -void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr) -{ - struct wpa_tdls_peer *peer; - - if (sm->tdls_disabled || !sm->tdls_supported) - return; - - for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) - break; - } - - if (peer == NULL || !peer->tpk_success) - return; - - if (sm->tdls_external_setup) { - /* - * Disable previous link to allow renegotiation to be completed - * on AP path. - */ - wpa_tdls_disable_peer_link(sm, peer); - } -} - - -/** - * wpa_supplicant_rx_tdls - Receive TDLS data frame - * - * This function is called to receive TDLS (ethertype = 0x890d) data frames. - */ -static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len) -{ - struct wpa_sm *sm = ctx; - struct wpa_tdls_frame *tf; - - wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation", - buf, len); - - if (sm->tdls_disabled || !sm->tdls_supported) { - wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled " - "or unsupported by driver"); - return; - } - - if (os_memcmp(src_addr, sm->own_addr, ETH_ALEN) == 0) { - wpa_printf(MSG_DEBUG, "TDLS: Discard copy of own message"); - return; - } - - if (len < sizeof(*tf)) { - wpa_printf(MSG_INFO, "TDLS: Drop too short frame"); - return; - } - - /* Check to make sure its a valid encapsulated TDLS frame */ - tf = (struct wpa_tdls_frame *) buf; - if (tf->payloadtype != 2 /* TDLS_RFTYPE */ || - tf->category != WLAN_ACTION_TDLS) { - wpa_printf(MSG_INFO, "TDLS: Invalid frame - payloadtype=%u " - "category=%u action=%u", - tf->payloadtype, tf->category, tf->action); - return; - } - - switch (tf->action) { - case WLAN_TDLS_SETUP_REQUEST: - wpa_tdls_process_tpk_m1(sm, src_addr, buf, len); - break; - case WLAN_TDLS_SETUP_RESPONSE: - wpa_tdls_process_tpk_m2(sm, src_addr, buf, len); - break; - case WLAN_TDLS_SETUP_CONFIRM: - wpa_tdls_process_tpk_m3(sm, src_addr, buf, len); - break; - 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", - tf->action); - break; - } -} - - -/** - * wpa_tdls_init - Initialize driver interface parameters for TDLS - * @wpa_s: Pointer to wpa_supplicant data - * Returns: 0 on success, -1 on failure - * - * This function is called to initialize driver interface parameters for TDLS. - * wpa_drv_init() must have been called before this function to initialize the - * driver interface. - */ -int wpa_tdls_init(struct wpa_sm *sm) -{ - if (sm == NULL) - return -1; - - sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname : - sm->ifname, - sm->own_addr, - ETH_P_80211_ENCAP, wpa_supplicant_rx_tdls, - sm, 0); - if (sm->l2_tdls == NULL) { - wpa_printf(MSG_ERROR, "TDLS: Failed to open l2_packet " - "connection"); - 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; -} - - -void wpa_tdls_teardown_peers(struct wpa_sm *sm) -{ - struct wpa_tdls_peer *peer; - - peer = sm->tdls; - - wpa_printf(MSG_DEBUG, "TDLS: Tear down peers"); - - while (peer) { - wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR, - MAC2STR(peer->addr)); - if (sm->tdls_external_setup) - wpa_tdls_send_teardown(sm, peer->addr, - WLAN_REASON_DEAUTH_LEAVING); - else - wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr); - - peer = peer->next; - } -} - - -static void wpa_tdls_remove_peers(struct wpa_sm *sm) -{ - struct wpa_tdls_peer *peer, *tmp; - - peer = sm->tdls; - sm->tdls = NULL; - - while (peer) { - int res; - tmp = peer->next; - res = wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); - wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)", - MAC2STR(peer->addr), res); - wpa_tdls_peer_free(sm, peer); - os_free(peer); - peer = tmp; - } -} - - -/** - * wpa_tdls_deinit - Deinitialize driver interface parameters for TDLS - * - * This function is called to recover driver interface parameters for TDLS - * and frees resources allocated for it. - */ -void wpa_tdls_deinit(struct wpa_sm *sm) -{ - if (sm == NULL) - return; - - if (sm->l2_tdls) - l2_packet_deinit(sm->l2_tdls); - sm->l2_tdls = NULL; - - wpa_tdls_remove_peers(sm); -} - - -void wpa_tdls_assoc(struct wpa_sm *sm) -{ - wpa_printf(MSG_DEBUG, "TDLS: Remove peers on association"); - wpa_tdls_remove_peers(sm); -} - - -void wpa_tdls_disassoc(struct wpa_sm *sm) -{ - wpa_printf(MSG_DEBUG, "TDLS: Remove peers on disassociation"); - wpa_tdls_remove_peers(sm); -} - - -static int wpa_tdls_prohibited(const u8 *ies, size_t len) -{ - struct wpa_eapol_ie_parse elems; - - if (ies == NULL) - return 0; - - if (wpa_supplicant_parse_ies(ies, len, &elems) < 0) - return 0; - - if (elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5) - return 0; - - /* bit 38 - TDLS Prohibited */ - return !!(elems.ext_capab[2 + 4] & 0x40); -} - - -void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len) -{ - sm->tdls_prohibited = wpa_tdls_prohibited(ies, len); - wpa_printf(MSG_DEBUG, "TDLS: TDLS is %s in the target BSS", - sm->tdls_prohibited ? "prohibited" : "allowed"); -} - - -void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len) -{ - if (!sm->tdls_prohibited && wpa_tdls_prohibited(ies, len)) { - wpa_printf(MSG_DEBUG, "TDLS: TDLS prohibited based on " - "(Re)Association Response IEs"); - sm->tdls_prohibited = 1; - } -} - - -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/contrib/hostapd/src/rsn_supp/wpa.c b/contrib/hostapd/src/rsn_supp/wpa.c deleted file mode 100644 index 4474c3b117..0000000000 --- a/contrib/hostapd/src/rsn_supp/wpa.c +++ /dev/null @@ -1,2786 +0,0 @@ -/* - * WPA Supplicant - WPA state machine and EAPOL-Key processing - * Copyright (c) 2003-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/aes_wrap.h" -#include "crypto/crypto.h" -#include "crypto/random.h" -#include "common/ieee802_11_defs.h" -#include "eapol_supp/eapol_supp_sm.h" -#include "wpa.h" -#include "eloop.h" -#include "preauth.h" -#include "pmksa_cache.h" -#include "wpa_i.h" -#include "wpa_ie.h" -#include "peerkey.h" - - -/** - * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @kck: Key Confirmation Key (KCK, part of PTK) - * @ver: Version field from Key Info - * @dest: Destination address for the frame - * @proto: Ethertype (usually ETH_P_EAPOL) - * @msg: EAPOL-Key message - * @msg_len: Length of message - * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written - */ -void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, - int ver, const u8 *dest, u16 proto, - u8 *msg, size_t msg_len, u8 *key_mic) -{ - if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) { - /* - * Association event was not yet received; try to fetch - * BSSID from the driver. - */ - if (wpa_sm_get_bssid(sm, sm->bssid) < 0) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: Failed to read BSSID for " - "EAPOL-Key destination address"); - } else { - dest = sm->bssid; - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: Use BSSID (" MACSTR - ") as the destination for EAPOL-Key", - MAC2STR(dest)); - } - } - if (key_mic && - wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) { - wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, - "WPA: Failed to generate EAPOL-Key " - "version %d MIC", ver); - goto out; - } - wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16); - wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, 16); - wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len); - wpa_sm_ether_send(sm, dest, proto, msg, msg_len); - eapol_sm_notify_tx_eapol_key(sm->eapol); -out: - os_free(msg); -} - - -/** - * wpa_sm_key_request - Send EAPOL-Key Request - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @error: Indicate whether this is an Michael MIC error report - * @pairwise: 1 = error report for pairwise packet, 0 = for group packet - * - * Send an EAPOL-Key Request to the current authenticator. This function is - * used to request rekeying and it is usually called when a local Michael MIC - * failure is detected. - */ -void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) -{ - size_t rlen; - struct wpa_eapol_key *reply; - int key_info, ver; - u8 bssid[ETH_ALEN], *rbuf; - - if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt)) - ver = WPA_KEY_INFO_TYPE_AES_128_CMAC; - else if (sm->pairwise_cipher != WPA_CIPHER_TKIP) - ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; - else - ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; - - if (wpa_sm_get_bssid(sm, bssid) < 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "Failed to read BSSID for EAPOL-Key request"); - return; - } - - rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, - sizeof(*reply), &rlen, (void *) &reply); - if (rbuf == NULL) - return; - - reply->type = sm->proto == WPA_PROTO_RSN ? - EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; - key_info = WPA_KEY_INFO_REQUEST | ver; - if (sm->ptk_set) - key_info |= WPA_KEY_INFO_MIC; - if (error) - key_info |= WPA_KEY_INFO_ERROR; - if (pairwise) - key_info |= WPA_KEY_INFO_KEY_TYPE; - WPA_PUT_BE16(reply->key_info, key_info); - WPA_PUT_BE16(reply->key_length, 0); - os_memcpy(reply->replay_counter, sm->request_counter, - WPA_REPLAY_COUNTER_LEN); - inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); - - WPA_PUT_BE16(reply->key_data_length, 0); - - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Sending EAPOL-Key Request (error=%d " - "pairwise=%d ptk_set=%d len=%lu)", - error, pairwise, sm->ptk_set, (unsigned long) rlen); - wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL, - rbuf, rlen, key_info & WPA_KEY_INFO_MIC ? - reply->key_mic : NULL); -} - - -static int wpa_supplicant_get_pmk(struct wpa_sm *sm, - const unsigned char *src_addr, - const u8 *pmkid) -{ - int abort_cached = 0; - - if (pmkid && !sm->cur_pmksa) { - /* When using drivers that generate RSN IE, wpa_supplicant may - * not have enough time to get the association information - * event before receiving this 1/4 message, so try to find a - * matching PMKSA cache entry here. */ - sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid, - NULL); - if (sm->cur_pmksa) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "RSN: found matching PMKID from PMKSA cache"); - } else { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "RSN: no matching PMKID found"); - abort_cached = 1; - } - } - - if (pmkid && sm->cur_pmksa && - os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) { - wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN); - wpa_sm_set_pmk_from_pmksa(sm); - wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache", - sm->pmk, sm->pmk_len); - eapol_sm_notify_cached(sm->eapol); -#ifdef CONFIG_IEEE80211R - sm->xxkey_len = 0; -#endif /* CONFIG_IEEE80211R */ - } else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) { - int res, pmk_len; - pmk_len = PMK_LEN; - res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN); - if (res) { - /* - * EAP-LEAP is an exception from other EAP methods: it - * uses only 16-byte PMK. - */ - res = eapol_sm_get_key(sm->eapol, sm->pmk, 16); - pmk_len = 16; - } else { -#ifdef CONFIG_IEEE80211R - u8 buf[2 * PMK_LEN]; - if (eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0) - { - os_memcpy(sm->xxkey, buf + PMK_LEN, PMK_LEN); - sm->xxkey_len = PMK_LEN; - os_memset(buf, 0, sizeof(buf)); - } -#endif /* CONFIG_IEEE80211R */ - } - if (res == 0) { - struct rsn_pmksa_cache_entry *sa = NULL; - wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state " - "machines", sm->pmk, pmk_len); - sm->pmk_len = pmk_len; - if (sm->proto == WPA_PROTO_RSN && - !wpa_key_mgmt_ft(sm->key_mgmt)) { - sa = pmksa_cache_add(sm->pmksa, - sm->pmk, pmk_len, - src_addr, sm->own_addr, - sm->network_ctx, - sm->key_mgmt); - } - if (!sm->cur_pmksa && pmkid && - pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL)) - { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "RSN: the new PMK matches with the " - "PMKID"); - abort_cached = 0; - } - - if (!sm->cur_pmksa) - sm->cur_pmksa = sa; - } else { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Failed to get master session key from " - "EAPOL state machines - key handshake " - "aborted"); - if (sm->cur_pmksa) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "RSN: Cancelled PMKSA caching " - "attempt"); - sm->cur_pmksa = NULL; - abort_cached = 1; - } else if (!abort_cached) { - return -1; - } - } - } - - if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && - !wpa_key_mgmt_ft(sm->key_mgmt)) { - /* Send EAPOL-Start to trigger full EAP authentication. */ - u8 *buf; - size_t buflen; - - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "RSN: no PMKSA entry found - trigger " - "full EAP authentication"); - buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START, - NULL, 0, &buflen, NULL); - if (buf) { - wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL, - buf, buflen); - os_free(buf); - return -2; - } - - return -1; - } - - return 0; -} - - -/** - * wpa_supplicant_send_2_of_4 - Send message 2 of WPA/RSN 4-Way Handshake - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @dst: Destination address for the frame - * @key: Pointer to the EAPOL-Key frame header - * @ver: Version bits from EAPOL-Key Key Info - * @nonce: Nonce value for the EAPOL-Key frame - * @wpa_ie: WPA/RSN IE - * @wpa_ie_len: Length of the WPA/RSN IE - * @ptk: PTK to use for keyed hash and encryption - * Returns: 0 on success, -1 on failure - */ -int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, - const struct wpa_eapol_key *key, - int ver, const u8 *nonce, - const u8 *wpa_ie, size_t wpa_ie_len, - struct wpa_ptk *ptk) -{ - size_t rlen; - struct wpa_eapol_key *reply; - u8 *rbuf; - u8 *rsn_ie_buf = NULL; - - if (wpa_ie == NULL) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No wpa_ie set - " - "cannot generate msg 2/4"); - return -1; - } - -#ifdef CONFIG_IEEE80211R - if (wpa_key_mgmt_ft(sm->key_mgmt)) { - int res; - - /* - * Add PMKR1Name into RSN IE (PMKID-List) and add MDIE and - * FTIE from (Re)Association Response. - */ - rsn_ie_buf = os_malloc(wpa_ie_len + 2 + 2 + PMKID_LEN + - sm->assoc_resp_ies_len); - if (rsn_ie_buf == NULL) - return -1; - os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len); - res = wpa_insert_pmkid(rsn_ie_buf, wpa_ie_len, - sm->pmk_r1_name); - if (res < 0) { - os_free(rsn_ie_buf); - return -1; - } - wpa_ie_len += res; - - if (sm->assoc_resp_ies) { - os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies, - sm->assoc_resp_ies_len); - wpa_ie_len += sm->assoc_resp_ies_len; - } - - wpa_ie = rsn_ie_buf; - } -#endif /* CONFIG_IEEE80211R */ - - wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len); - - rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, - NULL, sizeof(*reply) + wpa_ie_len, - &rlen, (void *) &reply); - if (rbuf == NULL) { - os_free(rsn_ie_buf); - return -1; - } - - reply->type = sm->proto == WPA_PROTO_RSN ? - EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; - WPA_PUT_BE16(reply->key_info, - ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC); - if (sm->proto == WPA_PROTO_RSN) - WPA_PUT_BE16(reply->key_length, 0); - else - os_memcpy(reply->key_length, key->key_length, 2); - os_memcpy(reply->replay_counter, key->replay_counter, - WPA_REPLAY_COUNTER_LEN); - wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter, - WPA_REPLAY_COUNTER_LEN); - - WPA_PUT_BE16(reply->key_data_length, wpa_ie_len); - os_memcpy(reply + 1, wpa_ie, wpa_ie_len); - os_free(rsn_ie_buf); - - os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); - - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4"); - wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL, - rbuf, rlen, reply->key_mic); - - return 0; -} - - -static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, - const struct wpa_eapol_key *key, - struct wpa_ptk *ptk) -{ - size_t ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64; -#ifdef CONFIG_IEEE80211R - if (wpa_key_mgmt_ft(sm->key_mgmt)) - return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len); -#endif /* CONFIG_IEEE80211R */ - - wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion", - sm->own_addr, sm->bssid, sm->snonce, key->key_nonce, - (u8 *) ptk, ptk_len, - wpa_key_mgmt_sha256(sm->key_mgmt)); - return 0; -} - - -static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, - const unsigned char *src_addr, - const struct wpa_eapol_key *key, - u16 ver) -{ - struct wpa_eapol_ie_parse ie; - struct wpa_ptk *ptk; - u8 buf[8]; - int res; - u8 *kde, *kde_buf = NULL; - size_t kde_len; - - if (wpa_sm_get_network_ctx(sm) == NULL) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info " - "found (msg 1 of 4)"); - return; - } - - wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of 4-Way " - "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver); - - os_memset(&ie, 0, sizeof(ie)); - - if (sm->proto == WPA_PROTO_RSN) { - /* RSN: msg 1/4 should contain PMKID for the selected PMK */ - 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); - 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); - } - } - - res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid); - if (res == -2) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Do not reply to " - "msg 1/4 - requesting full EAP authentication"); - return; - } - if (res) - goto failed; - - if (sm->renew_snonce) { - if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Failed to get random data for SNonce"); - goto failed; - } - sm->renew_snonce = 0; - wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce", - sm->snonce, WPA_NONCE_LEN); - } - - /* Calculate PTK which will be stored as a temporary PTK until it has - * been verified when processing message 3/4. */ - ptk = &sm->tptk; - wpa_derive_ptk(sm, src_addr, key, ptk); - /* Supplicant: swap tx/rx Mic keys */ - os_memcpy(buf, ptk->u.auth.tx_mic_key, 8); - os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8); - os_memcpy(ptk->u.auth.rx_mic_key, buf, 8); - sm->tptk_set = 1; - - kde = sm->assoc_wpa_ie; - kde_len = sm->assoc_wpa_ie_len; - -#ifdef CONFIG_P2P - if (sm->p2p) { - kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1); - if (kde_buf) { - u8 *pos; - wpa_printf(MSG_DEBUG, "P2P: Add IP Address Request KDE " - "into EAPOL-Key 2/4"); - os_memcpy(kde_buf, kde, kde_len); - kde = kde_buf; - pos = kde + kde_len; - *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = RSN_SELECTOR_LEN + 1; - RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ); - pos += RSN_SELECTOR_LEN; - *pos++ = 0x01; - kde_len = pos - kde; - } - } -#endif /* CONFIG_P2P */ - - if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce, - kde, kde_len, ptk)) - goto failed; - - os_free(kde_buf); - os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN); - return; - -failed: - os_free(kde_buf); - wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); -} - - -static void wpa_sm_start_preauth(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_sm *sm = eloop_ctx; - rsn_preauth_candidate_process(sm); -} - - -static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm, - const u8 *addr, int secure) -{ - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Key negotiation completed with " - MACSTR " [PTK=%s GTK=%s]", MAC2STR(addr), - wpa_cipher_txt(sm->pairwise_cipher), - wpa_cipher_txt(sm->group_cipher)); - wpa_sm_cancel_auth_timeout(sm); - wpa_sm_set_state(sm, WPA_COMPLETED); - - if (secure) { - wpa_sm_mlme_setprotection( - sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX, - MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); - eapol_sm_notify_portValid(sm->eapol, TRUE); - if (wpa_key_mgmt_wpa_psk(sm->key_mgmt)) - eapol_sm_notify_eap_success(sm->eapol, TRUE); - /* - * 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 - * likelihood of the first preauth EAPOL-Start frame getting to - * the target AP. - */ - eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL); - } - - if (sm->cur_pmksa && sm->cur_pmksa->opportunistic) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "RSN: Authenticator accepted " - "opportunistic PMKSA entry - marking it valid"); - sm->cur_pmksa->opportunistic = 0; - } - -#ifdef CONFIG_IEEE80211R - if (wpa_key_mgmt_ft(sm->key_mgmt)) { - /* Prepare for the next transition */ - wpa_ft_prepare_auth_request(sm, NULL); - } -#endif /* CONFIG_IEEE80211R */ -} - - -static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_sm *sm = eloop_ctx; - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Request PTK rekeying"); - wpa_sm_key_request(sm, 0, 1); -} - - -static int wpa_supplicant_install_ptk(struct wpa_sm *sm, - const struct wpa_eapol_key *key) -{ - int keylen, rsclen; - enum wpa_alg alg; - const u8 *key_rsc; - u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: Installing PTK to the driver"); - - if (sm->pairwise_cipher == WPA_CIPHER_NONE) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Pairwise Cipher " - "Suite: NONE - do not use pairwise keys"); - return 0; - } - - if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Unsupported pairwise cipher %d", - sm->pairwise_cipher); - return -1; - } - - alg = wpa_cipher_to_alg(sm->pairwise_cipher); - keylen = wpa_cipher_key_len(sm->pairwise_cipher); - rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher); - - if (sm->proto == WPA_PROTO_RSN) { - key_rsc = null_rsc; - } else { - key_rsc = key->key_rsc; - wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen); - } - - if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen, - (u8 *) sm->ptk.tk1, keylen) < 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Failed to set PTK to the " - "driver (alg=%d keylen=%d bssid=" MACSTR ")", - alg, keylen, MAC2STR(sm->bssid)); - return -1; - } - - if (sm->wpa_ptk_rekey) { - eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); - eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk, - sm, NULL); - } - - return 0; -} - - -static int wpa_supplicant_check_group_cipher(struct wpa_sm *sm, - int group_cipher, - int keylen, int maxkeylen, - int *key_rsc_len, - enum wpa_alg *alg) -{ - int klen; - - *alg = wpa_cipher_to_alg(group_cipher); - if (*alg == WPA_ALG_NONE) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Unsupported Group Cipher %d", - group_cipher); - return -1; - } - *key_rsc_len = wpa_cipher_rsc_len(group_cipher); - - klen = wpa_cipher_key_len(group_cipher); - if (keylen != klen || maxkeylen < klen) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Unsupported %s Group Cipher key length %d (%d)", - wpa_cipher_txt(group_cipher), keylen, maxkeylen); - return -1; - } - return 0; -} - - -struct wpa_gtk_data { - enum wpa_alg alg; - int tx, key_rsc_len, keyidx; - u8 gtk[32]; - int gtk_len; -}; - - -static int wpa_supplicant_install_gtk(struct wpa_sm *sm, - const struct wpa_gtk_data *gd, - const u8 *key_rsc) -{ - const u8 *_gtk = gd->gtk; - u8 gtk_buf[32]; - - wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len); - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)", - gd->keyidx, gd->tx, gd->gtk_len); - wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, gd->key_rsc_len); - if (sm->group_cipher == WPA_CIPHER_TKIP) { - /* Swap Tx/Rx keys for Michael MIC */ - os_memcpy(gtk_buf, gd->gtk, 16); - os_memcpy(gtk_buf + 16, gd->gtk + 24, 8); - os_memcpy(gtk_buf + 24, gd->gtk + 16, 8); - _gtk = gtk_buf; - } - if (sm->pairwise_cipher == WPA_CIPHER_NONE) { - if (wpa_sm_set_key(sm, gd->alg, NULL, - gd->keyidx, 1, key_rsc, gd->key_rsc_len, - _gtk, gd->gtk_len) < 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Failed to set GTK to the driver " - "(Group only)"); - return -1; - } - } else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr, - gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len, - _gtk, gd->gtk_len) < 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Failed to set GTK to " - "the driver (alg=%d keylen=%d keyidx=%d)", - gd->alg, gd->gtk_len, gd->keyidx); - return -1; - } - - return 0; -} - - -static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm, - int tx) -{ - if (tx && sm->pairwise_cipher != WPA_CIPHER_NONE) { - /* Ignore Tx bit for GTK if a pairwise key is used. One AP - * seemed to set this bit (incorrectly, since Tx is only when - * doing Group Key only APs) and without this workaround, the - * data connection does not work because wpa_supplicant - * configured non-zero keyidx to be used for unicast. */ - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Tx bit set for GTK, but pairwise " - "keys are used - ignore Tx bit"); - return 0; - } - return tx; -} - - -static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, - const struct wpa_eapol_key *key, - const u8 *gtk, size_t gtk_len, - int key_info) -{ - struct wpa_gtk_data gd; - - /* - * IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x - * GTK KDE format: - * KeyID[bits 0-1], Tx [bit 2], Reserved [bits 3-7] - * Reserved [bits 0-7] - * GTK - */ - - os_memset(&gd, 0, sizeof(gd)); - wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in pairwise handshake", - gtk, gtk_len); - - if (gtk_len < 2 || gtk_len - 2 > sizeof(gd.gtk)) - return -1; - - gd.keyidx = gtk[0] & 0x3; - gd.tx = wpa_supplicant_gtk_tx_bit_workaround(sm, - !!(gtk[0] & BIT(2))); - gtk += 2; - gtk_len -= 2; - - os_memcpy(gd.gtk, gtk, gtk_len); - gd.gtk_len = gtk_len; - - if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED && - (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, - gtk_len, gtk_len, - &gd.key_rsc_len, &gd.alg) || - wpa_supplicant_install_gtk(sm, &gd, key->key_rsc))) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "RSN: Failed to install GTK"); - return -1; - } - - wpa_supplicant_key_neg_complete(sm, sm->bssid, - key_info & WPA_KEY_INFO_SECURE); - return 0; -} - - -static int ieee80211w_set_keys(struct wpa_sm *sm, - struct wpa_eapol_ie_parse *ie) -{ -#ifdef CONFIG_IEEE80211W - if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) - return 0; - - if (ie->igtk) { - const struct wpa_igtk_kde *igtk; - u16 keyidx; - if (ie->igtk_len != sizeof(*igtk)) - return -1; - igtk = (const struct wpa_igtk_kde *) ie->igtk; - keyidx = WPA_GET_LE16(igtk->keyid); - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d " - "pn %02x%02x%02x%02x%02x%02x", - keyidx, MAC2STR(igtk->pn)); - wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", - igtk->igtk, WPA_IGTK_LEN); - if (keyidx > 4095) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Invalid IGTK KeyID %d", keyidx); - return -1; - } - if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, - keyidx, 0, igtk->pn, sizeof(igtk->pn), - igtk->igtk, WPA_IGTK_LEN) < 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Failed to configure IGTK to the driver"); - return -1; - } - } - - return 0; -#else /* CONFIG_IEEE80211W */ - return 0; -#endif /* CONFIG_IEEE80211W */ -} - - -static void wpa_report_ie_mismatch(struct wpa_sm *sm, - const char *reason, const u8 *src_addr, - const u8 *wpa_ie, size_t wpa_ie_len, - const u8 *rsn_ie, size_t rsn_ie_len) -{ - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: %s (src=" MACSTR ")", - reason, MAC2STR(src_addr)); - - if (sm->ap_wpa_ie) { - wpa_hexdump(MSG_INFO, "WPA: WPA IE in Beacon/ProbeResp", - sm->ap_wpa_ie, sm->ap_wpa_ie_len); - } - if (wpa_ie) { - if (!sm->ap_wpa_ie) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: No WPA IE in Beacon/ProbeResp"); - } - wpa_hexdump(MSG_INFO, "WPA: WPA IE in 3/4 msg", - wpa_ie, wpa_ie_len); - } - - if (sm->ap_rsn_ie) { - wpa_hexdump(MSG_INFO, "WPA: RSN IE in Beacon/ProbeResp", - sm->ap_rsn_ie, sm->ap_rsn_ie_len); - } - if (rsn_ie) { - if (!sm->ap_rsn_ie) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: No RSN IE in Beacon/ProbeResp"); - } - wpa_hexdump(MSG_INFO, "WPA: RSN IE in 3/4 msg", - rsn_ie, rsn_ie_len); - } - - wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS); -} - - -#ifdef CONFIG_IEEE80211R - -static int ft_validate_mdie(struct wpa_sm *sm, - const unsigned char *src_addr, - struct wpa_eapol_ie_parse *ie, - const u8 *assoc_resp_mdie) -{ - struct rsn_mdie *mdie; - - mdie = (struct rsn_mdie *) (ie->mdie + 2); - if (ie->mdie == NULL || ie->mdie_len < 2 + sizeof(*mdie) || - os_memcmp(mdie->mobility_domain, sm->mobility_domain, - MOBILITY_DOMAIN_ID_LEN) != 0) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE in msg 3/4 did " - "not match with the current mobility domain"); - return -1; - } - - if (assoc_resp_mdie && - (assoc_resp_mdie[1] != ie->mdie[1] || - os_memcmp(assoc_resp_mdie, ie->mdie, 2 + ie->mdie[1]) != 0)) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE mismatch"); - wpa_hexdump(MSG_DEBUG, "FT: MDIE in EAPOL-Key msg 3/4", - ie->mdie, 2 + ie->mdie[1]); - wpa_hexdump(MSG_DEBUG, "FT: MDIE in (Re)Association Response", - assoc_resp_mdie, 2 + assoc_resp_mdie[1]); - return -1; - } - - return 0; -} - - -static int ft_validate_ftie(struct wpa_sm *sm, - const unsigned char *src_addr, - struct wpa_eapol_ie_parse *ie, - const u8 *assoc_resp_ftie) -{ - if (ie->ftie == NULL) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "FT: No FTIE in EAPOL-Key msg 3/4"); - return -1; - } - - if (assoc_resp_ftie == NULL) - return 0; - - if (assoc_resp_ftie[1] != ie->ftie[1] || - os_memcmp(assoc_resp_ftie, ie->ftie, 2 + ie->ftie[1]) != 0) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: FTIE mismatch"); - wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 3/4", - ie->ftie, 2 + ie->ftie[1]); - wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)Association Response", - assoc_resp_ftie, 2 + assoc_resp_ftie[1]); - return -1; - } - - return 0; -} - - -static int ft_validate_rsnie(struct wpa_sm *sm, - const unsigned char *src_addr, - struct wpa_eapol_ie_parse *ie) -{ - struct wpa_ie_data rsn; - - if (!ie->rsn_ie) - return 0; - - /* - * Verify that PMKR1Name from EAPOL-Key message 3/4 - * matches with the value we derived. - */ - if (wpa_parse_wpa_ie_rsn(ie->rsn_ie, ie->rsn_ie_len, &rsn) < 0 || - rsn.num_pmkid != 1 || rsn.pmkid == NULL) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: No PMKR1Name in " - "FT 4-way handshake message 3/4"); - return -1; - } - - if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "FT: PMKR1Name mismatch in " - "FT 4-way handshake message 3/4"); - wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Authenticator", - rsn.pmkid, WPA_PMK_NAME_LEN); - wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", - sm->pmk_r1_name, WPA_PMK_NAME_LEN); - return -1; - } - - return 0; -} - - -static int wpa_supplicant_validate_ie_ft(struct wpa_sm *sm, - const unsigned char *src_addr, - struct wpa_eapol_ie_parse *ie) -{ - const u8 *pos, *end, *mdie = NULL, *ftie = NULL; - - if (sm->assoc_resp_ies) { - pos = sm->assoc_resp_ies; - end = pos + sm->assoc_resp_ies_len; - while (pos + 2 < end) { - if (pos + 2 + pos[1] > end) - break; - switch (*pos) { - case WLAN_EID_MOBILITY_DOMAIN: - mdie = pos; - break; - case WLAN_EID_FAST_BSS_TRANSITION: - ftie = pos; - break; - } - pos += 2 + pos[1]; - } - } - - if (ft_validate_mdie(sm, src_addr, ie, mdie) < 0 || - ft_validate_ftie(sm, src_addr, ie, ftie) < 0 || - ft_validate_rsnie(sm, src_addr, ie) < 0) - return -1; - - return 0; -} - -#endif /* CONFIG_IEEE80211R */ - - -static int wpa_supplicant_validate_ie(struct wpa_sm *sm, - const unsigned char *src_addr, - struct wpa_eapol_ie_parse *ie) -{ - if (sm->ap_wpa_ie == NULL && sm->ap_rsn_ie == NULL) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: No WPA/RSN IE for this AP known. " - "Trying to get from scan results"); - if (wpa_sm_get_beacon_ie(sm) < 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Could not find AP from " - "the scan results"); - } else { - wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: Found the current AP from " - "updated scan results"); - } - } - - if (ie->wpa_ie == NULL && ie->rsn_ie == NULL && - (sm->ap_wpa_ie || sm->ap_rsn_ie)) { - wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match " - "with IE in Beacon/ProbeResp (no IE?)", - src_addr, ie->wpa_ie, ie->wpa_ie_len, - ie->rsn_ie, ie->rsn_ie_len); - return -1; - } - - if ((ie->wpa_ie && sm->ap_wpa_ie && - (ie->wpa_ie_len != sm->ap_wpa_ie_len || - os_memcmp(ie->wpa_ie, sm->ap_wpa_ie, ie->wpa_ie_len) != 0)) || - (ie->rsn_ie && sm->ap_rsn_ie && - wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt), - sm->ap_rsn_ie, sm->ap_rsn_ie_len, - ie->rsn_ie, ie->rsn_ie_len))) { - wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match " - "with IE in Beacon/ProbeResp", - src_addr, ie->wpa_ie, ie->wpa_ie_len, - ie->rsn_ie, ie->rsn_ie_len); - return -1; - } - - if (sm->proto == WPA_PROTO_WPA && - ie->rsn_ie && sm->ap_rsn_ie == NULL && sm->rsn_enabled) { - wpa_report_ie_mismatch(sm, "Possible downgrade attack " - "detected - RSN was enabled and RSN IE " - "was in msg 3/4, but not in " - "Beacon/ProbeResp", - src_addr, ie->wpa_ie, ie->wpa_ie_len, - ie->rsn_ie, ie->rsn_ie_len); - return -1; - } - -#ifdef CONFIG_IEEE80211R - if (wpa_key_mgmt_ft(sm->key_mgmt) && - wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0) - return -1; -#endif /* CONFIG_IEEE80211R */ - - return 0; -} - - -/** - * wpa_supplicant_send_4_of_4 - Send message 4 of WPA/RSN 4-Way Handshake - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @dst: Destination address for the frame - * @key: Pointer to the EAPOL-Key frame header - * @ver: Version bits from EAPOL-Key Key Info - * @key_info: Key Info - * @kde: KDEs to include the EAPOL-Key frame - * @kde_len: Length of KDEs - * @ptk: PTK to use for keyed hash and encryption - * Returns: 0 on success, -1 on failure - */ -int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, - const struct wpa_eapol_key *key, - u16 ver, u16 key_info, - const u8 *kde, size_t kde_len, - struct wpa_ptk *ptk) -{ - size_t rlen; - struct wpa_eapol_key *reply; - u8 *rbuf; - - if (kde) - wpa_hexdump(MSG_DEBUG, "WPA: KDE for msg 4/4", kde, kde_len); - - rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, - sizeof(*reply) + kde_len, - &rlen, (void *) &reply); - if (rbuf == NULL) - return -1; - - reply->type = sm->proto == WPA_PROTO_RSN ? - EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; - key_info &= WPA_KEY_INFO_SECURE; - key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC; - WPA_PUT_BE16(reply->key_info, key_info); - if (sm->proto == WPA_PROTO_RSN) - WPA_PUT_BE16(reply->key_length, 0); - else - os_memcpy(reply->key_length, key->key_length, 2); - os_memcpy(reply->replay_counter, key->replay_counter, - WPA_REPLAY_COUNTER_LEN); - - WPA_PUT_BE16(reply->key_data_length, kde_len); - if (kde) - os_memcpy(reply + 1, kde, kde_len); - - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4"); - wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL, - rbuf, rlen, reply->key_mic); - - return 0; -} - - -static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, - const struct wpa_eapol_key *key, - u16 ver) -{ - u16 key_info, keylen, len; - const u8 *pos; - struct wpa_eapol_ie_parse ie; - - wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 3 of 4-Way " - "Handshake from " MACSTR " (ver=%d)", MAC2STR(sm->bssid), ver); - - key_info = WPA_GET_BE16(key->key_info); - - pos = (const u8 *) (key + 1); - len = WPA_GET_BE16(key->key_data_length); - wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len); - 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"); - goto failed; - } -#ifdef CONFIG_IEEE80211W - if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: IGTK KDE in unencrypted key data"); - goto failed; - } - - if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Invalid IGTK KDE length %lu", - (unsigned long) ie.igtk_len); - goto failed; - } -#endif /* CONFIG_IEEE80211W */ - - if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0) - goto failed; - - if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: ANonce from message 1 of 4-Way Handshake " - "differs from 3 of 4-Way Handshake - drop packet (src=" - MACSTR ")", MAC2STR(sm->bssid)); - goto failed; - } - - keylen = WPA_GET_BE16(key->key_length); - if (keylen != wpa_cipher_key_len(sm->pairwise_cipher)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Invalid %s key length %d (src=" MACSTR - ")", wpa_cipher_txt(sm->pairwise_cipher), keylen, - MAC2STR(sm->bssid)); - goto failed; - } - -#ifdef CONFIG_P2P - if (ie.ip_addr_alloc) { - os_memcpy(sm->p2p_ip_addr, ie.ip_addr_alloc, 3 * 4); - wpa_hexdump(MSG_DEBUG, "P2P: IP address info", - sm->p2p_ip_addr, sizeof(sm->p2p_ip_addr)); - } -#endif /* CONFIG_P2P */ - - if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info, - NULL, 0, &sm->ptk)) { - goto failed; - } - - /* SNonce was successfully used in msg 3/4, so mark it to be renewed - * for the next 4-Way Handshake. If msg 3 is received again, the old - * SNonce will still be used to avoid changing PTK. */ - sm->renew_snonce = 1; - - if (key_info & WPA_KEY_INFO_INSTALL) { - if (wpa_supplicant_install_ptk(sm, key)) - goto failed; - } - - if (key_info & WPA_KEY_INFO_SECURE) { - wpa_sm_mlme_setprotection( - sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX, - MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); - eapol_sm_notify_portValid(sm->eapol, TRUE); - } - wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); - - if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) { - wpa_supplicant_key_neg_complete(sm, sm->bssid, - key_info & WPA_KEY_INFO_SECURE); - } else if (ie.gtk && - wpa_supplicant_pairwise_gtk(sm, key, - ie.gtk, ie.gtk_len, key_info) < 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "RSN: Failed to configure GTK"); - goto failed; - } - - if (ieee80211w_set_keys(sm, &ie) < 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "RSN: Failed to configure IGTK"); - goto failed; - } - - if (ie.gtk) - wpa_sm_set_rekey_offload(sm); - - return; - -failed: - wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); -} - - -static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm, - const u8 *keydata, - size_t keydatalen, - u16 key_info, - struct wpa_gtk_data *gd) -{ - int maxkeylen; - struct wpa_eapol_ie_parse ie; - - wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen); - 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"); - return -1; - } - if (ie.gtk == NULL) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: No GTK IE in Group Key msg 1/2"); - return -1; - } - maxkeylen = gd->gtk_len = ie.gtk_len - 2; - - if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, - gd->gtk_len, maxkeylen, - &gd->key_rsc_len, &gd->alg)) - return -1; - - wpa_hexdump(MSG_DEBUG, "RSN: received GTK in group key handshake", - ie.gtk, ie.gtk_len); - gd->keyidx = ie.gtk[0] & 0x3; - gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm, - !!(ie.gtk[0] & BIT(2))); - if (ie.gtk_len - 2 > sizeof(gd->gtk)) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "RSN: Too long GTK in GTK IE (len=%lu)", - (unsigned long) ie.gtk_len - 2); - return -1; - } - os_memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2); - - if (ieee80211w_set_keys(sm, &ie) < 0) - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "RSN: Failed to configure IGTK"); - - return 0; -} - - -static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, - const struct wpa_eapol_key *key, - size_t keydatalen, int key_info, - size_t extra_len, u16 ver, - struct wpa_gtk_data *gd) -{ - size_t maxkeylen; - u8 ek[32]; - - gd->gtk_len = WPA_GET_BE16(key->key_length); - maxkeylen = keydatalen; - if (keydatalen > extra_len) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Truncated EAPOL-Key packet: " - "key_data_length=%lu > extra_len=%lu", - (unsigned long) keydatalen, (unsigned long) extra_len); - return -1; - } - if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { - if (maxkeylen < 8) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Too short maxkeylen (%lu)", - (unsigned long) maxkeylen); - return -1; - } - maxkeylen -= 8; - } - - if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, - gd->gtk_len, maxkeylen, - &gd->key_rsc_len, &gd->alg)) - return -1; - - gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> - WPA_KEY_INFO_KEY_INDEX_SHIFT; - if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { - os_memcpy(ek, key->key_iv, 16); - os_memcpy(ek + 16, sm->ptk.kek, 16); - if (keydatalen > sizeof(gd->gtk)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: RC4 key data too long (%lu)", - (unsigned long) keydatalen); - return -1; - } - os_memcpy(gd->gtk, key + 1, keydatalen); - if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) { - wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, - "WPA: RC4 failed"); - return -1; - } - } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { - if (keydatalen % 8) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Unsupported AES-WRAP len %lu", - (unsigned long) keydatalen); - return -1; - } - if (maxkeylen > sizeof(gd->gtk)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: AES-WRAP key data " - "too long (keydatalen=%lu maxkeylen=%lu)", - (unsigned long) keydatalen, - (unsigned long) maxkeylen); - return -1; - } - if (aes_unwrap(sm->ptk.kek, maxkeylen / 8, - (const u8 *) (key + 1), gd->gtk)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: AES unwrap failed - could not decrypt " - "GTK"); - return -1; - } - } else { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Unsupported key_info type %d", ver); - return -1; - } - gd->tx = wpa_supplicant_gtk_tx_bit_workaround( - sm, !!(key_info & WPA_KEY_INFO_TXRX)); - return 0; -} - - -static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, - const struct wpa_eapol_key *key, - int ver, u16 key_info) -{ - size_t rlen; - struct wpa_eapol_key *reply; - u8 *rbuf; - - rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, - sizeof(*reply), &rlen, (void *) &reply); - if (rbuf == NULL) - return -1; - - reply->type = sm->proto == WPA_PROTO_RSN ? - EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; - key_info &= WPA_KEY_INFO_KEY_INDEX_MASK; - key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE; - WPA_PUT_BE16(reply->key_info, key_info); - if (sm->proto == WPA_PROTO_RSN) - WPA_PUT_BE16(reply->key_length, 0); - else - os_memcpy(reply->key_length, key->key_length, 2); - os_memcpy(reply->replay_counter, key->replay_counter, - WPA_REPLAY_COUNTER_LEN); - - WPA_PUT_BE16(reply->key_data_length, 0); - - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2"); - wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL, - rbuf, rlen, reply->key_mic); - - return 0; -} - - -static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, - const unsigned char *src_addr, - const struct wpa_eapol_key *key, - int extra_len, u16 ver) -{ - u16 key_info, keydatalen; - int rekey, ret; - struct wpa_gtk_data gd; - - os_memset(&gd, 0, sizeof(gd)); - - rekey = wpa_sm_get_state(sm) == WPA_COMPLETED; - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of Group Key " - "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver); - - key_info = WPA_GET_BE16(key->key_info); - keydatalen = WPA_GET_BE16(key->key_data_length); - - if (sm->proto == WPA_PROTO_RSN) { - ret = wpa_supplicant_process_1_of_2_rsn(sm, - (const u8 *) (key + 1), - keydatalen, key_info, - &gd); - } else { - ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen, - key_info, extra_len, - ver, &gd); - } - - wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); - - if (ret) - goto failed; - - if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) || - wpa_supplicant_send_2_of_2(sm, key, ver, key_info)) - goto failed; - - if (rekey) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying " - "completed with " MACSTR " [GTK=%s]", - MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher)); - wpa_sm_cancel_auth_timeout(sm); - wpa_sm_set_state(sm, WPA_COMPLETED); - } else { - wpa_supplicant_key_neg_complete(sm, sm->bssid, - key_info & - WPA_KEY_INFO_SECURE); - } - - wpa_sm_set_rekey_offload(sm); - - return; - -failed: - wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); -} - - -static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm, - struct wpa_eapol_key *key, - u16 ver, - const u8 *buf, size_t len) -{ - u8 mic[16]; - int ok = 0; - - os_memcpy(mic, key->key_mic, 16); - if (sm->tptk_set) { - os_memset(key->key_mic, 0, 16); - wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len, - key->key_mic); - if (os_memcmp(mic, key->key_mic, 16) != 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Invalid EAPOL-Key MIC " - "when using TPTK - ignoring TPTK"); - } else { - ok = 1; - sm->tptk_set = 0; - sm->ptk_set = 1; - os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk)); - } - } - - if (!ok && sm->ptk_set) { - os_memset(key->key_mic, 0, 16); - wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len, - key->key_mic); - if (os_memcmp(mic, key->key_mic, 16) != 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Invalid EAPOL-Key MIC - " - "dropping packet"); - return -1; - } - ok = 1; - } - - if (!ok) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Could not verify EAPOL-Key MIC - " - "dropping packet"); - return -1; - } - - os_memcpy(sm->rx_replay_counter, key->replay_counter, - WPA_REPLAY_COUNTER_LEN); - sm->rx_replay_counter_set = 1; - return 0; -} - - -/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */ -static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, - struct wpa_eapol_key *key, u16 ver) -{ - u16 keydatalen = WPA_GET_BE16(key->key_data_length); - - wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data", - (u8 *) (key + 1), keydatalen); - if (!sm->ptk_set) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: PTK not available, cannot decrypt EAPOL-Key Key " - "Data"); - return -1; - } - - /* Decrypt key data here so that this operation does not need - * to be implemented separately for each message type. */ - if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { - u8 ek[32]; - os_memcpy(ek, key->key_iv, 16); - os_memcpy(ek + 16, sm->ptk.kek, 16); - if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) { - wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, - "WPA: RC4 failed"); - return -1; - } - } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || - ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) { - u8 *buf; - if (keydatalen % 8) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Unsupported AES-WRAP len %d", - keydatalen); - return -1; - } - keydatalen -= 8; /* AES-WRAP adds 8 bytes */ - buf = os_malloc(keydatalen); - if (buf == NULL) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: No memory for AES-UNWRAP buffer"); - return -1; - } - if (aes_unwrap(sm->ptk.kek, keydatalen / 8, - (u8 *) (key + 1), buf)) { - os_free(buf); - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: AES unwrap failed - " - "could not decrypt EAPOL-Key key data"); - return -1; - } - os_memcpy(key + 1, buf, keydatalen); - os_free(buf); - WPA_PUT_BE16(key->key_data_length, keydatalen); - } else { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Unsupported key_info type %d", ver); - return -1; - } - wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data", - (u8 *) (key + 1), keydatalen); - return 0; -} - - -/** - * wpa_sm_aborted_cached - Notify WPA that PMKSA caching was aborted - * @sm: Pointer to WPA state machine data from wpa_sm_init() - */ -void wpa_sm_aborted_cached(struct wpa_sm *sm) -{ - if (sm && sm->cur_pmksa) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "RSN: Cancelling PMKSA caching attempt"); - sm->cur_pmksa = NULL; - } -} - - -static void wpa_eapol_key_dump(struct wpa_sm *sm, - const struct wpa_eapol_key *key) -{ -#ifndef CONFIG_NO_STDOUT_DEBUG - u16 key_info = WPA_GET_BE16(key->key_info); - - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, " EAPOL-Key type=%d", key->type); - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - " key_info 0x%x (ver=%d keyidx=%d rsvd=%d %s%s%s%s%s%s%s%s)", - key_info, key_info & WPA_KEY_INFO_TYPE_MASK, - (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> - WPA_KEY_INFO_KEY_INDEX_SHIFT, - (key_info & (BIT(13) | BIT(14) | BIT(15))) >> 13, - key_info & WPA_KEY_INFO_KEY_TYPE ? "Pairwise" : "Group", - key_info & WPA_KEY_INFO_INSTALL ? " Install" : "", - key_info & WPA_KEY_INFO_ACK ? " Ack" : "", - key_info & WPA_KEY_INFO_MIC ? " MIC" : "", - key_info & WPA_KEY_INFO_SECURE ? " Secure" : "", - key_info & WPA_KEY_INFO_ERROR ? " Error" : "", - key_info & WPA_KEY_INFO_REQUEST ? " Request" : "", - key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : ""); - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - " key_length=%u key_data_length=%u", - WPA_GET_BE16(key->key_length), - WPA_GET_BE16(key->key_data_length)); - wpa_hexdump(MSG_DEBUG, " replay_counter", - key->replay_counter, WPA_REPLAY_COUNTER_LEN); - wpa_hexdump(MSG_DEBUG, " key_nonce", key->key_nonce, WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, " key_iv", key->key_iv, 16); - wpa_hexdump(MSG_DEBUG, " key_rsc", key->key_rsc, 8); - wpa_hexdump(MSG_DEBUG, " key_id (reserved)", key->key_id, 8); - wpa_hexdump(MSG_DEBUG, " key_mic", key->key_mic, 16); -#endif /* CONFIG_NO_STDOUT_DEBUG */ -} - - -/** - * wpa_sm_rx_eapol - Process received WPA EAPOL frames - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @src_addr: Source MAC address of the EAPOL packet - * @buf: Pointer to the beginning of the EAPOL data (EAPOL header) - * @len: Length of the EAPOL frame - * Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure - * - * This function is called for each received EAPOL frame. Other than EAPOL-Key - * frames can be skipped if filtering is done elsewhere. wpa_sm_rx_eapol() is - * only processing WPA and WPA2 EAPOL-Key frames. - * - * The received EAPOL-Key packets are validated and valid packets are replied - * to. In addition, key material (PTK, GTK) is configured at the end of a - * successful key handshake. - */ -int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len) -{ - size_t plen, data_len, extra_len; - struct ieee802_1x_hdr *hdr; - struct wpa_eapol_key *key; - u16 key_info, ver; - u8 *tmp; - int ret = -1; - struct wpa_peerkey *peerkey = NULL; - -#ifdef CONFIG_IEEE80211R - sm->ft_completed = 0; -#endif /* CONFIG_IEEE80211R */ - - if (len < sizeof(*hdr) + sizeof(*key)) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: EAPOL frame too short to be a WPA " - "EAPOL-Key (len %lu, expecting at least %lu)", - (unsigned long) len, - (unsigned long) sizeof(*hdr) + sizeof(*key)); - return 0; - } - - tmp = os_malloc(len); - if (tmp == NULL) - return -1; - os_memcpy(tmp, buf, len); - - hdr = (struct ieee802_1x_hdr *) tmp; - key = (struct wpa_eapol_key *) (hdr + 1); - plen = be_to_host16(hdr->length); - data_len = plen + sizeof(*hdr); - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "IEEE 802.1X RX: version=%d type=%d length=%lu", - hdr->version, hdr->type, (unsigned long) plen); - - if (hdr->version < EAPOL_VERSION) { - /* TODO: backwards compatibility */ - } - if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: EAPOL frame (type %u) discarded, " - "not a Key frame", hdr->type); - ret = 0; - goto out; - } - if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: EAPOL frame payload size %lu " - "invalid (frame size %lu)", - (unsigned long) plen, (unsigned long) len); - ret = 0; - goto out; - } - - if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN) - { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: EAPOL-Key type (%d) unknown, discarded", - key->type); - ret = 0; - goto out; - } - wpa_eapol_key_dump(sm, key); - - eapol_sm_notify_lower_layer_success(sm->eapol, 0); - wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len); - if (data_len < len) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: ignoring %lu bytes after the IEEE 802.1X data", - (unsigned long) len - data_len); - } - key_info = WPA_GET_BE16(key->key_info); - ver = key_info & WPA_KEY_INFO_TYPE_MASK; - if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && -#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) - ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && -#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ - ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Unsupported EAPOL-Key descriptor version %d", - ver); - goto out; - } - -#ifdef CONFIG_IEEE80211R - if (wpa_key_mgmt_ft(sm->key_mgmt)) { - /* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */ - if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "FT: AP did not use AES-128-CMAC"); - goto out; - } - } else -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - if (wpa_key_mgmt_sha256(sm->key_mgmt)) { - if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: AP did not use the " - "negotiated AES-128-CMAC"); - goto out; - } - } else -#endif /* CONFIG_IEEE80211W */ - if (sm->pairwise_cipher == WPA_CIPHER_CCMP && - ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: CCMP is used, but EAPOL-Key " - "descriptor version (%d) is not 2", ver); - if (sm->group_cipher != WPA_CIPHER_CCMP && - !(key_info & WPA_KEY_INFO_KEY_TYPE)) { - /* Earlier versions of IEEE 802.11i did not explicitly - * require version 2 descriptor for all EAPOL-Key - * packets, so allow group keys to use version 1 if - * CCMP is not used for them. */ - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Backwards compatibility: allow invalid " - "version for non-CCMP group keys"); - } else - goto out; - } - if (sm->pairwise_cipher == WPA_CIPHER_GCMP && - ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: GCMP is used, but EAPOL-Key " - "descriptor version (%d) is not 2", ver); - goto out; - } - -#ifdef CONFIG_PEERKEY - for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) { - if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0) - break; - } - - if (!(key_info & WPA_KEY_INFO_SMK_MESSAGE) && peerkey) { - if (!peerkey->initiator && peerkey->replay_counter_set && - os_memcmp(key->replay_counter, peerkey->replay_counter, - WPA_REPLAY_COUNTER_LEN) <= 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "RSN: EAPOL-Key Replay Counter did not " - "increase (STK) - dropping packet"); - goto out; - } else if (peerkey->initiator) { - u8 _tmp[WPA_REPLAY_COUNTER_LEN]; - os_memcpy(_tmp, key->replay_counter, - WPA_REPLAY_COUNTER_LEN); - inc_byte_array(_tmp, WPA_REPLAY_COUNTER_LEN); - if (os_memcmp(_tmp, peerkey->replay_counter, - WPA_REPLAY_COUNTER_LEN) != 0) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "RSN: EAPOL-Key Replay " - "Counter did not match (STK) - " - "dropping packet"); - goto out; - } - } - } - - if (peerkey && peerkey->initiator && (key_info & WPA_KEY_INFO_ACK)) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "RSN: Ack bit in key_info from STK peer"); - goto out; - } -#endif /* CONFIG_PEERKEY */ - - if (!peerkey && sm->rx_replay_counter_set && - os_memcmp(key->replay_counter, sm->rx_replay_counter, - WPA_REPLAY_COUNTER_LEN) <= 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: EAPOL-Key Replay Counter did not increase - " - "dropping packet"); - goto out; - } - - if (!(key_info & (WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE)) -#ifdef CONFIG_PEERKEY - && (peerkey == NULL || !peerkey->initiator) -#endif /* CONFIG_PEERKEY */ - ) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: No Ack bit in key_info"); - goto out; - } - - if (key_info & WPA_KEY_INFO_REQUEST) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: EAPOL-Key with Request bit - dropped"); - goto out; - } - - if ((key_info & WPA_KEY_INFO_MIC) && !peerkey && - wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len)) - goto out; - -#ifdef CONFIG_PEERKEY - if ((key_info & WPA_KEY_INFO_MIC) && peerkey && - peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp, data_len)) - goto out; -#endif /* CONFIG_PEERKEY */ - - extra_len = data_len - sizeof(*hdr) - sizeof(*key); - - if (WPA_GET_BE16(key->key_data_length) > extra_len) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key " - "frame - key_data overflow (%d > %lu)", - WPA_GET_BE16(key->key_data_length), - (unsigned long) extra_len); - goto out; - } - extra_len = WPA_GET_BE16(key->key_data_length); - - if (sm->proto == WPA_PROTO_RSN && - (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { - if (wpa_supplicant_decrypt_key_data(sm, key, ver)) - goto out; - extra_len = WPA_GET_BE16(key->key_data_length); - } - - if (key_info & WPA_KEY_INFO_KEY_TYPE) { - if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Ignored EAPOL-Key (Pairwise) with " - "non-zero key index"); - goto out; - } - if (peerkey) { - /* PeerKey 4-Way Handshake */ - peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver); - } else if (key_info & WPA_KEY_INFO_MIC) { - /* 3/4 4-Way Handshake */ - wpa_supplicant_process_3_of_4(sm, key, ver); - } else { - /* 1/4 4-Way Handshake */ - wpa_supplicant_process_1_of_4(sm, src_addr, key, - ver); - } - } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) { - /* PeerKey SMK Handshake */ - peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info, - ver); - } else { - if (key_info & WPA_KEY_INFO_MIC) { - /* 1/2 Group Key Handshake */ - wpa_supplicant_process_1_of_2(sm, src_addr, key, - extra_len, ver); - } else { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: EAPOL-Key (Group) without Mic bit - " - "dropped"); - } - } - - ret = 1; - -out: - os_free(tmp); - return ret; -} - - -#ifdef CONFIG_CTRL_IFACE -static u32 wpa_key_mgmt_suite(struct wpa_sm *sm) -{ - switch (sm->key_mgmt) { - case WPA_KEY_MGMT_IEEE8021X: - return (sm->proto == WPA_PROTO_RSN ? - RSN_AUTH_KEY_MGMT_UNSPEC_802_1X : - WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); - case WPA_KEY_MGMT_PSK: - return (sm->proto == WPA_PROTO_RSN ? - RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X : - WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); -#ifdef CONFIG_IEEE80211R - case WPA_KEY_MGMT_FT_IEEE8021X: - return RSN_AUTH_KEY_MGMT_FT_802_1X; - case WPA_KEY_MGMT_FT_PSK: - return RSN_AUTH_KEY_MGMT_FT_PSK; -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - case WPA_KEY_MGMT_IEEE8021X_SHA256: - return RSN_AUTH_KEY_MGMT_802_1X_SHA256; - case WPA_KEY_MGMT_PSK_SHA256: - return RSN_AUTH_KEY_MGMT_PSK_SHA256; -#endif /* CONFIG_IEEE80211W */ - case WPA_KEY_MGMT_CCKM: - return (sm->proto == WPA_PROTO_RSN ? - RSN_AUTH_KEY_MGMT_CCKM: - WPA_AUTH_KEY_MGMT_CCKM); - case WPA_KEY_MGMT_WPA_NONE: - return WPA_AUTH_KEY_MGMT_NONE; - default: - return 0; - } -} - - -#define RSN_SUITE "%02x-%02x-%02x-%d" -#define RSN_SUITE_ARG(s) \ -((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff - -/** - * wpa_sm_get_mib - Dump text list of MIB entries - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @buf: Buffer for the list - * @buflen: Length of the buffer - * Returns: Number of bytes written to buffer - * - * This function is used fetch dot11 MIB variables. - */ -int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen) -{ - char pmkid_txt[PMKID_LEN * 2 + 1]; - int rsna, ret; - size_t len; - - if (sm->cur_pmksa) { - wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt), - sm->cur_pmksa->pmkid, PMKID_LEN); - } else - pmkid_txt[0] = '\0'; - - if ((wpa_key_mgmt_wpa_psk(sm->key_mgmt) || - wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) && - sm->proto == WPA_PROTO_RSN) - rsna = 1; - else - rsna = 0; - - ret = os_snprintf(buf, buflen, - "dot11RSNAOptionImplemented=TRUE\n" - "dot11RSNAPreauthenticationImplemented=TRUE\n" - "dot11RSNAEnabled=%s\n" - "dot11RSNAPreauthenticationEnabled=%s\n" - "dot11RSNAConfigVersion=%d\n" - "dot11RSNAConfigPairwiseKeysSupported=5\n" - "dot11RSNAConfigGroupCipherSize=%d\n" - "dot11RSNAConfigPMKLifetime=%d\n" - "dot11RSNAConfigPMKReauthThreshold=%d\n" - "dot11RSNAConfigNumberOfPTKSAReplayCounters=1\n" - "dot11RSNAConfigSATimeout=%d\n", - rsna ? "TRUE" : "FALSE", - rsna ? "TRUE" : "FALSE", - RSN_VERSION, - wpa_cipher_key_len(sm->group_cipher) * 8, - sm->dot11RSNAConfigPMKLifetime, - sm->dot11RSNAConfigPMKReauthThreshold, - sm->dot11RSNAConfigSATimeout); - if (ret < 0 || (size_t) ret >= buflen) - return 0; - len = ret; - - ret = os_snprintf( - buf + len, buflen - len, - "dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n" - "dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n" - "dot11RSNAGroupCipherSelected=" RSN_SUITE "\n" - "dot11RSNAPMKIDUsed=%s\n" - "dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n" - "dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n" - "dot11RSNAGroupCipherRequested=" RSN_SUITE "\n" - "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n" - "dot11RSNA4WayHandshakeFailures=%u\n", - RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)), - RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto, - sm->pairwise_cipher)), - RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto, - sm->group_cipher)), - pmkid_txt, - RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)), - RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto, - sm->pairwise_cipher)), - RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto, - sm->group_cipher)), - sm->dot11RSNA4WayHandshakeFailures); - if (ret >= 0 && (size_t) ret < buflen) - len += ret; - - return (int) len; -} -#endif /* CONFIG_CTRL_IFACE */ - - -static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry, - void *ctx, enum pmksa_free_reason reason) -{ - struct wpa_sm *sm = ctx; - int deauth = 0; - - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA cache entry free_cb: " - MACSTR " reason=%d", MAC2STR(entry->aa), reason); - - if (sm->cur_pmksa == entry) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "RSN: %s current PMKSA entry", - reason == PMKSA_REPLACE ? "replaced" : "removed"); - pmksa_cache_clear_current(sm); - - /* - * If an entry is simply being replaced, there's no need to - * deauthenticate because it will be immediately re-added. - * This happens when EAP authentication is completed again - * (reauth or failed PMKSA caching attempt). - */ - if (reason != PMKSA_REPLACE) - deauth = 1; - } - - if (reason == PMKSA_EXPIRE && - (sm->pmk_len == entry->pmk_len && - os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "RSN: deauthenticating due to expired PMK"); - pmksa_cache_clear_current(sm); - deauth = 1; - } - - if (deauth) { - os_memset(sm->pmk, 0, sizeof(sm->pmk)); - wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); - } -} - - -/** - * wpa_sm_init - Initialize WPA state machine - * @ctx: Context pointer for callbacks; this needs to be an allocated buffer - * Returns: Pointer to the allocated WPA state machine data - * - * This function is used to allocate a new WPA state machine and the returned - * value is passed to all WPA state machine calls. - */ -struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx) -{ - struct wpa_sm *sm; - - sm = os_zalloc(sizeof(*sm)); - if (sm == NULL) - return NULL; - dl_list_init(&sm->pmksa_candidates); - sm->renew_snonce = 1; - sm->ctx = ctx; - - sm->dot11RSNAConfigPMKLifetime = 43200; - sm->dot11RSNAConfigPMKReauthThreshold = 70; - sm->dot11RSNAConfigSATimeout = 60; - - sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm); - if (sm->pmksa == NULL) { - wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, - "RSN: PMKSA cache initialization failed"); - os_free(sm); - return NULL; - } - - return sm; -} - - -/** - * wpa_sm_deinit - Deinitialize WPA state machine - * @sm: Pointer to WPA state machine data from wpa_sm_init() - */ -void wpa_sm_deinit(struct wpa_sm *sm) -{ - if (sm == NULL) - return; - pmksa_cache_deinit(sm->pmksa); - eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL); - eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); - os_free(sm->assoc_wpa_ie); - os_free(sm->ap_wpa_ie); - os_free(sm->ap_rsn_ie); - os_free(sm->ctx); - peerkey_deinit(sm); -#ifdef CONFIG_IEEE80211R - os_free(sm->assoc_resp_ies); -#endif /* CONFIG_IEEE80211R */ - os_free(sm); -} - - -/** - * wpa_sm_notify_assoc - Notify WPA state machine about association - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @bssid: The BSSID of the new association - * - * This function is called to let WPA state machine know that the connection - * was established. - */ -void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) -{ - int clear_ptk = 1; - - if (sm == NULL) - return; - - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: Association event - clear replay counter"); - os_memcpy(sm->bssid, bssid, ETH_ALEN); - os_memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN); - sm->rx_replay_counter_set = 0; - sm->renew_snonce = 1; - if (os_memcmp(sm->preauth_bssid, bssid, ETH_ALEN) == 0) - rsn_preauth_deinit(sm); - -#ifdef CONFIG_IEEE80211R - if (wpa_ft_is_completed(sm)) { - /* - * Clear portValid to kick EAPOL state machine to re-enter - * AUTHENTICATED state to get the EAPOL port Authorized. - */ - eapol_sm_notify_portValid(sm->eapol, FALSE); - wpa_supplicant_key_neg_complete(sm, sm->bssid, 1); - - /* Prepare for the next transition */ - wpa_ft_prepare_auth_request(sm, NULL); - - clear_ptk = 0; - } -#endif /* CONFIG_IEEE80211R */ - - if (clear_ptk) { - /* - * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if - * this is not part of a Fast BSS Transition. - */ - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PTK"); - sm->ptk_set = 0; - sm->tptk_set = 0; - } - -#ifdef CONFIG_TDLS - wpa_tdls_assoc(sm); -#endif /* CONFIG_TDLS */ - -#ifdef CONFIG_P2P - os_memset(sm->p2p_ip_addr, 0, sizeof(sm->p2p_ip_addr)); -#endif /* CONFIG_P2P */ -} - - -/** - * wpa_sm_notify_disassoc - Notify WPA state machine about disassociation - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * - * This function is called to let WPA state machine know that the connection - * was lost. This will abort any existing pre-authentication session. - */ -void wpa_sm_notify_disassoc(struct wpa_sm *sm) -{ - peerkey_deinit(sm); - rsn_preauth_deinit(sm); - pmksa_cache_clear_current(sm); - if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE) - sm->dot11RSNA4WayHandshakeFailures++; -#ifdef CONFIG_TDLS - wpa_tdls_disassoc(sm); -#endif /* CONFIG_TDLS */ -} - - -/** - * wpa_sm_set_pmk - Set PMK - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @pmk: The new PMK - * @pmk_len: The length of the new PMK in bytes - * - * Configure the PMK for WPA state machine. - */ -void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len) -{ - if (sm == NULL) - return; - - sm->pmk_len = pmk_len; - os_memcpy(sm->pmk, pmk, pmk_len); - -#ifdef CONFIG_IEEE80211R - /* Set XXKey to be PSK for FT key derivation */ - sm->xxkey_len = pmk_len; - os_memcpy(sm->xxkey, pmk, pmk_len); -#endif /* CONFIG_IEEE80211R */ -} - - -/** - * wpa_sm_set_pmk_from_pmksa - Set PMK based on the current PMKSA - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * - * Take the PMK from the current PMKSA into use. If no PMKSA is active, the PMK - * will be cleared. - */ -void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm) -{ - if (sm == NULL) - return; - - if (sm->cur_pmksa) { - sm->pmk_len = sm->cur_pmksa->pmk_len; - os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len); - } else { - sm->pmk_len = PMK_LEN; - os_memset(sm->pmk, 0, PMK_LEN); - } -} - - -/** - * wpa_sm_set_fast_reauth - Set fast reauthentication (EAP) enabled/disabled - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @fast_reauth: Whether fast reauthentication (EAP) is allowed - */ -void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth) -{ - if (sm) - sm->fast_reauth = fast_reauth; -} - - -/** - * wpa_sm_set_scard_ctx - Set context pointer for smartcard callbacks - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @scard_ctx: Context pointer for smartcard related callback functions - */ -void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx) -{ - if (sm == NULL) - return; - sm->scard_ctx = scard_ctx; - if (sm->preauth_eapol) - eapol_sm_register_scard_ctx(sm->preauth_eapol, scard_ctx); -} - - -/** - * wpa_sm_set_config - Notification of current configration change - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @config: Pointer to current network configuration - * - * Notify WPA state machine that configuration has changed. config will be - * stored as a backpointer to network configuration. This can be %NULL to clear - * the stored pointed. - */ -void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) -{ - if (!sm) - return; - - if (config) { - sm->network_ctx = config->network_ctx; - sm->peerkey_enabled = config->peerkey_enabled; - sm->allowed_pairwise_cipher = config->allowed_pairwise_cipher; - sm->proactive_key_caching = config->proactive_key_caching; - sm->eap_workaround = config->eap_workaround; - sm->eap_conf_ctx = config->eap_conf_ctx; - if (config->ssid) { - os_memcpy(sm->ssid, config->ssid, config->ssid_len); - sm->ssid_len = config->ssid_len; - } else - sm->ssid_len = 0; - sm->wpa_ptk_rekey = config->wpa_ptk_rekey; - sm->p2p = config->p2p; - } else { - sm->network_ctx = NULL; - sm->peerkey_enabled = 0; - sm->allowed_pairwise_cipher = 0; - sm->proactive_key_caching = 0; - sm->eap_workaround = 0; - sm->eap_conf_ctx = NULL; - sm->ssid_len = 0; - sm->wpa_ptk_rekey = 0; - sm->p2p = 0; - } -} - - -/** - * wpa_sm_set_own_addr - Set own MAC address - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @addr: Own MAC address - */ -void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr) -{ - if (sm) - os_memcpy(sm->own_addr, addr, ETH_ALEN); -} - - -/** - * wpa_sm_set_ifname - Set network interface name - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @ifname: Interface name - * @bridge_ifname: Optional bridge interface name (for pre-auth) - */ -void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname, - const char *bridge_ifname) -{ - if (sm) { - sm->ifname = ifname; - sm->bridge_ifname = bridge_ifname; - } -} - - -/** - * wpa_sm_set_eapol - Set EAPOL state machine pointer - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @eapol: Pointer to EAPOL state machine allocated with eapol_sm_init() - */ -void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol) -{ - if (sm) - sm->eapol = eapol; -} - - -/** - * wpa_sm_set_param - Set WPA state machine parameters - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @param: Parameter field - * @value: Parameter value - * Returns: 0 on success, -1 on failure - */ -int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, - unsigned int value) -{ - int ret = 0; - - if (sm == NULL) - return -1; - - switch (param) { - case RSNA_PMK_LIFETIME: - if (value > 0) - sm->dot11RSNAConfigPMKLifetime = value; - else - ret = -1; - break; - case RSNA_PMK_REAUTH_THRESHOLD: - if (value > 0 && value <= 100) - sm->dot11RSNAConfigPMKReauthThreshold = value; - else - ret = -1; - break; - case RSNA_SA_TIMEOUT: - if (value > 0) - sm->dot11RSNAConfigSATimeout = value; - else - ret = -1; - break; - case WPA_PARAM_PROTO: - sm->proto = value; - break; - case WPA_PARAM_PAIRWISE: - sm->pairwise_cipher = value; - break; - case WPA_PARAM_GROUP: - sm->group_cipher = value; - break; - case WPA_PARAM_KEY_MGMT: - sm->key_mgmt = value; - break; -#ifdef CONFIG_IEEE80211W - case WPA_PARAM_MGMT_GROUP: - sm->mgmt_group_cipher = value; - break; -#endif /* CONFIG_IEEE80211W */ - case WPA_PARAM_RSN_ENABLED: - sm->rsn_enabled = value; - break; - case WPA_PARAM_MFP: - sm->mfp = value; - break; - default: - break; - } - - return ret; -} - - -/** - * wpa_sm_get_param - Get WPA state machine parameters - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @param: Parameter field - * Returns: Parameter value - */ -unsigned int wpa_sm_get_param(struct wpa_sm *sm, enum wpa_sm_conf_params param) -{ - if (sm == NULL) - return 0; - - switch (param) { - case RSNA_PMK_LIFETIME: - return sm->dot11RSNAConfigPMKLifetime; - case RSNA_PMK_REAUTH_THRESHOLD: - return sm->dot11RSNAConfigPMKReauthThreshold; - case RSNA_SA_TIMEOUT: - return sm->dot11RSNAConfigSATimeout; - case WPA_PARAM_PROTO: - return sm->proto; - case WPA_PARAM_PAIRWISE: - return sm->pairwise_cipher; - case WPA_PARAM_GROUP: - return sm->group_cipher; - case WPA_PARAM_KEY_MGMT: - return sm->key_mgmt; -#ifdef CONFIG_IEEE80211W - case WPA_PARAM_MGMT_GROUP: - return sm->mgmt_group_cipher; -#endif /* CONFIG_IEEE80211W */ - case WPA_PARAM_RSN_ENABLED: - return sm->rsn_enabled; - default: - return 0; - } -} - - -/** - * wpa_sm_get_status - Get WPA state machine - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @buf: Buffer for status information - * @buflen: Maximum buffer length - * @verbose: Whether to include verbose status information - * Returns: Number of bytes written to buf. - * - * Query WPA state machine for status information. This function fills in - * a text area with current status information. If the buffer (buf) is not - * large enough, status information will be truncated to fit the buffer. - */ -int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen, - int verbose) -{ - char *pos = buf, *end = buf + buflen; - int ret; - - ret = os_snprintf(pos, end - pos, - "pairwise_cipher=%s\n" - "group_cipher=%s\n" - "key_mgmt=%s\n", - wpa_cipher_txt(sm->pairwise_cipher), - wpa_cipher_txt(sm->group_cipher), - wpa_key_mgmt_txt(sm->key_mgmt, sm->proto)); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - - if (sm->mfp != NO_MGMT_FRAME_PROTECTION && sm->ap_rsn_ie) { - struct wpa_ie_data rsn; - if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn) - >= 0 && - rsn.capabilities & (WPA_CAPABILITY_MFPR | - WPA_CAPABILITY_MFPC)) { - ret = os_snprintf(pos, end - pos, "pmf=%d\n", - (rsn.capabilities & - WPA_CAPABILITY_MFPR) ? 2 : 1); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - } - - return pos - buf; -} - - -int wpa_sm_pmf_enabled(struct wpa_sm *sm) -{ - struct wpa_ie_data rsn; - - if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !sm->ap_rsn_ie) - return 0; - - if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn) >= 0 && - rsn.capabilities & (WPA_CAPABILITY_MFPR | WPA_CAPABILITY_MFPC)) - return 1; - - return 0; -} - - -/** - * wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @wpa_ie: Pointer to buffer for WPA/RSN IE - * @wpa_ie_len: Pointer to the length of the wpa_ie buffer - * Returns: 0 on success, -1 on failure - */ -int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie, - size_t *wpa_ie_len) -{ - int res; - - if (sm == NULL) - return -1; - - res = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len); - if (res < 0) - return -1; - *wpa_ie_len = res; - - wpa_hexdump(MSG_DEBUG, "WPA: Set own WPA IE default", - wpa_ie, *wpa_ie_len); - - if (sm->assoc_wpa_ie == NULL) { - /* - * Make a copy of the WPA/RSN IE so that 4-Way Handshake gets - * the correct version of the IE even if PMKSA caching is - * aborted (which would remove PMKID from IE generation). - */ - sm->assoc_wpa_ie = os_malloc(*wpa_ie_len); - if (sm->assoc_wpa_ie == NULL) - return -1; - - os_memcpy(sm->assoc_wpa_ie, wpa_ie, *wpa_ie_len); - sm->assoc_wpa_ie_len = *wpa_ie_len; - } - - return 0; -} - - -/** - * wpa_sm_set_assoc_wpa_ie - Set own WPA/RSN IE from (Re)AssocReq - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @ie: Pointer to IE data (starting from id) - * @len: IE length - * Returns: 0 on success, -1 on failure - * - * Inform WPA state machine about the WPA/RSN IE used in (Re)Association - * Request frame. The IE will be used to override the default value generated - * with wpa_sm_set_assoc_wpa_ie_default(). - */ -int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len) -{ - if (sm == NULL) - return -1; - - os_free(sm->assoc_wpa_ie); - if (ie == NULL || len == 0) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: clearing own WPA/RSN IE"); - sm->assoc_wpa_ie = NULL; - sm->assoc_wpa_ie_len = 0; - } else { - wpa_hexdump(MSG_DEBUG, "WPA: set own WPA/RSN IE", ie, len); - sm->assoc_wpa_ie = os_malloc(len); - if (sm->assoc_wpa_ie == NULL) - return -1; - - os_memcpy(sm->assoc_wpa_ie, ie, len); - sm->assoc_wpa_ie_len = len; - } - - return 0; -} - - -/** - * wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @ie: Pointer to IE data (starting from id) - * @len: IE length - * Returns: 0 on success, -1 on failure - * - * Inform WPA state machine about the WPA IE used in Beacon / Probe Response - * frame. - */ -int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len) -{ - if (sm == NULL) - return -1; - - os_free(sm->ap_wpa_ie); - if (ie == NULL || len == 0) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: clearing AP WPA IE"); - sm->ap_wpa_ie = NULL; - sm->ap_wpa_ie_len = 0; - } else { - wpa_hexdump(MSG_DEBUG, "WPA: set AP WPA IE", ie, len); - sm->ap_wpa_ie = os_malloc(len); - if (sm->ap_wpa_ie == NULL) - return -1; - - os_memcpy(sm->ap_wpa_ie, ie, len); - sm->ap_wpa_ie_len = len; - } - - return 0; -} - - -/** - * wpa_sm_set_ap_rsn_ie - Set AP RSN IE from Beacon/ProbeResp - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @ie: Pointer to IE data (starting from id) - * @len: IE length - * Returns: 0 on success, -1 on failure - * - * Inform WPA state machine about the RSN IE used in Beacon / Probe Response - * frame. - */ -int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len) -{ - if (sm == NULL) - return -1; - - os_free(sm->ap_rsn_ie); - if (ie == NULL || len == 0) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: clearing AP RSN IE"); - sm->ap_rsn_ie = NULL; - sm->ap_rsn_ie_len = 0; - } else { - wpa_hexdump(MSG_DEBUG, "WPA: set AP RSN IE", ie, len); - sm->ap_rsn_ie = os_malloc(len); - if (sm->ap_rsn_ie == NULL) - return -1; - - os_memcpy(sm->ap_rsn_ie, ie, len); - sm->ap_rsn_ie_len = len; - } - - return 0; -} - - -/** - * wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @data: Pointer to data area for parsing results - * Returns: 0 on success, -1 if IE is not known, or -2 on parsing failure - * - * Parse the contents of the own WPA or RSN IE from (Re)AssocReq and write the - * parsed data into data. - */ -int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data) -{ - if (sm == NULL) - return -1; - - if (sm->assoc_wpa_ie == NULL) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: No WPA/RSN IE available from association info"); - return -1; - } - if (wpa_parse_wpa_ie(sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, data)) - return -2; - return 0; -} - - -int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len) -{ - return pmksa_cache_list(sm->pmksa, buf, len); -} - - -void wpa_sm_drop_sa(struct wpa_sm *sm) -{ - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK"); - sm->ptk_set = 0; - sm->tptk_set = 0; - os_memset(sm->pmk, 0, sizeof(sm->pmk)); - os_memset(&sm->ptk, 0, sizeof(sm->ptk)); - os_memset(&sm->tptk, 0, sizeof(sm->tptk)); -} - - -int wpa_sm_has_ptk(struct wpa_sm *sm) -{ - if (sm == NULL) - 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) -{ - pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0); -} - - -#ifdef CONFIG_WNM -int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) -{ - struct wpa_gtk_data gd; -#ifdef CONFIG_IEEE80211W - struct wpa_igtk_kde igd; - u16 keyidx; -#endif /* CONFIG_IEEE80211W */ - u16 keyinfo; - u8 keylen; /* plaintext key len */ - u8 *key_rsc; - - os_memset(&gd, 0, sizeof(gd)); -#ifdef CONFIG_IEEE80211W - os_memset(&igd, 0, sizeof(igd)); -#endif /* CONFIG_IEEE80211W */ - - keylen = wpa_cipher_key_len(sm->group_cipher); - gd.key_rsc_len = wpa_cipher_rsc_len(sm->group_cipher); - gd.alg = wpa_cipher_to_alg(sm->group_cipher); - if (gd.alg == WPA_ALG_NONE) { - wpa_printf(MSG_DEBUG, "Unsupported group cipher suite"); - return -1; - } - - if (subelem_id == WNM_SLEEP_SUBELEM_GTK) { - key_rsc = buf + 5; - keyinfo = WPA_GET_LE16(buf + 2); - gd.gtk_len = keylen; - if (gd.gtk_len != buf[4]) { - wpa_printf(MSG_DEBUG, "GTK len mismatch len %d vs %d", - gd.gtk_len, buf[4]); - return -1; - } - gd.keyidx = keyinfo & 0x03; /* B0 - B1 */ - gd.tx = wpa_supplicant_gtk_tx_bit_workaround( - sm, !!(keyinfo & WPA_KEY_INFO_TXRX)); - - os_memcpy(gd.gtk, buf + 13, gd.gtk_len); - - wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)", - gd.gtk, gd.gtk_len); - if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) { - wpa_printf(MSG_DEBUG, "Failed to install the GTK in " - "WNM mode"); - return -1; - } -#ifdef CONFIG_IEEE80211W - } else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) { - os_memcpy(igd.keyid, buf + 2, 2); - os_memcpy(igd.pn, buf + 4, 6); - - keyidx = WPA_GET_LE16(igd.keyid); - os_memcpy(igd.igtk, buf + 10, WPA_IGTK_LEN); - - wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)", - igd.igtk, WPA_IGTK_LEN); - if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, - keyidx, 0, igd.pn, sizeof(igd.pn), - igd.igtk, WPA_IGTK_LEN) < 0) { - wpa_printf(MSG_DEBUG, "Failed to install the IGTK in " - "WNM mode"); - return -1; - } -#endif /* CONFIG_IEEE80211W */ - } else { - wpa_printf(MSG_DEBUG, "Unknown element id"); - return -1; - } - - return 0; -} -#endif /* CONFIG_WNM */ - - -#ifdef CONFIG_PEERKEY -int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len) -{ - struct wpa_peerkey *peerkey; - - for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) { - if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0) - break; - } - - if (!peerkey) - return 0; - - wpa_sm_rx_eapol(sm, src_addr, buf, len); - - return 1; -} -#endif /* CONFIG_PEERKEY */ - - -#ifdef CONFIG_P2P - -int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf) -{ - if (sm == NULL || WPA_GET_BE32(sm->p2p_ip_addr) == 0) - return -1; - os_memcpy(buf, sm->p2p_ip_addr, 3 * 4); - return 0; -} - -#endif /* CONFIG_P2P */ diff --git a/contrib/hostapd/src/rsn_supp/wpa.h b/contrib/hostapd/src/rsn_supp/wpa.h deleted file mode 100644 index 20b3f6211f..0000000000 --- a/contrib/hostapd/src/rsn_supp/wpa.h +++ /dev/null @@ -1,402 +0,0 @@ -/* - * wpa_supplicant - WPA definitions - * Copyright (c) 2003-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_H -#define WPA_H - -#include "common/defs.h" -#include "common/eapol_common.h" -#include "common/wpa_common.h" -#include "common/ieee802_11_defs.h" - -struct wpa_sm; -struct eapol_sm; -struct wpa_config_blob; - -struct wpa_sm_ctx { - void *ctx; /* pointer to arbitrary upper level context */ - void *msg_ctx; /* upper level context for wpa_msg() calls */ - - void (*set_state)(void *ctx, enum wpa_states state); - enum wpa_states (*get_state)(void *ctx); - void (*deauthenticate)(void * ctx, int reason_code); - int (*set_key)(void *ctx, 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); - void * (*get_network_ctx)(void *ctx); - int (*get_bssid)(void *ctx, u8 *bssid); - int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf, - size_t len); - int (*get_beacon_ie)(void *ctx); - void (*cancel_auth_timeout)(void *ctx); - u8 * (*alloc_eapol)(void *ctx, u8 type, const void *data, u16 data_len, - size_t *msg_len, void **data_pos); - int (*add_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid); - int (*remove_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid); - void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob); - const struct wpa_config_blob * (*get_config_blob)(void *ctx, - const char *name); - int (*mlme_setprotection)(void *ctx, const u8 *addr, - int protection_type, int key_type); - int (*update_ft_ies)(void *ctx, const u8 *md, const u8 *ies, - size_t ies_len); - int (*send_ft_action)(void *ctx, u8 action, const u8 *target_ap, - 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 aid, - u16 capability, const u8 *supp_rates, - size_t supp_rates_len, - const struct ieee80211_ht_capabilities *ht_capab, - const struct ieee80211_vht_capabilities *vht_capab, - u8 qosinfo, const u8 *ext_capab, - size_t ext_capab_len, const u8 *supp_channels, - size_t supp_channels_len, - const u8 *supp_oper_classes, - size_t supp_oper_classes_len); -#endif /* CONFIG_TDLS */ - void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck, - const u8 *replay_ctr); -}; - - -enum wpa_sm_conf_params { - RSNA_PMK_LIFETIME /* dot11RSNAConfigPMKLifetime */, - RSNA_PMK_REAUTH_THRESHOLD /* dot11RSNAConfigPMKReauthThreshold */, - RSNA_SA_TIMEOUT /* dot11RSNAConfigSATimeout */, - WPA_PARAM_PROTO, - WPA_PARAM_PAIRWISE, - WPA_PARAM_GROUP, - WPA_PARAM_KEY_MGMT, - WPA_PARAM_MGMT_GROUP, - WPA_PARAM_RSN_ENABLED, - WPA_PARAM_MFP -}; - -struct rsn_supp_config { - void *network_ctx; - int peerkey_enabled; - int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */ - int proactive_key_caching; - int eap_workaround; - void *eap_conf_ctx; - const u8 *ssid; - size_t ssid_len; - int wpa_ptk_rekey; - int p2p; -}; - -#ifndef CONFIG_NO_WPA - -struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx); -void wpa_sm_deinit(struct wpa_sm *sm); -void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid); -void wpa_sm_notify_disassoc(struct wpa_sm *sm); -void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len); -void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm); -void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth); -void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx); -void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config); -void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr); -void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname, - const char *bridge_ifname); -void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol); -int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len); -int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie, - size_t *wpa_ie_len); -int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len); -int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len); -int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen); - -int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, - unsigned int value); -unsigned int wpa_sm_get_param(struct wpa_sm *sm, - enum wpa_sm_conf_params param); - -int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen, - int verbose); -int wpa_sm_pmf_enabled(struct wpa_sm *sm); - -void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise); - -int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, - struct wpa_ie_data *data); - -void wpa_sm_aborted_cached(struct wpa_sm *sm); -int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len); -int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data); -int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len); -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); - -int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf); - -#else /* CONFIG_NO_WPA */ - -static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx) -{ - return (struct wpa_sm *) 1; -} - -static inline void wpa_sm_deinit(struct wpa_sm *sm) -{ -} - -static inline void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) -{ -} - -static inline void wpa_sm_notify_disassoc(struct wpa_sm *sm) -{ -} - -static inline void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, - size_t pmk_len) -{ -} - -static inline void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm) -{ -} - -static inline void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth) -{ -} - -static inline void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx) -{ -} - -static inline void wpa_sm_set_config(struct wpa_sm *sm, - struct rsn_supp_config *config) -{ -} - -static inline void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr) -{ -} - -static inline void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname, - const char *bridge_ifname) -{ -} - -static inline void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol) -{ -} - -static inline int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, - size_t len) -{ - return -1; -} - -static inline int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, - u8 *wpa_ie, - size_t *wpa_ie_len) -{ - return -1; -} - -static inline int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, - size_t len) -{ - return -1; -} - -static inline int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, - size_t len) -{ - return -1; -} - -static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen) -{ - return 0; -} - -static inline int wpa_sm_set_param(struct wpa_sm *sm, - enum wpa_sm_conf_params param, - unsigned int value) -{ - return -1; -} - -static inline unsigned int wpa_sm_get_param(struct wpa_sm *sm, - enum wpa_sm_conf_params param) -{ - return 0; -} - -static inline int wpa_sm_get_status(struct wpa_sm *sm, char *buf, - size_t buflen, int verbose) -{ - return 0; -} - -static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm) -{ - return 0; -} - -static inline void wpa_sm_key_request(struct wpa_sm *sm, int error, - int pairwise) -{ -} - -static inline int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, - struct wpa_ie_data *data) -{ - return -1; -} - -static inline void wpa_sm_aborted_cached(struct wpa_sm *sm) -{ -} - -static inline int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len) -{ - return -1; -} - -static inline int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, - struct wpa_ie_data *data) -{ - return -1; -} - -static inline int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, - size_t len) -{ - return -1; -} - -static inline void wpa_sm_drop_sa(struct wpa_sm *sm) -{ -} - -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 -int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer); -int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len); -#else /* CONFIG_PEERKEY */ -static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) -{ - return -1; -} - -static inline int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len) -{ - return 0; -} -#endif /* CONFIG_PEERKEY */ - -#ifdef CONFIG_IEEE80211R - -int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len); -int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie); -int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, - int ft_action, const u8 *target_ap, - const u8 *ric_ies, size_t ric_ies_len); -int wpa_ft_is_completed(struct wpa_sm *sm); -void wpa_reset_ft_completed(struct wpa_sm *sm); -int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, - size_t ies_len, const u8 *src_addr); -int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap, - const u8 *mdie); - -#else /* CONFIG_IEEE80211R */ - -static inline int -wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) -{ - return 0; -} - -static inline int wpa_ft_prepare_auth_request(struct wpa_sm *sm, - const u8 *mdie) -{ - return 0; -} - -static inline int -wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, - int ft_action, const u8 *target_ap) -{ - return 0; -} - -static inline int wpa_ft_is_completed(struct wpa_sm *sm) -{ - return 0; -} - -static inline void wpa_reset_ft_completed(struct wpa_sm *sm) -{ -} - -static inline int -wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len, - const u8 *src_addr) -{ - return -1; -} - -#endif /* CONFIG_IEEE80211R */ - - -/* tdls.c */ -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); -void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr); -int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code); -int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code); -int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr); -int wpa_tdls_init(struct wpa_sm *sm); -void wpa_tdls_teardown_peers(struct wpa_sm *sm); -void wpa_tdls_deinit(struct wpa_sm *sm); -void wpa_tdls_enable(struct wpa_sm *sm, int enabled); -void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr); -const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr); -int wpa_tdls_is_external_setup(struct wpa_sm *sm); - -int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf); - -#endif /* WPA_H */ diff --git a/contrib/hostapd/src/rsn_supp/wpa_ft.c b/contrib/hostapd/src/rsn_supp/wpa_ft.c deleted file mode 100644 index c8d8cfc8b6..0000000000 --- a/contrib/hostapd/src/rsn_supp/wpa_ft.c +++ /dev/null @@ -1,848 +0,0 @@ -/* - * WPA Supplicant - IEEE 802.11r - Fast BSS Transition - * Copyright (c) 2006-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/aes_wrap.h" -#include "crypto/random.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "wpa.h" -#include "wpa_i.h" - -#ifdef CONFIG_IEEE80211R - -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) -{ - u8 ptk_name[WPA_PMK_NAME_LEN]; - const u8 *anonce = key->key_nonce; - - if (sm->xxkey_len == 0) { - wpa_printf(MSG_DEBUG, "FT: XXKey not available for key " - "derivation"); - return -1; - } - - wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid, - sm->ssid_len, sm->mobility_domain, - sm->r0kh_id, sm->r0kh_id_len, sm->own_addr, - sm->pmk_r0, sm->pmk_r0_name); - wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", - sm->pmk_r0_name, WPA_PMK_NAME_LEN); - wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id, - sm->own_addr, sm->pmk_r1, sm->pmk_r1_name); - wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name, - WPA_PMK_NAME_LEN); - wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr, - sm->bssid, sm->pmk_r1_name, - (u8 *) ptk, ptk_len, ptk_name); - wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len); - wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); - - return 0; -} - - -/** - * wpa_sm_set_ft_params - Set FT (IEEE 802.11r) parameters - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @ies: Association Response IEs or %NULL to clear FT parameters - * @ies_len: Length of ies buffer in octets - * Returns: 0 on success, -1 on failure - */ -int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) -{ - struct wpa_ft_ies ft; - - if (sm == NULL) - return 0; - - if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0) - return -1; - - if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) - return -1; - - if (ft.mdie) { - wpa_hexdump(MSG_DEBUG, "FT: Mobility domain", - ft.mdie, MOBILITY_DOMAIN_ID_LEN); - os_memcpy(sm->mobility_domain, ft.mdie, - MOBILITY_DOMAIN_ID_LEN); - sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN]; - wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x", - sm->mdie_ft_capab); - } else - os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN); - - if (ft.r0kh_id) { - wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", - ft.r0kh_id, ft.r0kh_id_len); - os_memcpy(sm->r0kh_id, ft.r0kh_id, ft.r0kh_id_len); - sm->r0kh_id_len = ft.r0kh_id_len; - } else { - /* FIX: When should R0KH-ID be cleared? We need to keep the - * old R0KH-ID in order to be able to use this during FT. */ - /* - * os_memset(sm->r0kh_id, 0, FT_R0KH_ID_LEN); - * sm->r0kh_id_len = 0; - */ - } - - if (ft.r1kh_id) { - wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", - ft.r1kh_id, FT_R1KH_ID_LEN); - os_memcpy(sm->r1kh_id, ft.r1kh_id, FT_R1KH_ID_LEN); - } else - os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN); - - os_free(sm->assoc_resp_ies); - sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2); - if (sm->assoc_resp_ies) { - u8 *pos = sm->assoc_resp_ies; - if (ft.mdie) { - os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2); - pos += ft.mdie_len + 2; - } - if (ft.ftie) { - os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2); - pos += ft.ftie_len + 2; - } - sm->assoc_resp_ies_len = pos - sm->assoc_resp_ies; - wpa_hexdump(MSG_DEBUG, "FT: Stored MDIE and FTIE from " - "(Re)Association Response", - sm->assoc_resp_ies, sm->assoc_resp_ies_len); - } - - return 0; -} - - -/** - * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth/ReAssoc Request - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @len: Buffer for returning the length of the IEs - * @anonce: ANonce or %NULL if not yet available - * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List - * @kck: 128-bit KCK for MIC or %NULL if no MIC is used - * @target_ap: Target AP address - * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL - * @ric_ies_len: Length of ric_ies buffer in octets - * @ap_mdie: Mobility Domain IE from the target AP - * Returns: Pointer to buffer with IEs or %NULL on failure - * - * Caller is responsible for freeing the returned buffer with os_free(); - */ -static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, - const u8 *anonce, const u8 *pmk_name, - const u8 *kck, const u8 *target_ap, - const u8 *ric_ies, size_t ric_ies_len, - const u8 *ap_mdie) -{ - size_t buf_len; - u8 *buf, *pos, *ftie_len, *ftie_pos; - struct rsn_mdie *mdie; - struct rsn_ftie *ftie; - struct rsn_ie_hdr *rsnie; - u16 capab; - - sm->ft_completed = 0; - - buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + - 2 + sm->r0kh_id_len + ric_ies_len + 100; - buf = os_zalloc(buf_len); - if (buf == NULL) - return NULL; - pos = buf; - - /* RSNIE[PMKR0Name/PMKR1Name] */ - rsnie = (struct rsn_ie_hdr *) pos; - rsnie->elem_id = WLAN_EID_RSN; - WPA_PUT_LE16(rsnie->version, RSN_VERSION); - pos = (u8 *) (rsnie + 1); - - /* Group Suite Selector */ - if (sm->group_cipher != WPA_CIPHER_CCMP && - sm->group_cipher != WPA_CIPHER_GCMP && - sm->group_cipher != WPA_CIPHER_TKIP) { - wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)", - sm->group_cipher); - os_free(buf); - return NULL; - } - RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, - sm->group_cipher)); - pos += RSN_SELECTOR_LEN; - - /* Pairwise Suite Count */ - WPA_PUT_LE16(pos, 1); - pos += 2; - - /* Pairwise Suite List */ - if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) { - wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)", - sm->pairwise_cipher); - os_free(buf); - return NULL; - } - RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, - sm->pairwise_cipher)); - pos += RSN_SELECTOR_LEN; - - /* Authenticated Key Management Suite Count */ - WPA_PUT_LE16(pos, 1); - pos += 2; - - /* Authenticated Key Management Suite List */ - if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); - else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); - else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE) - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); - else { - wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)", - sm->key_mgmt); - os_free(buf); - return NULL; - } - pos += RSN_SELECTOR_LEN; - - /* RSN Capabilities */ - capab = 0; -#ifdef CONFIG_IEEE80211W - if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) - capab |= WPA_CAPABILITY_MFPC; -#endif /* CONFIG_IEEE80211W */ - WPA_PUT_LE16(pos, capab); - pos += 2; - - /* PMKID Count */ - WPA_PUT_LE16(pos, 1); - pos += 2; - - /* PMKID List [PMKR0Name/PMKR1Name] */ - os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN); - pos += WPA_PMK_NAME_LEN; - -#ifdef CONFIG_IEEE80211W - if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { - /* Management Group Cipher Suite */ - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); - pos += RSN_SELECTOR_LEN; - } -#endif /* CONFIG_IEEE80211W */ - - rsnie->len = (pos - (u8 *) rsnie) - 2; - - /* MDIE */ - *pos++ = WLAN_EID_MOBILITY_DOMAIN; - *pos++ = sizeof(*mdie); - mdie = (struct rsn_mdie *) pos; - pos += sizeof(*mdie); - os_memcpy(mdie->mobility_domain, sm->mobility_domain, - MOBILITY_DOMAIN_ID_LEN); - mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] : - sm->mdie_ft_capab; - - /* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */ - ftie_pos = pos; - *pos++ = WLAN_EID_FAST_BSS_TRANSITION; - ftie_len = pos++; - ftie = (struct rsn_ftie *) pos; - pos += sizeof(*ftie); - os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN); - if (anonce) - os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN); - if (kck) { - /* R1KH-ID sub-element in third FT message */ - *pos++ = FTIE_SUBELEM_R1KH_ID; - *pos++ = FT_R1KH_ID_LEN; - os_memcpy(pos, sm->r1kh_id, FT_R1KH_ID_LEN); - pos += FT_R1KH_ID_LEN; - } - /* R0KH-ID sub-element */ - *pos++ = FTIE_SUBELEM_R0KH_ID; - *pos++ = sm->r0kh_id_len; - os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len); - pos += sm->r0kh_id_len; - *ftie_len = pos - ftie_len - 1; - - if (ric_ies) { - /* RIC Request */ - os_memcpy(pos, ric_ies, ric_ies_len); - pos += ric_ies_len; - } - - if (kck) { - /* - * IEEE Std 802.11r-2008, 11A.8.4 - * MIC shall be calculated over: - * non-AP STA MAC address - * Target AP MAC address - * Transaction seq number (5 for ReassocReq, 3 otherwise) - * RSN IE - * MDIE - * FTIE (with MIC field set to 0) - * RIC-Request (if present) - */ - /* Information element count */ - ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies, - ric_ies_len); - if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5, - ((u8 *) mdie) - 2, 2 + sizeof(*mdie), - ftie_pos, 2 + *ftie_len, - (u8 *) rsnie, 2 + rsnie->len, ric_ies, - ric_ies_len, ftie->mic) < 0) { - wpa_printf(MSG_INFO, "FT: Failed to calculate MIC"); - os_free(buf); - return NULL; - } - } - - *len = pos - buf; - - return buf; -} - - -static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid) -{ - int keylen; - enum wpa_alg alg; - u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 }; - - wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver."); - - if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) { - wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d", - sm->pairwise_cipher); - return -1; - } - - alg = wpa_cipher_to_alg(sm->pairwise_cipher); - keylen = wpa_cipher_key_len(sm->pairwise_cipher); - - if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, - sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) { - wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver"); - return -1; - } - - return 0; -} - - -/** - * wpa_ft_prepare_auth_request - Generate over-the-air auth request - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @mdie: Target AP MDIE - * Returns: 0 on success, -1 on failure - */ -int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie) -{ - u8 *ft_ies; - size_t ft_ies_len; - - /* Generate a new SNonce */ - if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) { - wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce"); - return -1; - } - - ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, - NULL, sm->bssid, NULL, 0, mdie); - if (ft_ies) { - wpa_sm_update_ft_ies(sm, sm->mobility_domain, - ft_ies, ft_ies_len); - os_free(ft_ies); - } - - return 0; -} - - -int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, - int ft_action, const u8 *target_ap, - const u8 *ric_ies, size_t ric_ies_len) -{ - u8 *ft_ies; - size_t ft_ies_len, ptk_len; - struct wpa_ft_ies parse; - struct rsn_mdie *mdie; - struct rsn_ftie *ftie; - u8 ptk_name[WPA_PMK_NAME_LEN]; - int ret; - const u8 *bssid; - - wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); - wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len); - - if (ft_action) { - if (!sm->over_the_ds_in_progress) { - wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress " - "- drop FT Action Response"); - return -1; - } - - if (os_memcmp(target_ap, sm->target_ap, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress " - "with this Target AP - drop FT Action " - "Response"); - return -1; - } - } - - if (!wpa_key_mgmt_ft(sm->key_mgmt)) { - wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " - "enabled for this connection"); - return -1; - } - - if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { - wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); - return -1; - } - - mdie = (struct rsn_mdie *) parse.mdie; - if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || - os_memcmp(mdie->mobility_domain, sm->mobility_domain, - MOBILITY_DOMAIN_ID_LEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); - return -1; - } - - ftie = (struct rsn_ftie *) parse.ftie; - if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); - return -1; - } - - if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); - wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", - ftie->snonce, WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", - sm->snonce, WPA_NONCE_LEN); - return -1; - } - - if (parse.r0kh_id == NULL) { - wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); - return -1; - } - - if (parse.r0kh_id_len != sm->r0kh_id_len || - os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { - wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " - "the current R0KH-ID"); - wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", - parse.r0kh_id, parse.r0kh_id_len); - wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", - sm->r0kh_id, sm->r0kh_id_len); - return -1; - } - - if (parse.r1kh_id == NULL) { - wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); - return -1; - } - - if (parse.rsn_pmkid == NULL || - os_memcmp(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) { - wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in " - "RSNIE"); - return -1; - } - - os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN); - wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN); - wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN); - os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN); - wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id, - sm->own_addr, sm->pmk_r1, sm->pmk_r1_name); - wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", - sm->pmk_r1_name, WPA_PMK_NAME_LEN); - - bssid = target_ap; - ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64; - wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr, - bssid, sm->pmk_r1_name, - (u8 *) &sm->ptk, ptk_len, ptk_name); - wpa_hexdump_key(MSG_DEBUG, "FT: PTK", - (u8 *) &sm->ptk, ptk_len); - wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); - - ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce, - sm->pmk_r1_name, sm->ptk.kck, bssid, - ric_ies, ric_ies_len, - parse.mdie ? parse.mdie - 2 : NULL); - if (ft_ies) { - wpa_sm_update_ft_ies(sm, sm->mobility_domain, - ft_ies, ft_ies_len); - os_free(ft_ies); - } - - wpa_sm_mark_authenticated(sm, bssid); - ret = wpa_ft_install_ptk(sm, bssid); - if (ret) { - /* - * Some drivers do not support key configuration when we are - * not associated with the target AP. Work around this by - * trying again after the following reassociation gets - * completed. - */ - wpa_printf(MSG_DEBUG, "FT: Failed to set PTK prior to " - "association - try again after reassociation"); - sm->set_ptk_after_assoc = 1; - } else - sm->set_ptk_after_assoc = 0; - - sm->ft_completed = 1; - if (ft_action) { - /* - * The caller is expected trigger re-association with the - * Target AP. - */ - os_memcpy(sm->bssid, target_ap, ETH_ALEN); - } - - return 0; -} - - -int wpa_ft_is_completed(struct wpa_sm *sm) -{ - if (sm == NULL) - return 0; - - if (!wpa_key_mgmt_ft(sm->key_mgmt)) - return 0; - - return sm->ft_completed; -} - - -void wpa_reset_ft_completed(struct wpa_sm *sm) -{ - if (sm != NULL) - sm->ft_completed = 0; -} - - -static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem, - size_t gtk_elem_len) -{ - u8 gtk[32]; - int keyidx; - enum wpa_alg alg; - size_t gtk_len, keylen, rsc_len; - - if (gtk_elem == NULL) { - wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE"); - return 0; - } - - wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp", - gtk_elem, gtk_elem_len); - - if (gtk_elem_len < 11 + 24 || (gtk_elem_len - 11) % 8 || - gtk_elem_len - 19 > sizeof(gtk)) { - wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem " - "length %lu", (unsigned long) gtk_elem_len); - return -1; - } - gtk_len = gtk_elem_len - 19; - if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 11, gtk)) { - wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " - "decrypt GTK"); - return -1; - } - - keylen = wpa_cipher_key_len(sm->group_cipher); - rsc_len = wpa_cipher_rsc_len(sm->group_cipher); - alg = wpa_cipher_to_alg(sm->group_cipher); - if (alg == WPA_ALG_NONE) { - wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d", - sm->group_cipher); - return -1; - } - - if (gtk_len < keylen) { - wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE"); - return -1; - } - - /* Key Info[2] | Key Length[1] | RSC[8] | Key[5..32]. */ - - keyidx = WPA_GET_LE16(gtk_elem) & 0x03; - - if (gtk_elem[2] != keylen) { - wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d " - "negotiated %lu", - gtk_elem[2], (unsigned long) keylen); - return -1; - } - - wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen); - if (sm->group_cipher == WPA_CIPHER_TKIP) { - /* Swap Tx/Rx keys for Michael MIC */ - u8 tmp[8]; - os_memcpy(tmp, gtk + 16, 8); - os_memcpy(gtk + 16, gtk + 24, 8); - os_memcpy(gtk + 24, tmp, 8); - } - if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0, - gtk_elem + 3, rsc_len, gtk, keylen) < 0) { - wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the " - "driver."); - return -1; - } - - return 0; -} - - -#ifdef CONFIG_IEEE80211W -static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem, - size_t igtk_elem_len) -{ - u8 igtk[WPA_IGTK_LEN]; - u16 keyidx; - - if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) - return 0; - - if (igtk_elem == NULL) { - wpa_printf(MSG_DEBUG, "FT: No IGTK included in FTIE"); - return 0; - } - - wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp", - igtk_elem, igtk_elem_len); - - if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) { - wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem " - "length %lu", (unsigned long) igtk_elem_len); - return -1; - } - if (igtk_elem[8] != WPA_IGTK_LEN) { - wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length " - "%d", igtk_elem[8]); - return -1; - } - - if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) { - wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " - "decrypt IGTK"); - return -1; - } - - /* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */ - - keyidx = WPA_GET_LE16(igtk_elem); - - wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk, - WPA_IGTK_LEN); - if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, keyidx, 0, - igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) < 0) { - wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the " - "driver."); - return -1; - } - - return 0; -} -#endif /* CONFIG_IEEE80211W */ - - -int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, - size_t ies_len, const u8 *src_addr) -{ - struct wpa_ft_ies parse; - struct rsn_mdie *mdie; - struct rsn_ftie *ftie; - unsigned int count; - u8 mic[16]; - - wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); - - if (!wpa_key_mgmt_ft(sm->key_mgmt)) { - wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " - "enabled for this connection"); - return -1; - } - - if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { - wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); - return -1; - } - - mdie = (struct rsn_mdie *) parse.mdie; - if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || - os_memcmp(mdie->mobility_domain, sm->mobility_domain, - MOBILITY_DOMAIN_ID_LEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); - return -1; - } - - ftie = (struct rsn_ftie *) parse.ftie; - if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); - return -1; - } - - if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); - wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", - ftie->snonce, WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", - sm->snonce, WPA_NONCE_LEN); - return -1; - } - - if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE"); - wpa_hexdump(MSG_DEBUG, "FT: Received ANonce", - ftie->anonce, WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce", - sm->anonce, WPA_NONCE_LEN); - return -1; - } - - if (parse.r0kh_id == NULL) { - wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); - return -1; - } - - if (parse.r0kh_id_len != sm->r0kh_id_len || - os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { - wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " - "the current R0KH-ID"); - wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", - parse.r0kh_id, parse.r0kh_id_len); - wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", - sm->r0kh_id, sm->r0kh_id_len); - return -1; - } - - if (parse.r1kh_id == NULL) { - wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); - return -1; - } - - if (os_memcmp(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in " - "ReassocResp"); - return -1; - } - - if (parse.rsn_pmkid == NULL || - os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) { - wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in " - "RSNIE (pmkid=%d)", !!parse.rsn_pmkid); - return -1; - } - - count = 3; - 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", - ftie->mic_control[1], count); - return -1; - } - - if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6, - parse.mdie - 2, parse.mdie_len + 2, - parse.ftie - 2, parse.ftie_len + 2, - parse.rsn - 2, parse.rsn_len + 2, - parse.ric, parse.ric_len, - mic) < 0) { - wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); - return -1; - } - - if (os_memcmp(mic, ftie->mic, 16) != 0) { - wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE"); - wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16); - wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16); - return -1; - } - - if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0) - return -1; - -#ifdef CONFIG_IEEE80211W - if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0) - return -1; -#endif /* CONFIG_IEEE80211W */ - - if (sm->set_ptk_after_assoc) { - wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we " - "are associated"); - if (wpa_ft_install_ptk(sm, src_addr) < 0) - return -1; - sm->set_ptk_after_assoc = 0; - } - - if (parse.ric) { - wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response", - parse.ric, parse.ric_len); - /* TODO: parse response and inform driver about results when - * using wpa_supplicant SME */ - } - - wpa_printf(MSG_DEBUG, "FT: Completed successfully"); - - return 0; -} - - -/** - * wpa_ft_start_over_ds - Generate over-the-DS auth request - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @target_ap: Target AP Address - * @mdie: Mobility Domain IE from the target AP - * Returns: 0 on success, -1 on failure - */ -int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap, - const u8 *mdie) -{ - u8 *ft_ies; - size_t ft_ies_len; - - wpa_printf(MSG_DEBUG, "FT: Request over-the-DS with " MACSTR, - MAC2STR(target_ap)); - - /* Generate a new SNonce */ - if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) { - wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce"); - return -1; - } - - ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, - NULL, target_ap, NULL, 0, mdie); - if (ft_ies) { - sm->over_the_ds_in_progress = 1; - os_memcpy(sm->target_ap, target_ap, ETH_ALEN); - wpa_sm_send_ft_action(sm, 1, target_ap, ft_ies, ft_ies_len); - os_free(ft_ies); - } - - return 0; -} - -#endif /* CONFIG_IEEE80211R */ diff --git a/contrib/hostapd/src/rsn_supp/wpa_i.h b/contrib/hostapd/src/rsn_supp/wpa_i.h deleted file mode 100644 index 75cfb479e0..0000000000 --- a/contrib/hostapd/src/rsn_supp/wpa_i.h +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Internal WPA/RSN supplicant state machine definitions - * Copyright (c) 2004-2010, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_I_H -#define WPA_I_H - -#include "utils/list.h" - -struct wpa_peerkey; -struct wpa_tdls_peer; -struct wpa_eapol_key; - -/** - * struct wpa_sm - Internal WPA state machine data - */ -struct wpa_sm { - u8 pmk[PMK_LEN]; - size_t pmk_len; - struct wpa_ptk ptk, tptk; - int ptk_set, tptk_set; - u8 snonce[WPA_NONCE_LEN]; - u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */ - int renew_snonce; - u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN]; - int rx_replay_counter_set; - u8 request_counter[WPA_REPLAY_COUNTER_LEN]; - - struct eapol_sm *eapol; /* EAPOL state machine from upper level code */ - - struct rsn_pmksa_cache *pmksa; /* PMKSA cache */ - struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */ - struct dl_list pmksa_candidates; - - struct l2_packet_data *l2_preauth; - struct l2_packet_data *l2_preauth_br; - struct l2_packet_data *l2_tdls; - u8 preauth_bssid[ETH_ALEN]; /* current RSN pre-auth peer or - * 00:00:00:00:00:00 if no pre-auth is - * in progress */ - struct eapol_sm *preauth_eapol; - - struct wpa_sm_ctx *ctx; - - void *scard_ctx; /* context for smartcard callbacks */ - int fast_reauth; /* whether EAP fast re-authentication is enabled */ - - void *network_ctx; - int peerkey_enabled; - int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */ - int proactive_key_caching; - int eap_workaround; - void *eap_conf_ctx; - u8 ssid[32]; - size_t ssid_len; - int wpa_ptk_rekey; - int p2p; - - u8 own_addr[ETH_ALEN]; - const char *ifname; - const char *bridge_ifname; - u8 bssid[ETH_ALEN]; - - unsigned int dot11RSNAConfigPMKLifetime; - unsigned int dot11RSNAConfigPMKReauthThreshold; - unsigned int dot11RSNAConfigSATimeout; - - unsigned int dot11RSNA4WayHandshakeFailures; - - /* Selected configuration (based on Beacon/ProbeResp WPA IE) */ - unsigned int proto; - unsigned int pairwise_cipher; - unsigned int group_cipher; - unsigned int key_mgmt; - unsigned int mgmt_group_cipher; - - int rsn_enabled; /* Whether RSN is enabled in configuration */ - int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */ - - u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */ - size_t assoc_wpa_ie_len; - u8 *ap_wpa_ie, *ap_rsn_ie; - size_t ap_wpa_ie_len, ap_rsn_ie_len; - -#ifdef CONFIG_PEERKEY - struct wpa_peerkey *peerkey; -#endif /* CONFIG_PEERKEY */ -#ifdef CONFIG_TDLS - 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 - u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */ - size_t xxkey_len; - u8 pmk_r0[PMK_LEN]; - u8 pmk_r0_name[WPA_PMK_NAME_LEN]; - u8 pmk_r1[PMK_LEN]; - u8 pmk_r1_name[WPA_PMK_NAME_LEN]; - u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; - u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; - size_t r0kh_id_len; - u8 r1kh_id[FT_R1KH_ID_LEN]; - int ft_completed; - int over_the_ds_in_progress; - u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */ - int set_ptk_after_assoc; - u8 mdie_ft_capab; /* FT Capability and Policy from target AP MDIE */ - u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */ - size_t assoc_resp_ies_len; -#endif /* CONFIG_IEEE80211R */ - -#ifdef CONFIG_P2P - u8 p2p_ip_addr[3 * 4]; -#endif /* CONFIG_P2P */ -}; - - -static inline void wpa_sm_set_state(struct wpa_sm *sm, enum wpa_states state) -{ - WPA_ASSERT(sm->ctx->set_state); - sm->ctx->set_state(sm->ctx->ctx, state); -} - -static inline enum wpa_states wpa_sm_get_state(struct wpa_sm *sm) -{ - WPA_ASSERT(sm->ctx->get_state); - return sm->ctx->get_state(sm->ctx->ctx); -} - -static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, int reason_code) -{ - WPA_ASSERT(sm->ctx->deauthenticate); - sm->ctx->deauthenticate(sm->ctx->ctx, reason_code); -} - -static inline int wpa_sm_set_key(struct wpa_sm *sm, 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) -{ - WPA_ASSERT(sm->ctx->set_key); - return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx, - seq, seq_len, key, key_len); -} - -static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm) -{ - WPA_ASSERT(sm->ctx->get_network_ctx); - return sm->ctx->get_network_ctx(sm->ctx->ctx); -} - -static inline int wpa_sm_get_bssid(struct wpa_sm *sm, u8 *bssid) -{ - WPA_ASSERT(sm->ctx->get_bssid); - return sm->ctx->get_bssid(sm->ctx->ctx, bssid); -} - -static inline int wpa_sm_ether_send(struct wpa_sm *sm, const u8 *dest, - u16 proto, const u8 *buf, size_t len) -{ - WPA_ASSERT(sm->ctx->ether_send); - return sm->ctx->ether_send(sm->ctx->ctx, dest, proto, buf, len); -} - -static inline int wpa_sm_get_beacon_ie(struct wpa_sm *sm) -{ - WPA_ASSERT(sm->ctx->get_beacon_ie); - return sm->ctx->get_beacon_ie(sm->ctx->ctx); -} - -static inline void wpa_sm_cancel_auth_timeout(struct wpa_sm *sm) -{ - WPA_ASSERT(sm->ctx->cancel_auth_timeout); - sm->ctx->cancel_auth_timeout(sm->ctx->ctx); -} - -static inline u8 * wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type, - const void *data, u16 data_len, - size_t *msg_len, void **data_pos) -{ - WPA_ASSERT(sm->ctx->alloc_eapol); - return sm->ctx->alloc_eapol(sm->ctx->ctx, type, data, data_len, - msg_len, data_pos); -} - -static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, const u8 *bssid, - const u8 *pmkid) -{ - WPA_ASSERT(sm->ctx->add_pmkid); - return sm->ctx->add_pmkid(sm->ctx->ctx, bssid, pmkid); -} - -static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, const u8 *bssid, - const u8 *pmkid) -{ - WPA_ASSERT(sm->ctx->remove_pmkid); - return sm->ctx->remove_pmkid(sm->ctx->ctx, bssid, pmkid); -} - -static inline int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr, - int protect_type, int key_type) -{ - WPA_ASSERT(sm->ctx->mlme_setprotection); - return sm->ctx->mlme_setprotection(sm->ctx->ctx, addr, protect_type, - key_type); -} - -static inline int wpa_sm_update_ft_ies(struct wpa_sm *sm, const u8 *md, - const u8 *ies, size_t ies_len) -{ - if (sm->ctx->update_ft_ies) - return sm->ctx->update_ft_ies(sm->ctx->ctx, md, ies, ies_len); - return -1; -} - -static inline int wpa_sm_send_ft_action(struct wpa_sm *sm, u8 action, - const u8 *target_ap, - const u8 *ies, size_t ies_len) -{ - if (sm->ctx->send_ft_action) - return sm->ctx->send_ft_action(sm->ctx->ctx, action, target_ap, - ies, ies_len); - return -1; -} - -static inline int wpa_sm_mark_authenticated(struct wpa_sm *sm, - const u8 *target_ap) -{ - if (sm->ctx->mark_authenticated) - return sm->ctx->mark_authenticated(sm->ctx->ctx, target_ap); - 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, - size_t len) -{ - if (sm->ctx->send_tdls_mgmt) - return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code, - dialog_token, status_code, - buf, len); - return -1; -} - -static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper, - const u8 *peer) -{ - if (sm->ctx->tdls_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 aid, u16 capability, const u8 *supp_rates, - size_t supp_rates_len, - const struct ieee80211_ht_capabilities *ht_capab, - const struct ieee80211_vht_capabilities *vht_capab, - u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len, - const u8 *supp_channels, size_t supp_channels_len, - const u8 *supp_oper_classes, - size_t supp_oper_classes_len) -{ - if (sm->ctx->tdls_peer_addset) - return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add, - aid, capability, supp_rates, - supp_rates_len, ht_capab, - vht_capab, qosinfo, - ext_capab, ext_capab_len, - supp_channels, - supp_channels_len, - supp_oper_classes, - supp_oper_classes_len); - return -1; -} -#endif /* CONFIG_TDLS */ - -void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, - int ver, const u8 *dest, u16 proto, - u8 *msg, size_t msg_len, u8 *key_mic); -int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, - const struct wpa_eapol_key *key, - int ver, const u8 *nonce, - const u8 *wpa_ie, size_t wpa_ie_len, - struct wpa_ptk *ptk); -int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, - const struct wpa_eapol_key *key, - u16 ver, u16 key_info, - const u8 *kde, size_t kde_len, - struct wpa_ptk *ptk); - -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); - -void wpa_tdls_assoc(struct wpa_sm *sm); -void wpa_tdls_disassoc(struct wpa_sm *sm); - -#endif /* WPA_I_H */ diff --git a/contrib/hostapd/src/rsn_supp/wpa_ie.c b/contrib/hostapd/src/rsn_supp/wpa_ie.c deleted file mode 100644 index e58bdc477c..0000000000 --- a/contrib/hostapd/src/rsn_supp/wpa_ie.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * wpa_supplicant - WPA/RSN IE and KDE processing - * Copyright (c) 2003-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "wpa.h" -#include "pmksa_cache.h" -#include "common/ieee802_11_defs.h" -#include "wpa_i.h" -#include "wpa_ie.h" - - -/** - * wpa_parse_wpa_ie - Parse WPA/RSN IE - * @wpa_ie: Pointer to WPA or RSN IE - * @wpa_ie_len: Length of the WPA/RSN IE - * @data: Pointer to data area for parsing results - * Returns: 0 on success, -1 on failure - * - * Parse the contents of WPA or RSN IE and write the parsed data into data. - */ -int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, - struct wpa_ie_data *data) -{ - if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) - return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); - else - return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); -} - - -static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, - int pairwise_cipher, int group_cipher, - int key_mgmt) -{ - u8 *pos; - struct wpa_ie_hdr *hdr; - u32 suite; - - if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + - 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) - return -1; - - hdr = (struct wpa_ie_hdr *) wpa_ie; - hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; - RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); - WPA_PUT_LE16(hdr->version, WPA_VERSION); - pos = (u8 *) (hdr + 1); - - suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher); - if (suite == 0) { - wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", - group_cipher); - return -1; - } - RSN_SELECTOR_PUT(pos, suite); - pos += WPA_SELECTOR_LEN; - - *pos++ = 1; - *pos++ = 0; - suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher); - if (suite == 0 || - (!wpa_cipher_valid_pairwise(pairwise_cipher) && - pairwise_cipher != WPA_CIPHER_NONE)) { - wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", - pairwise_cipher); - return -1; - } - RSN_SELECTOR_PUT(pos, suite); - pos += WPA_SELECTOR_LEN; - - *pos++ = 1; - *pos++ = 0; - if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { - RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); - } else if (key_mgmt == WPA_KEY_MGMT_PSK) { - RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); - } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { - RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); - } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { - RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM); - } else { - wpa_printf(MSG_WARNING, "Invalid key management type (%d).", - key_mgmt); - return -1; - } - pos += WPA_SELECTOR_LEN; - - /* WPA Capabilities; use defaults, so no need to include it */ - - hdr->len = (pos - wpa_ie) - 2; - - WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); - - return pos - wpa_ie; -} - - -static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, - int pairwise_cipher, int group_cipher, - int key_mgmt, int mgmt_group_cipher, - struct wpa_sm *sm) -{ - u8 *pos; - struct rsn_ie_hdr *hdr; - u16 capab; - u32 suite; - - if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + - 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + - (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) { - wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", - (unsigned long) rsn_ie_len); - return -1; - } - - hdr = (struct rsn_ie_hdr *) rsn_ie; - hdr->elem_id = WLAN_EID_RSN; - WPA_PUT_LE16(hdr->version, RSN_VERSION); - pos = (u8 *) (hdr + 1); - - suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); - if (suite == 0) { - wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", - group_cipher); - return -1; - } - RSN_SELECTOR_PUT(pos, suite); - pos += RSN_SELECTOR_LEN; - - *pos++ = 1; - *pos++ = 0; - suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); - if (suite == 0 || - (!wpa_cipher_valid_pairwise(pairwise_cipher) && - pairwise_cipher != WPA_CIPHER_NONE)) { - wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", - pairwise_cipher); - return -1; - } - RSN_SELECTOR_PUT(pos, suite); - pos += RSN_SELECTOR_LEN; - - *pos++ = 1; - *pos++ = 0; - if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); - } else if (key_mgmt == WPA_KEY_MGMT_PSK) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); - } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM); -#ifdef CONFIG_IEEE80211R - } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); - } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); - } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_SAE - } else if (key_mgmt == WPA_KEY_MGMT_SAE) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); - } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); -#endif /* CONFIG_SAE */ - } else { - wpa_printf(MSG_WARNING, "Invalid key management type (%d).", - key_mgmt); - return -1; - } - pos += RSN_SELECTOR_LEN; - - /* RSN Capabilities */ - capab = 0; -#ifdef CONFIG_IEEE80211W - if (sm->mfp) - capab |= WPA_CAPABILITY_MFPC; - if (sm->mfp == 2) - capab |= WPA_CAPABILITY_MFPR; -#endif /* CONFIG_IEEE80211W */ - WPA_PUT_LE16(pos, capab); - pos += 2; - - if (sm->cur_pmksa) { - /* PMKID Count (2 octets, little endian) */ - *pos++ = 1; - *pos++ = 0; - /* PMKID */ - os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); - pos += PMKID_LEN; - } - -#ifdef CONFIG_IEEE80211W - if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { - if (!sm->cur_pmksa) { - /* PMKID Count */ - WPA_PUT_LE16(pos, 0); - pos += 2; - } - - /* Management Group Cipher Suite */ - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); - pos += RSN_SELECTOR_LEN; - } -#endif /* CONFIG_IEEE80211W */ - - hdr->len = (pos - rsn_ie) - 2; - - WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); - - return pos - rsn_ie; -} - - -/** - * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE - * @wpa_ie_len: Maximum length of the generated WPA/RSN IE - * Returns: Length of the generated WPA/RSN IE or -1 on failure - */ -int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) -{ - if (sm->proto == WPA_PROTO_RSN) - return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, - sm->pairwise_cipher, - sm->group_cipher, - sm->key_mgmt, sm->mgmt_group_cipher, - sm); - else - return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, - sm->pairwise_cipher, - sm->group_cipher, - sm->key_mgmt); -} - - -/** - * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs - * @pos: Pointer to the IE header - * @end: Pointer to the end of the Key Data buffer - * @ie: Pointer to parsed IE data - * Returns: 0 on success, 1 if end mark is found, -1 on failure - */ -static int wpa_parse_generic(const u8 *pos, const u8 *end, - struct wpa_eapol_ie_parse *ie) -{ - if (pos[1] == 0) - return 1; - - if (pos[1] >= 6 && - RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && - pos[2 + WPA_SELECTOR_LEN] == 1 && - pos[2 + WPA_SELECTOR_LEN + 1] == 0) { - ie->wpa_ie = pos; - ie->wpa_ie_len = pos[1] + 2; - wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", - ie->wpa_ie, ie->wpa_ie_len); - return 0; - } - - if (pos + 1 + RSN_SELECTOR_LEN < end && - pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { - ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { - ie->gtk = pos + 2 + RSN_SELECTOR_LEN; - ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { - ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; - ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - -#ifdef CONFIG_PEERKEY - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { - ie->smk = pos + 2 + RSN_SELECTOR_LEN; - ie->smk_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { - ie->nonce = pos + 2 + RSN_SELECTOR_LEN; - ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { - ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; - ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { - ie->error = pos + 2 + RSN_SELECTOR_LEN; - ie->error_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } -#endif /* CONFIG_PEERKEY */ - -#ifdef CONFIG_IEEE80211W - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { - ie->igtk = pos + 2 + RSN_SELECTOR_LEN; - ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } -#endif /* CONFIG_IEEE80211W */ - -#ifdef CONFIG_P2P - if (pos[1] >= RSN_SELECTOR_LEN + 1 && - RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) { - ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key", - ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN); - return 0; - } - - if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 && - RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) { - ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, - "WPA: IP Address Allocation in EAPOL-Key", - ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN); - return 0; - } -#endif /* CONFIG_P2P */ - - return 0; -} - - -/** - * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs - * @buf: Pointer to the Key Data buffer - * @len: Key Data Length - * @ie: Pointer to parsed IE data - * Returns: 0 on success, -1 on failure - */ -int wpa_supplicant_parse_ies(const u8 *buf, size_t len, - struct wpa_eapol_ie_parse *ie) -{ - const u8 *pos, *end; - int ret = 0; - - os_memset(ie, 0, sizeof(*ie)); - for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { - if (pos[0] == 0xdd && - ((pos == buf + len - 1) || pos[1] == 0)) { - /* Ignore padding */ - break; - } - if (pos + 2 + pos[1] > end) { - wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " - "underflow (ie=%d len=%d pos=%d)", - pos[0], pos[1], (int) (pos - buf)); - wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", - buf, len); - ret = -1; - break; - } - if (*pos == WLAN_EID_RSN) { - ie->rsn_ie = pos; - ie->rsn_ie_len = pos[1] + 2; - wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", - ie->rsn_ie, ie->rsn_ie_len); - } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { - ie->mdie = pos; - ie->mdie_len = pos[1] + 2; - wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key", - ie->mdie, ie->mdie_len); - } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { - ie->ftie = pos; - ie->ftie_len = pos[1] + 2; - wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key", - ie->ftie, ie->ftie_len); - } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) { - if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) { - ie->reassoc_deadline = pos; - wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline " - "in EAPOL-Key", - ie->reassoc_deadline, pos[1] + 2); - } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) { - ie->key_lifetime = pos; - wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime " - "in EAPOL-Key", - ie->key_lifetime, pos[1] + 2); - } else { - wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized " - "EAPOL-Key Key Data IE", - pos, 2 + pos[1]); - } - } else if (*pos == WLAN_EID_LINK_ID) { - 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_HT_CAP) { - ie->ht_capabilities = pos + 2; - ie->ht_capabilities_len = pos[1]; - } else if (*pos == WLAN_EID_VHT_AID) { - if (pos[1] >= 2) - ie->aid = WPA_GET_LE16(pos + 2); - } else if (*pos == WLAN_EID_VHT_CAP) { - ie->vht_capabilities = pos + 2; - ie->vht_capabilities_len = pos[1]; - } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) { - ie->qosinfo = pos[2]; - } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) { - ie->supp_channels = pos + 2; - ie->supp_channels_len = pos[1]; - } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) { - ie->supp_oper_classes = pos + 2; - ie->supp_oper_classes_len = pos[1]; - } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { - ret = wpa_parse_generic(pos, end, ie); - if (ret < 0) - break; - if (ret > 0) { - ret = 0; - break; - } - } else { - wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " - "Key Data IE", pos, 2 + pos[1]); - } - } - - return ret; -} diff --git a/contrib/hostapd/src/rsn_supp/wpa_ie.h b/contrib/hostapd/src/rsn_supp/wpa_ie.h deleted file mode 100644 index 82b6fa3fba..0000000000 --- a/contrib/hostapd/src/rsn_supp/wpa_ie.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * wpa_supplicant - WPA/RSN IE and KDE definitions - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_IE_H -#define WPA_IE_H - -struct wpa_sm; - -struct wpa_eapol_ie_parse { - const u8 *wpa_ie; - size_t wpa_ie_len; - const u8 *rsn_ie; - size_t rsn_ie_len; - const u8 *pmkid; - const u8 *gtk; - size_t gtk_len; - const u8 *mac_addr; - size_t mac_addr_len; -#ifdef CONFIG_PEERKEY - const u8 *smk; - size_t smk_len; - const u8 *nonce; - size_t nonce_len; - const u8 *lifetime; - size_t lifetime_len; - const u8 *error; - size_t error_len; -#endif /* CONFIG_PEERKEY */ -#ifdef CONFIG_IEEE80211W - const u8 *igtk; - size_t igtk_len; -#endif /* CONFIG_IEEE80211W */ - const u8 *mdie; - size_t mdie_len; - const u8 *ftie; - size_t ftie_len; - const u8 *reassoc_deadline; - const u8 *key_lifetime; - const u8 *lnkid; - 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; - const u8 *ht_capabilities; - size_t ht_capabilities_len; - const u8 *vht_capabilities; - size_t vht_capabilities_len; - const u8 *supp_channels; - size_t supp_channels_len; - const u8 *supp_oper_classes; - size_t supp_oper_classes_len; - u8 qosinfo; - u16 aid; -#ifdef CONFIG_P2P - const u8 *ip_addr_req; - const u8 *ip_addr_alloc; -#endif /* CONFIG_P2P */ -}; - -int wpa_supplicant_parse_ies(const u8 *buf, size_t len, - struct wpa_eapol_ie_parse *ie); -int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len); - -#endif /* WPA_IE_H */ diff --git a/contrib/hostapd/src/tls/asn1.c b/contrib/hostapd/src/tls/asn1.c deleted file mode 100644 index 53acd530d9..0000000000 --- a/contrib/hostapd/src/tls/asn1.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * ASN.1 DER parsing - * Copyright (c) 2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "asn1.h" - -int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) -{ - const u8 *pos, *end; - u8 tmp; - - os_memset(hdr, 0, sizeof(*hdr)); - pos = buf; - end = buf + len; - - hdr->identifier = *pos++; - hdr->class = hdr->identifier >> 6; - hdr->constructed = !!(hdr->identifier & (1 << 5)); - - if ((hdr->identifier & 0x1f) == 0x1f) { - hdr->tag = 0; - do { - if (pos >= end) { - wpa_printf(MSG_DEBUG, "ASN.1: Identifier " - "underflow"); - return -1; - } - tmp = *pos++; - wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: " - "0x%02x", tmp); - hdr->tag = (hdr->tag << 7) | (tmp & 0x7f); - } while (tmp & 0x80); - } else - hdr->tag = hdr->identifier & 0x1f; - - tmp = *pos++; - if (tmp & 0x80) { - if (tmp == 0xff) { - wpa_printf(MSG_DEBUG, "ASN.1: Reserved length " - "value 0xff used"); - return -1; - } - tmp &= 0x7f; /* number of subsequent octets */ - hdr->length = 0; - if (tmp > 4) { - wpa_printf(MSG_DEBUG, "ASN.1: Too long length field"); - return -1; - } - while (tmp--) { - if (pos >= end) { - wpa_printf(MSG_DEBUG, "ASN.1: Length " - "underflow"); - return -1; - } - hdr->length = (hdr->length << 8) | *pos++; - } - } else { - /* Short form - length 0..127 in one octet */ - hdr->length = tmp; - } - - if (end < pos || hdr->length > (unsigned int) (end - pos)) { - wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow"); - return -1; - } - - hdr->payload = pos; - return 0; -} - - -int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid) -{ - const u8 *pos, *end; - unsigned long val; - u8 tmp; - - os_memset(oid, 0, sizeof(*oid)); - - pos = buf; - end = buf + len; - - while (pos < end) { - val = 0; - - do { - if (pos >= end) - return -1; - tmp = *pos++; - val = (val << 7) | (tmp & 0x7f); - } while (tmp & 0x80); - - if (oid->len >= ASN1_MAX_OID_LEN) { - wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value"); - return -1; - } - if (oid->len == 0) { - /* - * The first octet encodes the first two object - * identifier components in (X*40) + Y formula. - * X = 0..2. - */ - oid->oid[0] = val / 40; - if (oid->oid[0] > 2) - oid->oid[0] = 2; - oid->oid[1] = val - oid->oid[0] * 40; - oid->len = 2; - } else - oid->oid[oid->len++] = val; - } - - return 0; -} - - -int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, - const u8 **next) -{ - struct asn1_hdr hdr; - - if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0) - return -1; - - if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) { - wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d " - "tag 0x%x", hdr.class, hdr.tag); - return -1; - } - - *next = hdr.payload + hdr.length; - - return asn1_parse_oid(hdr.payload, hdr.length, oid); -} - - -void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len) -{ - char *pos = buf; - size_t i; - int ret; - - if (len == 0) - return; - - buf[0] = '\0'; - - for (i = 0; i < oid->len; i++) { - ret = os_snprintf(pos, buf + len - pos, - "%s%lu", - i == 0 ? "" : ".", oid->oid[i]); - if (ret < 0 || ret >= buf + len - pos) - break; - pos += ret; - } - buf[len - 1] = '\0'; -} - - -static u8 rotate_bits(u8 octet) -{ - int i; - u8 res; - - res = 0; - for (i = 0; i < 8; i++) { - res <<= 1; - if (octet & 1) - res |= 1; - octet >>= 1; - } - - return res; -} - - -unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len) -{ - unsigned long val = 0; - const u8 *pos = buf; - - /* BER requires that unused bits are zero, so we can ignore the number - * of unused bits */ - pos++; - - if (len >= 2) - val |= rotate_bits(*pos++); - if (len >= 3) - val |= ((unsigned long) rotate_bits(*pos++)) << 8; - if (len >= 4) - val |= ((unsigned long) rotate_bits(*pos++)) << 16; - if (len >= 5) - val |= ((unsigned long) rotate_bits(*pos++)) << 24; - if (len >= 6) - wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored " - "(BIT STRING length %lu)", - __func__, (unsigned long) len); - - return val; -} diff --git a/contrib/hostapd/src/tls/asn1.h b/contrib/hostapd/src/tls/asn1.h deleted file mode 100644 index 6342c4cc79..0000000000 --- a/contrib/hostapd/src/tls/asn1.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * ASN.1 DER parsing - * Copyright (c) 2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef ASN1_H -#define ASN1_H - -#define ASN1_TAG_EOC 0x00 /* not used with DER */ -#define ASN1_TAG_BOOLEAN 0x01 -#define ASN1_TAG_INTEGER 0x02 -#define ASN1_TAG_BITSTRING 0x03 -#define ASN1_TAG_OCTETSTRING 0x04 -#define ASN1_TAG_NULL 0x05 -#define ASN1_TAG_OID 0x06 -#define ASN1_TAG_OBJECT_DESCRIPTOR 0x07 /* not yet parsed */ -#define ASN1_TAG_EXTERNAL 0x08 /* not yet parsed */ -#define ASN1_TAG_REAL 0x09 /* not yet parsed */ -#define ASN1_TAG_ENUMERATED 0x0A /* not yet parsed */ -#define ASN1_TAG_UTF8STRING 0x0C /* not yet parsed */ -#define ANS1_TAG_RELATIVE_OID 0x0D -#define ASN1_TAG_SEQUENCE 0x10 /* shall be constructed */ -#define ASN1_TAG_SET 0x11 -#define ASN1_TAG_NUMERICSTRING 0x12 /* not yet parsed */ -#define ASN1_TAG_PRINTABLESTRING 0x13 -#define ASN1_TAG_TG1STRING 0x14 /* not yet parsed */ -#define ASN1_TAG_VIDEOTEXSTRING 0x15 /* not yet parsed */ -#define ASN1_TAG_IA5STRING 0x16 -#define ASN1_TAG_UTCTIME 0x17 -#define ASN1_TAG_GENERALIZEDTIME 0x18 /* not yet parsed */ -#define ASN1_TAG_GRAPHICSTRING 0x19 /* not yet parsed */ -#define ASN1_TAG_VISIBLESTRING 0x1A -#define ASN1_TAG_GENERALSTRING 0x1B /* not yet parsed */ -#define ASN1_TAG_UNIVERSALSTRING 0x1C /* not yet parsed */ -#define ASN1_TAG_BMPSTRING 0x1D /* not yet parsed */ - -#define ASN1_CLASS_UNIVERSAL 0 -#define ASN1_CLASS_APPLICATION 1 -#define ASN1_CLASS_CONTEXT_SPECIFIC 2 -#define ASN1_CLASS_PRIVATE 3 - - -struct asn1_hdr { - const u8 *payload; - u8 identifier, class, constructed; - unsigned int tag, length; -}; - -#define ASN1_MAX_OID_LEN 20 -struct asn1_oid { - unsigned long oid[ASN1_MAX_OID_LEN]; - size_t len; -}; - - -int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr); -int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid); -int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, - const u8 **next); -void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len); -unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len); - -#endif /* ASN1_H */ diff --git a/contrib/hostapd/src/tls/bignum.c b/contrib/hostapd/src/tls/bignum.c deleted file mode 100644 index f3baafe106..0000000000 --- a/contrib/hostapd/src/tls/bignum.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Big number math - * Copyright (c) 2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "bignum.h" - -#ifdef CONFIG_INTERNAL_LIBTOMMATH -#include "libtommath.c" -#else /* CONFIG_INTERNAL_LIBTOMMATH */ -#include -#endif /* CONFIG_INTERNAL_LIBTOMMATH */ - - -/* - * The current version is just a wrapper for LibTomMath library, so - * struct bignum is just typecast to mp_int. - */ - -/** - * bignum_init - Allocate memory for bignum - * Returns: Pointer to allocated bignum or %NULL on failure - */ -struct bignum * bignum_init(void) -{ - struct bignum *n = os_zalloc(sizeof(mp_int)); - if (n == NULL) - return NULL; - if (mp_init((mp_int *) n) != MP_OKAY) { - os_free(n); - n = NULL; - } - return n; -} - - -/** - * bignum_deinit - Free bignum - * @n: Bignum from bignum_init() - */ -void bignum_deinit(struct bignum *n) -{ - if (n) { - mp_clear((mp_int *) n); - os_free(n); - } -} - - -/** - * bignum_get_unsigned_bin - Get length of bignum as an unsigned binary buffer - * @n: Bignum from bignum_init() - * Returns: Length of n if written to a binary buffer - */ -size_t bignum_get_unsigned_bin_len(struct bignum *n) -{ - return mp_unsigned_bin_size((mp_int *) n); -} - - -/** - * bignum_get_unsigned_bin - Set binary buffer to unsigned bignum - * @n: Bignum from bignum_init() - * @buf: Buffer for the binary number - * @len: Length of the buffer, can be %NULL if buffer is known to be long - * enough. Set to used buffer length on success if not %NULL. - * Returns: 0 on success, -1 on failure - */ -int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len) -{ - size_t need = mp_unsigned_bin_size((mp_int *) n); - if (len && need > *len) { - *len = need; - return -1; - } - if (mp_to_unsigned_bin((mp_int *) n, buf) != MP_OKAY) { - wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); - return -1; - } - if (len) - *len = need; - return 0; -} - - -/** - * bignum_set_unsigned_bin - Set bignum based on unsigned binary buffer - * @n: Bignum from bignum_init(); to be set to the given value - * @buf: Buffer with unsigned binary value - * @len: Length of buf in octets - * Returns: 0 on success, -1 on failure - */ -int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len) -{ - if (mp_read_unsigned_bin((mp_int *) n, (u8 *) buf, len) != MP_OKAY) { - wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); - return -1; - } - return 0; -} - - -/** - * bignum_cmp - Signed comparison - * @a: Bignum from bignum_init() - * @b: Bignum from bignum_init() - * Returns: 0 on success, -1 on failure - */ -int bignum_cmp(const struct bignum *a, const struct bignum *b) -{ - return mp_cmp((mp_int *) a, (mp_int *) b); -} - - -/** - * bignum_cmd_d - Compare bignum to standard integer - * @a: Bignum from bignum_init() - * @b: Small integer - * Returns: 0 on success, -1 on failure - */ -int bignum_cmp_d(const struct bignum *a, unsigned long b) -{ - return mp_cmp_d((mp_int *) a, b); -} - - -/** - * bignum_add - c = a + b - * @a: Bignum from bignum_init() - * @b: Bignum from bignum_init() - * @c: Bignum from bignum_init(); used to store the result of a + b - * Returns: 0 on success, -1 on failure - */ -int bignum_add(const struct bignum *a, const struct bignum *b, - struct bignum *c) -{ - if (mp_add((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { - wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); - return -1; - } - return 0; -} - - -/** - * bignum_sub - c = a - b - * @a: Bignum from bignum_init() - * @b: Bignum from bignum_init() - * @c: Bignum from bignum_init(); used to store the result of a - b - * Returns: 0 on success, -1 on failure - */ -int bignum_sub(const struct bignum *a, const struct bignum *b, - struct bignum *c) -{ - if (mp_sub((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { - wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); - return -1; - } - return 0; -} - - -/** - * bignum_mul - c = a * b - * @a: Bignum from bignum_init() - * @b: Bignum from bignum_init() - * @c: Bignum from bignum_init(); used to store the result of a * b - * Returns: 0 on success, -1 on failure - */ -int bignum_mul(const struct bignum *a, const struct bignum *b, - struct bignum *c) -{ - if (mp_mul((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { - wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); - return -1; - } - return 0; -} - - -/** - * bignum_mulmod - d = a * b (mod c) - * @a: Bignum from bignum_init() - * @b: Bignum from bignum_init() - * @c: Bignum from bignum_init(); modulus - * @d: Bignum from bignum_init(); used to store the result of a * b (mod c) - * Returns: 0 on success, -1 on failure - */ -int bignum_mulmod(const struct bignum *a, const struct bignum *b, - const struct bignum *c, struct bignum *d) -{ - if (mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) - != MP_OKAY) { - wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); - return -1; - } - return 0; -} - - -/** - * bignum_exptmod - Modular exponentiation: d = a^b (mod c) - * @a: Bignum from bignum_init(); base - * @b: Bignum from bignum_init(); exponent - * @c: Bignum from bignum_init(); modulus - * @d: Bignum from bignum_init(); used to store the result of a^b (mod c) - * Returns: 0 on success, -1 on failure - */ -int bignum_exptmod(const struct bignum *a, const struct bignum *b, - const struct bignum *c, struct bignum *d) -{ - if (mp_exptmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) - != MP_OKAY) { - wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); - return -1; - } - return 0; -} diff --git a/contrib/hostapd/src/tls/bignum.h b/contrib/hostapd/src/tls/bignum.h deleted file mode 100644 index 24acdce597..0000000000 --- a/contrib/hostapd/src/tls/bignum.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Big number math - * Copyright (c) 2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef BIGNUM_H -#define BIGNUM_H - -struct bignum; - -struct bignum * bignum_init(void); -void bignum_deinit(struct bignum *n); -size_t bignum_get_unsigned_bin_len(struct bignum *n); -int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len); -int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len); -int bignum_cmp(const struct bignum *a, const struct bignum *b); -int bignum_cmp_d(const struct bignum *a, unsigned long b); -int bignum_add(const struct bignum *a, const struct bignum *b, - struct bignum *c); -int bignum_sub(const struct bignum *a, const struct bignum *b, - struct bignum *c); -int bignum_mul(const struct bignum *a, const struct bignum *b, - struct bignum *c); -int bignum_mulmod(const struct bignum *a, const struct bignum *b, - const struct bignum *c, struct bignum *d); -int bignum_exptmod(const struct bignum *a, const struct bignum *b, - const struct bignum *c, struct bignum *d); - -#endif /* BIGNUM_H */ diff --git a/contrib/hostapd/src/tls/libtommath.c b/contrib/hostapd/src/tls/libtommath.c deleted file mode 100644 index 3fb8fbed25..0000000000 --- a/contrib/hostapd/src/tls/libtommath.c +++ /dev/null @@ -1,3401 +0,0 @@ -/* - * Minimal code for RSA support from LibTomMath 0.41 - * http://libtom.org/ - * http://libtom.org/files/ltm-0.41.tar.bz2 - * This library was released in public domain by Tom St Denis. - * - * The combination in this file may not use all of the optimized algorithms - * from LibTomMath and may be considerable slower than the LibTomMath with its - * default settings. The main purpose of having this version here is to make it - * easier to build bignum.c wrapper without having to install and build an - * external library. - * - * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this - * libtommath.c file instead of using the external LibTomMath library. - */ - -#ifndef CHAR_BIT -#define CHAR_BIT 8 -#endif - -#define BN_MP_INVMOD_C -#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would - * require BN_MP_EXPTMOD_FAST_C instead */ -#define BN_S_MP_MUL_DIGS_C -#define BN_MP_INVMOD_SLOW_C -#define BN_S_MP_SQR_C -#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this - * would require other than mp_reduce */ - -#ifdef LTM_FAST - -/* Use faster div at the cost of about 1 kB */ -#define BN_MP_MUL_D_C - -/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */ -#define BN_MP_EXPTMOD_FAST_C -#define BN_MP_MONTGOMERY_SETUP_C -#define BN_FAST_MP_MONTGOMERY_REDUCE_C -#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C -#define BN_MP_MUL_2_C - -/* Include faster sqr at the cost of about 0.5 kB in code */ -#define BN_FAST_S_MP_SQR_C - -/* About 0.25 kB of code, but ~1.7kB of stack space! */ -#define BN_FAST_S_MP_MUL_DIGS_C - -#else /* LTM_FAST */ - -#define BN_MP_DIV_SMALL -#define BN_MP_INIT_MULTI_C -#define BN_MP_CLEAR_MULTI_C -#define BN_MP_ABS_C -#endif /* LTM_FAST */ - -/* Current uses do not require support for negative exponent in exptmod, so we - * can save about 1.5 kB in leaving out invmod. */ -#define LTM_NO_NEG_EXP - -/* from tommath.h */ - -#ifndef MIN - #define MIN(x,y) ((x)<(y)?(x):(y)) -#endif - -#ifndef MAX - #define MAX(x,y) ((x)>(y)?(x):(y)) -#endif - -#define OPT_CAST(x) - -#ifdef __x86_64__ -typedef unsigned long mp_digit; -typedef unsigned long mp_word __attribute__((mode(TI))); - -#define DIGIT_BIT 60 -#define MP_64BIT -#else -typedef unsigned long mp_digit; -typedef u64 mp_word; - -#define DIGIT_BIT 28 -#define MP_28BIT -#endif - - -#define XMALLOC os_malloc -#define XFREE os_free -#define XREALLOC os_realloc - - -#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) - -#define MP_LT -1 /* less than */ -#define MP_EQ 0 /* equal to */ -#define MP_GT 1 /* greater than */ - -#define MP_ZPOS 0 /* positive integer */ -#define MP_NEG 1 /* negative */ - -#define MP_OKAY 0 /* ok result */ -#define MP_MEM -2 /* out of mem */ -#define MP_VAL -3 /* invalid input */ - -#define MP_YES 1 /* yes response */ -#define MP_NO 0 /* no response */ - -typedef int mp_err; - -/* define this to use lower memory usage routines (exptmods mostly) */ -#define MP_LOW_MEM - -/* default precision */ -#ifndef MP_PREC - #ifndef MP_LOW_MEM - #define MP_PREC 32 /* default digits of precision */ - #else - #define MP_PREC 8 /* default digits of precision */ - #endif -#endif - -/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ -#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) - -/* the infamous mp_int structure */ -typedef struct { - int used, alloc, sign; - mp_digit *dp; -} mp_int; - - -/* ---> Basic Manipulations <--- */ -#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) -#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO) -#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO) - - -/* prototypes for copied functions */ -#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) -static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); -static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); -static int s_mp_sqr(mp_int * a, mp_int * b); -static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs); - -#ifdef BN_FAST_S_MP_MUL_DIGS_C -static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); -#endif - -#ifdef BN_MP_INIT_MULTI_C -static int mp_init_multi(mp_int *mp, ...); -#endif -#ifdef BN_MP_CLEAR_MULTI_C -static void mp_clear_multi(mp_int *mp, ...); -#endif -static int mp_lshd(mp_int * a, int b); -static void mp_set(mp_int * a, mp_digit b); -static void mp_clamp(mp_int * a); -static void mp_exch(mp_int * a, mp_int * b); -static void mp_rshd(mp_int * a, int b); -static void mp_zero(mp_int * a); -static int mp_mod_2d(mp_int * a, int b, mp_int * c); -static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d); -static int mp_init_copy(mp_int * a, mp_int * b); -static int mp_mul_2d(mp_int * a, int b, mp_int * c); -#ifndef LTM_NO_NEG_EXP -static int mp_div_2(mp_int * a, mp_int * b); -static int mp_invmod(mp_int * a, mp_int * b, mp_int * c); -static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c); -#endif /* LTM_NO_NEG_EXP */ -static int mp_copy(mp_int * a, mp_int * b); -static int mp_count_bits(mp_int * a); -static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d); -static int mp_mod(mp_int * a, mp_int * b, mp_int * c); -static int mp_grow(mp_int * a, int size); -static int mp_cmp_mag(mp_int * a, mp_int * b); -#ifdef BN_MP_ABS_C -static int mp_abs(mp_int * a, mp_int * b); -#endif -static int mp_sqr(mp_int * a, mp_int * b); -static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d); -static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d); -static int mp_2expt(mp_int * a, int b); -static int mp_reduce_setup(mp_int * a, mp_int * b); -static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu); -static int mp_init_size(mp_int * a, int size); -#ifdef BN_MP_EXPTMOD_FAST_C -static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); -#endif /* BN_MP_EXPTMOD_FAST_C */ -#ifdef BN_FAST_S_MP_SQR_C -static int fast_s_mp_sqr (mp_int * a, mp_int * b); -#endif /* BN_FAST_S_MP_SQR_C */ -#ifdef BN_MP_MUL_D_C -static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c); -#endif /* BN_MP_MUL_D_C */ - - - -/* functions from bn_.c */ - - -/* reverse an array, used for radix code */ -static void bn_reverse (unsigned char *s, int len) -{ - int ix, iy; - unsigned char t; - - ix = 0; - iy = len - 1; - while (ix < iy) { - t = s[ix]; - s[ix] = s[iy]; - s[iy] = t; - ++ix; - --iy; - } -} - - -/* low level addition, based on HAC pp.594, Algorithm 14.7 */ -static int s_mp_add (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int *x; - int olduse, res, min, max; - - /* find sizes, we let |a| <= |b| which means we have to sort - * them. "x" will point to the input with the most digits - */ - if (a->used > b->used) { - min = b->used; - max = a->used; - x = a; - } else { - min = a->used; - max = b->used; - x = b; - } - - /* init result */ - if (c->alloc < max + 1) { - if ((res = mp_grow (c, max + 1)) != MP_OKAY) { - return res; - } - } - - /* get old used digit count and set new one */ - olduse = c->used; - c->used = max + 1; - - { - register mp_digit u, *tmpa, *tmpb, *tmpc; - register int i; - - /* alias for digit pointers */ - - /* first input */ - tmpa = a->dp; - - /* second input */ - tmpb = b->dp; - - /* destination */ - tmpc = c->dp; - - /* zero the carry */ - u = 0; - for (i = 0; i < min; i++) { - /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ - *tmpc = *tmpa++ + *tmpb++ + u; - - /* U = carry bit of T[i] */ - u = *tmpc >> ((mp_digit)DIGIT_BIT); - - /* take away carry bit from T[i] */ - *tmpc++ &= MP_MASK; - } - - /* now copy higher words if any, that is in A+B - * if A or B has more digits add those in - */ - if (min != max) { - for (; i < max; i++) { - /* T[i] = X[i] + U */ - *tmpc = x->dp[i] + u; - - /* U = carry bit of T[i] */ - u = *tmpc >> ((mp_digit)DIGIT_BIT); - - /* take away carry bit from T[i] */ - *tmpc++ &= MP_MASK; - } - } - - /* add carry */ - *tmpc++ = u; - - /* clear digits above oldused */ - for (i = c->used; i < olduse; i++) { - *tmpc++ = 0; - } - } - - mp_clamp (c); - return MP_OKAY; -} - - -/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ -static int s_mp_sub (mp_int * a, mp_int * b, mp_int * c) -{ - int olduse, res, min, max; - - /* find sizes */ - min = b->used; - max = a->used; - - /* init result */ - if (c->alloc < max) { - if ((res = mp_grow (c, max)) != MP_OKAY) { - return res; - } - } - olduse = c->used; - c->used = max; - - { - register mp_digit u, *tmpa, *tmpb, *tmpc; - register int i; - - /* alias for digit pointers */ - tmpa = a->dp; - tmpb = b->dp; - tmpc = c->dp; - - /* set carry to zero */ - u = 0; - for (i = 0; i < min; i++) { - /* T[i] = A[i] - B[i] - U */ - *tmpc = *tmpa++ - *tmpb++ - u; - - /* U = carry bit of T[i] - * Note this saves performing an AND operation since - * if a carry does occur it will propagate all the way to the - * MSB. As a result a single shift is enough to get the carry - */ - u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); - - /* Clear carry from T[i] */ - *tmpc++ &= MP_MASK; - } - - /* now copy higher words if any, e.g. if A has more digits than B */ - for (; i < max; i++) { - /* T[i] = A[i] - U */ - *tmpc = *tmpa++ - u; - - /* U = carry bit of T[i] */ - u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); - - /* Clear carry from T[i] */ - *tmpc++ &= MP_MASK; - } - - /* clear digits above used (since we may not have grown result above) */ - for (i = c->used; i < olduse; i++) { - *tmpc++ = 0; - } - } - - mp_clamp (c); - return MP_OKAY; -} - - -/* init a new mp_int */ -static int mp_init (mp_int * a) -{ - int i; - - /* allocate memory required and clear it */ - a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC); - if (a->dp == NULL) { - return MP_MEM; - } - - /* set the digits to zero */ - for (i = 0; i < MP_PREC; i++) { - a->dp[i] = 0; - } - - /* set the used to zero, allocated digits to the default precision - * and sign to positive */ - a->used = 0; - a->alloc = MP_PREC; - a->sign = MP_ZPOS; - - return MP_OKAY; -} - - -/* clear one (frees) */ -static void mp_clear (mp_int * a) -{ - int i; - - /* only do anything if a hasn't been freed previously */ - if (a->dp != NULL) { - /* first zero the digits */ - for (i = 0; i < a->used; i++) { - a->dp[i] = 0; - } - - /* free ram */ - XFREE(a->dp); - - /* reset members to make debugging easier */ - a->dp = NULL; - a->alloc = a->used = 0; - a->sign = MP_ZPOS; - } -} - - -/* high level addition (handles signs) */ -static int mp_add (mp_int * a, mp_int * b, mp_int * c) -{ - int sa, sb, res; - - /* get sign of both inputs */ - sa = a->sign; - sb = b->sign; - - /* handle two cases, not four */ - if (sa == sb) { - /* both positive or both negative */ - /* add their magnitudes, copy the sign */ - c->sign = sa; - res = s_mp_add (a, b, c); - } else { - /* one positive, the other negative */ - /* subtract the one with the greater magnitude from */ - /* the one of the lesser magnitude. The result gets */ - /* the sign of the one with the greater magnitude. */ - if (mp_cmp_mag (a, b) == MP_LT) { - c->sign = sb; - res = s_mp_sub (b, a, c); - } else { - c->sign = sa; - res = s_mp_sub (a, b, c); - } - } - return res; -} - - -/* high level subtraction (handles signs) */ -static int mp_sub (mp_int * a, mp_int * b, mp_int * c) -{ - int sa, sb, res; - - sa = a->sign; - sb = b->sign; - - if (sa != sb) { - /* subtract a negative from a positive, OR */ - /* subtract a positive from a negative. */ - /* In either case, ADD their magnitudes, */ - /* and use the sign of the first number. */ - c->sign = sa; - res = s_mp_add (a, b, c); - } else { - /* subtract a positive from a positive, OR */ - /* subtract a negative from a negative. */ - /* First, take the difference between their */ - /* magnitudes, then... */ - if (mp_cmp_mag (a, b) != MP_LT) { - /* Copy the sign from the first */ - c->sign = sa; - /* The first has a larger or equal magnitude */ - res = s_mp_sub (a, b, c); - } else { - /* The result has the *opposite* sign from */ - /* the first number. */ - c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; - /* The second has a larger magnitude */ - res = s_mp_sub (b, a, c); - } - } - return res; -} - - -/* high level multiplication (handles sign) */ -static int mp_mul (mp_int * a, mp_int * b, mp_int * c) -{ - int res, neg; - neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; - - /* use Toom-Cook? */ -#ifdef BN_MP_TOOM_MUL_C - if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) { - res = mp_toom_mul(a, b, c); - } else -#endif -#ifdef BN_MP_KARATSUBA_MUL_C - /* use Karatsuba? */ - if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { - res = mp_karatsuba_mul (a, b, c); - } else -#endif - { - /* can we use the fast multiplier? - * - * The fast multiplier can be used if the output will - * have less than MP_WARRAY digits and the number of - * digits won't affect carry propagation - */ -#ifdef BN_FAST_S_MP_MUL_DIGS_C - int digs = a->used + b->used + 1; - - if ((digs < MP_WARRAY) && - MIN(a->used, b->used) <= - (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { - res = fast_s_mp_mul_digs (a, b, c, digs); - } else -#endif -#ifdef BN_S_MP_MUL_DIGS_C - res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */ -#else -#error mp_mul could fail - res = MP_VAL; -#endif - - } - c->sign = (c->used > 0) ? neg : MP_ZPOS; - return res; -} - - -/* d = a * b (mod c) */ -static int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) -{ - int res; - mp_int t; - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_mul (a, b, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - res = mp_mod (&t, c, d); - mp_clear (&t); - return res; -} - - -/* c = a mod b, 0 <= c < b */ -static int mp_mod (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int t; - int res; - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - if (t.sign != b->sign) { - res = mp_add (b, &t, c); - } else { - res = MP_OKAY; - mp_exch (&t, c); - } - - mp_clear (&t); - return res; -} - - -/* 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 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) -{ - int dr; - - /* modulus P must be positive */ - if (P->sign == MP_NEG) { - return MP_VAL; - } - - /* if exponent X is negative we have to recurse */ - if (X->sign == MP_NEG) { -#ifdef LTM_NO_NEG_EXP - return MP_VAL; -#else /* LTM_NO_NEG_EXP */ -#ifdef BN_MP_INVMOD_C - mp_int tmpG, tmpX; - int err; - - /* first compute 1/G mod P */ - if ((err = mp_init(&tmpG)) != MP_OKAY) { - return err; - } - if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { - mp_clear(&tmpG); - return err; - } - - /* now get |X| */ - if ((err = mp_init(&tmpX)) != MP_OKAY) { - mp_clear(&tmpG); - return err; - } - if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { - mp_clear_multi(&tmpG, &tmpX, NULL); - return err; - } - - /* and now compute (1/G)**|X| instead of G**X [X < 0] */ - err = mp_exptmod(&tmpG, &tmpX, P, Y); - mp_clear_multi(&tmpG, &tmpX, NULL); - return err; -#else -#error mp_exptmod would always fail - /* no invmod */ - return MP_VAL; -#endif -#endif /* LTM_NO_NEG_EXP */ - } - -/* modified diminished radix reduction */ -#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C) - if (mp_reduce_is_2k_l(P) == MP_YES) { - return s_mp_exptmod(G, X, P, Y, 1); - } -#endif - -#ifdef BN_MP_DR_IS_MODULUS_C - /* is it a DR modulus? */ - dr = mp_dr_is_modulus(P); -#else - /* default to no */ - dr = 0; -#endif - -#ifdef BN_MP_REDUCE_IS_2K_C - /* if not, is it a unrestricted DR modulus? */ - if (dr == 0) { - dr = mp_reduce_is_2k(P) << 1; - } -#endif - - /* if the modulus is odd or dr != 0 use the montgomery method */ -#ifdef BN_MP_EXPTMOD_FAST_C - if (mp_isodd (P) == 1 || dr != 0) { - return mp_exptmod_fast (G, X, P, Y, dr); - } else { -#endif -#ifdef BN_S_MP_EXPTMOD_C - /* otherwise use the generic Barrett reduction technique */ - return s_mp_exptmod (G, X, P, Y, 0); -#else -#error mp_exptmod could fail - /* no exptmod for evens */ - return MP_VAL; -#endif -#ifdef BN_MP_EXPTMOD_FAST_C - } -#endif - if (dr == 0) { - /* avoid compiler warnings about possibly unused variable */ - } -} - - -/* compare two ints (signed)*/ -static int mp_cmp (mp_int * a, mp_int * b) -{ - /* compare based on sign */ - if (a->sign != b->sign) { - if (a->sign == MP_NEG) { - return MP_LT; - } else { - return MP_GT; - } - } - - /* compare digits */ - if (a->sign == MP_NEG) { - /* if negative compare opposite direction */ - return mp_cmp_mag(b, a); - } else { - return mp_cmp_mag(a, b); - } -} - - -/* compare a digit */ -static int mp_cmp_d(mp_int * a, mp_digit b) -{ - /* compare based on sign */ - if (a->sign == MP_NEG) { - return MP_LT; - } - - /* compare based on magnitude */ - if (a->used > 1) { - return MP_GT; - } - - /* compare the only digit of a to b */ - if (a->dp[0] > b) { - return MP_GT; - } else if (a->dp[0] < b) { - return MP_LT; - } else { - return MP_EQ; - } -} - - -#ifndef LTM_NO_NEG_EXP -/* hac 14.61, pp608 */ -static int mp_invmod (mp_int * a, mp_int * b, mp_int * c) -{ - /* b cannot be negative */ - if (b->sign == MP_NEG || mp_iszero(b) == 1) { - return MP_VAL; - } - -#ifdef BN_FAST_MP_INVMOD_C - /* if the modulus is odd we can use a faster routine instead */ - if (mp_isodd (b) == 1) { - return fast_mp_invmod (a, b, c); - } -#endif - -#ifdef BN_MP_INVMOD_SLOW_C - return mp_invmod_slow(a, b, c); -#endif - -#ifndef BN_FAST_MP_INVMOD_C -#ifndef BN_MP_INVMOD_SLOW_C -#error mp_invmod would always fail -#endif -#endif - return MP_VAL; -} -#endif /* LTM_NO_NEG_EXP */ - - -/* get the size for an unsigned equivalent */ -static int mp_unsigned_bin_size (mp_int * a) -{ - int size = mp_count_bits (a); - return (size / 8 + ((size & 7) != 0 ? 1 : 0)); -} - - -#ifndef LTM_NO_NEG_EXP -/* hac 14.61, pp608 */ -static int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int x, y, u, v, A, B, C, D; - int res; - - /* b cannot be negative */ - if (b->sign == MP_NEG || mp_iszero(b) == 1) { - return MP_VAL; - } - - /* init temps */ - if ((res = mp_init_multi(&x, &y, &u, &v, - &A, &B, &C, &D, NULL)) != MP_OKAY) { - return res; - } - - /* x = a, y = b */ - if ((res = mp_mod(a, b, &x)) != MP_OKAY) { - goto LBL_ERR; - } - if ((res = mp_copy (b, &y)) != MP_OKAY) { - goto LBL_ERR; - } - - /* 2. [modified] if x,y are both even then return an error! */ - if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { - res = MP_VAL; - goto LBL_ERR; - } - - /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ - if ((res = mp_copy (&x, &u)) != MP_OKAY) { - goto LBL_ERR; - } - if ((res = mp_copy (&y, &v)) != MP_OKAY) { - goto LBL_ERR; - } - mp_set (&A, 1); - mp_set (&D, 1); - -top: - /* 4. while u is even do */ - while (mp_iseven (&u) == 1) { - /* 4.1 u = u/2 */ - if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { - goto LBL_ERR; - } - /* 4.2 if A or B is odd then */ - if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { - /* A = (A+y)/2, B = (B-x)/2 */ - if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { - goto LBL_ERR; - } - if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { - goto LBL_ERR; - } - } - /* A = A/2, B = B/2 */ - if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { - goto LBL_ERR; - } - if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { - goto LBL_ERR; - } - } - - /* 5. while v is even do */ - while (mp_iseven (&v) == 1) { - /* 5.1 v = v/2 */ - if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { - goto LBL_ERR; - } - /* 5.2 if C or D is odd then */ - if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { - /* C = (C+y)/2, D = (D-x)/2 */ - if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { - goto LBL_ERR; - } - if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { - goto LBL_ERR; - } - } - /* C = C/2, D = D/2 */ - if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { - goto LBL_ERR; - } - if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { - goto LBL_ERR; - } - } - - /* 6. if u >= v then */ - if (mp_cmp (&u, &v) != MP_LT) { - /* u = u - v, A = A - C, B = B - D */ - if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { - goto LBL_ERR; - } - - if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { - goto LBL_ERR; - } - - if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { - goto LBL_ERR; - } - } else { - /* v - v - u, C = C - A, D = D - B */ - if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { - goto LBL_ERR; - } - - if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { - goto LBL_ERR; - } - - if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { - goto LBL_ERR; - } - } - - /* if not zero goto step 4 */ - if (mp_iszero (&u) == 0) - goto top; - - /* now a = C, b = D, gcd == g*v */ - - /* if v != 1 then there is no inverse */ - if (mp_cmp_d (&v, 1) != MP_EQ) { - res = MP_VAL; - goto LBL_ERR; - } - - /* if its too low */ - while (mp_cmp_d(&C, 0) == MP_LT) { - if ((res = mp_add(&C, b, &C)) != MP_OKAY) { - goto LBL_ERR; - } - } - - /* too big */ - while (mp_cmp_mag(&C, b) != MP_LT) { - if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { - goto LBL_ERR; - } - } - - /* C is now the inverse */ - mp_exch (&C, c); - res = MP_OKAY; -LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); - return res; -} -#endif /* LTM_NO_NEG_EXP */ - - -/* compare maginitude of two ints (unsigned) */ -static int mp_cmp_mag (mp_int * a, mp_int * b) -{ - int n; - mp_digit *tmpa, *tmpb; - - /* compare based on # of non-zero digits */ - if (a->used > b->used) { - return MP_GT; - } - - if (a->used < b->used) { - return MP_LT; - } - - /* alias for a */ - tmpa = a->dp + (a->used - 1); - - /* alias for b */ - tmpb = b->dp + (a->used - 1); - - /* compare based on digits */ - for (n = 0; n < a->used; ++n, --tmpa, --tmpb) { - if (*tmpa > *tmpb) { - return MP_GT; - } - - if (*tmpa < *tmpb) { - return MP_LT; - } - } - return MP_EQ; -} - - -/* reads a unsigned char array, assumes the msb is stored first [big endian] */ -static int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c) -{ - int res; - - /* make sure there are at least two digits */ - if (a->alloc < 2) { - if ((res = mp_grow(a, 2)) != MP_OKAY) { - return res; - } - } - - /* zero the int */ - mp_zero (a); - - /* read the bytes in */ - while (c-- > 0) { - if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { - return res; - } - -#ifndef MP_8BIT - a->dp[0] |= *b++; - a->used += 1; -#else - a->dp[0] = (*b & MP_MASK); - a->dp[1] |= ((*b++ >> 7U) & 1); - a->used += 2; -#endif - } - mp_clamp (a); - return MP_OKAY; -} - - -/* store in unsigned [big endian] format */ -static int mp_to_unsigned_bin (mp_int * a, unsigned char *b) -{ - int x, res; - mp_int t; - - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return res; - } - - x = 0; - while (mp_iszero (&t) == 0) { -#ifndef MP_8BIT - b[x++] = (unsigned char) (t.dp[0] & 255); -#else - b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); -#endif - if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { - mp_clear (&t); - return res; - } - } - bn_reverse (b, x); - mp_clear (&t); - return MP_OKAY; -} - - -/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ -static int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) -{ - mp_digit D, r, rr; - int x, res; - mp_int t; - - - /* if the shift count is <= 0 then we do no work */ - if (b <= 0) { - res = mp_copy (a, c); - if (d != NULL) { - mp_zero (d); - } - return res; - } - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - /* get the remainder */ - if (d != NULL) { - if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - } - - /* copy */ - if ((res = mp_copy (a, c)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - /* shift by as many digits in the bit count */ - if (b >= (int)DIGIT_BIT) { - mp_rshd (c, b / DIGIT_BIT); - } - - /* shift any bit count < DIGIT_BIT */ - D = (mp_digit) (b % DIGIT_BIT); - if (D != 0) { - register mp_digit *tmpc, mask, shift; - - /* mask */ - mask = (((mp_digit)1) << D) - 1; - - /* shift for lsb */ - shift = DIGIT_BIT - D; - - /* alias */ - tmpc = c->dp + (c->used - 1); - - /* carry */ - r = 0; - for (x = c->used - 1; x >= 0; x--) { - /* get the lower bits of this word in a temp */ - rr = *tmpc & mask; - - /* shift the current word and mix in the carry bits from the previous word */ - *tmpc = (*tmpc >> D) | (r << shift); - --tmpc; - - /* set the carry to the carry bits of the current word found above */ - r = rr; - } - } - mp_clamp (c); - if (d != NULL) { - mp_exch (&t, d); - } - mp_clear (&t); - return MP_OKAY; -} - - -static int mp_init_copy (mp_int * a, mp_int * b) -{ - int res; - - if ((res = mp_init (a)) != MP_OKAY) { - return res; - } - return mp_copy (b, a); -} - - -/* set to zero */ -static void mp_zero (mp_int * a) -{ - int n; - mp_digit *tmp; - - a->sign = MP_ZPOS; - a->used = 0; - - tmp = a->dp; - for (n = 0; n < a->alloc; n++) { - *tmp++ = 0; - } -} - - -/* copy, b = a */ -static int mp_copy (mp_int * a, mp_int * b) -{ - int res, n; - - /* if dst == src do nothing */ - if (a == b) { - return MP_OKAY; - } - - /* grow dest */ - if (b->alloc < a->used) { - if ((res = mp_grow (b, a->used)) != MP_OKAY) { - return res; - } - } - - /* zero b and copy the parameters over */ - { - register mp_digit *tmpa, *tmpb; - - /* pointer aliases */ - - /* source */ - tmpa = a->dp; - - /* destination */ - tmpb = b->dp; - - /* copy all the digits */ - for (n = 0; n < a->used; n++) { - *tmpb++ = *tmpa++; - } - - /* clear high digits */ - for (; n < b->used; n++) { - *tmpb++ = 0; - } - } - - /* copy used count and sign */ - b->used = a->used; - b->sign = a->sign; - return MP_OKAY; -} - - -/* shift right a certain amount of digits */ -static void mp_rshd (mp_int * a, int b) -{ - int x; - - /* if b <= 0 then ignore it */ - if (b <= 0) { - return; - } - - /* if b > used then simply zero it and return */ - if (a->used <= b) { - mp_zero (a); - return; - } - - { - register mp_digit *bottom, *top; - - /* shift the digits down */ - - /* bottom */ - bottom = a->dp; - - /* top [offset into digits] */ - top = a->dp + b; - - /* this is implemented as a sliding window where - * the window is b-digits long and digits from - * the top of the window are copied to the bottom - * - * e.g. - - b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> - /\ | ----> - \-------------------/ ----> - */ - for (x = 0; x < (a->used - b); x++) { - *bottom++ = *top++; - } - - /* zero the top digits */ - for (; x < a->used; x++) { - *bottom++ = 0; - } - } - - /* remove excess digits */ - a->used -= b; -} - - -/* swap the elements of two integers, for cases where you can't simply swap the - * mp_int pointers around - */ -static void mp_exch (mp_int * a, mp_int * b) -{ - mp_int t; - - t = *a; - *a = *b; - *b = t; -} - - -/* trim unused digits - * - * This is used to ensure that leading zero digits are - * trimed and the leading "used" digit will be non-zero - * Typically very fast. Also fixes the sign if there - * are no more leading digits - */ -static void mp_clamp (mp_int * a) -{ - /* decrease used while the most significant digit is - * zero. - */ - while (a->used > 0 && a->dp[a->used - 1] == 0) { - --(a->used); - } - - /* reset the sign flag if used == 0 */ - if (a->used == 0) { - a->sign = MP_ZPOS; - } -} - - -/* grow as required */ -static int mp_grow (mp_int * a, int size) -{ - int i; - mp_digit *tmp; - - /* if the alloc size is smaller alloc more ram */ - if (a->alloc < size) { - /* ensure there are always at least MP_PREC digits extra on top */ - size += (MP_PREC * 2) - (size % MP_PREC); - - /* reallocate the array a->dp - * - * We store the return in a temporary variable - * in case the operation failed we don't want - * to overwrite the dp member of a. - */ - tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size); - if (tmp == NULL) { - /* reallocation failed but "a" is still valid [can be freed] */ - return MP_MEM; - } - - /* reallocation succeeded so set a->dp */ - a->dp = tmp; - - /* zero excess digits */ - i = a->alloc; - a->alloc = size; - for (; i < a->alloc; i++) { - a->dp[i] = 0; - } - } - return MP_OKAY; -} - - -#ifdef BN_MP_ABS_C -/* b = |a| - * - * Simple function copies the input and fixes the sign to positive - */ -static int mp_abs (mp_int * a, mp_int * b) -{ - int res; - - /* copy a to b */ - if (a != b) { - if ((res = mp_copy (a, b)) != MP_OKAY) { - return res; - } - } - - /* force the sign of b to positive */ - b->sign = MP_ZPOS; - - return MP_OKAY; -} -#endif - - -/* set to a digit */ -static void mp_set (mp_int * a, mp_digit b) -{ - mp_zero (a); - a->dp[0] = b & MP_MASK; - a->used = (a->dp[0] != 0) ? 1 : 0; -} - - -#ifndef LTM_NO_NEG_EXP -/* b = a/2 */ -static int mp_div_2(mp_int * a, mp_int * b) -{ - int x, res, oldused; - - /* copy */ - if (b->alloc < a->used) { - if ((res = mp_grow (b, a->used)) != MP_OKAY) { - return res; - } - } - - oldused = b->used; - b->used = a->used; - { - register mp_digit r, rr, *tmpa, *tmpb; - - /* source alias */ - tmpa = a->dp + b->used - 1; - - /* dest alias */ - tmpb = b->dp + b->used - 1; - - /* carry */ - r = 0; - for (x = b->used - 1; x >= 0; x--) { - /* get the carry for the next iteration */ - rr = *tmpa & 1; - - /* shift the current digit, add in carry and store */ - *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); - - /* forward carry to next iteration */ - r = rr; - } - - /* zero excess digits */ - tmpb = b->dp + b->used; - for (x = b->used; x < oldused; x++) { - *tmpb++ = 0; - } - } - b->sign = a->sign; - mp_clamp (b); - return MP_OKAY; -} -#endif /* LTM_NO_NEG_EXP */ - - -/* shift left by a certain bit count */ -static int mp_mul_2d (mp_int * a, int b, mp_int * c) -{ - mp_digit d; - int res; - - /* copy */ - if (a != c) { - if ((res = mp_copy (a, c)) != MP_OKAY) { - return res; - } - } - - if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { - if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { - return res; - } - } - - /* shift by as many digits in the bit count */ - if (b >= (int)DIGIT_BIT) { - if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { - return res; - } - } - - /* shift any bit count < DIGIT_BIT */ - d = (mp_digit) (b % DIGIT_BIT); - if (d != 0) { - register mp_digit *tmpc, shift, mask, r, rr; - register int x; - - /* bitmask for carries */ - mask = (((mp_digit)1) << d) - 1; - - /* shift for msbs */ - shift = DIGIT_BIT - d; - - /* alias */ - tmpc = c->dp; - - /* carry */ - r = 0; - for (x = 0; x < c->used; x++) { - /* get the higher bits of the current word */ - rr = (*tmpc >> shift) & mask; - - /* shift the current word and OR in the carry */ - *tmpc = ((*tmpc << d) | r) & MP_MASK; - ++tmpc; - - /* set the carry to the carry bits of the current word */ - r = rr; - } - - /* set final carry */ - if (r != 0) { - c->dp[(c->used)++] = r; - } - } - mp_clamp (c); - return MP_OKAY; -} - - -#ifdef BN_MP_INIT_MULTI_C -static int mp_init_multi(mp_int *mp, ...) -{ - mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ - int n = 0; /* Number of ok inits */ - mp_int* cur_arg = mp; - va_list args; - - va_start(args, mp); /* init args to next argument from caller */ - while (cur_arg != NULL) { - if (mp_init(cur_arg) != MP_OKAY) { - /* Oops - error! Back-track and mp_clear what we already - succeeded in init-ing, then return error. - */ - va_list clean_args; - - /* end the current list */ - va_end(args); - - /* now start cleaning up */ - cur_arg = mp; - va_start(clean_args, mp); - while (n--) { - mp_clear(cur_arg); - cur_arg = va_arg(clean_args, mp_int*); - } - va_end(clean_args); - res = MP_MEM; - break; - } - n++; - cur_arg = va_arg(args, mp_int*); - } - va_end(args); - return res; /* Assumed ok, if error flagged above. */ -} -#endif - - -#ifdef BN_MP_CLEAR_MULTI_C -static void mp_clear_multi(mp_int *mp, ...) -{ - mp_int* next_mp = mp; - va_list args; - va_start(args, mp); - while (next_mp != NULL) { - mp_clear(next_mp); - next_mp = va_arg(args, mp_int*); - } - va_end(args); -} -#endif - - -/* shift left a certain amount of digits */ -static int mp_lshd (mp_int * a, int b) -{ - int x, res; - - /* if its less than zero return */ - if (b <= 0) { - return MP_OKAY; - } - - /* grow to fit the new digits */ - if (a->alloc < a->used + b) { - if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { - return res; - } - } - - { - register mp_digit *top, *bottom; - - /* increment the used by the shift amount then copy upwards */ - a->used += b; - - /* top */ - top = a->dp + a->used - 1; - - /* base */ - bottom = a->dp + a->used - 1 - b; - - /* much like mp_rshd this is implemented using a sliding window - * except the window goes the otherway around. Copying from - * the bottom to the top. see bn_mp_rshd.c for more info. - */ - for (x = a->used - 1; x >= b; x--) { - *top-- = *bottom--; - } - - /* zero the lower digits */ - top = a->dp; - for (x = 0; x < b; x++) { - *top++ = 0; - } - } - return MP_OKAY; -} - - -/* returns the number of bits in an int */ -static int mp_count_bits (mp_int * a) -{ - int r; - mp_digit q; - - /* shortcut */ - if (a->used == 0) { - return 0; - } - - /* get number of digits and add that */ - r = (a->used - 1) * DIGIT_BIT; - - /* take the last digit and count the bits in it */ - q = a->dp[a->used - 1]; - while (q > ((mp_digit) 0)) { - ++r; - q >>= ((mp_digit) 1); - } - return r; -} - - -/* calc a value mod 2**b */ -static int mp_mod_2d (mp_int * a, int b, mp_int * c) -{ - int x, res; - - /* if b is <= 0 then zero the int */ - if (b <= 0) { - mp_zero (c); - return MP_OKAY; - } - - /* if the modulus is larger than the value than return */ - if (b >= (int) (a->used * DIGIT_BIT)) { - res = mp_copy (a, c); - return res; - } - - /* copy */ - if ((res = mp_copy (a, c)) != MP_OKAY) { - return res; - } - - /* zero digits above the last digit of the modulus */ - for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { - c->dp[x] = 0; - } - /* clear the digit that is not completely outside/inside the modulus */ - c->dp[b / DIGIT_BIT] &= - (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); - mp_clamp (c); - return MP_OKAY; -} - - -#ifdef BN_MP_DIV_SMALL - -/* slower bit-bang division... also smaller */ -static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d) -{ - mp_int ta, tb, tq, q; - int res, n, n2; - - /* is divisor zero ? */ - if (mp_iszero (b) == 1) { - return MP_VAL; - } - - /* if a < b then q=0, r = a */ - if (mp_cmp_mag (a, b) == MP_LT) { - if (d != NULL) { - res = mp_copy (a, d); - } else { - res = MP_OKAY; - } - if (c != NULL) { - mp_zero (c); - } - return res; - } - - /* init our temps */ - if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) { - return res; - } - - - mp_set(&tq, 1); - n = mp_count_bits(a) - mp_count_bits(b); - if (((res = mp_abs(a, &ta)) != MP_OKAY) || - ((res = mp_abs(b, &tb)) != MP_OKAY) || - ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || - ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { - goto LBL_ERR; - } - - while (n-- >= 0) { - if (mp_cmp(&tb, &ta) != MP_GT) { - if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || - ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { - goto LBL_ERR; - } - } - if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) || - ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) { - goto LBL_ERR; - } - } - - /* now q == quotient and ta == remainder */ - n = a->sign; - n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG); - if (c != NULL) { - mp_exch(c, &q); - c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2; - } - if (d != NULL) { - mp_exch(d, &ta); - d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; - } -LBL_ERR: - mp_clear_multi(&ta, &tb, &tq, &q, NULL); - return res; -} - -#else - -/* integer signed division. - * c*b + d == a [e.g. a/b, c=quotient, d=remainder] - * HAC pp.598 Algorithm 14.20 - * - * Note that the description in HAC is horribly - * incomplete. For example, it doesn't consider - * the case where digits are removed from 'x' in - * the inner loop. It also doesn't consider the - * case that y has fewer than three digits, etc.. - * - * The overall algorithm is as described as - * 14.20 from HAC but fixed to treat these cases. -*/ -static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) -{ - mp_int q, x, y, t1, t2; - int res, n, t, i, norm, neg; - - /* is divisor zero ? */ - if (mp_iszero (b) == 1) { - return MP_VAL; - } - - /* if a < b then q=0, r = a */ - if (mp_cmp_mag (a, b) == MP_LT) { - if (d != NULL) { - res = mp_copy (a, d); - } else { - res = MP_OKAY; - } - if (c != NULL) { - mp_zero (c); - } - return res; - } - - if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { - return res; - } - q.used = a->used + 2; - - if ((res = mp_init (&t1)) != MP_OKAY) { - goto LBL_Q; - } - - if ((res = mp_init (&t2)) != MP_OKAY) { - goto LBL_T1; - } - - if ((res = mp_init_copy (&x, a)) != MP_OKAY) { - goto LBL_T2; - } - - if ((res = mp_init_copy (&y, b)) != MP_OKAY) { - goto LBL_X; - } - - /* fix the sign */ - neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; - x.sign = y.sign = MP_ZPOS; - - /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ - norm = mp_count_bits(&y) % DIGIT_BIT; - if (norm < (int)(DIGIT_BIT-1)) { - norm = (DIGIT_BIT-1) - norm; - if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { - goto LBL_Y; - } - if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { - goto LBL_Y; - } - } else { - norm = 0; - } - - /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ - n = x.used - 1; - t = y.used - 1; - - /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ - if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ - goto LBL_Y; - } - - while (mp_cmp (&x, &y) != MP_LT) { - ++(q.dp[n - t]); - if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { - goto LBL_Y; - } - } - - /* reset y by shifting it back down */ - mp_rshd (&y, n - t); - - /* step 3. for i from n down to (t + 1) */ - for (i = n; i >= (t + 1); i--) { - if (i > x.used) { - continue; - } - - /* step 3.1 if xi == yt then set q{i-t-1} to b-1, - * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ - if (x.dp[i] == y.dp[t]) { - q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); - } else { - mp_word tmp; - tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); - tmp |= ((mp_word) x.dp[i - 1]); - tmp /= ((mp_word) y.dp[t]); - if (tmp > (mp_word) MP_MASK) - tmp = MP_MASK; - q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); - } - - /* while (q{i-t-1} * (yt * b + y{t-1})) > - xi * b**2 + xi-1 * b + xi-2 - - do q{i-t-1} -= 1; - */ - q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; - do { - q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; - - /* find left hand */ - mp_zero (&t1); - t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; - t1.dp[1] = y.dp[t]; - t1.used = 2; - if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { - goto LBL_Y; - } - - /* find right hand */ - t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; - t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; - t2.dp[2] = x.dp[i]; - t2.used = 3; - } while (mp_cmp_mag(&t1, &t2) == MP_GT); - - /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ - if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { - goto LBL_Y; - } - - if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { - goto LBL_Y; - } - - if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { - goto LBL_Y; - } - - /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ - if (x.sign == MP_NEG) { - if ((res = mp_copy (&y, &t1)) != MP_OKAY) { - goto LBL_Y; - } - if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { - goto LBL_Y; - } - if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { - goto LBL_Y; - } - - q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; - } - } - - /* now q is the quotient and x is the remainder - * [which we have to normalize] - */ - - /* get sign before writing to c */ - x.sign = x.used == 0 ? MP_ZPOS : a->sign; - - if (c != NULL) { - mp_clamp (&q); - mp_exch (&q, c); - c->sign = neg; - } - - if (d != NULL) { - mp_div_2d (&x, norm, &x, NULL); - mp_exch (&x, d); - } - - res = MP_OKAY; - -LBL_Y:mp_clear (&y); -LBL_X:mp_clear (&x); -LBL_T2:mp_clear (&t2); -LBL_T1:mp_clear (&t1); -LBL_Q:mp_clear (&q); - return res; -} - -#endif - - -#ifdef MP_LOW_MEM - #define TAB_SIZE 32 -#else - #define TAB_SIZE 256 -#endif - -static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) -{ - mp_int M[TAB_SIZE], res, mu; - mp_digit buf; - int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; - int (*redux)(mp_int*,mp_int*,mp_int*); - - /* find window size */ - x = mp_count_bits (X); - if (x <= 7) { - winsize = 2; - } else if (x <= 36) { - winsize = 3; - } else if (x <= 140) { - winsize = 4; - } else if (x <= 450) { - winsize = 5; - } else if (x <= 1303) { - winsize = 6; - } else if (x <= 3529) { - winsize = 7; - } else { - winsize = 8; - } - -#ifdef MP_LOW_MEM - if (winsize > 5) { - winsize = 5; - } -#endif - - /* init M array */ - /* init first cell */ - if ((err = mp_init(&M[1])) != MP_OKAY) { - return err; - } - - /* now init the second half of the array */ - for (x = 1<<(winsize-1); x < (1 << winsize); x++) { - if ((err = mp_init(&M[x])) != MP_OKAY) { - for (y = 1<<(winsize-1); y < x; y++) { - mp_clear (&M[y]); - } - mp_clear(&M[1]); - return err; - } - } - - /* create mu, used for Barrett reduction */ - if ((err = mp_init (&mu)) != MP_OKAY) { - goto LBL_M; - } - - if (redmode == 0) { - if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { - goto LBL_MU; - } - redux = mp_reduce; - } else { - if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) { - goto LBL_MU; - } - redux = mp_reduce_2k_l; - } - - /* create M table - * - * The M table contains powers of the base, - * e.g. M[x] = G**x mod P - * - * The first half of the table is not - * computed though accept for M[0] and M[1] - */ - if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { - goto LBL_MU; - } - - /* compute the value at M[1<<(winsize-1)] by squaring - * M[1] (winsize-1) times - */ - if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { - goto LBL_MU; - } - - for (x = 0; x < (winsize - 1); x++) { - /* square it */ - if ((err = mp_sqr (&M[1 << (winsize - 1)], - &M[1 << (winsize - 1)])) != MP_OKAY) { - goto LBL_MU; - } - - /* reduce modulo P */ - if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { - goto LBL_MU; - } - } - - /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) - * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) - */ - for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { - if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { - goto LBL_MU; - } - if ((err = redux (&M[x], P, &mu)) != MP_OKAY) { - goto LBL_MU; - } - } - - /* setup result */ - if ((err = mp_init (&res)) != MP_OKAY) { - goto LBL_MU; - } - mp_set (&res, 1); - - /* set initial mode and bit cnt */ - mode = 0; - bitcnt = 1; - buf = 0; - digidx = X->used - 1; - bitcpy = 0; - bitbuf = 0; - - for (;;) { - /* grab next digit as required */ - if (--bitcnt == 0) { - /* if digidx == -1 we are out of digits */ - if (digidx == -1) { - break; - } - /* read next digit and reset the bitcnt */ - buf = X->dp[digidx--]; - bitcnt = (int) DIGIT_BIT; - } - - /* grab the next msb from the exponent */ - y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; - buf <<= (mp_digit)1; - - /* if the bit is zero and mode == 0 then we ignore it - * These represent the leading zero bits before the first 1 bit - * in the exponent. Technically this opt is not required but it - * does lower the # of trivial squaring/reductions used - */ - if (mode == 0 && y == 0) { - continue; - } - - /* if the bit is zero and mode == 1 then we square */ - if (mode == 1 && y == 0) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto LBL_RES; - } - if ((err = redux (&res, P, &mu)) != MP_OKAY) { - goto LBL_RES; - } - continue; - } - - /* else we add it to the window */ - bitbuf |= (y << (winsize - ++bitcpy)); - mode = 2; - - if (bitcpy == winsize) { - /* ok window is filled so square as required and multiply */ - /* square first */ - for (x = 0; x < winsize; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto LBL_RES; - } - if ((err = redux (&res, P, &mu)) != MP_OKAY) { - goto LBL_RES; - } - } - - /* then multiply */ - if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { - goto LBL_RES; - } - if ((err = redux (&res, P, &mu)) != MP_OKAY) { - goto LBL_RES; - } - - /* empty window and reset */ - bitcpy = 0; - bitbuf = 0; - mode = 1; - } - } - - /* if bits remain then square/multiply */ - if (mode == 2 && bitcpy > 0) { - /* square then multiply if the bit is set */ - for (x = 0; x < bitcpy; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto LBL_RES; - } - if ((err = redux (&res, P, &mu)) != MP_OKAY) { - goto LBL_RES; - } - - bitbuf <<= 1; - if ((bitbuf & (1 << winsize)) != 0) { - /* then multiply */ - if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { - goto LBL_RES; - } - if ((err = redux (&res, P, &mu)) != MP_OKAY) { - goto LBL_RES; - } - } - } - } - - mp_exch (&res, Y); - err = MP_OKAY; -LBL_RES:mp_clear (&res); -LBL_MU:mp_clear (&mu); -LBL_M: - mp_clear(&M[1]); - for (x = 1<<(winsize-1); x < (1 << winsize); x++) { - mp_clear (&M[x]); - } - return err; -} - - -/* computes b = a*a */ -static int mp_sqr (mp_int * a, mp_int * b) -{ - int res; - -#ifdef BN_MP_TOOM_SQR_C - /* use Toom-Cook? */ - if (a->used >= TOOM_SQR_CUTOFF) { - res = mp_toom_sqr(a, b); - /* Karatsuba? */ - } else -#endif -#ifdef BN_MP_KARATSUBA_SQR_C -if (a->used >= KARATSUBA_SQR_CUTOFF) { - res = mp_karatsuba_sqr (a, b); - } else -#endif - { -#ifdef BN_FAST_S_MP_SQR_C - /* can we use the fast comba multiplier? */ - if ((a->used * 2 + 1) < MP_WARRAY && - a->used < - (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { - res = fast_s_mp_sqr (a, b); - } else -#endif -#ifdef BN_S_MP_SQR_C - res = s_mp_sqr (a, b); -#else -#error mp_sqr could fail - res = MP_VAL; -#endif - } - b->sign = MP_ZPOS; - return res; -} - - -/* reduces a modulo n where n is of the form 2**p - d - This differs from reduce_2k since "d" can be larger - than a single digit. -*/ -static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d) -{ - mp_int q; - int p, res; - - if ((res = mp_init(&q)) != MP_OKAY) { - return res; - } - - p = mp_count_bits(n); -top: - /* q = a/2**p, a = a mod 2**p */ - if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { - goto ERR; - } - - /* q = q * d */ - if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { - goto ERR; - } - - /* a = a + q */ - if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { - goto ERR; - } - - if (mp_cmp_mag(a, n) != MP_LT) { - s_mp_sub(a, n, a); - goto top; - } - -ERR: - mp_clear(&q); - return res; -} - - -/* determines the setup value */ -static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d) -{ - int res; - mp_int tmp; - - if ((res = mp_init(&tmp)) != MP_OKAY) { - return res; - } - - if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { - goto ERR; - } - - if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) { - goto ERR; - } - -ERR: - mp_clear(&tmp); - return res; -} - - -/* computes a = 2**b - * - * Simple algorithm which zeroes the int, grows it then just sets one bit - * as required. - */ -static int mp_2expt (mp_int * a, int b) -{ - int res; - - /* zero a as per default */ - mp_zero (a); - - /* grow a to accommodate the single bit */ - if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { - return res; - } - - /* set the used count of where the bit will go */ - a->used = b / DIGIT_BIT + 1; - - /* put the single bit in its place */ - a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT); - - return MP_OKAY; -} - - -/* pre-calculate the value required for Barrett reduction - * For a given modulus "b" it calulates the value required in "a" - */ -static int mp_reduce_setup (mp_int * a, mp_int * b) -{ - int res; - - if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { - return res; - } - return mp_div (a, b, a, NULL); -} - - -/* reduces x mod m, assumes 0 < x < m**2, mu is - * precomputed via mp_reduce_setup. - * From HAC pp.604 Algorithm 14.42 - */ -static int mp_reduce (mp_int * x, mp_int * m, mp_int * mu) -{ - mp_int q; - int res, um = m->used; - - /* q = x */ - if ((res = mp_init_copy (&q, x)) != MP_OKAY) { - return res; - } - - /* q1 = x / b**(k-1) */ - mp_rshd (&q, um - 1); - - /* according to HAC this optimization is ok */ - if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) { - if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { - goto CLEANUP; - } - } else { -#ifdef BN_S_MP_MUL_HIGH_DIGS_C - if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { - goto CLEANUP; - } -#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C) - if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { - goto CLEANUP; - } -#else - { -#error mp_reduce would always fail - res = MP_VAL; - goto CLEANUP; - } -#endif - } - - /* q3 = q2 / b**(k+1) */ - mp_rshd (&q, um + 1); - - /* x = x mod b**(k+1), quick (no division) */ - if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { - goto CLEANUP; - } - - /* q = q * m mod b**(k+1), quick (no division) */ - if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { - goto CLEANUP; - } - - /* x = x - q */ - if ((res = mp_sub (x, &q, x)) != MP_OKAY) { - goto CLEANUP; - } - - /* If x < 0, add b**(k+1) to it */ - if (mp_cmp_d (x, 0) == MP_LT) { - mp_set (&q, 1); - if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) { - goto CLEANUP; - } - if ((res = mp_add (x, &q, x)) != MP_OKAY) { - goto CLEANUP; - } - } - - /* Back off if it's too big */ - while (mp_cmp (x, m) != MP_LT) { - if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { - goto CLEANUP; - } - } - -CLEANUP: - mp_clear (&q); - - return res; -} - - -/* 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. - */ -static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -{ - mp_int t; - int res, pa, pb, ix, iy; - mp_digit u; - mp_word r; - mp_digit tmpx, *tmpt, *tmpy; - -#ifdef BN_FAST_S_MP_MUL_DIGS_C - /* can we use the fast multiplier? */ - if (((digs) < MP_WARRAY) && - MIN (a->used, b->used) < - (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { - return fast_s_mp_mul_digs (a, b, c, digs); - } -#endif - - if ((res = mp_init_size (&t, digs)) != MP_OKAY) { - return res; - } - t.used = digs; - - /* compute the digits of the product directly */ - pa = a->used; - for (ix = 0; ix < pa; ix++) { - /* set the carry to zero */ - u = 0; - - /* limit ourselves to making digs digits of output */ - pb = MIN (b->used, digs - ix); - - /* setup some aliases */ - /* copy of the digit from a used within the nested loop */ - tmpx = a->dp[ix]; - - /* an alias for the destination shifted ix places */ - tmpt = t.dp + ix; - - /* an alias for the digits of b */ - tmpy = b->dp; - - /* compute the columns of the output and propagate the carry */ - for (iy = 0; iy < pb; iy++) { - /* compute the column as a mp_word */ - r = ((mp_word)*tmpt) + - ((mp_word)tmpx) * ((mp_word)*tmpy++) + - ((mp_word) u); - - /* the new column is the lower part of the result */ - *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); - - /* get the carry word from the result */ - u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); - } - /* set carry if it is placed below digs */ - if (ix + iy < digs) { - *tmpt = u; - } - } - - mp_clamp (&t); - mp_exch (&t, c); - - mp_clear (&t); - return MP_OKAY; -} - - -#ifdef BN_FAST_S_MP_MUL_DIGS_C -/* Fast (comba) multiplier - * - * This is the fast column-array [comba] multiplier. It is - * designed to compute the columns of the product first - * then handle the carries afterwards. This has the effect - * of making the nested loops that compute the columns very - * simple and schedulable on super-scalar processors. - * - * This has been modified to produce a variable number of - * digits of output so if say only a half-product is required - * you don't have to compute the upper half (a feature - * required for fast Barrett reduction). - * - * Based on Algorithm 14.12 on pp.595 of HAC. - * - */ -static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -{ - int olduse, res, pa, ix, iz; - mp_digit W[MP_WARRAY]; - register mp_word _W; - - /* grow the destination as required */ - if (c->alloc < digs) { - if ((res = mp_grow (c, digs)) != MP_OKAY) { - return res; - } - } - - /* number of output digits to produce */ - pa = MIN(digs, a->used + b->used); - - /* clear the carry */ - _W = 0; - for (ix = 0; ix < pa; ix++) { - int tx, ty; - int iy; - mp_digit *tmpx, *tmpy; - - /* get offsets into the two bignums */ - ty = MIN(b->used-1, ix); - tx = ix - ty; - - /* setup temp aliases */ - tmpx = a->dp + tx; - tmpy = b->dp + ty; - - /* this is the number of times the loop will iterrate, essentially - while (tx++ < a->used && ty-- >= 0) { ... } - */ - iy = MIN(a->used-tx, ty+1); - - /* execute loop */ - for (iz = 0; iz < iy; ++iz) { - _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); - - } - - /* store term */ - W[ix] = ((mp_digit)_W) & MP_MASK; - - /* make next carry */ - _W = _W >> ((mp_word)DIGIT_BIT); - } - - /* setup dest */ - olduse = c->used; - c->used = pa; - - { - register mp_digit *tmpc; - tmpc = c->dp; - for (ix = 0; ix < pa+1; ix++) { - /* now extract the previous digit [below the carry] */ - *tmpc++ = W[ix]; - } - - /* clear unused digits [that existed in the old copy of c] */ - for (; ix < olduse; ix++) { - *tmpc++ = 0; - } - } - mp_clamp (c); - return MP_OKAY; -} -#endif /* BN_FAST_S_MP_MUL_DIGS_C */ - - -/* init an mp_init for a given size */ -static int mp_init_size (mp_int * a, int size) -{ - int x; - - /* pad size so there are always extra digits */ - size += (MP_PREC * 2) - (size % MP_PREC); - - /* alloc mem */ - a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size); - if (a->dp == NULL) { - return MP_MEM; - } - - /* set the members */ - a->used = 0; - a->alloc = size; - a->sign = MP_ZPOS; - - /* zero the digits */ - for (x = 0; x < size; x++) { - a->dp[x] = 0; - } - - return MP_OKAY; -} - - -/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ -static int s_mp_sqr (mp_int * a, mp_int * b) -{ - mp_int t; - int res, ix, iy, pa; - mp_word r; - mp_digit u, tmpx, *tmpt; - - pa = a->used; - if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) { - return res; - } - - /* default used is maximum possible size */ - t.used = 2*pa + 1; - - for (ix = 0; ix < pa; ix++) { - /* first calculate the digit at 2*ix */ - /* calculate double precision result */ - r = ((mp_word) t.dp[2*ix]) + - ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]); - - /* store lower part in result */ - t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK)); - - /* get the carry */ - u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); - - /* left hand side of A[ix] * A[iy] */ - tmpx = a->dp[ix]; - - /* alias for where to store the results */ - tmpt = t.dp + (2*ix + 1); - - for (iy = ix + 1; iy < pa; iy++) { - /* first calculate the product */ - r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]); - - /* now calculate the double precision result, note we use - * addition instead of *2 since it's easier to optimize - */ - r = ((mp_word) *tmpt) + r + r + ((mp_word) u); - - /* store lower part */ - *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); - - /* get carry */ - u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); - } - /* propagate upwards */ - while (u != ((mp_digit) 0)) { - r = ((mp_word) *tmpt) + ((mp_word) u); - *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); - u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); - } - } - - mp_clamp (&t); - mp_exch (&t, b); - mp_clear (&t); - return MP_OKAY; -} - - -/* multiplies |a| * |b| and does not compute the lower digs digits - * [meant to get the higher part of the product] - */ -static int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -{ - mp_int t; - int res, pa, pb, ix, iy; - mp_digit u; - mp_word r; - mp_digit tmpx, *tmpt, *tmpy; - - /* can we use the fast multiplier? */ -#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C - if (((a->used + b->used + 1) < MP_WARRAY) - && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { - return fast_s_mp_mul_high_digs (a, b, c, digs); - } -#endif - - if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { - return res; - } - t.used = a->used + b->used + 1; - - pa = a->used; - pb = b->used; - for (ix = 0; ix < pa; ix++) { - /* clear the carry */ - u = 0; - - /* left hand side of A[ix] * B[iy] */ - tmpx = a->dp[ix]; - - /* alias to the address of where the digits will be stored */ - tmpt = &(t.dp[digs]); - - /* alias for where to read the right hand side from */ - tmpy = b->dp + (digs - ix); - - for (iy = digs - ix; iy < pb; iy++) { - /* calculate the double precision result */ - r = ((mp_word)*tmpt) + - ((mp_word)tmpx) * ((mp_word)*tmpy++) + - ((mp_word) u); - - /* get the lower part */ - *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); - - /* carry the carry */ - u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); - } - *tmpt = u; - } - mp_clamp (&t); - mp_exch (&t, c); - mp_clear (&t); - return MP_OKAY; -} - - -#ifdef BN_MP_MONTGOMERY_SETUP_C -/* setups the montgomery reduction stuff */ -static int -mp_montgomery_setup (mp_int * n, mp_digit * rho) -{ - mp_digit x, b; - -/* fast inversion mod 2**k - * - * Based on the fact that - * - * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) - * => 2*X*A - X*X*A*A = 1 - * => 2*(1) - (1) = 1 - */ - b = n->dp[0]; - - if ((b & 1) == 0) { - return MP_VAL; - } - - x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ - x *= 2 - b * x; /* here x*a==1 mod 2**8 */ -#if !defined(MP_8BIT) - x *= 2 - b * x; /* here x*a==1 mod 2**16 */ -#endif -#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) - x *= 2 - b * x; /* here x*a==1 mod 2**32 */ -#endif -#ifdef MP_64BIT - x *= 2 - b * x; /* here x*a==1 mod 2**64 */ -#endif - - /* rho = -1/m mod b */ - *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK; - - return MP_OKAY; -} -#endif - - -#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C -/* computes xR**-1 == x (mod N) via Montgomery Reduction - * - * This is an optimized implementation of montgomery_reduce - * which uses the comba method to quickly calculate the columns of the - * reduction. - * - * Based on Algorithm 14.32 on pp.601 of HAC. -*/ -static int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) -{ - int ix, res, olduse; - mp_word W[MP_WARRAY]; - - /* get old used count */ - olduse = x->used; - - /* grow a as required */ - if (x->alloc < n->used + 1) { - if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { - return res; - } - } - - /* first we have to get the digits of the input into - * an array of double precision words W[...] - */ - { - register mp_word *_W; - register mp_digit *tmpx; - - /* alias for the W[] array */ - _W = W; - - /* alias for the digits of x*/ - tmpx = x->dp; - - /* copy the digits of a into W[0..a->used-1] */ - for (ix = 0; ix < x->used; ix++) { - *_W++ = *tmpx++; - } - - /* zero the high words of W[a->used..m->used*2] */ - for (; ix < n->used * 2 + 1; ix++) { - *_W++ = 0; - } - } - - /* now we proceed to zero successive digits - * from the least significant upwards - */ - for (ix = 0; ix < n->used; ix++) { - /* mu = ai * m' mod b - * - * We avoid a double precision multiplication (which isn't required) - * by casting the value down to a mp_digit. Note this requires - * that W[ix-1] have the carry cleared (see after the inner loop) - */ - register mp_digit mu; - mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK); - - /* a = a + mu * m * b**i - * - * This is computed in place and on the fly. The multiplication - * by b**i is handled by offseting which columns the results - * are added to. - * - * Note the comba method normally doesn't handle carries in the - * inner loop In this case we fix the carry from the previous - * column since the Montgomery reduction requires digits of the - * result (so far) [see above] to work. This is - * handled by fixing up one carry after the inner loop. The - * carry fixups are done in order so after these loops the - * first m->used words of W[] have the carries fixed - */ - { - register int iy; - register mp_digit *tmpn; - register mp_word *_W; - - /* alias for the digits of the modulus */ - tmpn = n->dp; - - /* Alias for the columns set by an offset of ix */ - _W = W + ix; - - /* inner loop */ - for (iy = 0; iy < n->used; iy++) { - *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++); - } - } - - /* now fix carry for next digit, W[ix+1] */ - W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); - } - - /* now we have to propagate the carries and - * shift the words downward [all those least - * significant digits we zeroed]. - */ - { - register mp_digit *tmpx; - register mp_word *_W, *_W1; - - /* nox fix rest of carries */ - - /* alias for current word */ - _W1 = W + ix; - - /* alias for next word, where the carry goes */ - _W = W + ++ix; - - for (; ix <= n->used * 2 + 1; ix++) { - *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); - } - - /* copy out, A = A/b**n - * - * The result is A/b**n but instead of converting from an - * array of mp_word to mp_digit than calling mp_rshd - * we just copy them in the right order - */ - - /* alias for destination word */ - tmpx = x->dp; - - /* alias for shifted double precision result */ - _W = W + n->used; - - for (ix = 0; ix < n->used + 1; ix++) { - *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK)); - } - - /* zero oldused digits, if the input a was larger than - * m->used+1 we'll have to clear the digits - */ - for (; ix < olduse; ix++) { - *tmpx++ = 0; - } - } - - /* set the max used and clamp */ - x->used = n->used + 1; - mp_clamp (x); - - /* if A >= m then A = A - m */ - if (mp_cmp_mag (x, n) != MP_LT) { - return s_mp_sub (x, n, x); - } - return MP_OKAY; -} -#endif - - -#ifdef BN_MP_MUL_2_C -/* b = a*2 */ -static int mp_mul_2(mp_int * a, mp_int * b) -{ - int x, res, oldused; - - /* grow to accommodate result */ - if (b->alloc < a->used + 1) { - if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { - return res; - } - } - - oldused = b->used; - b->used = a->used; - - { - register mp_digit r, rr, *tmpa, *tmpb; - - /* alias for source */ - tmpa = a->dp; - - /* alias for dest */ - tmpb = b->dp; - - /* carry */ - r = 0; - for (x = 0; x < a->used; x++) { - - /* get what will be the *next* carry bit from the - * MSB of the current digit - */ - rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); - - /* now shift up this digit, add in the carry [from the previous] */ - *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; - - /* copy the carry that would be from the source - * digit into the next iteration - */ - r = rr; - } - - /* new leading digit? */ - if (r != 0) { - /* add a MSB which is always 1 at this point */ - *tmpb = 1; - ++(b->used); - } - - /* now zero any excess digits on the destination - * that we didn't write to - */ - tmpb = b->dp + b->used; - for (x = b->used; x < oldused; x++) { - *tmpb++ = 0; - } - } - b->sign = a->sign; - return MP_OKAY; -} -#endif - - -#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C -/* - * shifts with subtractions when the result is greater than b. - * - * 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) -{ - int x, bits, res; - - /* how many bits of last digit does b use */ - bits = mp_count_bits (b) % DIGIT_BIT; - - if (b->used > 1) { - if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { - return res; - } - } else { - mp_set(a, 1); - bits = 1; - } - - - /* now compute C = A * B mod b */ - for (x = bits - 1; x < (int)DIGIT_BIT; x++) { - if ((res = mp_mul_2 (a, a)) != MP_OKAY) { - return res; - } - if (mp_cmp_mag (a, b) != MP_LT) { - if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { - return res; - } - } - } - - return MP_OKAY; -} -#endif - - -#ifdef BN_MP_EXPTMOD_FAST_C -/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 - * - * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. - * The value of k changes based on the size of the exponent. - * - * Uses Montgomery or Diminished Radix reduction [whichever appropriate] - */ - -static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) -{ - mp_int M[TAB_SIZE], res; - mp_digit buf, mp; - int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; - - /* use a pointer to the reduction algorithm. This allows us to use - * one of many reduction algorithms without modding the guts of - * the code with if statements everywhere. - */ - int (*redux)(mp_int*,mp_int*,mp_digit); - - /* find window size */ - x = mp_count_bits (X); - if (x <= 7) { - winsize = 2; - } else if (x <= 36) { - winsize = 3; - } else if (x <= 140) { - winsize = 4; - } else if (x <= 450) { - winsize = 5; - } else if (x <= 1303) { - winsize = 6; - } else if (x <= 3529) { - winsize = 7; - } else { - winsize = 8; - } - -#ifdef MP_LOW_MEM - if (winsize > 5) { - winsize = 5; - } -#endif - - /* init M array */ - /* init first cell */ - if ((err = mp_init(&M[1])) != MP_OKAY) { - return err; - } - - /* now init the second half of the array */ - for (x = 1<<(winsize-1); x < (1 << winsize); x++) { - if ((err = mp_init(&M[x])) != MP_OKAY) { - for (y = 1<<(winsize-1); y < x; y++) { - mp_clear (&M[y]); - } - mp_clear(&M[1]); - return err; - } - } - - /* determine and setup reduction code */ - if (redmode == 0) { -#ifdef BN_MP_MONTGOMERY_SETUP_C - /* now setup montgomery */ - if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { - goto LBL_M; - } -#else - err = MP_VAL; - goto LBL_M; -#endif - - /* automatically pick the comba one if available (saves quite a few calls/ifs) */ -#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C - if (((P->used * 2 + 1) < MP_WARRAY) && - P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { - redux = fast_mp_montgomery_reduce; - } else -#endif - { -#ifdef BN_MP_MONTGOMERY_REDUCE_C - /* use slower baseline Montgomery method */ - redux = mp_montgomery_reduce; -#else - err = MP_VAL; - goto LBL_M; -#endif - } - } else if (redmode == 1) { -#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C) - /* setup DR reduction for moduli of the form B**k - b */ - mp_dr_setup(P, &mp); - redux = mp_dr_reduce; -#else - err = MP_VAL; - goto LBL_M; -#endif - } else { -#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C) - /* setup DR reduction for moduli of the form 2**k - b */ - if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { - goto LBL_M; - } - redux = mp_reduce_2k; -#else - err = MP_VAL; - goto LBL_M; -#endif - } - - /* setup result */ - if ((err = mp_init (&res)) != MP_OKAY) { - goto LBL_M; - } - - /* create M table - * - - * - * The first half of the table is not computed though accept for M[0] and M[1] - */ - - if (redmode == 0) { -#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C - /* now we need R mod m */ - if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { - goto LBL_RES; - } -#else - err = MP_VAL; - goto LBL_RES; -#endif - - /* now set M[1] to G * R mod m */ - if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { - goto LBL_RES; - } - } else { - mp_set(&res, 1); - if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { - goto LBL_RES; - } - } - - /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ - if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { - goto LBL_RES; - } - - for (x = 0; x < (winsize - 1); x++) { - if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { - goto LBL_RES; - } - if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { - goto LBL_RES; - } - } - - /* create upper table */ - for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { - if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { - goto LBL_RES; - } - if ((err = redux (&M[x], P, mp)) != MP_OKAY) { - goto LBL_RES; - } - } - - /* set initial mode and bit cnt */ - mode = 0; - bitcnt = 1; - buf = 0; - digidx = X->used - 1; - bitcpy = 0; - bitbuf = 0; - - for (;;) { - /* grab next digit as required */ - if (--bitcnt == 0) { - /* if digidx == -1 we are out of digits so break */ - if (digidx == -1) { - break; - } - /* read next digit and reset bitcnt */ - buf = X->dp[digidx--]; - bitcnt = (int)DIGIT_BIT; - } - - /* grab the next msb from the exponent */ - y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; - buf <<= (mp_digit)1; - - /* if the bit is zero and mode == 0 then we ignore it - * These represent the leading zero bits before the first 1 bit - * in the exponent. Technically this opt is not required but it - * does lower the # of trivial squaring/reductions used - */ - if (mode == 0 && y == 0) { - continue; - } - - /* if the bit is zero and mode == 1 then we square */ - if (mode == 1 && y == 0) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto LBL_RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto LBL_RES; - } - continue; - } - - /* else we add it to the window */ - bitbuf |= (y << (winsize - ++bitcpy)); - mode = 2; - - if (bitcpy == winsize) { - /* ok window is filled so square as required and multiply */ - /* square first */ - for (x = 0; x < winsize; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto LBL_RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto LBL_RES; - } - } - - /* then multiply */ - if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { - goto LBL_RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto LBL_RES; - } - - /* empty window and reset */ - bitcpy = 0; - bitbuf = 0; - mode = 1; - } - } - - /* if bits remain then square/multiply */ - if (mode == 2 && bitcpy > 0) { - /* square then multiply if the bit is set */ - for (x = 0; x < bitcpy; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto LBL_RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto LBL_RES; - } - - /* get next bit of the window */ - bitbuf <<= 1; - if ((bitbuf & (1 << winsize)) != 0) { - /* then multiply */ - if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { - goto LBL_RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto LBL_RES; - } - } - } - } - - if (redmode == 0) { - /* fixup result if Montgomery reduction is used - * recall that any value in a Montgomery system is - * actually multiplied by R mod n. So we have - * to reduce one more time to cancel out the factor - * of R. - */ - if ((err = redux(&res, P, mp)) != MP_OKAY) { - goto LBL_RES; - } - } - - /* swap res with Y */ - mp_exch (&res, Y); - err = MP_OKAY; -LBL_RES:mp_clear (&res); -LBL_M: - mp_clear(&M[1]); - for (x = 1<<(winsize-1); x < (1 << winsize); x++) { - mp_clear (&M[x]); - } - return err; -} -#endif - - -#ifdef BN_FAST_S_MP_SQR_C -/* the jist of squaring... - * you do like mult except the offset of the tmpx [one that - * starts closer to zero] can't equal the offset of tmpy. - * So basically you set up iy like before then you min it with - * (ty-tx) so that it never happens. You double all those - * you add in the inner loop - -After that loop you do the squares and add them in. -*/ - -static int fast_s_mp_sqr (mp_int * a, mp_int * b) -{ - int olduse, res, pa, ix, iz; - mp_digit W[MP_WARRAY], *tmpx; - mp_word W1; - - /* grow the destination as required */ - pa = a->used + a->used; - if (b->alloc < pa) { - if ((res = mp_grow (b, pa)) != MP_OKAY) { - return res; - } - } - - /* number of output digits to produce */ - W1 = 0; - for (ix = 0; ix < pa; ix++) { - int tx, ty, iy; - mp_word _W; - mp_digit *tmpy; - - /* clear counter */ - _W = 0; - - /* get offsets into the two bignums */ - ty = MIN(a->used-1, ix); - tx = ix - ty; - - /* setup temp aliases */ - tmpx = a->dp + tx; - tmpy = a->dp + ty; - - /* this is the number of times the loop will iterrate, essentially - while (tx++ < a->used && ty-- >= 0) { ... } - */ - iy = MIN(a->used-tx, ty+1); - - /* now for squaring tx can never equal ty - * we halve the distance since they approach at a rate of 2x - * and we have to round because odd cases need to be executed - */ - iy = MIN(iy, (ty-tx+1)>>1); - - /* execute loop */ - for (iz = 0; iz < iy; iz++) { - _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); - } - - /* double the inner product and add carry */ - _W = _W + _W + W1; - - /* even columns have the square term in them */ - if ((ix&1) == 0) { - _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]); - } - - /* store it */ - W[ix] = (mp_digit)(_W & MP_MASK); - - /* make next carry */ - W1 = _W >> ((mp_word)DIGIT_BIT); - } - - /* setup dest */ - olduse = b->used; - b->used = a->used+a->used; - - { - mp_digit *tmpb; - tmpb = b->dp; - for (ix = 0; ix < pa; ix++) { - *tmpb++ = W[ix] & MP_MASK; - } - - /* clear unused digits [that existed in the old copy of c] */ - for (; ix < olduse; ix++) { - *tmpb++ = 0; - } - } - mp_clamp (b); - return MP_OKAY; -} -#endif - - -#ifdef BN_MP_MUL_D_C -/* multiply by a digit */ -static int -mp_mul_d (mp_int * a, mp_digit b, mp_int * c) -{ - mp_digit u, *tmpa, *tmpc; - mp_word r; - int ix, res, olduse; - - /* make sure c is big enough to hold a*b */ - if (c->alloc < a->used + 1) { - if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) { - return res; - } - } - - /* get the original destinations used count */ - olduse = c->used; - - /* set the sign */ - c->sign = a->sign; - - /* alias for a->dp [source] */ - tmpa = a->dp; - - /* alias for c->dp [dest] */ - tmpc = c->dp; - - /* zero carry */ - u = 0; - - /* compute columns */ - for (ix = 0; ix < a->used; ix++) { - /* compute product and carry sum for this term */ - r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b); - - /* mask off higher bits to get a single digit */ - *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); - - /* send carry into next iteration */ - u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); - } - - /* store final carry [if any] and increment ix offset */ - *tmpc++ = u; - ++ix; - - /* now zero digits above the top */ - while (ix++ < olduse) { - *tmpc++ = 0; - } - - /* set used count */ - c->used = a->used + 1; - mp_clamp(c); - - return MP_OKAY; -} -#endif diff --git a/contrib/hostapd/src/tls/pkcs1.c b/contrib/hostapd/src/tls/pkcs1.c deleted file mode 100644 index b6fde5ee86..0000000000 --- a/contrib/hostapd/src/tls/pkcs1.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * PKCS #1 (RSA Encryption) - * Copyright (c) 2006-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "rsa.h" -#include "pkcs1.h" - - -static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - size_t ps_len; - u8 *pos; - - /* - * PKCS #1 v1.5, 8.1: - * - * EB = 00 || BT || PS || 00 || D - * BT = 00 or 01 for private-key operation; 02 for public-key operation - * PS = k-3-||D||; at least eight octets - * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero) - * k = length of modulus in octets (modlen) - */ - - if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) { - wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer " - "lengths (modlen=%lu outlen=%lu inlen=%lu)", - __func__, (unsigned long) modlen, - (unsigned long) *outlen, - (unsigned long) inlen); - return -1; - } - - pos = out; - *pos++ = 0x00; - *pos++ = block_type; /* BT */ - ps_len = modlen - inlen - 3; - switch (block_type) { - case 0: - os_memset(pos, 0x00, ps_len); - pos += ps_len; - break; - case 1: - os_memset(pos, 0xff, ps_len); - pos += ps_len; - break; - case 2: - if (os_get_random(pos, ps_len) < 0) { - wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get " - "random data for PS", __func__); - return -1; - } - while (ps_len--) { - if (*pos == 0x00) - *pos = 0x01; - pos++; - } - break; - default: - wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type " - "%d", __func__, block_type); - return -1; - } - *pos++ = 0x00; - os_memcpy(pos, in, inlen); /* D */ - - return 0; -} - - -int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key, - int use_private, const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - size_t modlen; - - modlen = crypto_rsa_get_modulus_len(key); - - if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen, - out, outlen) < 0) - return -1; - - return crypto_rsa_exptmod(out, modlen, out, outlen, key, use_private); -} - - -int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - int res; - u8 *pos, *end; - - res = crypto_rsa_exptmod(in, inlen, out, outlen, key, 1); - if (res) - return res; - - if (*outlen < 2 || out[0] != 0 || out[1] != 2) - return -1; - - /* Skip PS (pseudorandom non-zero octets) */ - pos = out + 2; - end = out + *outlen; - while (*pos && pos < end) - pos++; - if (pos == end) - return -1; - pos++; - - *outlen -= pos - out; - - /* Strip PKCS #1 header */ - os_memmove(out, pos, *outlen); - - return 0; -} - - -int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, - const u8 *crypt, size_t crypt_len, - u8 *plain, size_t *plain_len) -{ - size_t len; - u8 *pos; - - len = *plain_len; - if (crypto_rsa_exptmod(crypt, crypt_len, plain, &len, key, 0) < 0) - return -1; - - /* - * PKCS #1 v1.5, 8.1: - * - * EB = 00 || BT || PS || 00 || D - * BT = 00 or 01 - * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01) - * k = length of modulus in octets - */ - - if (len < 3 + 8 + 16 /* min hash len */ || - plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " - "structure"); - return -1; - } - - pos = plain + 3; - if (plain[1] == 0x00) { - /* BT = 00 */ - if (plain[2] != 0x00) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " - "PS (BT=00)"); - return -1; - } - while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00) - pos++; - } else { - /* BT = 01 */ - if (plain[2] != 0xff) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " - "PS (BT=01)"); - return -1; - } - while (pos < plain + len && *pos == 0xff) - pos++; - } - - if (pos - plain - 2 < 8) { - /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ - wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature " - "padding"); - return -1; - } - - if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " - "structure (2)"); - return -1; - } - pos++; - len -= pos - plain; - - /* Strip PKCS #1 header */ - os_memmove(plain, pos, len); - *plain_len = len; - - return 0; -} diff --git a/contrib/hostapd/src/tls/pkcs1.h b/contrib/hostapd/src/tls/pkcs1.h deleted file mode 100644 index ed64defaaf..0000000000 --- a/contrib/hostapd/src/tls/pkcs1.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * PKCS #1 (RSA Encryption) - * Copyright (c) 2006-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef PKCS1_H -#define PKCS1_H - -int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key, - int use_private, const u8 *in, size_t inlen, - u8 *out, size_t *outlen); -int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen); -int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, - const u8 *crypt, size_t crypt_len, - u8 *plain, size_t *plain_len); - -#endif /* PKCS1_H */ diff --git a/contrib/hostapd/src/tls/pkcs5.c b/contrib/hostapd/src/tls/pkcs5.c deleted file mode 100644 index 8a93483781..0000000000 --- a/contrib/hostapd/src/tls/pkcs5.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * PKCS #5 (Password-based Encryption) - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/crypto.h" -#include "crypto/md5.h" -#include "asn1.h" -#include "pkcs5.h" - - -struct pkcs5_params { - enum pkcs5_alg { - PKCS5_ALG_UNKNOWN, - PKCS5_ALG_MD5_DES_CBC - } alg; - u8 salt[8]; - size_t salt_len; - unsigned int iter_count; -}; - - -static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid) -{ - if (oid->len == 7 && - oid->oid[0] == 1 /* iso */ && - oid->oid[1] == 2 /* member-body */ && - oid->oid[2] == 840 /* us */ && - oid->oid[3] == 113549 /* rsadsi */ && - oid->oid[4] == 1 /* pkcs */ && - oid->oid[5] == 5 /* pkcs-5 */ && - oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */) - return PKCS5_ALG_MD5_DES_CBC; - - return PKCS5_ALG_UNKNOWN; -} - - -static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len, - struct pkcs5_params *params) -{ - struct asn1_hdr hdr; - const u8 *enc_alg_end, *pos, *end; - struct asn1_oid oid; - char obuf[80]; - - /* AlgorithmIdentifier */ - - enc_alg_end = enc_alg + enc_alg_len; - - os_memset(params, 0, sizeof(*params)); - - if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) { - wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID " - "(algorithm)"); - return -1; - } - - asn1_oid_to_str(&oid, obuf, sizeof(obuf)); - wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf); - params->alg = pkcs5_get_alg(&oid); - if (params->alg == PKCS5_ALG_UNKNOWN) { - wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption " - "algorithm %s", obuf); - return -1; - } - - /* - * PKCS#5, Section 8 - * PBEParameter ::= SEQUENCE { - * salt OCTET STRING SIZE(8), - * iterationCount INTEGER } - */ - - if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE " - "(PBEParameter) - found class %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - pos = hdr.payload; - end = hdr.payload + hdr.length; - - /* salt OCTET STRING SIZE(8) */ - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_OCTETSTRING || - hdr.length != 8) { - wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) " - "(salt) - found class %d tag 0x%x size %d", - hdr.class, hdr.tag, hdr.length); - return -1; - } - pos = hdr.payload + hdr.length; - os_memcpy(params->salt, hdr.payload, hdr.length); - params->salt_len = hdr.length; - wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", - params->salt, params->salt_len); - - /* iterationCount INTEGER */ - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { - wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found " - "class %d tag 0x%x", hdr.class, hdr.tag); - return -1; - } - if (hdr.length == 1) - params->iter_count = *hdr.payload; - else if (hdr.length == 2) - params->iter_count = WPA_GET_BE16(hdr.payload); - else if (hdr.length == 4) - params->iter_count = WPA_GET_BE32(hdr.payload); - else { - wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value " - " (iterationCount)", - hdr.payload, hdr.length); - return -1; - } - wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x", - params->iter_count); - if (params->iter_count == 0 || params->iter_count > 0xffff) { - wpa_printf(MSG_INFO, "PKCS #5: Unsupported " - "iterationCount=0x%x", params->iter_count); - return -1; - } - - return 0; -} - - -static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params, - const char *passwd) -{ - unsigned int i; - u8 hash[MD5_MAC_LEN]; - const u8 *addr[2]; - size_t len[2]; - - if (params->alg != PKCS5_ALG_MD5_DES_CBC) - return NULL; - - addr[0] = (const u8 *) passwd; - len[0] = os_strlen(passwd); - addr[1] = params->salt; - len[1] = params->salt_len; - if (md5_vector(2, addr, len, hash) < 0) - return NULL; - addr[0] = hash; - len[0] = MD5_MAC_LEN; - for (i = 1; i < params->iter_count; i++) { - if (md5_vector(1, addr, len, hash) < 0) - return NULL; - } - /* TODO: DES key parity bits(?) */ - wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8); - wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8); - - return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8); -} - - -u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, - const u8 *enc_data, size_t enc_data_len, - const char *passwd, size_t *data_len) -{ - struct crypto_cipher *ctx; - u8 *eb, pad; - struct pkcs5_params params; - unsigned int i; - - if (pkcs5_get_params(enc_alg, enc_alg_len, ¶ms) < 0) { - wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters"); - return NULL; - } - - ctx = pkcs5_crypto_init(¶ms, passwd); - if (ctx == NULL) { - wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto"); - return NULL; - } - - /* PKCS #5, Section 7 - Decryption process */ - if (enc_data_len < 16 || enc_data_len % 8) { - wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext " - "%d", (int) enc_data_len); - crypto_cipher_deinit(ctx); - return NULL; - } - - eb = os_malloc(enc_data_len); - if (eb == NULL) { - crypto_cipher_deinit(ctx); - return NULL; - } - - if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) { - wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB"); - crypto_cipher_deinit(ctx); - os_free(eb); - return NULL; - } - crypto_cipher_deinit(ctx); - - pad = eb[enc_data_len - 1]; - if (pad > 8) { - wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad); - os_free(eb); - return NULL; - } - for (i = enc_data_len - pad; i < enc_data_len; i++) { - if (eb[i] != pad) { - wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS", - eb + enc_data_len - pad, pad); - os_free(eb); - return NULL; - } - } - - wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)", - eb, enc_data_len - pad); - - *data_len = enc_data_len - pad; - return eb; -} diff --git a/contrib/hostapd/src/tls/pkcs5.h b/contrib/hostapd/src/tls/pkcs5.h deleted file mode 100644 index 20ddadc457..0000000000 --- a/contrib/hostapd/src/tls/pkcs5.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * PKCS #5 (Password-based Encryption) - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef PKCS5_H -#define PKCS5_H - -u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, - const u8 *enc_data, size_t enc_data_len, - const char *passwd, size_t *data_len); - -#endif /* PKCS5_H */ diff --git a/contrib/hostapd/src/tls/pkcs8.c b/contrib/hostapd/src/tls/pkcs8.c deleted file mode 100644 index 52e43a4403..0000000000 --- a/contrib/hostapd/src/tls/pkcs8.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * PKCS #8 (Private-key information syntax) - * Copyright (c) 2006-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "asn1.h" -#include "bignum.h" -#include "rsa.h" -#include "pkcs5.h" -#include "pkcs8.h" - - -struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len) -{ - struct asn1_hdr hdr; - const u8 *pos, *end; - struct bignum *zero; - struct asn1_oid oid; - char obuf[80]; - - /* PKCS #8, Chapter 6 */ - - /* PrivateKeyInfo ::= SEQUENCE */ - if (asn1_get_next(buf, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 " - "header (SEQUENCE); assume PKCS #8 not used"); - return NULL; - } - pos = hdr.payload; - end = pos + hdr.length; - - /* version Version (Version ::= INTEGER) */ - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { - wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found " - "class %d tag 0x%x; assume PKCS #8 not used", - hdr.class, hdr.tag); - return NULL; - } - - zero = bignum_init(); - if (zero == NULL) - return NULL; - - if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) { - wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER"); - bignum_deinit(zero); - return NULL; - } - pos = hdr.payload + hdr.length; - - if (bignum_cmp_d(zero, 0) != 0) { - wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the " - "beginning of private key; not found; assume " - "PKCS #8 not used"); - bignum_deinit(zero); - return NULL; - } - bignum_deinit(zero); - - /* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier - * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */ - if (asn1_get_next(pos, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE " - "(AlgorithmIdentifier) - found class %d tag 0x%x; " - "assume PKCS #8 not used", - hdr.class, hdr.tag); - return NULL; - } - - if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) { - wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID " - "(algorithm); assume PKCS #8 not used"); - return NULL; - } - - asn1_oid_to_str(&oid, obuf, sizeof(obuf)); - wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf); - - if (oid.len != 7 || - oid.oid[0] != 1 /* iso */ || - oid.oid[1] != 2 /* member-body */ || - oid.oid[2] != 840 /* us */ || - oid.oid[3] != 113549 /* rsadsi */ || - oid.oid[4] != 1 /* pkcs */ || - oid.oid[5] != 1 /* pkcs-1 */ || - oid.oid[6] != 1 /* rsaEncryption */) { - wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key " - "algorithm %s", obuf); - return NULL; - } - - pos = hdr.payload + hdr.length; - - /* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */ - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_OCTETSTRING) { - wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING " - "(privateKey) - found class %d tag 0x%x", - hdr.class, hdr.tag); - return NULL; - } - wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey"); - - return (struct crypto_private_key *) - crypto_rsa_import_private_key(hdr.payload, hdr.length); -} - - -struct crypto_private_key * -pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd) -{ - struct asn1_hdr hdr; - const u8 *pos, *end, *enc_alg; - size_t enc_alg_len; - u8 *data; - size_t data_len; - - if (passwd == NULL) - return NULL; - - /* - * PKCS #8, Chapter 7 - * EncryptedPrivateKeyInfo ::= SEQUENCE { - * encryptionAlgorithm EncryptionAlgorithmIdentifier, - * encryptedData EncryptedData } - * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier - * EncryptedData ::= OCTET STRING - */ - - if (asn1_get_next(buf, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 " - "header (SEQUENCE); assume encrypted PKCS #8 not " - "used"); - return NULL; - } - pos = hdr.payload; - end = pos + hdr.length; - - /* encryptionAlgorithm EncryptionAlgorithmIdentifier */ - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE " - "(AlgorithmIdentifier) - found class %d tag 0x%x; " - "assume encrypted PKCS #8 not used", - hdr.class, hdr.tag); - return NULL; - } - enc_alg = hdr.payload; - enc_alg_len = hdr.length; - pos = hdr.payload + hdr.length; - - /* encryptedData EncryptedData */ - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_OCTETSTRING) { - wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING " - "(encryptedData) - found class %d tag 0x%x", - hdr.class, hdr.tag); - return NULL; - } - - data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length, - passwd, &data_len); - if (data) { - struct crypto_private_key *key; - key = pkcs8_key_import(data, data_len); - os_free(data); - return key; - } - - return NULL; -} diff --git a/contrib/hostapd/src/tls/pkcs8.h b/contrib/hostapd/src/tls/pkcs8.h deleted file mode 100644 index bebf840ba7..0000000000 --- a/contrib/hostapd/src/tls/pkcs8.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * PKCS #8 (Private-key information syntax) - * Copyright (c) 2006-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef PKCS8_H -#define PKCS8_H - -struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len); -struct crypto_private_key * -pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd); - -#endif /* PKCS8_H */ diff --git a/contrib/hostapd/src/tls/rsa.c b/contrib/hostapd/src/tls/rsa.c deleted file mode 100644 index 125c4205b7..0000000000 --- a/contrib/hostapd/src/tls/rsa.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * RSA - * Copyright (c) 2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "asn1.h" -#include "bignum.h" -#include "rsa.h" - - -struct crypto_rsa_key { - int private_key; /* whether private key is set */ - struct bignum *n; /* modulus (p * q) */ - struct bignum *e; /* public exponent */ - /* The following parameters are available only if private_key is set */ - struct bignum *d; /* private exponent */ - struct bignum *p; /* prime p (factor of n) */ - struct bignum *q; /* prime q (factor of n) */ - struct bignum *dmp1; /* d mod (p - 1); CRT exponent */ - struct bignum *dmq1; /* d mod (q - 1); CRT exponent */ - struct bignum *iqmp; /* 1 / q mod p; CRT coefficient */ -}; - - -static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end, - struct bignum *num) -{ - struct asn1_hdr hdr; - - if (pos == NULL) - return NULL; - - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { - wpa_printf(MSG_DEBUG, "RSA: Expected INTEGER - found class %d " - "tag 0x%x", hdr.class, hdr.tag); - return NULL; - } - - if (bignum_set_unsigned_bin(num, hdr.payload, hdr.length) < 0) { - wpa_printf(MSG_DEBUG, "RSA: Failed to parse INTEGER"); - return NULL; - } - - return hdr.payload + hdr.length; -} - - -/** - * crypto_rsa_import_public_key - Import an RSA public key - * @buf: Key buffer (DER encoded RSA public key) - * @len: Key buffer length in bytes - * Returns: Pointer to the public key or %NULL on failure - */ -struct crypto_rsa_key * -crypto_rsa_import_public_key(const u8 *buf, size_t len) -{ - struct crypto_rsa_key *key; - struct asn1_hdr hdr; - const u8 *pos, *end; - - key = os_zalloc(sizeof(*key)); - if (key == NULL) - return NULL; - - key->n = bignum_init(); - key->e = bignum_init(); - if (key->n == NULL || key->e == NULL) { - crypto_rsa_free(key); - return NULL; - } - - /* - * PKCS #1, 7.1: - * RSAPublicKey ::= SEQUENCE { - * modulus INTEGER, -- n - * publicExponent INTEGER -- e - * } - */ - - if (asn1_get_next(buf, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE " - "(public key) - found class %d tag 0x%x", - hdr.class, hdr.tag); - goto error; - } - pos = hdr.payload; - end = pos + hdr.length; - - pos = crypto_rsa_parse_integer(pos, end, key->n); - pos = crypto_rsa_parse_integer(pos, end, key->e); - - if (pos == NULL) - goto error; - - if (pos != end) { - wpa_hexdump(MSG_DEBUG, - "RSA: Extra data in public key SEQUENCE", - pos, end - pos); - goto error; - } - - return key; - -error: - crypto_rsa_free(key); - return NULL; -} - - -/** - * crypto_rsa_import_private_key - Import an RSA private key - * @buf: Key buffer (DER encoded RSA private key) - * @len: Key buffer length in bytes - * Returns: Pointer to the private key or %NULL on failure - */ -struct crypto_rsa_key * -crypto_rsa_import_private_key(const u8 *buf, size_t len) -{ - struct crypto_rsa_key *key; - struct bignum *zero; - struct asn1_hdr hdr; - const u8 *pos, *end; - - key = os_zalloc(sizeof(*key)); - if (key == NULL) - return NULL; - - key->private_key = 1; - - key->n = bignum_init(); - key->e = bignum_init(); - key->d = bignum_init(); - key->p = bignum_init(); - key->q = bignum_init(); - key->dmp1 = bignum_init(); - key->dmq1 = bignum_init(); - key->iqmp = bignum_init(); - - if (key->n == NULL || key->e == NULL || key->d == NULL || - key->p == NULL || key->q == NULL || key->dmp1 == NULL || - key->dmq1 == NULL || key->iqmp == NULL) { - crypto_rsa_free(key); - return NULL; - } - - /* - * PKCS #1, 7.2: - * RSAPrivateKey ::= SEQUENCE { - * version Version, - * modulus INTEGER, -- n - * publicExponent INTEGER, -- e - * privateExponent INTEGER, -- d - * prime1 INTEGER, -- p - * prime2 INTEGER, -- q - * exponent1 INTEGER, -- d mod (p-1) - * exponent2 INTEGER, -- d mod (q-1) - * coefficient INTEGER -- (inverse of q) mod p - * } - * - * Version ::= INTEGER -- shall be 0 for this version of the standard - */ - if (asn1_get_next(buf, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE " - "(public key) - found class %d tag 0x%x", - hdr.class, hdr.tag); - goto error; - } - pos = hdr.payload; - end = pos + hdr.length; - - zero = bignum_init(); - if (zero == NULL) - goto error; - pos = crypto_rsa_parse_integer(pos, end, zero); - if (pos == NULL || bignum_cmp_d(zero, 0) != 0) { - wpa_printf(MSG_DEBUG, "RSA: Expected zero INTEGER in the " - "beginning of private key; not found"); - bignum_deinit(zero); - goto error; - } - bignum_deinit(zero); - - pos = crypto_rsa_parse_integer(pos, end, key->n); - pos = crypto_rsa_parse_integer(pos, end, key->e); - pos = crypto_rsa_parse_integer(pos, end, key->d); - pos = crypto_rsa_parse_integer(pos, end, key->p); - pos = crypto_rsa_parse_integer(pos, end, key->q); - pos = crypto_rsa_parse_integer(pos, end, key->dmp1); - pos = crypto_rsa_parse_integer(pos, end, key->dmq1); - pos = crypto_rsa_parse_integer(pos, end, key->iqmp); - - if (pos == NULL) - goto error; - - if (pos != end) { - wpa_hexdump(MSG_DEBUG, - "RSA: Extra data in public key SEQUENCE", - pos, end - pos); - goto error; - } - - return key; - -error: - crypto_rsa_free(key); - return NULL; -} - - -/** - * crypto_rsa_get_modulus_len - Get the modulus length of the RSA key - * @key: RSA key - * Returns: Modulus length of the key - */ -size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key) -{ - return bignum_get_unsigned_bin_len(key->n); -} - - -/** - * crypto_rsa_exptmod - RSA modular exponentiation - * @in: Input data - * @inlen: Input data length - * @out: Buffer for output data - * @outlen: Maximum size of the output buffer and used size on success - * @key: RSA key - * @use_private: 1 = Use RSA private key, 0 = Use RSA public key - * Returns: 0 on success, -1 on failure - */ -int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, - struct crypto_rsa_key *key, int use_private) -{ - struct bignum *tmp, *a = NULL, *b = NULL; - int ret = -1; - size_t modlen; - - if (use_private && !key->private_key) - return -1; - - tmp = bignum_init(); - if (tmp == NULL) - return -1; - - if (bignum_set_unsigned_bin(tmp, in, inlen) < 0) - goto error; - if (bignum_cmp(key->n, tmp) < 0) { - /* Too large input value for the RSA key modulus */ - goto error; - } - - if (use_private) { - /* - * Decrypt (or sign) using Chinese remainer theorem to speed - * up calculation. This is equivalent to tmp = tmp^d mod n - * (which would require more CPU to calculate directly). - * - * dmp1 = (1/e) mod (p-1) - * dmq1 = (1/e) mod (q-1) - * iqmp = (1/q) mod p, where p > q - * m1 = c^dmp1 mod p - * m2 = c^dmq1 mod q - * h = q^-1 (m1 - m2) mod p - * m = m2 + hq - */ - a = bignum_init(); - b = bignum_init(); - if (a == NULL || b == NULL) - goto error; - - /* a = tmp^dmp1 mod p */ - if (bignum_exptmod(tmp, key->dmp1, key->p, a) < 0) - goto error; - - /* b = tmp^dmq1 mod q */ - if (bignum_exptmod(tmp, key->dmq1, key->q, b) < 0) - goto error; - - /* tmp = (a - b) * (1/q mod p) (mod p) */ - if (bignum_sub(a, b, tmp) < 0 || - bignum_mulmod(tmp, key->iqmp, key->p, tmp) < 0) - goto error; - - /* tmp = b + q * tmp */ - if (bignum_mul(tmp, key->q, tmp) < 0 || - bignum_add(tmp, b, tmp) < 0) - goto error; - } else { - /* Encrypt (or verify signature) */ - /* tmp = tmp^e mod N */ - if (bignum_exptmod(tmp, key->e, key->n, tmp) < 0) - goto error; - } - - modlen = crypto_rsa_get_modulus_len(key); - if (modlen > *outlen) { - *outlen = modlen; - goto error; - } - - if (bignum_get_unsigned_bin_len(tmp) > modlen) - goto error; /* should never happen */ - - *outlen = modlen; - os_memset(out, 0, modlen); - if (bignum_get_unsigned_bin( - tmp, out + - (modlen - bignum_get_unsigned_bin_len(tmp)), NULL) < 0) - goto error; - - ret = 0; - -error: - bignum_deinit(tmp); - bignum_deinit(a); - bignum_deinit(b); - return ret; -} - - -/** - * crypto_rsa_free - Free RSA key - * @key: RSA key to be freed - * - * This function frees an RSA key imported with either - * crypto_rsa_import_public_key() or crypto_rsa_import_private_key(). - */ -void crypto_rsa_free(struct crypto_rsa_key *key) -{ - if (key) { - bignum_deinit(key->n); - bignum_deinit(key->e); - bignum_deinit(key->d); - bignum_deinit(key->p); - bignum_deinit(key->q); - bignum_deinit(key->dmp1); - bignum_deinit(key->dmq1); - bignum_deinit(key->iqmp); - os_free(key); - } -} diff --git a/contrib/hostapd/src/tls/rsa.h b/contrib/hostapd/src/tls/rsa.h deleted file mode 100644 index c236a9df44..0000000000 --- a/contrib/hostapd/src/tls/rsa.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * RSA - * Copyright (c) 2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef RSA_H -#define RSA_H - -struct crypto_rsa_key; - -struct crypto_rsa_key * -crypto_rsa_import_public_key(const u8 *buf, size_t len); -struct crypto_rsa_key * -crypto_rsa_import_private_key(const u8 *buf, size_t len); -size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key); -int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, - struct crypto_rsa_key *key, int use_private); -void crypto_rsa_free(struct crypto_rsa_key *key); - -#endif /* RSA_H */ diff --git a/contrib/hostapd/src/tls/tlsv1_client.c b/contrib/hostapd/src/tls/tlsv1_client.c deleted file mode 100644 index 12148b61dd..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_client.c +++ /dev/null @@ -1,794 +0,0 @@ -/* - * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246) - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha1.h" -#include "crypto/tls.h" -#include "tlsv1_common.h" -#include "tlsv1_record.h" -#include "tlsv1_client.h" -#include "tlsv1_client_i.h" - -/* TODO: - * Support for a message fragmented across several records (RFC 2246, 6.2.1) - */ - - -void tls_alert(struct tlsv1_client *conn, u8 level, u8 description) -{ - conn->alert_level = level; - conn->alert_description = description; -} - - -void tlsv1_client_free_dh(struct tlsv1_client *conn) -{ - os_free(conn->dh_p); - os_free(conn->dh_g); - os_free(conn->dh_ys); - conn->dh_p = conn->dh_g = conn->dh_ys = NULL; -} - - -int tls_derive_pre_master_secret(u8 *pre_master_secret) -{ - WPA_PUT_BE16(pre_master_secret, TLS_VERSION); - if (os_get_random(pre_master_secret + 2, - TLS_PRE_MASTER_SECRET_LEN - 2)) - return -1; - return 0; -} - - -int tls_derive_keys(struct tlsv1_client *conn, - const u8 *pre_master_secret, size_t pre_master_secret_len) -{ - u8 seed[2 * TLS_RANDOM_LEN]; - u8 key_block[TLS_MAX_KEY_BLOCK_LEN]; - u8 *pos; - size_t key_block_len; - - if (pre_master_secret) { - wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret", - pre_master_secret, pre_master_secret_len); - os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); - os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, - TLS_RANDOM_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 " - "master_secret"); - return -1; - } - wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret", - conn->master_secret, TLS_MASTER_SECRET_LEN); - } - - 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); - 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"); - return -1; - } - wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block", - key_block, key_block_len); - - pos = key_block; - - /* client_write_MAC_secret */ - os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size); - pos += conn->rl.hash_size; - /* server_write_MAC_secret */ - os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size); - pos += conn->rl.hash_size; - - /* client_write_key */ - os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len); - pos += conn->rl.key_material_len; - /* server_write_key */ - os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len); - pos += conn->rl.key_material_len; - - 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; -} - - -/** - * tlsv1_client_handshake - Process TLS handshake - * @conn: TLSv1 client connection data from tlsv1_client_init() - * @in_data: Input data from TLS peer - * @in_len: Input data length - * @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, int *need_more_data) -{ - const u8 *pos, *end; - 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) - return NULL; - 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; - - pos = in_data; - end = in_data + in_len; - in_msg = os_malloc(in_len); - if (in_msg == NULL) - return NULL; - - /* Each received packet may include multiple records */ - while (pos < end) { - in_msg_len = in_len; - 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; - in_end = in_msg + in_msg_len; - - /* Each received record may include multiple messages of the - * same ContentType. */ - while (in_pos < in_end) { - in_msg_len = in_end - in_pos; - if (tlsv1_client_process_handshake(conn, ct, in_pos, - &in_msg_len, - appl_data, - appl_data_len) < 0) - goto failed; - in_pos += in_msg_len; - } - - pos += used; - } - - os_free(in_msg); - in_msg = NULL; - - no_appl_data = appl_data == NULL || *appl_data == NULL; - msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data); - -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, - conn->alert_description, - out_len); - } else if (msg == NULL) { - msg = os_zalloc(1); - *out_len = 0; - } - - if (need_more_data == NULL || !(*need_more_data)) { - wpabuf_free(conn->partial_input); - conn->partial_input = NULL; - } - - return msg; -} - - -/** - * tlsv1_client_encrypt - Encrypt data into TLS tunnel - * @conn: TLSv1 client connection data from tlsv1_client_init() - * @in_data: Pointer to plaintext data to be encrypted - * @in_len: Input buffer length - * @out_data: Pointer to output buffer (encrypted TLS data) - * @out_len: Maximum out_data length - * Returns: Number of bytes written to out_data, -1 on failure - * - * This function is used after TLS handshake has been completed successfully to - * send data in the encrypted tunnel. - */ -int tlsv1_client_encrypt(struct tlsv1_client *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) -{ - size_t rlen; - - wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData", - in_data, in_len); - - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA, - 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); - return -1; - } - - return rlen; -} - - -/** - * tlsv1_client_decrypt - Decrypt data from TLS tunnel - * @conn: TLSv1 client connection data from tlsv1_client_init() - * @in_data: Pointer to input buffer (encrypted TLS data) - * @in_len: Input buffer length - * @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. - */ -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 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; - - while (pos < in_end) { - ct = pos[0]; - if (wpabuf_resize(&buf, in_end - pos) < 0) { - alert = TLS_ALERT_INTERNAL_ERROR; - goto fail; - } - 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"); - goto fail; - } - 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; - } - - 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; - } - - 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; -} - - -/** - * tlsv1_client_global_init - Initialize TLSv1 client - * Returns: 0 on success, -1 on failure - * - * This function must be called before using any other TLSv1 client functions. - */ -int tlsv1_client_global_init(void) -{ - return crypto_global_init(); -} - - -/** - * tlsv1_client_global_deinit - Deinitialize TLSv1 client - * - * This function can be used to deinitialize the TLSv1 client that was - * initialized by calling tlsv1_client_global_init(). No TLSv1 client functions - * can be called after this before calling tlsv1_client_global_init() again. - */ -void tlsv1_client_global_deinit(void) -{ - crypto_global_deinit(); -} - - -/** - * tlsv1_client_init - Initialize TLSv1 client connection - * Returns: Pointer to TLSv1 client connection data or %NULL on failure - */ -struct tlsv1_client * tlsv1_client_init(void) -{ - struct tlsv1_client *conn; - size_t count; - u16 *suites; - - conn = os_zalloc(sizeof(*conn)); - if (conn == NULL) - return NULL; - - conn->state = CLIENT_HELLO; - - if (tls_verify_hash_init(&conn->verify) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify " - "hash"); - os_free(conn); - return NULL; - } - - count = 0; - suites = conn->cipher_suites; - suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256; - suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA; - 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; -} - - -/** - * tlsv1_client_deinit - Deinitialize TLSv1 client connection - * @conn: TLSv1 client connection data from tlsv1_client_init() - */ -void tlsv1_client_deinit(struct tlsv1_client *conn) -{ - crypto_public_key_free(conn->server_rsa_key); - tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL); - tlsv1_record_change_write_cipher(&conn->rl); - tlsv1_record_change_read_cipher(&conn->rl); - tls_verify_hash_free(&conn->verify); - os_free(conn->client_hello_ext); - tlsv1_client_free_dh(conn); - tlsv1_cred_free(conn->cred); - wpabuf_free(conn->partial_input); - os_free(conn); -} - - -/** - * tlsv1_client_established - Check whether connection has been established - * @conn: TLSv1 client connection data from tlsv1_client_init() - * Returns: 1 if connection is established, 0 if not - */ -int tlsv1_client_established(struct tlsv1_client *conn) -{ - return conn->state == ESTABLISHED; -} - - -/** - * tlsv1_client_prf - Use TLS-PRF to derive keying material - * @conn: TLSv1 client connection data from tlsv1_client_init() - * @label: Label (e.g., description of the key) for PRF - * @server_random_first: seed is 0 = client_random|server_random, - * 1 = server_random|client_random - * @out: Buffer for output data from TLS-PRF - * @out_len: Length of the output buffer - * Returns: 0 on success, -1 on failure - */ -int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, - int server_random_first, u8 *out, size_t out_len) -{ - u8 seed[2 * TLS_RANDOM_LEN]; - - if (conn->state != ESTABLISHED) - return -1; - - if (server_random_first) { - os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); - os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, - TLS_RANDOM_LEN); - } else { - os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); - os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, - TLS_RANDOM_LEN); - } - - return tls_prf(conn->rl.tls_version, - conn->master_secret, TLS_MASTER_SECRET_LEN, - label, seed, 2 * TLS_RANDOM_LEN, out, out_len); -} - - -/** - * tlsv1_client_get_cipher - Get current cipher name - * @conn: TLSv1 client connection data from tlsv1_client_init() - * @buf: Buffer for the cipher name - * @buflen: buf size - * Returns: 0 on success, -1 on failure - * - * Get the name of the currently used cipher. - */ -int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf, - size_t buflen) -{ - char *cipher; - - switch (conn->rl.cipher_suite) { - case TLS_RSA_WITH_RC4_128_MD5: - cipher = "RC4-MD5"; - break; - case TLS_RSA_WITH_RC4_128_SHA: - cipher = "RC4-SHA"; - break; - case TLS_RSA_WITH_DES_CBC_SHA: - cipher = "DES-CBC-SHA"; - break; - 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; - } - - if (os_strlcpy(buf, cipher, buflen) >= buflen) - return -1; - return 0; -} - - -/** - * tlsv1_client_shutdown - Shutdown TLS connection - * @conn: TLSv1 client connection data from tlsv1_client_init() - * Returns: 0 on success, -1 on failure - */ -int tlsv1_client_shutdown(struct tlsv1_client *conn) -{ - conn->state = CLIENT_HELLO; - - if (tls_verify_hash_init(&conn->verify) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify " - "hash"); - return -1; - } - - tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL); - tlsv1_record_change_write_cipher(&conn->rl); - tlsv1_record_change_read_cipher(&conn->rl); - - conn->certificate_requested = 0; - crypto_public_key_free(conn->server_rsa_key); - conn->server_rsa_key = NULL; - conn->session_resumed = 0; - - return 0; -} - - -/** - * tlsv1_client_resumed - Was session resumption used - * @conn: TLSv1 client connection data from tlsv1_client_init() - * Returns: 1 if current session used session resumption, 0 if not - */ -int tlsv1_client_resumed(struct tlsv1_client *conn) -{ - return !!conn->session_resumed; -} - - -/** - * tlsv1_client_hello_ext - Set TLS extension for ClientHello - * @conn: TLSv1 client connection data from tlsv1_client_init() - * @ext_type: Extension type - * @data: Extension payload (%NULL to remove extension) - * @data_len: Extension payload length - * Returns: 0 on success, -1 on failure - */ -int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type, - const u8 *data, size_t data_len) -{ - u8 *pos; - - conn->session_ticket_included = 0; - os_free(conn->client_hello_ext); - conn->client_hello_ext = NULL; - conn->client_hello_ext_len = 0; - - if (data == NULL || data_len == 0) - return 0; - - pos = conn->client_hello_ext = os_malloc(6 + data_len); - if (pos == NULL) - return -1; - - WPA_PUT_BE16(pos, 4 + data_len); - pos += 2; - WPA_PUT_BE16(pos, ext_type); - pos += 2; - WPA_PUT_BE16(pos, data_len); - pos += 2; - os_memcpy(pos, data, data_len); - conn->client_hello_ext_len = 6 + data_len; - - if (ext_type == TLS_EXT_PAC_OPAQUE) { - conn->session_ticket_included = 1; - wpa_printf(MSG_DEBUG, "TLSv1: Using session ticket"); - } - - return 0; -} - - -/** - * tlsv1_client_get_keys - Get master key and random data from TLS connection - * @conn: TLSv1 client connection data from tlsv1_client_init() - * @keys: Structure of key/random data (filled on success) - * Returns: 0 on success, -1 on failure - */ -int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys) -{ - os_memset(keys, 0, sizeof(*keys)); - if (conn->state == CLIENT_HELLO) - return -1; - - keys->client_random = conn->client_random; - keys->client_random_len = TLS_RANDOM_LEN; - - if (conn->state != SERVER_HELLO) { - keys->server_random = conn->server_random; - keys->server_random_len = TLS_RANDOM_LEN; - keys->master_key = conn->master_secret; - keys->master_key_len = TLS_MASTER_SECRET_LEN; - } - - return 0; -} - - -/** - * tlsv1_client_get_keyblock_size - Get TLS key_block size - * @conn: TLSv1 client connection data from tlsv1_client_init() - * Returns: Size of the key_block for the negotiated cipher suite or -1 on - * failure - */ -int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn) -{ - if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO) - return -1; - - return 2 * (conn->rl.hash_size + conn->rl.key_material_len + - conn->rl.iv_size); -} - - -/** - * tlsv1_client_set_cipher_list - Configure acceptable cipher suites - * @conn: TLSv1 client connection data from tlsv1_client_init() - * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers - * (TLS_CIPHER_*). - * Returns: 0 on success, -1 on failure - */ -int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers) -{ - size_t count; - u16 *suites; - - /* TODO: implement proper configuration of cipher suites */ - if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) { - count = 0; - suites = conn->cipher_suites; - suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA256; - suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA; - 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; - suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA; - - /* - * Cisco AP (at least 350 and 1200 series) local authentication - * server does not know how to search cipher suites from the - * list and seem to require that the last entry in the list is - * the one that it wants to use. However, TLS specification - * requires the list to be in the client preference order. As a - * workaround, add anon-DH AES-128-SHA1 again at the end of the - * list to allow the Cisco code to find it. - */ - suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA; - conn->num_cipher_suites = count; - } - - return 0; -} - - -/** - * tlsv1_client_set_cred - Set client credentials - * @conn: TLSv1 client connection data from tlsv1_client_init() - * @cred: Credentials from tlsv1_cred_alloc() - * Returns: 0 on success, -1 on failure - * - * On success, the client takes ownership of the credentials block and caller - * must not free it. On failure, caller is responsible for freeing the - * credential block. - */ -int tlsv1_client_set_cred(struct tlsv1_client *conn, - struct tlsv1_credentials *cred) -{ - tlsv1_cred_free(conn->cred); - conn->cred = cred; - return 0; -} - - -void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled) -{ - conn->disable_time_checks = !enabled; -} - - -void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn, - tlsv1_client_session_ticket_cb cb, - void *ctx) -{ - wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)", - cb, ctx); - conn->session_ticket_cb = cb; - conn->session_ticket_cb_ctx = ctx; -} diff --git a/contrib/hostapd/src/tls/tlsv1_client.h b/contrib/hostapd/src/tls/tlsv1_client.h deleted file mode 100644 index 8ec85f1a91..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_client.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246) - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef TLSV1_CLIENT_H -#define TLSV1_CLIENT_H - -#include "tlsv1_cred.h" - -struct tlsv1_client; - -int tlsv1_client_global_init(void); -void tlsv1_client_global_deinit(void); -struct tlsv1_client * tlsv1_client_init(void); -void tlsv1_client_deinit(struct tlsv1_client *conn); -int tlsv1_client_established(struct tlsv1_client *conn); -int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, - int server_random_first, u8 *out, size_t out_len); -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, 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); -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); -int tlsv1_client_resumed(struct tlsv1_client *conn); -int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type, - const u8 *data, size_t data_len); -int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys); -int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn); -int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers); -int tlsv1_client_set_cred(struct tlsv1_client *conn, - struct tlsv1_credentials *cred); -void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled); - -typedef int (*tlsv1_client_session_ticket_cb) -(void *ctx, const u8 *ticket, size_t len, const u8 *client_random, - const u8 *server_random, u8 *master_secret); - -void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn, - tlsv1_client_session_ticket_cb cb, - void *ctx); - -#endif /* TLSV1_CLIENT_H */ diff --git a/contrib/hostapd/src/tls/tlsv1_client_i.h b/contrib/hostapd/src/tls/tlsv1_client_i.h deleted file mode 100644 index 55fdcf8d04..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_client_i.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * TLSv1 client - internal structures - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef TLSV1_CLIENT_I_H -#define TLSV1_CLIENT_I_H - -struct tlsv1_client { - enum { - CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE, - SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST, - SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC, - SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED, - ESTABLISHED, FAILED - } state; - - struct tlsv1_record_layer rl; - - u8 session_id[TLS_SESSION_ID_MAX_LEN]; - size_t session_id_len; - u8 client_random[TLS_RANDOM_LEN]; - u8 server_random[TLS_RANDOM_LEN]; - u8 master_secret[TLS_MASTER_SECRET_LEN]; - - u8 alert_level; - u8 alert_description; - - unsigned int certificate_requested:1; - unsigned int session_resumed:1; - unsigned int session_ticket_included:1; - unsigned int use_session_ticket:1; - unsigned int disable_time_checks:1; - - struct crypto_public_key *server_rsa_key; - - struct tls_verify_hash verify; - -#define MAX_CIPHER_COUNT 30 - u16 cipher_suites[MAX_CIPHER_COUNT]; - size_t num_cipher_suites; - - u16 prev_cipher_suite; - - u8 *client_hello_ext; - size_t client_hello_ext_len; - - /* The prime modulus used for Diffie-Hellman */ - u8 *dh_p; - size_t dh_p_len; - /* The generator used for Diffie-Hellman */ - u8 *dh_g; - size_t dh_g_len; - /* The server's Diffie-Hellman public value */ - u8 *dh_ys; - size_t dh_ys_len; - - struct tlsv1_credentials *cred; - - tlsv1_client_session_ticket_cb session_ticket_cb; - void *session_ticket_cb_ctx; - - struct wpabuf *partial_input; -}; - - -void tls_alert(struct tlsv1_client *conn, u8 level, u8 description); -void tlsv1_client_free_dh(struct tlsv1_client *conn); -int tls_derive_pre_master_secret(u8 *pre_master_secret); -int tls_derive_keys(struct tlsv1_client *conn, - const u8 *pre_master_secret, size_t pre_master_secret_len); -u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len); -u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level, - u8 description, size_t *out_len); -u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len, - int no_appl_data); -int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct, - const u8 *buf, size_t *len, - u8 **out_data, size_t *out_len); - -#endif /* TLSV1_CLIENT_I_H */ diff --git a/contrib/hostapd/src/tls/tlsv1_client_read.c b/contrib/hostapd/src/tls/tlsv1_client_read.c deleted file mode 100644 index 3269ecf668..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_client_read.c +++ /dev/null @@ -1,999 +0,0 @@ -/* - * TLSv1 client - read handshake message - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/md5.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "crypto/tls.h" -#include "x509v3.h" -#include "tlsv1_common.h" -#include "tlsv1_record.h" -#include "tlsv1_client.h" -#include "tlsv1_client_i.h" - -static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct, - const u8 *in_data, size_t *in_len); -static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct, - const u8 *in_data, size_t *in_len); -static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct, - const u8 *in_data, size_t *in_len); - - -static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct, - const u8 *in_data, size_t *in_len) -{ - 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; " - "received content type 0x%x", ct); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - if (left < 4) - goto decode_error; - - /* HandshakeType msg_type */ - if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) { - wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " - "message %d (expected ServerHello)", *pos); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello"); - pos++; - /* uint24 length */ - len = WPA_GET_BE24(pos); - pos += 3; - left -= 4; - - if (len > left) - goto decode_error; - - /* body - ServerHello */ - - wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len); - end = pos + len; - - /* ProtocolVersion server_version */ - if (end - pos < 2) - goto decode_error; - tls_version = WPA_GET_BE16(pos); - if (!tls_version_ok(tls_version)) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in " - "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; - - os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN); - pos += TLS_RANDOM_LEN; - wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random", - conn->server_random, TLS_RANDOM_LEN); - - /* SessionID session_id */ - if (end - pos < 1) - goto decode_error; - if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN) - goto decode_error; - if (conn->session_id_len && conn->session_id_len == *pos && - os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) { - pos += 1 + conn->session_id_len; - wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session"); - conn->session_resumed = 1; - } else { - conn->session_id_len = *pos; - pos++; - os_memcpy(conn->session_id, pos, conn->session_id_len); - pos += conn->session_id_len; - } - wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id", - conn->session_id, conn->session_id_len); - - /* CipherSuite cipher_suite */ - if (end - pos < 2) - goto decode_error; - cipher_suite = WPA_GET_BE16(pos); - pos += 2; - for (i = 0; i < conn->num_cipher_suites; i++) { - if (cipher_suite == conn->cipher_suites[i]) - break; - } - if (i == conn->num_cipher_suites) { - wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected " - "cipher suite 0x%04x", cipher_suite); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_ILLEGAL_PARAMETER); - return -1; - } - - if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) { - wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different " - "cipher suite for a resumed connection (0x%04x != " - "0x%04x)", cipher_suite, conn->prev_cipher_suite); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_ILLEGAL_PARAMETER); - return -1; - } - - if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for " - "record layer"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - conn->prev_cipher_suite = cipher_suite; - - /* CompressionMethod compression_method */ - if (end - pos < 1) - goto decode_error; - if (*pos != TLS_COMPRESSION_NULL) { - wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected " - "compression 0x%02x", *pos); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_ILLEGAL_PARAMETER); - return -1; - } - pos++; - - if (end != pos) { - /* TODO: ServerHello extensions */ - wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the " - "end of ServerHello", pos, end - pos); - goto decode_error; - } - - if (conn->session_ticket_included && conn->session_ticket_cb) { - /* TODO: include SessionTicket extension if one was included in - * ServerHello */ - int res = conn->session_ticket_cb( - conn->session_ticket_cb_ctx, NULL, 0, - conn->client_random, conn->server_random, - conn->master_secret); - if (res < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback " - "indicated failure"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_HANDSHAKE_FAILURE); - return -1; - } - conn->use_session_ticket = !!res; - } - - if ((conn->session_resumed || conn->use_session_ticket) && - tls_derive_keys(conn, NULL, 0)) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - *in_len = end - in_data; - - conn->state = (conn->session_resumed || conn->use_session_ticket) ? - SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE; - - return 0; - -decode_error: - wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); - return -1; -} - - -static int tls_process_certificate(struct tlsv1_client *conn, u8 ct, - const u8 *in_data, size_t *in_len) -{ - const u8 *pos, *end; - size_t left, len, list_len, cert_len, idx; - u8 type; - struct x509_certificate *chain = NULL, *last = NULL, *cert; - int reason; - - if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " - "received content type 0x%x", ct); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - if (left < 4) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message " - "(len=%lu)", (unsigned long) left); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); - return -1; - } - - type = *pos++; - len = WPA_GET_BE24(pos); - pos += 3; - left -= 4; - - if (len > left) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message " - "length (len=%lu != left=%lu)", - (unsigned long) len, (unsigned long) left); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); - return -1; - } - - if (type == TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) - return tls_process_server_key_exchange(conn, ct, in_data, - in_len); - if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) - return tls_process_certificate_request(conn, ct, in_data, - in_len); - if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) - return tls_process_server_hello_done(conn, ct, in_data, - in_len); - if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) { - wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " - "message %d (expected Certificate/" - "ServerKeyExchange/CertificateRequest/" - "ServerHelloDone)", type); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - wpa_printf(MSG_DEBUG, - "TLSv1: Received Certificate (certificate_list len %lu)", - (unsigned long) len); - - /* - * opaque ASN.1Cert<2^24-1>; - * - * struct { - * ASN.1Cert certificate_list<1..2^24-1>; - * } Certificate; - */ - - end = pos + len; - - if (end - pos < 3) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate " - "(left=%lu)", (unsigned long) left); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); - return -1; - } - - list_len = WPA_GET_BE24(pos); - pos += 3; - - if ((size_t) (end - pos) != list_len) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list " - "length (len=%lu left=%lu)", - (unsigned long) list_len, - (unsigned long) (end - pos)); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); - return -1; - } - - idx = 0; - while (pos < end) { - if (end - pos < 3) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " - "certificate_list"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - x509_certificate_chain_free(chain); - return -1; - } - - cert_len = WPA_GET_BE24(pos); - pos += 3; - - if ((size_t) (end - pos) < cert_len) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate " - "length (len=%lu left=%lu)", - (unsigned long) cert_len, - (unsigned long) (end - pos)); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - x509_certificate_chain_free(chain); - return -1; - } - - wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)", - (unsigned long) idx, (unsigned long) cert_len); - - if (idx == 0) { - crypto_public_key_free(conn->server_rsa_key); - if (tls_parse_cert(pos, cert_len, - &conn->server_rsa_key)) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " - "the certificate"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_BAD_CERTIFICATE); - x509_certificate_chain_free(chain); - return -1; - } - } - - cert = x509_certificate_parse(pos, cert_len); - if (cert == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " - "the certificate"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_BAD_CERTIFICATE); - x509_certificate_chain_free(chain); - return -1; - } - - if (last == NULL) - chain = cert; - else - last->next = cert; - last = cert; - - idx++; - pos += cert_len; - } - - if (conn->cred && - x509_certificate_chain_validate(conn->cred->trusted_certs, chain, - &reason, conn->disable_time_checks) - < 0) { - int tls_reason; - wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain " - "validation failed (reason=%d)", reason); - switch (reason) { - case X509_VALIDATE_BAD_CERTIFICATE: - tls_reason = TLS_ALERT_BAD_CERTIFICATE; - break; - case X509_VALIDATE_UNSUPPORTED_CERTIFICATE: - tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE; - break; - case X509_VALIDATE_CERTIFICATE_REVOKED: - tls_reason = TLS_ALERT_CERTIFICATE_REVOKED; - break; - case X509_VALIDATE_CERTIFICATE_EXPIRED: - tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED; - break; - case X509_VALIDATE_CERTIFICATE_UNKNOWN: - tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN; - break; - case X509_VALIDATE_UNKNOWN_CA: - tls_reason = TLS_ALERT_UNKNOWN_CA; - break; - default: - tls_reason = TLS_ALERT_BAD_CERTIFICATE; - break; - } - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason); - x509_certificate_chain_free(chain); - return -1; - } - - x509_certificate_chain_free(chain); - - *in_len = end - in_data; - - conn->state = SERVER_KEY_EXCHANGE; - - return 0; -} - - -static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn, - const u8 *buf, size_t len) -{ - const u8 *pos, *end; - - tlsv1_client_free_dh(conn); - - pos = buf; - end = buf + len; - - if (end - pos < 3) - goto fail; - conn->dh_p_len = WPA_GET_BE16(pos); - pos += 2; - if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) { - wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu", - (unsigned long) conn->dh_p_len); - goto fail; - } - conn->dh_p = os_malloc(conn->dh_p_len); - if (conn->dh_p == NULL) - goto fail; - os_memcpy(conn->dh_p, pos, conn->dh_p_len); - pos += conn->dh_p_len; - wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)", - conn->dh_p, conn->dh_p_len); - - if (end - pos < 3) - goto fail; - conn->dh_g_len = WPA_GET_BE16(pos); - pos += 2; - if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len) - goto fail; - conn->dh_g = os_malloc(conn->dh_g_len); - if (conn->dh_g == NULL) - goto fail; - os_memcpy(conn->dh_g, pos, conn->dh_g_len); - pos += conn->dh_g_len; - wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)", - conn->dh_g, conn->dh_g_len); - if (conn->dh_g_len == 1 && conn->dh_g[0] < 2) - goto fail; - - if (end - pos < 3) - goto fail; - conn->dh_ys_len = WPA_GET_BE16(pos); - pos += 2; - if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len) - goto fail; - conn->dh_ys = os_malloc(conn->dh_ys_len); - if (conn->dh_ys == NULL) - goto fail; - os_memcpy(conn->dh_ys, pos, conn->dh_ys_len); - pos += conn->dh_ys_len; - wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)", - conn->dh_ys, conn->dh_ys_len); - - return 0; - -fail: - wpa_printf(MSG_DEBUG, "TLSv1: Processing DH params failed"); - tlsv1_client_free_dh(conn); - return -1; -} - - -static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct, - const u8 *in_data, size_t *in_len) -{ - const u8 *pos, *end; - size_t left, len; - u8 type; - const struct tls_cipher_suite *suite; - - if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " - "received content type 0x%x", ct); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - if (left < 4) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerKeyExchange " - "(Left=%lu)", (unsigned long) left); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); - return -1; - } - - type = *pos++; - len = WPA_GET_BE24(pos); - pos += 3; - left -= 4; - - if (len > left) { - wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerKeyExchange " - "length (len=%lu != left=%lu)", - (unsigned long) len, (unsigned long) left); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); - return -1; - } - - end = pos + len; - - if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) - return tls_process_certificate_request(conn, ct, in_data, - in_len); - if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) - return tls_process_server_hello_done(conn, ct, in_data, - in_len); - if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) { - wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " - "message %d (expected ServerKeyExchange/" - "CertificateRequest/ServerHelloDone)", type); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange"); - - if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) { - wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed " - "with the selected cipher suite"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len); - suite = tls_get_cipher_suite(conn->rl.cipher_suite); - if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) { - if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) { - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - } else { - wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - *in_len = end - in_data; - - conn->state = SERVER_CERTIFICATE_REQUEST; - - return 0; -} - - -static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct, - const u8 *in_data, size_t *in_len) -{ - const u8 *pos, *end; - size_t left, len; - u8 type; - - if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " - "received content type 0x%x", ct); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - if (left < 4) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateRequest " - "(left=%lu)", (unsigned long) left); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); - return -1; - } - - type = *pos++; - len = WPA_GET_BE24(pos); - pos += 3; - left -= 4; - - if (len > left) { - wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in CertificateRequest " - "length (len=%lu != left=%lu)", - (unsigned long) len, (unsigned long) left); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); - return -1; - } - - end = pos + len; - - if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) - return tls_process_server_hello_done(conn, ct, in_data, - in_len); - if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) { - wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " - "message %d (expected CertificateRequest/" - "ServerHelloDone)", type); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateRequest"); - - conn->certificate_requested = 1; - - *in_len = end - in_data; - - conn->state = SERVER_HELLO_DONE; - - return 0; -} - - -static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct, - const u8 *in_data, size_t *in_len) -{ - const u8 *pos, *end; - size_t left, len; - u8 type; - - if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " - "received content type 0x%x", ct); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - if (left < 4) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerHelloDone " - "(left=%lu)", (unsigned long) left); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); - return -1; - } - - type = *pos++; - len = WPA_GET_BE24(pos); - pos += 3; - left -= 4; - - if (len > left) { - wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerHelloDone " - "length (len=%lu != left=%lu)", - (unsigned long) len, (unsigned long) left); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); - return -1; - } - end = pos + len; - - if (type != TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) { - wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " - "message %d (expected ServerHelloDone)", type); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone"); - - *in_len = end - in_data; - - conn->state = CLIENT_KEY_EXCHANGE; - - return 0; -} - - -static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn, - u8 ct, const u8 *in_data, - size_t *in_len) -{ - const u8 *pos; - size_t left; - - if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " - "received content type 0x%x", ct); - if (conn->use_session_ticket) { - int res; - wpa_printf(MSG_DEBUG, "TLSv1: Server may have " - "rejected SessionTicket"); - conn->use_session_ticket = 0; - - /* Notify upper layers that SessionTicket failed */ - res = conn->session_ticket_cb( - conn->session_ticket_cb_ctx, NULL, 0, NULL, - NULL, NULL); - if (res < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket " - "callback indicated failure"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_HANDSHAKE_FAILURE); - return -1; - } - - conn->state = SERVER_CERTIFICATE; - return tls_process_certificate(conn, ct, in_data, - in_len); - } - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - if (left < 1) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); - return -1; - } - - if (*pos != TLS_CHANGE_CIPHER_SPEC) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " - "received data 0x%x", *pos); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec"); - if (tlsv1_record_change_read_cipher(&conn->rl) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher " - "for record layer"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - *in_len = pos + 1 - in_data; - - conn->state = SERVER_FINISHED; - - return 0; -} - - -static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct, - const u8 *in_data, size_t *in_len) -{ - const u8 *pos, *end; - size_t left, len, hlen; - u8 verify_data[TLS_VERIFY_DATA_LEN]; - u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; - - if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; " - "received content type 0x%x", ct); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - if (left < 4) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for " - "Finished", - (unsigned long) left); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received " - "type 0x%x", pos[0]); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - len = WPA_GET_BE24(pos + 1); - - pos += 4; - left -= 4; - - if (len > left) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished " - "(len=%lu > left=%lu)", - (unsigned long) len, (unsigned long) left); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - end = pos + len; - if (len != TLS_VERIFY_DATA_LEN) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length " - "in Finished: %lu (expected %d)", - (unsigned long) len, TLS_VERIFY_DATA_LEN); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - 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) { - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - conn->verify.md5_server = NULL; - crypto_hash_finish(conn->verify.sha1_server, NULL, NULL); - conn->verify.sha1_server = NULL; - return -1; - } - conn->verify.md5_server = NULL; - hlen = SHA1_MAC_LEN; - if (conn->verify.sha1_server == NULL || - crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN, - &hlen) < 0) { - conn->verify.sha1_server = NULL; - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - conn->verify.sha1_server = NULL; - hlen = MD5_MAC_LEN + SHA1_MAC_LEN; - -#ifdef CONFIG_TLSV12 - } -#endif /* CONFIG_TLSV12 */ - - 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, - TLS_ALERT_DECRYPT_ERROR); - return -1; - } - wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", - verify_data, TLS_VERIFY_DATA_LEN); - - if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { - wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data"); - return -1; - } - - wpa_printf(MSG_DEBUG, "TLSv1: Received Finished"); - - *in_len = end - in_data; - - conn->state = (conn->session_resumed || conn->use_session_ticket) ? - CHANGE_CIPHER_SPEC : ACK_FINISHED; - - return 0; -} - - -static int tls_process_application_data(struct tlsv1_client *conn, u8 ct, - const u8 *in_data, size_t *in_len, - u8 **out_data, size_t *out_len) -{ - const u8 *pos; - size_t left; - - if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected Application Data; " - "received content type 0x%x", ct); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - wpa_hexdump(MSG_DEBUG, "TLSv1: Application Data included in Handshake", - pos, left); - - *out_data = os_malloc(left); - if (*out_data) { - os_memcpy(*out_data, pos, left); - *out_len = left; - } - - return 0; -} - - -int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct, - const u8 *buf, size_t *len, - u8 **out_data, size_t *out_len) -{ - if (ct == TLS_CONTENT_TYPE_ALERT) { - if (*len < 2) { - wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d", - buf[0], buf[1]); - *len = 2; - conn->state = FAILED; - return -1; - } - - if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 && - buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) { - size_t hr_len = WPA_GET_BE24(buf + 1); - if (hr_len > *len - 4) { - wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest"); - *len = 4 + hr_len; - return 0; - } - - switch (conn->state) { - case SERVER_HELLO: - if (tls_process_server_hello(conn, ct, buf, len)) - return -1; - break; - case SERVER_CERTIFICATE: - if (tls_process_certificate(conn, ct, buf, len)) - return -1; - break; - case SERVER_KEY_EXCHANGE: - if (tls_process_server_key_exchange(conn, ct, buf, len)) - return -1; - break; - case SERVER_CERTIFICATE_REQUEST: - if (tls_process_certificate_request(conn, ct, buf, len)) - return -1; - break; - case SERVER_HELLO_DONE: - if (tls_process_server_hello_done(conn, ct, buf, len)) - return -1; - break; - case SERVER_CHANGE_CIPHER_SPEC: - if (tls_process_server_change_cipher_spec(conn, ct, buf, len)) - return -1; - break; - case SERVER_FINISHED: - if (tls_process_server_finished(conn, ct, buf, len)) - return -1; - break; - case ACK_FINISHED: - if (out_data && - tls_process_application_data(conn, ct, buf, len, out_data, - out_len)) - return -1; - break; - default: - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d " - "while processing received message", - conn->state); - return -1; - } - - if (ct == TLS_CONTENT_TYPE_HANDSHAKE) - tls_verify_hash_add(&conn->verify, buf, *len); - - return 0; -} diff --git a/contrib/hostapd/src/tls/tlsv1_client_write.c b/contrib/hostapd/src/tls/tlsv1_client_write.c deleted file mode 100644 index d789efb425..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_client_write.c +++ /dev/null @@ -1,866 +0,0 @@ -/* - * TLSv1 client - write handshake message - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/md5.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "crypto/tls.h" -#include "crypto/random.h" -#include "x509v3.h" -#include "tlsv1_common.h" -#include "tlsv1_record.h" -#include "tlsv1_client.h" -#include "tlsv1_client_i.h" - - -static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn) -{ - size_t len = 0; - struct x509_certificate *cert; - - if (conn->cred == NULL) - return 0; - - cert = conn->cred->cert; - while (cert) { - len += 3 + cert->cert_len; - if (x509_certificate_self_signed(cert)) - break; - cert = x509_certificate_get_subject(conn->cred->trusted_certs, - &cert->issuer); - } - - return len; -} - - -u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len) -{ - u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr; - struct os_time now; - size_t len, i; - - wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello"); - *out_len = 0; - - os_get_time(&now); - WPA_PUT_BE32(conn->client_random, now.sec); - if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) { - wpa_printf(MSG_ERROR, "TLSv1: Could not generate " - "client_random"); - return NULL; - } - wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random", - conn->client_random, TLS_RANDOM_LEN); - - len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len; - hello = os_malloc(len); - if (hello == NULL) - return NULL; - end = hello + len; - - rhdr = hello; - pos = rhdr + TLS_RECORD_HEADER_LEN; - - /* opaque fragment[TLSPlaintext.length] */ - - /* Handshake */ - hs_start = pos; - /* HandshakeType msg_type */ - *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO; - /* uint24 length (to be filled) */ - hs_length = pos; - pos += 3; - /* body - ClientHello */ - /* ProtocolVersion client_version */ - WPA_PUT_BE16(pos, TLS_VERSION); - pos += 2; - /* Random random: uint32 gmt_unix_time, opaque random_bytes */ - os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN); - pos += TLS_RANDOM_LEN; - /* SessionID session_id */ - *pos++ = conn->session_id_len; - os_memcpy(pos, conn->session_id, conn->session_id_len); - pos += conn->session_id_len; - /* CipherSuite cipher_suites<2..2^16-1> */ - WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites); - pos += 2; - for (i = 0; i < conn->num_cipher_suites; i++) { - WPA_PUT_BE16(pos, conn->cipher_suites[i]); - pos += 2; - } - /* CompressionMethod compression_methods<1..2^8-1> */ - *pos++ = 1; - *pos++ = TLS_COMPRESSION_NULL; - - if (conn->client_hello_ext) { - os_memcpy(pos, conn->client_hello_ext, - conn->client_hello_ext_len); - pos += conn->client_hello_ext_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, 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); - os_free(hello); - return NULL; - } - - conn->state = SERVER_HELLO; - - return hello; -} - - -static int tls_write_client_certificate(struct tlsv1_client *conn, - u8 **msgpos, u8 *end) -{ - u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start; - size_t rlen; - struct x509_certificate *cert; - - pos = *msgpos; - - wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate"); - rhdr = pos; - pos += TLS_RECORD_HEADER_LEN; - - /* opaque fragment[TLSPlaintext.length] */ - - /* Handshake */ - hs_start = pos; - /* HandshakeType msg_type */ - *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE; - /* uint24 length (to be filled) */ - hs_length = pos; - pos += 3; - /* body - Certificate */ - /* uint24 length (to be filled) */ - cert_start = pos; - pos += 3; - cert = conn->cred ? conn->cred->cert : NULL; - while (cert) { - if (pos + 3 + cert->cert_len > end) { - wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space " - "for Certificate (cert_len=%lu left=%lu)", - (unsigned long) cert->cert_len, - (unsigned long) (end - pos)); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - WPA_PUT_BE24(pos, cert->cert_len); - pos += 3; - os_memcpy(pos, cert->cert_start, cert->cert_len); - pos += cert->cert_len; - - if (x509_certificate_self_signed(cert)) - break; - cert = x509_certificate_get_subject(conn->cred->trusted_certs, - &cert->issuer); - } - if (conn->cred == NULL || cert == conn->cred->cert || cert == NULL) { - /* - * Client was not configured with all the needed certificates - * to form a full certificate chain. The server may fail to - * validate the chain unless it is configured with all the - * missing CA certificates. - */ - wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain " - "not configured - validation may fail"); - } - WPA_PUT_BE24(cert_start, pos - cert_start - 3); - - WPA_PUT_BE24(hs_length, pos - hs_length - 3); - - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - 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); - return -1; - } - pos = rhdr + rlen; - - tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); - - *msgpos = pos; - - return 0; -} - - -static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end) -{ - /* ClientDiffieHellmanPublic */ - u8 *csecret, *csecret_start, *dh_yc, *shared; - size_t csecret_len, dh_yc_len, shared_len; - - csecret_len = conn->dh_p_len; - csecret = os_malloc(csecret_len); - if (csecret == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " - "memory for Yc (Diffie-Hellman)"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - if (random_get_bytes(csecret, csecret_len)) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " - "data for Diffie-Hellman"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(csecret); - return -1; - } - - if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0) - csecret[0] = 0; /* make sure Yc < p */ - - csecret_start = csecret; - while (csecret_len > 1 && *csecret_start == 0) { - csecret_start++; - csecret_len--; - } - wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value", - csecret_start, csecret_len); - - /* Yc = g^csecret mod p */ - dh_yc_len = conn->dh_p_len; - dh_yc = os_malloc(dh_yc_len); - if (dh_yc == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " - "memory for Diffie-Hellman"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(csecret); - return -1; - } - if (crypto_mod_exp(conn->dh_g, conn->dh_g_len, - csecret_start, csecret_len, - conn->dh_p, conn->dh_p_len, - dh_yc, &dh_yc_len)) { - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(csecret); - os_free(dh_yc); - return -1; - } - - wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)", - dh_yc, dh_yc_len); - - WPA_PUT_BE16(*pos, dh_yc_len); - *pos += 2; - if (*pos + dh_yc_len > end) { - wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the " - "message buffer for Yc"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(csecret); - os_free(dh_yc); - return -1; - } - os_memcpy(*pos, dh_yc, dh_yc_len); - *pos += dh_yc_len; - os_free(dh_yc); - - shared_len = conn->dh_p_len; - shared = os_malloc(shared_len); - if (shared == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for " - "DH"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(csecret); - return -1; - } - - /* shared = Ys^csecret mod p */ - if (crypto_mod_exp(conn->dh_ys, conn->dh_ys_len, - csecret_start, csecret_len, - conn->dh_p, conn->dh_p_len, - shared, &shared_len)) { - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(csecret); - os_free(shared); - return -1; - } - wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange", - shared, shared_len); - - os_memset(csecret_start, 0, csecret_len); - os_free(csecret); - if (tls_derive_keys(conn, shared, shared_len)) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(shared); - return -1; - } - os_memset(shared, 0, shared_len); - os_free(shared); - tlsv1_client_free_dh(conn); - return 0; -} - - -static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end) -{ - u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN]; - size_t clen; - int res; - - if (tls_derive_pre_master_secret(pre_master_secret) < 0 || - tls_derive_keys(conn, pre_master_secret, - TLS_PRE_MASTER_SECRET_LEN)) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - /* EncryptedPreMasterSecret */ - if (conn->server_rsa_key == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to " - "use for encrypting pre-master secret"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - /* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */ - *pos += 2; - clen = end - *pos; - res = crypto_public_key_encrypt_pkcs1_v15( - conn->server_rsa_key, - pre_master_secret, TLS_PRE_MASTER_SECRET_LEN, - *pos, &clen); - os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN); - if (res < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - WPA_PUT_BE16(*pos - 2, clen); - wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret", - *pos, clen); - *pos += clen; - - return 0; -} - - -static int tls_write_client_key_exchange(struct tlsv1_client *conn, - u8 **msgpos, u8 *end) -{ - u8 *pos, *rhdr, *hs_start, *hs_length; - size_t rlen; - tls_key_exchange keyx; - const struct tls_cipher_suite *suite; - - suite = tls_get_cipher_suite(conn->rl.cipher_suite); - if (suite == NULL) - keyx = TLS_KEY_X_NULL; - else - keyx = suite->key_exchange; - - pos = *msgpos; - - wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange"); - - rhdr = pos; - pos += TLS_RECORD_HEADER_LEN; - - /* opaque fragment[TLSPlaintext.length] */ - - /* Handshake */ - hs_start = pos; - /* HandshakeType msg_type */ - *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE; - /* uint24 length (to be filled) */ - hs_length = pos; - pos += 3; - /* body - ClientKeyExchange */ - if (keyx == TLS_KEY_X_DH_anon) { - if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0) - return -1; - } else { - if (tlsv1_key_x_rsa(conn, &pos, end) < 0) - return -1; - } - - WPA_PUT_BE24(hs_length, pos - hs_length - 3); - - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - 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); - return -1; - } - pos = rhdr + rlen; - tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); - - *msgpos = pos; - - return 0; -} - - -static int tls_write_client_certificate_verify(struct tlsv1_client *conn, - u8 **msgpos, u8 *end) -{ - u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start; - size_t rlen, hlen, clen; - u8 hash[100], *hpos; - enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; - - pos = *msgpos; - - wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify"); - rhdr = pos; - pos += TLS_RECORD_HEADER_LEN; - - /* Handshake */ - hs_start = pos; - /* HandshakeType msg_type */ - *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY; - /* uint24 length (to be filled) */ - hs_length = pos; - pos += 3; - - /* - * RFC 2246: 7.4.3 and 7.4.8: - * Signature signature - * - * RSA: - * digitally-signed struct { - * opaque md5_hash[16]; - * opaque sha_hash[20]; - * }; - * - * DSA: - * digitally-signed struct { - * opaque sha_hash[20]; - * }; - * - * The hash values are calculated over all handshake messages sent or - * received starting at ClientHello up to, but not including, this - * CertificateVerify message, including the type and length fields of - * the handshake messages. - */ - - 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 || - crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) - { - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - conn->verify.md5_cert = NULL; - crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); - conn->verify.sha1_cert = NULL; - return -1; - } - hpos += MD5_MAC_LEN; - } else - crypto_hash_finish(conn->verify.md5_cert, NULL, NULL); - - conn->verify.md5_cert = NULL; - hlen = SHA1_MAC_LEN; - if (conn->verify.sha1_cert == NULL || - crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) { - conn->verify.sha1_cert = NULL; - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - conn->verify.sha1_cert = NULL; - - 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 - * signing algorithm. A digitally-signed element is encoded as an - * opaque vector <0..2^16-1>, where the length is specified by the - * signing algorithm and key. - * - * In RSA signing, a 36-byte structure of two hashes (one SHA and one - * MD5) is signed (encrypted with the private key). It is encoded with - * PKCS #1 block type 0 or type 1 as described in [PKCS1]. - */ - signed_start = pos; /* length to be filled */ - pos += 2; - clen = end - pos; - if (conn->cred == NULL || - crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen, - pos, &clen) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - WPA_PUT_BE16(signed_start, clen); - - pos += clen; - - WPA_PUT_BE24(hs_length, pos - hs_length - 3); - - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - 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); - return -1; - } - pos = rhdr + rlen; - - tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); - - *msgpos = pos; - - return 0; -} - - -static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn, - u8 **msgpos, u8 *end) -{ - size_t rlen; - u8 payload[1]; - - wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec"); - - payload[0] = TLS_CHANGE_CIPHER_SPEC; - - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC, - *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); - return -1; - } - - if (tlsv1_record_change_write_cipher(&conn->rl) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for " - "record layer"); - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - *msgpos += rlen; - - return 0; -} - - -static int tls_write_client_finished(struct tlsv1_client *conn, - u8 **msgpos, u8 *end) -{ - u8 *pos, *hs_start; - size_t rlen, hlen; - u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN]; - u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; - - 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) { - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - conn->verify.md5_client = NULL; - crypto_hash_finish(conn->verify.sha1_client, NULL, NULL); - conn->verify.sha1_client = NULL; - return -1; - } - conn->verify.md5_client = NULL; - hlen = SHA1_MAC_LEN; - if (conn->verify.sha1_client == NULL || - crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN, - &hlen) < 0) { - conn->verify.sha1_client = NULL; - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - conn->verify.sha1_client = NULL; - hlen = MD5_MAC_LEN + SHA1_MAC_LEN; - -#ifdef CONFIG_TLSV12 - } -#endif /* CONFIG_TLSV12 */ - - 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 + 1 + 3, TLS_VERIFY_DATA_LEN); - - /* Handshake */ - pos = hs_start = verify_data; - /* HandshakeType msg_type */ - *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; - /* uint24 length */ - WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN); - pos += 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, - *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; - } - - *msgpos += rlen; - - return 0; -} - - -static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn, - size_t *out_len) -{ - u8 *msg, *end, *pos; - size_t msglen; - - *out_len = 0; - - msglen = 2000; - if (conn->certificate_requested) - msglen += tls_client_cert_chain_der_len(conn); - - msg = os_malloc(msglen); - if (msg == NULL) - return NULL; - - pos = msg; - end = msg + msglen; - - if (conn->certificate_requested) { - if (tls_write_client_certificate(conn, &pos, end) < 0) { - os_free(msg); - return NULL; - } - } - - if (tls_write_client_key_exchange(conn, &pos, end) < 0 || - (conn->certificate_requested && conn->cred && conn->cred->key && - tls_write_client_certificate_verify(conn, &pos, end) < 0) || - tls_write_client_change_cipher_spec(conn, &pos, end) < 0 || - tls_write_client_finished(conn, &pos, end) < 0) { - os_free(msg); - return NULL; - } - - *out_len = pos - msg; - - conn->state = SERVER_CHANGE_CIPHER_SPEC; - - return msg; -} - - -static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn, - size_t *out_len) -{ - u8 *msg, *end, *pos; - - *out_len = 0; - - msg = os_malloc(1000); - if (msg == NULL) - return NULL; - - pos = msg; - end = msg + 1000; - - if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 || - tls_write_client_finished(conn, &pos, end) < 0) { - os_free(msg); - return NULL; - } - - *out_len = pos - msg; - - wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed " - "successfully"); - conn->state = ESTABLISHED; - - return msg; -} - - -u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len, - int no_appl_data) -{ - switch (conn->state) { - case CLIENT_KEY_EXCHANGE: - return tls_send_client_key_exchange(conn, out_len); - case CHANGE_CIPHER_SPEC: - return tls_send_change_cipher_spec(conn, out_len); - case ACK_FINISHED: - wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed " - "successfully"); - conn->state = ESTABLISHED; - *out_len = 0; - if (no_appl_data) { - /* Need to return something to get final TLS ACK. */ - return os_malloc(1); - } - return NULL; - default: - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while " - "generating reply", conn->state); - return NULL; - } -} - - -u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level, - u8 description, size_t *out_len) -{ - u8 *alert, *pos, *length; - - wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description); - *out_len = 0; - - alert = os_malloc(10); - if (alert == NULL) - return NULL; - - pos = alert; - - /* TLSPlaintext */ - /* ContentType type */ - *pos++ = TLS_CONTENT_TYPE_ALERT; - /* ProtocolVersion version */ - WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version : - TLS_VERSION); - pos += 2; - /* uint16 length (to be filled) */ - length = pos; - pos += 2; - /* opaque fragment[TLSPlaintext.length] */ - - /* Alert */ - /* AlertLevel level */ - *pos++ = level; - /* AlertDescription description */ - *pos++ = description; - - WPA_PUT_BE16(length, pos - length - 2); - *out_len = pos - alert; - - return alert; -} diff --git a/contrib/hostapd/src/tls/tlsv1_common.c b/contrib/hostapd/src/tls/tlsv1_common.c deleted file mode 100644 index 4578b22727..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_common.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * TLSv1 common routines - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "x509v3.h" -#include "tlsv1_common.h" - - -/* - * TODO: - * RFC 2246 Section 9: Mandatory to implement TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA - * Add support for commonly used cipher suites; don't bother with exportable - * suites. - */ - -static const struct tls_cipher_suite tls_cipher_suites[] = { - { TLS_NULL_WITH_NULL_NULL, TLS_KEY_X_NULL, TLS_CIPHER_NULL, - TLS_HASH_NULL }, - { TLS_RSA_WITH_RC4_128_MD5, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128, - TLS_HASH_MD5 }, - { TLS_RSA_WITH_RC4_128_SHA, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128, - TLS_HASH_SHA }, - { TLS_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_DES_CBC, - TLS_HASH_SHA }, - { TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA, - TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA }, - { TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon, - TLS_CIPHER_RC4_128, TLS_HASH_MD5 }, - { TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon, - TLS_CIPHER_DES_CBC, TLS_HASH_SHA }, - { TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DH_anon, - TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA }, - { TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC, - TLS_HASH_SHA }, - { TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon, - TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA }, - { 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_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_TLS_CIPHER_SUITES ARRAY_SIZE(tls_cipher_suites) - - -static const struct tls_cipher_data tls_ciphers[] = { - { TLS_CIPHER_NULL, TLS_CIPHER_STREAM, 0, 0, 0, - CRYPTO_CIPHER_NULL }, - { TLS_CIPHER_IDEA_CBC, TLS_CIPHER_BLOCK, 16, 16, 8, - CRYPTO_CIPHER_NULL }, - { TLS_CIPHER_RC2_CBC_40, TLS_CIPHER_BLOCK, 5, 16, 0, - CRYPTO_CIPHER_ALG_RC2 }, - { TLS_CIPHER_RC4_40, TLS_CIPHER_STREAM, 5, 16, 0, - CRYPTO_CIPHER_ALG_RC4 }, - { TLS_CIPHER_RC4_128, TLS_CIPHER_STREAM, 16, 16, 0, - CRYPTO_CIPHER_ALG_RC4 }, - { TLS_CIPHER_DES40_CBC, TLS_CIPHER_BLOCK, 5, 8, 8, - CRYPTO_CIPHER_ALG_DES }, - { TLS_CIPHER_DES_CBC, TLS_CIPHER_BLOCK, 8, 8, 8, - CRYPTO_CIPHER_ALG_DES }, - { TLS_CIPHER_3DES_EDE_CBC, TLS_CIPHER_BLOCK, 24, 24, 8, - CRYPTO_CIPHER_ALG_3DES }, - { TLS_CIPHER_AES_128_CBC, TLS_CIPHER_BLOCK, 16, 16, 16, - CRYPTO_CIPHER_ALG_AES }, - { TLS_CIPHER_AES_256_CBC, TLS_CIPHER_BLOCK, 32, 32, 16, - CRYPTO_CIPHER_ALG_AES } -}; - -#define NUM_TLS_CIPHER_DATA ARRAY_SIZE(tls_ciphers) - - -/** - * tls_get_cipher_suite - Get TLS cipher suite - * @suite: Cipher suite identifier - * Returns: Pointer to the cipher data or %NULL if not found - */ -const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite) -{ - size_t i; - for (i = 0; i < NUM_TLS_CIPHER_SUITES; i++) - if (tls_cipher_suites[i].suite == suite) - return &tls_cipher_suites[i]; - return NULL; -} - - -const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher) -{ - size_t i; - for (i = 0; i < NUM_TLS_CIPHER_DATA; i++) - if (tls_ciphers[i].cipher == cipher) - return &tls_ciphers[i]; - return NULL; -} - - -int tls_server_key_exchange_allowed(tls_cipher cipher) -{ - const struct tls_cipher_suite *suite; - - /* RFC 2246, Section 7.4.3 */ - suite = tls_get_cipher_suite(cipher); - if (suite == NULL) - return 0; - - switch (suite->key_exchange) { - case TLS_KEY_X_DHE_DSS: - case TLS_KEY_X_DHE_DSS_EXPORT: - case TLS_KEY_X_DHE_RSA: - case TLS_KEY_X_DHE_RSA_EXPORT: - case TLS_KEY_X_DH_anon_EXPORT: - case TLS_KEY_X_DH_anon: - return 1; - case TLS_KEY_X_RSA_EXPORT: - return 1 /* FIX: public key len > 512 bits */; - default: - return 0; - } -} - - -/** - * tls_parse_cert - Parse DER encoded X.509 certificate and get public key - * @buf: ASN.1 DER encoded certificate - * @len: Length of the buffer - * @pk: Buffer for returning the allocated public key - * Returns: 0 on success, -1 on failure - * - * This functions parses an ASN.1 DER encoded X.509 certificate and retrieves - * the public key from it. The caller is responsible for freeing the public key - * by calling crypto_public_key_free(). - */ -int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk) -{ - struct x509_certificate *cert; - - wpa_hexdump(MSG_MSGDUMP, "TLSv1: Parse ASN.1 DER certificate", - buf, len); - - *pk = crypto_public_key_from_cert(buf, len); - if (*pk) - return 0; - - cert = x509_certificate_parse(buf, len); - if (cert == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse X.509 " - "certificate"); - return -1; - } - - /* TODO - * verify key usage (must allow encryption) - * - * All certificate profiles, key and cryptographic formats are - * defined by the IETF PKIX working group [PKIX]. When a key - * usage extension is present, the digitalSignature bit must be - * set for the key to be eligible for signing, as described - * above, and the keyEncipherment bit must be present to allow - * encryption, as described above. The keyAgreement bit must be - * set on Diffie-Hellman certificates. (PKIX: RFC 3280) - */ - - *pk = crypto_public_key_import(cert->public_key, cert->public_key_len); - x509_certificate_free(cert); - - if (*pk == NULL) { - wpa_printf(MSG_ERROR, "TLSv1: Failed to import " - "server public key"); - return -1; - } - - return 0; -} - - -int tls_verify_hash_init(struct tls_verify_hash *verify) -{ - tls_verify_hash_free(verify); - verify->md5_client = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0); - verify->md5_server = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0); - verify->md5_cert = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0); - verify->sha1_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0); - verify->sha1_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0); - verify->sha1_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0); - if (verify->md5_client == NULL || verify->md5_server == NULL || - verify->md5_cert == NULL || verify->sha1_client == NULL || - verify->sha1_server == NULL || verify->sha1_cert == NULL) { - 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; -} - - -void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf, - size_t len) -{ - if (verify->md5_client && verify->sha1_client) { - crypto_hash_update(verify->md5_client, buf, len); - crypto_hash_update(verify->sha1_client, buf, len); - } - if (verify->md5_server && verify->sha1_server) { - crypto_hash_update(verify->md5_server, buf, len); - crypto_hash_update(verify->sha1_server, buf, len); - } - if (verify->md5_cert && verify->sha1_cert) { - 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 */ -} - - -void tls_verify_hash_free(struct tls_verify_hash *verify) -{ - crypto_hash_finish(verify->md5_client, NULL, NULL); - crypto_hash_finish(verify->md5_server, NULL, NULL); - crypto_hash_finish(verify->md5_cert, NULL, NULL); - crypto_hash_finish(verify->sha1_client, NULL, NULL); - crypto_hash_finish(verify->sha1_server, NULL, NULL); - crypto_hash_finish(verify->sha1_cert, NULL, NULL); - verify->md5_client = NULL; - verify->md5_server = NULL; - verify->md5_cert = NULL; - 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/contrib/hostapd/src/tls/tlsv1_common.h b/contrib/hostapd/src/tls/tlsv1_common.h deleted file mode 100644 index f28c0cdc47..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_common.h +++ /dev/null @@ -1,261 +0,0 @@ -/* - * TLSv1 common definitions - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef TLSV1_COMMON_H -#define TLSV1_COMMON_H - -#include "crypto/crypto.h" - -#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 -#define TLS_SESSION_ID_MAX_LEN 32 -#define TLS_VERIFY_DATA_LEN 12 - -/* HandshakeType */ -enum { - TLS_HANDSHAKE_TYPE_HELLO_REQUEST = 0, - TLS_HANDSHAKE_TYPE_CLIENT_HELLO = 1, - TLS_HANDSHAKE_TYPE_SERVER_HELLO = 2, - TLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET = 4 /* RFC 4507 */, - TLS_HANDSHAKE_TYPE_CERTIFICATE = 11, - TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE = 12, - TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST = 13, - TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE = 14, - TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY = 15, - TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE = 16, - TLS_HANDSHAKE_TYPE_FINISHED = 20, - TLS_HANDSHAKE_TYPE_CERTIFICATE_URL = 21 /* RFC 4366 */, - TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS = 22 /* RFC 4366 */ -}; - -/* CipherSuite */ -#define TLS_NULL_WITH_NULL_NULL 0x0000 /* RFC 2246 */ -#define TLS_RSA_WITH_NULL_MD5 0x0001 /* RFC 2246 */ -#define TLS_RSA_WITH_NULL_SHA 0x0002 /* RFC 2246 */ -#define TLS_RSA_EXPORT_WITH_RC4_40_MD5 0x0003 /* RFC 2246 */ -#define TLS_RSA_WITH_RC4_128_MD5 0x0004 /* RFC 2246 */ -#define TLS_RSA_WITH_RC4_128_SHA 0x0005 /* RFC 2246 */ -#define TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 0x0006 /* RFC 2246 */ -#define TLS_RSA_WITH_IDEA_CBC_SHA 0x0007 /* RFC 2246 */ -#define TLS_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0008 /* RFC 2246 */ -#define TLS_RSA_WITH_DES_CBC_SHA 0x0009 /* RFC 2246 */ -#define TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x000A /* RFC 2246 */ -#define TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA 0x000B /* RFC 2246 */ -#define TLS_DH_DSS_WITH_DES_CBC_SHA 0x000C /* RFC 2246 */ -#define TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA 0x000D /* RFC 2246 */ -#define TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA 0x000E /* RFC 2246 */ -#define TLS_DH_RSA_WITH_DES_CBC_SHA 0x000F /* RFC 2246 */ -#define TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA 0x0010 /* RFC 2246 */ -#define TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA 0x0011 /* RFC 2246 */ -#define TLS_DHE_DSS_WITH_DES_CBC_SHA 0x0012 /* RFC 2246 */ -#define TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x0013 /* RFC 2246 */ -#define TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0014 /* RFC 2246 */ -#define TLS_DHE_RSA_WITH_DES_CBC_SHA 0x0015 /* RFC 2246 */ -#define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016 /* RFC 2246 */ -#define TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 0x0017 /* RFC 2246 */ -#define TLS_DH_anon_WITH_RC4_128_MD5 0x0018 /* RFC 2246 */ -#define TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA 0x0019 /* RFC 2246 */ -#define TLS_DH_anon_WITH_DES_CBC_SHA 0x001A /* RFC 2246 */ -#define TLS_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001B /* RFC 2246 */ -#define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F /* RFC 3268 */ -#define TLS_DH_DSS_WITH_AES_128_CBC_SHA 0x0030 /* RFC 3268 */ -#define TLS_DH_RSA_WITH_AES_128_CBC_SHA 0x0031 /* RFC 3268 */ -#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA 0x0032 /* RFC 3268 */ -#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033 /* RFC 3268 */ -#define TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034 /* RFC 3268 */ -#define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 /* RFC 3268 */ -#define TLS_DH_DSS_WITH_AES_256_CBC_SHA 0x0036 /* RFC 3268 */ -#define TLS_DH_RSA_WITH_AES_256_CBC_SHA 0x0037 /* RFC 3268 */ -#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 - -/* AlertDescription */ -#define TLS_ALERT_CLOSE_NOTIFY 0 -#define TLS_ALERT_UNEXPECTED_MESSAGE 10 -#define TLS_ALERT_BAD_RECORD_MAC 20 -#define TLS_ALERT_DECRYPTION_FAILED 21 -#define TLS_ALERT_RECORD_OVERFLOW 22 -#define TLS_ALERT_DECOMPRESSION_FAILURE 30 -#define TLS_ALERT_HANDSHAKE_FAILURE 40 -#define TLS_ALERT_BAD_CERTIFICATE 42 -#define TLS_ALERT_UNSUPPORTED_CERTIFICATE 43 -#define TLS_ALERT_CERTIFICATE_REVOKED 44 -#define TLS_ALERT_CERTIFICATE_EXPIRED 45 -#define TLS_ALERT_CERTIFICATE_UNKNOWN 46 -#define TLS_ALERT_ILLEGAL_PARAMETER 47 -#define TLS_ALERT_UNKNOWN_CA 48 -#define TLS_ALERT_ACCESS_DENIED 49 -#define TLS_ALERT_DECODE_ERROR 50 -#define TLS_ALERT_DECRYPT_ERROR 51 -#define TLS_ALERT_EXPORT_RESTRICTION 60 -#define TLS_ALERT_PROTOCOL_VERSION 70 -#define TLS_ALERT_INSUFFICIENT_SECURITY 71 -#define TLS_ALERT_INTERNAL_ERROR 80 -#define TLS_ALERT_USER_CANCELED 90 -#define TLS_ALERT_NO_RENEGOTIATION 100 -#define TLS_ALERT_UNSUPPORTED_EXTENSION 110 /* RFC 4366 */ -#define TLS_ALERT_CERTIFICATE_UNOBTAINABLE 111 /* RFC 4366 */ -#define TLS_ALERT_UNRECOGNIZED_NAME 112 /* RFC 4366 */ -#define TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE 113 /* RFC 4366 */ -#define TLS_ALERT_BAD_CERTIFICATE_HASH_VALUE 114 /* RFC 4366 */ - -/* ChangeCipherSpec */ -enum { - TLS_CHANGE_CIPHER_SPEC = 1 -}; - -/* TLS Extensions */ -#define TLS_EXT_SERVER_NAME 0 /* RFC 4366 */ -#define TLS_EXT_MAX_FRAGMENT_LENGTH 1 /* RFC 4366 */ -#define TLS_EXT_CLIENT_CERTIFICATE_URL 2 /* RFC 4366 */ -#define TLS_EXT_TRUSTED_CA_KEYS 3 /* RFC 4366 */ -#define TLS_EXT_TRUNCATED_HMAC 4 /* RFC 4366 */ -#define TLS_EXT_STATUS_REQUEST 5 /* RFC 4366 */ -#define TLS_EXT_SESSION_TICKET 35 /* RFC 4507 */ - -#define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */ - - -typedef enum { - TLS_KEY_X_NULL, - TLS_KEY_X_RSA, - TLS_KEY_X_RSA_EXPORT, - TLS_KEY_X_DH_DSS_EXPORT, - TLS_KEY_X_DH_DSS, - TLS_KEY_X_DH_RSA_EXPORT, - TLS_KEY_X_DH_RSA, - TLS_KEY_X_DHE_DSS_EXPORT, - TLS_KEY_X_DHE_DSS, - TLS_KEY_X_DHE_RSA_EXPORT, - TLS_KEY_X_DHE_RSA, - TLS_KEY_X_DH_anon_EXPORT, - TLS_KEY_X_DH_anon -} tls_key_exchange; - -typedef enum { - TLS_CIPHER_NULL, - TLS_CIPHER_RC4_40, - TLS_CIPHER_RC4_128, - TLS_CIPHER_RC2_CBC_40, - TLS_CIPHER_IDEA_CBC, - TLS_CIPHER_DES40_CBC, - TLS_CIPHER_DES_CBC, - TLS_CIPHER_3DES_EDE_CBC, - TLS_CIPHER_AES_128_CBC, - TLS_CIPHER_AES_256_CBC -} tls_cipher; - -typedef enum { - TLS_HASH_NULL, - TLS_HASH_MD5, - TLS_HASH_SHA, - TLS_HASH_SHA256 -} tls_hash; - -struct tls_cipher_suite { - u16 suite; - tls_key_exchange key_exchange; - tls_cipher cipher; - tls_hash hash; -}; - -typedef enum { - TLS_CIPHER_STREAM, - TLS_CIPHER_BLOCK -} tls_cipher_type; - -struct tls_cipher_data { - tls_cipher cipher; - tls_cipher_type type; - size_t key_material; - size_t expanded_key_material; - size_t block_size; /* also iv_size */ - enum crypto_cipher_alg alg; -}; - - -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; -}; - - -const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite); -const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher); -int tls_server_key_exchange_allowed(tls_cipher cipher); -int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk); -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/contrib/hostapd/src/tls/tlsv1_cred.c b/contrib/hostapd/src/tls/tlsv1_cred.c deleted file mode 100644 index 1ea6827b89..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_cred.c +++ /dev/null @@ -1,506 +0,0 @@ -/* - * TLSv1 credentials - * Copyright (c) 2006-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "base64.h" -#include "crypto/crypto.h" -#include "x509v3.h" -#include "tlsv1_cred.h" - - -struct tlsv1_credentials * tlsv1_cred_alloc(void) -{ - struct tlsv1_credentials *cred; - cred = os_zalloc(sizeof(*cred)); - return cred; -} - - -void tlsv1_cred_free(struct tlsv1_credentials *cred) -{ - if (cred == NULL) - return; - - x509_certificate_chain_free(cred->trusted_certs); - x509_certificate_chain_free(cred->cert); - crypto_private_key_free(cred->key); - os_free(cred->dh_p); - os_free(cred->dh_g); - os_free(cred); -} - - -static int tlsv1_add_cert_der(struct x509_certificate **chain, - const u8 *buf, size_t len) -{ - struct x509_certificate *cert, *p; - char name[128]; - - cert = x509_certificate_parse(buf, len); - if (cert == NULL) { - wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate", - __func__); - return -1; - } - - 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); - - return 0; -} - - -static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----"; -static const char *pem_cert_end = "-----END CERTIFICATE-----"; -static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----"; -static const char *pem_key_end = "-----END RSA PRIVATE KEY-----"; -static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----"; -static const char *pem_key2_end = "-----END PRIVATE KEY-----"; -static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----"; -static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----"; - - -static const u8 * search_tag(const char *tag, const u8 *buf, size_t len) -{ - size_t i, plen; - - plen = os_strlen(tag); - if (len < plen) - return NULL; - - for (i = 0; i < len - plen; i++) { - if (os_memcmp(buf + i, tag, plen) == 0) - return buf + i; - } - - return NULL; -} - - -static int tlsv1_add_cert(struct x509_certificate **chain, - const u8 *buf, size_t len) -{ - const u8 *pos, *end; - unsigned char *der; - size_t der_len; - - pos = search_tag(pem_cert_begin, buf, len); - if (!pos) { - wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - " - "assume DER format"); - return tlsv1_add_cert_der(chain, buf, len); - } - - wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into " - "DER format"); - - while (pos) { - pos += os_strlen(pem_cert_begin); - end = search_tag(pem_cert_end, pos, buf + len - pos); - if (end == NULL) { - wpa_printf(MSG_INFO, "TLSv1: Could not find PEM " - "certificate end tag (%s)", pem_cert_end); - return -1; - } - - der = base64_decode(pos, end - pos, &der_len); - if (der == NULL) { - wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM " - "certificate"); - return -1; - } - - if (tlsv1_add_cert_der(chain, der, der_len) < 0) { - wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM " - "certificate after DER conversion"); - os_free(der); - return -1; - } - - os_free(der); - - end += os_strlen(pem_cert_end); - pos = search_tag(pem_cert_begin, end, buf + len - end); - } - - return 0; -} - - -static int tlsv1_set_cert_chain(struct x509_certificate **chain, - const char *cert, const u8 *cert_blob, - size_t cert_blob_len) -{ - if (cert_blob) - return tlsv1_add_cert(chain, cert_blob, cert_blob_len); - - if (cert) { - u8 *buf; - size_t len; - int ret; - - buf = (u8 *) os_readfile(cert, &len); - if (buf == NULL) { - wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", - cert); - return -1; - } - - ret = tlsv1_add_cert(chain, buf, len); - os_free(buf); - return ret; - } - - return 0; -} - - -/** - * tlsv1_set_ca_cert - Set trusted CA certificate(s) - * @cred: TLSv1 credentials from tlsv1_cred_alloc() - * @cert: File or reference name for X.509 certificate in PEM or DER format - * @cert_blob: cert as inlined data or %NULL if not used - * @cert_blob_len: ca_cert_blob length - * @path: Path to CA certificates (not yet supported) - * Returns: 0 on success, -1 on failure - */ -int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert, - const u8 *cert_blob, size_t cert_blob_len, - const char *path) -{ - if (tlsv1_set_cert_chain(&cred->trusted_certs, cert, - cert_blob, cert_blob_len) < 0) - return -1; - - if (path) { - /* TODO: add support for reading number of certificate files */ - wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory " - "not yet supported"); - return -1; - } - - return 0; -} - - -/** - * tlsv1_set_cert - Set certificate - * @cred: TLSv1 credentials from tlsv1_cred_alloc() - * @cert: File or reference name for X.509 certificate in PEM or DER format - * @cert_blob: cert as inlined data or %NULL if not used - * @cert_blob_len: cert_blob length - * Returns: 0 on success, -1 on failure - */ -int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert, - const u8 *cert_blob, size_t cert_blob_len) -{ - return tlsv1_set_cert_chain(&cred->cert, cert, - cert_blob, cert_blob_len); -} - - -static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len) -{ - const u8 *pos, *end; - unsigned char *der; - size_t der_len; - struct crypto_private_key *pkey; - - pos = search_tag(pem_key_begin, key, len); - if (!pos) { - pos = search_tag(pem_key2_begin, key, len); - if (!pos) - return NULL; - pos += os_strlen(pem_key2_begin); - end = search_tag(pem_key2_end, pos, key + len - pos); - 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); - if (!der) - return NULL; - pkey = crypto_private_key_import(der, der_len, NULL); - os_free(der); - return pkey; -} - - -static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key, - size_t len, - const char *passwd) -{ - const u8 *pos, *end; - unsigned char *der; - size_t der_len; - struct crypto_private_key *pkey; - - if (passwd == NULL) - return NULL; - pos = search_tag(pem_key_enc_begin, key, len); - if (!pos) - return NULL; - pos += os_strlen(pem_key_enc_begin); - end = search_tag(pem_key_enc_end, pos, key + len - pos); - if (!end) - return NULL; - - der = base64_decode(pos, end - pos, &der_len); - if (!der) - return NULL; - pkey = crypto_private_key_import(der, der_len, passwd); - os_free(der); - return pkey; -} - - -static int tlsv1_set_key(struct tlsv1_credentials *cred, - const u8 *key, size_t len, const char *passwd) -{ - cred->key = crypto_private_key_import(key, len, passwd); - if (cred->key == NULL) - cred->key = tlsv1_set_key_pem(key, len); - if (cred->key == NULL) - cred->key = tlsv1_set_key_enc_pem(key, len, passwd); - if (cred->key == NULL) { - wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key"); - return -1; - } - return 0; -} - - -/** - * tlsv1_set_private_key - Set private key - * @cred: TLSv1 credentials from tlsv1_cred_alloc() - * @private_key: File or reference name for the key in PEM or DER format - * @private_key_passwd: Passphrase for decrypted private key, %NULL if no - * passphrase is used. - * @private_key_blob: private_key as inlined data or %NULL if not used - * @private_key_blob_len: private_key_blob length - * Returns: 0 on success, -1 on failure - */ -int tlsv1_set_private_key(struct tlsv1_credentials *cred, - const char *private_key, - const char *private_key_passwd, - const u8 *private_key_blob, - size_t private_key_blob_len) -{ - crypto_private_key_free(cred->key); - cred->key = NULL; - - if (private_key_blob) - return tlsv1_set_key(cred, private_key_blob, - private_key_blob_len, - private_key_passwd); - - if (private_key) { - u8 *buf; - size_t len; - int ret; - - buf = (u8 *) os_readfile(private_key, &len); - if (buf == NULL) { - wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", - private_key); - return -1; - } - - ret = tlsv1_set_key(cred, buf, len, private_key_passwd); - os_free(buf); - return ret; - } - - return 0; -} - - -static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred, - const u8 *dh, size_t len) -{ - struct asn1_hdr hdr; - const u8 *pos, *end; - - pos = dh; - end = dh + len; - - /* - * DHParameter ::= SEQUENCE { - * prime INTEGER, -- p - * base INTEGER, -- g - * privateValueLength INTEGER OPTIONAL } - */ - - /* DHParamer ::= SEQUENCE */ - if (asn1_get_next(pos, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a " - "valid SEQUENCE - found class %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - pos = hdr.payload; - - /* prime INTEGER */ - if (asn1_get_next(pos, end - pos, &hdr) < 0) - return -1; - - if (hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_INTEGER) { - wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; " - "class=%d tag=0x%x", hdr.class, hdr.tag); - return -1; - } - - wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length); - if (hdr.length == 0) - return -1; - os_free(cred->dh_p); - cred->dh_p = os_malloc(hdr.length); - if (cred->dh_p == NULL) - return -1; - os_memcpy(cred->dh_p, hdr.payload, hdr.length); - cred->dh_p_len = hdr.length; - pos = hdr.payload + hdr.length; - - /* base INTEGER */ - if (asn1_get_next(pos, end - pos, &hdr) < 0) - return -1; - - if (hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_INTEGER) { - wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; " - "class=%d tag=0x%x", hdr.class, hdr.tag); - return -1; - } - - wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length); - if (hdr.length == 0) - return -1; - os_free(cred->dh_g); - cred->dh_g = os_malloc(hdr.length); - if (cred->dh_g == NULL) - return -1; - os_memcpy(cred->dh_g, hdr.payload, hdr.length); - cred->dh_g_len = hdr.length; - - return 0; -} - - -static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----"; -static const char *pem_dhparams_end = "-----END DH PARAMETERS-----"; - - -static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred, - const u8 *buf, size_t len) -{ - const u8 *pos, *end; - unsigned char *der; - size_t der_len; - - pos = search_tag(pem_dhparams_begin, buf, len); - if (!pos) { - wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - " - "assume DER format"); - return tlsv1_set_dhparams_der(cred, buf, len); - } - - wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER " - "format"); - - pos += os_strlen(pem_dhparams_begin); - end = search_tag(pem_dhparams_end, pos, buf + len - pos); - if (end == NULL) { - wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end " - "tag (%s)", pem_dhparams_end); - return -1; - } - - der = base64_decode(pos, end - pos, &der_len); - if (der == NULL) { - wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams"); - return -1; - } - - if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) { - wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams " - "DER conversion"); - os_free(der); - return -1; - } - - os_free(der); - - return 0; -} - - -/** - * tlsv1_set_dhparams - Set Diffie-Hellman parameters - * @cred: TLSv1 credentials from tlsv1_cred_alloc() - * @dh_file: File or reference name for the DH params in PEM or DER format - * @dh_blob: DH params as inlined data or %NULL if not used - * @dh_blob_len: dh_blob length - * Returns: 0 on success, -1 on failure - */ -int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file, - const u8 *dh_blob, size_t dh_blob_len) -{ - if (dh_blob) - return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len); - - if (dh_file) { - u8 *buf; - size_t len; - int ret; - - buf = (u8 *) os_readfile(dh_file, &len); - if (buf == NULL) { - wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", - dh_file); - return -1; - } - - ret = tlsv1_set_dhparams_blob(cred, buf, len); - os_free(buf); - return ret; - } - - return 0; -} diff --git a/contrib/hostapd/src/tls/tlsv1_cred.h b/contrib/hostapd/src/tls/tlsv1_cred.h deleted file mode 100644 index 68fbdc9230..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_cred.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * TLSv1 credentials - * Copyright (c) 2006-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef TLSV1_CRED_H -#define TLSV1_CRED_H - -struct tlsv1_credentials { - struct x509_certificate *trusted_certs; - struct x509_certificate *cert; - struct crypto_private_key *key; - - /* Diffie-Hellman parameters */ - u8 *dh_p; /* prime */ - size_t dh_p_len; - u8 *dh_g; /* generator */ - size_t dh_g_len; -}; - - -struct tlsv1_credentials * tlsv1_cred_alloc(void); -void tlsv1_cred_free(struct tlsv1_credentials *cred); -int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert, - const u8 *cert_blob, size_t cert_blob_len, - const char *path); -int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert, - const u8 *cert_blob, size_t cert_blob_len); -int tlsv1_set_private_key(struct tlsv1_credentials *cred, - const char *private_key, - const char *private_key_passwd, - const u8 *private_key_blob, - size_t private_key_blob_len); -int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file, - const u8 *dh_blob, size_t dh_blob_len); - -#endif /* TLSV1_CRED_H */ diff --git a/contrib/hostapd/src/tls/tlsv1_record.c b/contrib/hostapd/src/tls/tlsv1_record.c deleted file mode 100644 index 3bec3be36f..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_record.c +++ /dev/null @@ -1,485 +0,0 @@ -/* - * TLSv1 Record Protocol - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/md5.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "tlsv1_common.h" -#include "tlsv1_record.h" - - -/** - * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite - * @rl: Pointer to TLS record layer data - * @cipher_suite: New cipher suite - * Returns: 0 on success, -1 on failure - * - * This function is used to prepare TLS record layer for cipher suite change. - * tlsv1_record_change_write_cipher() and - * tlsv1_record_change_read_cipher() functions can then be used to change the - * currently used ciphers. - */ -int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl, - u16 cipher_suite) -{ - const struct tls_cipher_suite *suite; - const struct tls_cipher_data *data; - - wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x", - cipher_suite); - rl->cipher_suite = cipher_suite; - - suite = tls_get_cipher_suite(cipher_suite); - if (suite == NULL) - return -1; - - if (suite->hash == TLS_HASH_MD5) { - rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5; - rl->hash_size = MD5_MAC_LEN; - } 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); - if (data == NULL) - return -1; - - rl->key_material_len = data->key_material; - rl->iv_size = data->block_size; - rl->cipher_alg = data->alg; - - return 0; -} - - -/** - * tlsv1_record_change_write_cipher - TLS record layer: Change write cipher - * @rl: Pointer to TLS record layer data - * Returns: 0 on success (cipher changed), -1 on failure - * - * This function changes TLS record layer to use the new cipher suite - * configured with tlsv1_record_set_cipher_suite() for writing. - */ -int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl) -{ - wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite " - "0x%04x", rl->cipher_suite); - rl->write_cipher_suite = rl->cipher_suite; - os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN); - - if (rl->write_cbc) { - crypto_cipher_deinit(rl->write_cbc); - rl->write_cbc = NULL; - } - if (rl->cipher_alg != CRYPTO_CIPHER_NULL) { - rl->write_cbc = crypto_cipher_init(rl->cipher_alg, - rl->write_iv, rl->write_key, - rl->key_material_len); - if (rl->write_cbc == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize " - "cipher"); - return -1; - } - } - - return 0; -} - - -/** - * tlsv1_record_change_read_cipher - TLS record layer: Change read cipher - * @rl: Pointer to TLS record layer data - * Returns: 0 on success (cipher changed), -1 on failure - * - * This function changes TLS record layer to use the new cipher suite - * configured with tlsv1_record_set_cipher_suite() for reading. - */ -int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl) -{ - wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite " - "0x%04x", rl->cipher_suite); - rl->read_cipher_suite = rl->cipher_suite; - os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN); - - if (rl->read_cbc) { - crypto_cipher_deinit(rl->read_cbc); - rl->read_cbc = NULL; - } - if (rl->cipher_alg != CRYPTO_CIPHER_NULL) { - rl->read_cbc = crypto_cipher_init(rl->cipher_alg, - rl->read_iv, rl->read_key, - rl->key_material_len); - if (rl->read_cbc == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize " - "cipher"); - return -1; - } - } - - return 0; -} - - -/** - * 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 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 - * - * This function fills in the TLS record layer header, adds HMAC, and encrypts - * 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, const u8 *payload, size_t payload_len, - size_t *out_len) -{ - 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, rl->tls_version); - pos += 2; - /* uint16 length */ - length = pos; - WPA_PUT_BE16(length, payload_len); - pos += 2; - - 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) { - wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " - "to initialize HMAC"); - return -1; - } - crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN); - /* type + version + length + fragment */ - 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 " - "enough room for MAC"); - crypto_hash_finish(hmac, NULL, NULL); - return -1; - } - - if (crypto_hash_finish(hmac, pos, &clen) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " - "to calculate HMAC"); - return -1; - } - wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC", - pos, clen); - pos += clen; - if (rl->iv_size) { - size_t len = pos - cpayload; - size_t pad; - pad = (len + 1) % rl->iv_size; - if (pad) - pad = rl->iv_size - pad; - if (pos + pad + 1 > buf + buf_size) { - wpa_printf(MSG_DEBUG, "TLSv1: No room for " - "block cipher padding"); - return -1; - } - os_memset(pos, pad, pad + 1); - pos += pad + 1; - } - - if (crypto_cipher_encrypt(rl->write_cbc, cpayload, - cpayload, pos - cpayload) < 0) - return -1; - } - - WPA_PUT_BE16(length, pos - length - 2); - inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN); - - *out_len = pos - buf; - - return 0; -} - - -/** - * tlsv1_record_receive - TLS record layer: Process a received message - * @rl: Pointer to TLS record layer data - * @in_data: Received data - * @in_len: Length of the received data - * @out_data: Buffer for output data (must be at least as long as in_data) - * @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: 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. - */ -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) -{ - size_t i, rlen, hlen; - u8 padlen; - struct crypto_hash *hmac; - u8 len[2], hash[100]; - 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) - " - "need more data", - (unsigned long) in_len); - 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", 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 " - "%u.%u", in_data[1], in_data[2]); - *alert = TLS_ALERT_PROTOCOL_VERSION; - return -1; - } - - /* 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)", - (unsigned long) (TLS_RECORD_HEADER_LEN + rlen)); - *alert = TLS_ALERT_RECORD_OVERFLOW; - return -1; - } - - in_data += TLS_RECORD_HEADER_LEN; - in_len -= TLS_RECORD_HEADER_LEN; - - if (rlen > in_len) { - wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included " - "(rlen=%lu > in_len=%lu)", - (unsigned long) rlen, (unsigned long) in_len); - 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; - } - - in_len = rlen; - - if (*out_len < in_len) { - wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for " - "processing received record"); - *alert = TLS_ALERT_INTERNAL_ERROR; - return -1; - } - - if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) { - 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) { - /* - * 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)"); - force_mac_error = 1; - goto check_mac; - } - padlen = out_data[plen - 1]; - if (padlen >= plen) { - wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad " - "length (%u, plen=%lu) in " - "received record", - padlen, (unsigned long) plen); - force_mac_error = 1; - goto check_mac; - } - 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 + plen - padlen - - 1, padlen + 1); - force_mac_error = 1; - goto check_mac; - } - } - - plen -= padlen + 1; - - wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - " - "Decrypted data with IV and padding " - "removed", out_data, plen); - } - - check_mac: - if (plen < rl->hash_size) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no " - "hash value"); - *alert = TLS_ALERT_BAD_RECORD_MAC; - return -1; - } - - plen -= rl->hash_size; - - hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret, - rl->hash_size); - if (hmac == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " - "to initialize HMAC"); - *alert = TLS_ALERT_INTERNAL_ERROR; - return -1; - } - - 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, plen); - crypto_hash_update(hmac, len, 2); - 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 + plen, hlen) != 0 || - force_mac_error) { - wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in " - "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 */ - if (TLS_RECORD_HEADER_LEN + *out_len > 17408) { - wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)", - (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len)); - *alert = TLS_ALERT_RECORD_OVERFLOW; - return -1; - } - - inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN); - - return TLS_RECORD_HEADER_LEN + rlen; -} diff --git a/contrib/hostapd/src/tls/tlsv1_record.h b/contrib/hostapd/src/tls/tlsv1_record.h deleted file mode 100644 index 48abcb0d25..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_record.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * TLSv1 Record Protocol - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef TLSV1_RECORD_H -#define TLSV1_RECORD_H - -#include "crypto/crypto.h" - -#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 + \ - TLS_MAX_WRITE_KEY_LEN + TLS_MAX_IV_LEN)) - -#define TLS_SEQ_NUM_LEN 8 -#define TLS_RECORD_HEADER_LEN 5 - -/* ContentType */ -enum { - TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20, - TLS_CONTENT_TYPE_ALERT = 21, - TLS_CONTENT_TYPE_HANDSHAKE = 22, - TLS_CONTENT_TYPE_APPLICATION_DATA = 23 -}; - -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]; - u8 read_key[TLS_MAX_WRITE_KEY_LEN]; - u8 write_iv[TLS_MAX_IV_LEN]; - u8 read_iv[TLS_MAX_IV_LEN]; - - size_t hash_size; - size_t key_material_len; - size_t iv_size; /* also block_size */ - - enum crypto_hash_alg hash_alg; - enum crypto_cipher_alg cipher_alg; - - u8 write_seq_num[TLS_SEQ_NUM_LEN]; - u8 read_seq_num[TLS_SEQ_NUM_LEN]; - - u16 cipher_suite; - u16 write_cipher_suite; - u16 read_cipher_suite; - - struct crypto_cipher *write_cbc; - struct crypto_cipher *read_cbc; -}; - - -int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl, - u16 cipher_suite); -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, 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); - -#endif /* TLSV1_RECORD_H */ diff --git a/contrib/hostapd/src/tls/tlsv1_server.c b/contrib/hostapd/src/tls/tlsv1_server.c deleted file mode 100644 index 2880309ebf..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_server.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246) - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha1.h" -#include "crypto/tls.h" -#include "tlsv1_common.h" -#include "tlsv1_record.h" -#include "tlsv1_server.h" -#include "tlsv1_server_i.h" - -/* TODO: - * Support for a message fragmented across several records (RFC 2246, 6.2.1) - */ - - -void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description) -{ - conn->alert_level = level; - conn->alert_description = description; -} - - -int tlsv1_server_derive_keys(struct tlsv1_server *conn, - const u8 *pre_master_secret, - size_t pre_master_secret_len) -{ - u8 seed[2 * TLS_RANDOM_LEN]; - u8 key_block[TLS_MAX_KEY_BLOCK_LEN]; - u8 *pos; - size_t key_block_len; - - if (pre_master_secret) { - wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret", - pre_master_secret, pre_master_secret_len); - os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); - os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, - TLS_RANDOM_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 " - "master_secret"); - return -1; - } - wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret", - conn->master_secret, TLS_MASTER_SECRET_LEN); - } - - 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->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"); - return -1; - } - wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block", - key_block, key_block_len); - - pos = key_block; - - /* client_write_MAC_secret */ - os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size); - pos += conn->rl.hash_size; - /* server_write_MAC_secret */ - os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size); - pos += conn->rl.hash_size; - - /* client_write_key */ - os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len); - pos += conn->rl.key_material_len; - /* server_write_key */ - os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len); - pos += conn->rl.key_material_len; - - /* client_write_IV */ - os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size); - pos += conn->rl.iv_size; - /* server_write_IV */ - os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size); - pos += conn->rl.iv_size; - - return 0; -} - - -/** - * tlsv1_server_handshake - Process TLS handshake - * @conn: TLSv1 server connection data from tlsv1_server_init() - * @in_data: Input data from TLS peer - * @in_len: Input data length - * @out_len: Length of the output buffer. - * Returns: Pointer to output data, %NULL on failure - */ -u8 * tlsv1_server_handshake(struct tlsv1_server *conn, - const u8 *in_data, size_t in_len, - size_t *out_len) -{ - 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"); - return NULL; - } - - pos = in_data; - end = in_data + in_len; - in_msg = os_malloc(in_len); - if (in_msg == NULL) - return NULL; - - /* Each received packet may include multiple records */ - while (pos < end) { - in_msg_len = in_len; - 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; - in_end = in_msg + in_msg_len; - - /* Each received record may include multiple messages of the - * same ContentType. */ - while (in_pos < in_end) { - in_msg_len = in_end - in_pos; - if (tlsv1_server_process_handshake(conn, ct, in_pos, - &in_msg_len) < 0) - goto failed; - in_pos += in_msg_len; - } - - pos += used; - } - - os_free(in_msg); - in_msg = NULL; - - msg = tlsv1_server_handshake_write(conn, out_len); - -failed: - os_free(in_msg); - if (conn->alert_level) { - if (conn->state == FAILED) { - /* Avoid alert loops */ - wpa_printf(MSG_DEBUG, "TLSv1: Drop alert loop"); - os_free(msg); - return NULL; - } - conn->state = FAILED; - os_free(msg); - msg = tlsv1_server_send_alert(conn, conn->alert_level, - conn->alert_description, - out_len); - } - - return msg; -} - - -/** - * tlsv1_server_encrypt - Encrypt data into TLS tunnel - * @conn: TLSv1 server connection data from tlsv1_server_init() - * @in_data: Pointer to plaintext data to be encrypted - * @in_len: Input buffer length - * @out_data: Pointer to output buffer (encrypted TLS data) - * @out_len: Maximum out_data length - * Returns: Number of bytes written to out_data, -1 on failure - * - * This function is used after TLS handshake has been completed successfully to - * send data in the encrypted tunnel. - */ -int tlsv1_server_encrypt(struct tlsv1_server *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) -{ - size_t rlen; - - wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData", - in_data, in_len); - - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA, - 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); - return -1; - } - - return rlen; -} - - -/** - * tlsv1_server_decrypt - Decrypt data from TLS tunnel - * @conn: TLSv1 server connection data from tlsv1_server_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 - * - * This function is used after TLS handshake has been completed successfully to - * receive data from the encrypted tunnel. - */ -int tlsv1_server_decrypt(struct tlsv1_server *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) -{ - const u8 *in_end, *pos; - int used; - u8 alert, *out_end, *out_pos, ct; - size_t olen; - - pos = in_data; - in_end = in_data + in_len; - out_pos = out_data; - out_end = out_data + out_len; - - while (pos < in_end) { - 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, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - out_pos += olen; - if (out_pos > out_end) { - wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough " - "for processing the received record"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - pos += used; - } - - return out_pos - out_data; -} - - -/** - * tlsv1_server_global_init - Initialize TLSv1 server - * Returns: 0 on success, -1 on failure - * - * This function must be called before using any other TLSv1 server functions. - */ -int tlsv1_server_global_init(void) -{ - return crypto_global_init(); -} - - -/** - * tlsv1_server_global_deinit - Deinitialize TLSv1 server - * - * This function can be used to deinitialize the TLSv1 server that was - * initialized by calling tlsv1_server_global_init(). No TLSv1 server functions - * can be called after this before calling tlsv1_server_global_init() again. - */ -void tlsv1_server_global_deinit(void) -{ - crypto_global_deinit(); -} - - -/** - * tlsv1_server_init - Initialize TLSv1 server connection - * @cred: Pointer to server credentials from tlsv1_server_cred_alloc() - * Returns: Pointer to TLSv1 server connection data or %NULL on failure - */ -struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred) -{ - struct tlsv1_server *conn; - size_t count; - u16 *suites; - - conn = os_zalloc(sizeof(*conn)); - if (conn == NULL) - return NULL; - - conn->cred = cred; - - conn->state = CLIENT_HELLO; - - if (tls_verify_hash_init(&conn->verify) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify " - "hash"); - os_free(conn); - return NULL; - } - - count = 0; - suites = conn->cipher_suites; - suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA; - 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; - - return conn; -} - - -static void tlsv1_server_clear_data(struct tlsv1_server *conn) -{ - tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL); - tlsv1_record_change_write_cipher(&conn->rl); - tlsv1_record_change_read_cipher(&conn->rl); - tls_verify_hash_free(&conn->verify); - - crypto_public_key_free(conn->client_rsa_key); - conn->client_rsa_key = NULL; - - os_free(conn->session_ticket); - conn->session_ticket = NULL; - conn->session_ticket_len = 0; - conn->use_session_ticket = 0; - - os_free(conn->dh_secret); - conn->dh_secret = NULL; - conn->dh_secret_len = 0; -} - - -/** - * tlsv1_server_deinit - Deinitialize TLSv1 server connection - * @conn: TLSv1 server connection data from tlsv1_server_init() - */ -void tlsv1_server_deinit(struct tlsv1_server *conn) -{ - tlsv1_server_clear_data(conn); - os_free(conn); -} - - -/** - * tlsv1_server_established - Check whether connection has been established - * @conn: TLSv1 server connection data from tlsv1_server_init() - * Returns: 1 if connection is established, 0 if not - */ -int tlsv1_server_established(struct tlsv1_server *conn) -{ - return conn->state == ESTABLISHED; -} - - -/** - * tlsv1_server_prf - Use TLS-PRF to derive keying material - * @conn: TLSv1 server connection data from tlsv1_server_init() - * @label: Label (e.g., description of the key) for PRF - * @server_random_first: seed is 0 = client_random|server_random, - * 1 = server_random|client_random - * @out: Buffer for output data from TLS-PRF - * @out_len: Length of the output buffer - * Returns: 0 on success, -1 on failure - */ -int tlsv1_server_prf(struct tlsv1_server *conn, const char *label, - int server_random_first, u8 *out, size_t out_len) -{ - u8 seed[2 * TLS_RANDOM_LEN]; - - if (conn->state != ESTABLISHED) - return -1; - - if (server_random_first) { - os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); - os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, - TLS_RANDOM_LEN); - } else { - os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); - os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, - TLS_RANDOM_LEN); - } - - return tls_prf(conn->rl.tls_version, - conn->master_secret, TLS_MASTER_SECRET_LEN, - label, seed, 2 * TLS_RANDOM_LEN, out, out_len); -} - - -/** - * tlsv1_server_get_cipher - Get current cipher name - * @conn: TLSv1 server connection data from tlsv1_server_init() - * @buf: Buffer for the cipher name - * @buflen: buf size - * Returns: 0 on success, -1 on failure - * - * Get the name of the currently used cipher. - */ -int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf, - size_t buflen) -{ - char *cipher; - - switch (conn->rl.cipher_suite) { - case TLS_RSA_WITH_RC4_128_MD5: - cipher = "RC4-MD5"; - break; - case TLS_RSA_WITH_RC4_128_SHA: - cipher = "RC4-SHA"; - break; - case TLS_RSA_WITH_DES_CBC_SHA: - cipher = "DES-CBC-SHA"; - break; - case TLS_RSA_WITH_3DES_EDE_CBC_SHA: - cipher = "DES-CBC3-SHA"; - 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_128_CBC_SHA: - cipher = "AES-128-SHA"; - break; - default: - return -1; - } - - if (os_strlcpy(buf, cipher, buflen) >= buflen) - return -1; - return 0; -} - - -/** - * tlsv1_server_shutdown - Shutdown TLS connection - * @conn: TLSv1 server connection data from tlsv1_server_init() - * Returns: 0 on success, -1 on failure - */ -int tlsv1_server_shutdown(struct tlsv1_server *conn) -{ - conn->state = CLIENT_HELLO; - - if (tls_verify_hash_init(&conn->verify) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify " - "hash"); - return -1; - } - - tlsv1_server_clear_data(conn); - - return 0; -} - - -/** - * tlsv1_server_resumed - Was session resumption used - * @conn: TLSv1 server connection data from tlsv1_server_init() - * Returns: 1 if current session used session resumption, 0 if not - */ -int tlsv1_server_resumed(struct tlsv1_server *conn) -{ - return 0; -} - - -/** - * tlsv1_server_get_keys - Get master key and random data from TLS connection - * @conn: TLSv1 server connection data from tlsv1_server_init() - * @keys: Structure of key/random data (filled on success) - * Returns: 0 on success, -1 on failure - */ -int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys) -{ - os_memset(keys, 0, sizeof(*keys)); - if (conn->state == CLIENT_HELLO) - return -1; - - keys->client_random = conn->client_random; - keys->client_random_len = TLS_RANDOM_LEN; - - if (conn->state != SERVER_HELLO) { - keys->server_random = conn->server_random; - keys->server_random_len = TLS_RANDOM_LEN; - keys->master_key = conn->master_secret; - keys->master_key_len = TLS_MASTER_SECRET_LEN; - } - - return 0; -} - - -/** - * tlsv1_server_get_keyblock_size - Get TLS key_block size - * @conn: TLSv1 server connection data from tlsv1_server_init() - * Returns: Size of the key_block for the negotiated cipher suite or -1 on - * failure - */ -int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn) -{ - if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO) - return -1; - - return 2 * (conn->rl.hash_size + conn->rl.key_material_len + - conn->rl.iv_size); -} - - -/** - * tlsv1_server_set_cipher_list - Configure acceptable cipher suites - * @conn: TLSv1 server connection data from tlsv1_server_init() - * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers - * (TLS_CIPHER_*). - * Returns: 0 on success, -1 on failure - */ -int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers) -{ - size_t count; - u16 *suites; - - /* TODO: implement proper configuration of cipher suites */ - if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) { - count = 0; - suites = conn->cipher_suites; - suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA; - 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; - suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA; - 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; - suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA; - conn->num_cipher_suites = count; - } - - return 0; -} - - -int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer) -{ - conn->verify_peer = verify_peer; - return 0; -} - - -void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn, - tlsv1_server_session_ticket_cb cb, - void *ctx) -{ - wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)", - cb, ctx); - conn->session_ticket_cb = cb; - conn->session_ticket_cb_ctx = ctx; -} diff --git a/contrib/hostapd/src/tls/tlsv1_server.h b/contrib/hostapd/src/tls/tlsv1_server.h deleted file mode 100644 index a18c69e37c..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_server.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246) - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef TLSV1_SERVER_H -#define TLSV1_SERVER_H - -#include "tlsv1_cred.h" - -struct tlsv1_server; - -int tlsv1_server_global_init(void); -void tlsv1_server_global_deinit(void); -struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred); -void tlsv1_server_deinit(struct tlsv1_server *conn); -int tlsv1_server_established(struct tlsv1_server *conn); -int tlsv1_server_prf(struct tlsv1_server *conn, const char *label, - int server_random_first, u8 *out, size_t out_len); -u8 * tlsv1_server_handshake(struct tlsv1_server *conn, - const u8 *in_data, size_t in_len, size_t *out_len); -int tlsv1_server_encrypt(struct tlsv1_server *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len); -int tlsv1_server_decrypt(struct tlsv1_server *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len); -int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf, - size_t buflen); -int tlsv1_server_shutdown(struct tlsv1_server *conn); -int tlsv1_server_resumed(struct tlsv1_server *conn); -int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys); -int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn); -int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers); -int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer); - -typedef int (*tlsv1_server_session_ticket_cb) -(void *ctx, const u8 *ticket, size_t len, const u8 *client_random, - const u8 *server_random, u8 *master_secret); - -void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn, - tlsv1_server_session_ticket_cb cb, - void *ctx); - -#endif /* TLSV1_SERVER_H */ diff --git a/contrib/hostapd/src/tls/tlsv1_server_i.h b/contrib/hostapd/src/tls/tlsv1_server_i.h deleted file mode 100644 index 1f61533a5a..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_server_i.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * TLSv1 server - internal structures - * Copyright (c) 2006-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef TLSV1_SERVER_I_H -#define TLSV1_SERVER_I_H - -struct tlsv1_server { - enum { - CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE, - SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST, - SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE, - CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED, - SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, - ESTABLISHED, FAILED - } state; - - struct tlsv1_record_layer rl; - - u8 session_id[TLS_SESSION_ID_MAX_LEN]; - size_t session_id_len; - u8 client_random[TLS_RANDOM_LEN]; - u8 server_random[TLS_RANDOM_LEN]; - u8 master_secret[TLS_MASTER_SECRET_LEN]; - - u8 alert_level; - u8 alert_description; - - struct crypto_public_key *client_rsa_key; - - struct tls_verify_hash verify; - -#define MAX_CIPHER_COUNT 30 - u16 cipher_suites[MAX_CIPHER_COUNT]; - size_t num_cipher_suites; - - u16 cipher_suite; - - struct tlsv1_credentials *cred; - - int verify_peer; - u16 client_version; - - u8 *session_ticket; - size_t session_ticket_len; - - tlsv1_server_session_ticket_cb session_ticket_cb; - void *session_ticket_cb_ctx; - - int use_session_ticket; - - u8 *dh_secret; - size_t dh_secret_len; -}; - - -void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description); -int tlsv1_server_derive_keys(struct tlsv1_server *conn, - const u8 *pre_master_secret, - size_t pre_master_secret_len); -u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len); -u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level, - u8 description, size_t *out_len); -int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct, - const u8 *buf, size_t *len); - -#endif /* TLSV1_SERVER_I_H */ diff --git a/contrib/hostapd/src/tls/tlsv1_server_read.c b/contrib/hostapd/src/tls/tlsv1_server_read.c deleted file mode 100644 index 6f6539b1bf..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_server_read.c +++ /dev/null @@ -1,1253 +0,0 @@ -/* - * TLSv1 server - read handshake message - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/md5.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "crypto/tls.h" -#include "x509v3.h" -#include "tlsv1_common.h" -#include "tlsv1_record.h" -#include "tlsv1_server.h" -#include "tlsv1_server_i.h" - - -static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct, - const u8 *in_data, size_t *in_len); -static int tls_process_change_cipher_spec(struct tlsv1_server *conn, - u8 ct, const u8 *in_data, - size_t *in_len); - - -static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct, - const u8 *in_data, size_t *in_len) -{ - const u8 *pos, *end, *c; - size_t left, len, i, j; - u16 cipher_suite; - u16 num_suites; - int compr_null_found; - u16 ext_type, ext_len; - - if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " - "received content type 0x%x", ct); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - if (left < 4) - goto decode_error; - - /* HandshakeType msg_type */ - if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) { - wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " - "message %d (expected ClientHello)", *pos); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello"); - pos++; - /* uint24 length */ - len = WPA_GET_BE24(pos); - pos += 3; - left -= 4; - - if (len > left) - goto decode_error; - - /* body - ClientHello */ - - wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len); - end = pos + len; - - /* ProtocolVersion client_version */ - if (end - pos < 2) - goto decode_error; - 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_1) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in " - "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; - - os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN); - pos += TLS_RANDOM_LEN; - wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random", - conn->client_random, TLS_RANDOM_LEN); - - /* SessionID session_id */ - if (end - pos < 1) - goto decode_error; - if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN) - goto decode_error; - wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos); - pos += 1 + *pos; - /* TODO: add support for session resumption */ - - /* CipherSuite cipher_suites<2..2^16-1> */ - if (end - pos < 2) - goto decode_error; - num_suites = WPA_GET_BE16(pos); - pos += 2; - if (end - pos < num_suites) - goto decode_error; - wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites", - pos, num_suites); - if (num_suites & 1) - goto decode_error; - num_suites /= 2; - - cipher_suite = 0; - for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) { - c = pos; - for (j = 0; j < num_suites; j++) { - u16 tmp = WPA_GET_BE16(c); - c += 2; - if (!cipher_suite && tmp == conn->cipher_suites[i]) { - cipher_suite = tmp; - break; - } - } - } - pos += num_suites * 2; - if (!cipher_suite) { - wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite " - "available"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_ILLEGAL_PARAMETER); - return -1; - } - - if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for " - "record layer"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - conn->cipher_suite = cipher_suite; - - /* CompressionMethod compression_methods<1..2^8-1> */ - if (end - pos < 1) - goto decode_error; - num_suites = *pos++; - if (end - pos < num_suites) - goto decode_error; - wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods", - pos, num_suites); - compr_null_found = 0; - for (i = 0; i < num_suites; i++) { - if (*pos++ == TLS_COMPRESSION_NULL) - compr_null_found = 1; - } - if (!compr_null_found) { - wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL " - "compression"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_ILLEGAL_PARAMETER); - return -1; - } - - if (end - pos == 1) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the " - "end of ClientHello: 0x%02x", *pos); - goto decode_error; - } - - if (end - pos >= 2) { - /* Extension client_hello_extension_list<0..2^16-1> */ - ext_len = WPA_GET_BE16(pos); - pos += 2; - - wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello " - "extensions", ext_len); - if (end - pos != ext_len) { - wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello " - "extension list length %u (expected %u)", - ext_len, (unsigned int) (end - pos)); - goto decode_error; - } - - /* - * struct { - * ExtensionType extension_type (0..65535) - * opaque extension_data<0..2^16-1> - * } Extension; - */ - - while (pos < end) { - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "TLSv1: Invalid " - "extension_type field"); - goto decode_error; - } - - ext_type = WPA_GET_BE16(pos); - pos += 2; - - if (end - pos < 2) { - wpa_printf(MSG_DEBUG, "TLSv1: Invalid " - "extension_data length field"); - goto decode_error; - } - - ext_len = WPA_GET_BE16(pos); - pos += 2; - - if (end - pos < ext_len) { - wpa_printf(MSG_DEBUG, "TLSv1: Invalid " - "extension_data field"); - goto decode_error; - } - - wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension " - "type %u", ext_type); - wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello " - "Extension data", pos, ext_len); - - if (ext_type == TLS_EXT_SESSION_TICKET) { - os_free(conn->session_ticket); - conn->session_ticket = os_malloc(ext_len); - if (conn->session_ticket) { - os_memcpy(conn->session_ticket, pos, - ext_len); - conn->session_ticket_len = ext_len; - } - } - - pos += ext_len; - } - } - - *in_len = end - in_data; - - wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to " - "ServerHello"); - conn->state = SERVER_HELLO; - - return 0; - -decode_error: - wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; -} - - -static int tls_process_certificate(struct tlsv1_server *conn, u8 ct, - const u8 *in_data, size_t *in_len) -{ - const u8 *pos, *end; - size_t left, len, list_len, cert_len, idx; - u8 type; - struct x509_certificate *chain = NULL, *last = NULL, *cert; - int reason; - - if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " - "received content type 0x%x", ct); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - if (left < 4) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message " - "(len=%lu)", (unsigned long) left); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - type = *pos++; - len = WPA_GET_BE24(pos); - pos += 3; - left -= 4; - - if (len > left) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message " - "length (len=%lu != left=%lu)", - (unsigned long) len, (unsigned long) left); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) { - if (conn->verify_peer) { - wpa_printf(MSG_DEBUG, "TLSv1: Client did not include " - "Certificate"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - return tls_process_client_key_exchange(conn, ct, in_data, - in_len); - } - if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) { - wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " - "message %d (expected Certificate/" - "ClientKeyExchange)", type); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - wpa_printf(MSG_DEBUG, - "TLSv1: Received Certificate (certificate_list len %lu)", - (unsigned long) len); - - /* - * opaque ASN.1Cert<2^24-1>; - * - * struct { - * ASN.1Cert certificate_list<1..2^24-1>; - * } Certificate; - */ - - end = pos + len; - - if (end - pos < 3) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate " - "(left=%lu)", (unsigned long) left); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - list_len = WPA_GET_BE24(pos); - pos += 3; - - if ((size_t) (end - pos) != list_len) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list " - "length (len=%lu left=%lu)", - (unsigned long) list_len, - (unsigned long) (end - pos)); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - idx = 0; - while (pos < end) { - if (end - pos < 3) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " - "certificate_list"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - x509_certificate_chain_free(chain); - return -1; - } - - cert_len = WPA_GET_BE24(pos); - pos += 3; - - if ((size_t) (end - pos) < cert_len) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate " - "length (len=%lu left=%lu)", - (unsigned long) cert_len, - (unsigned long) (end - pos)); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - x509_certificate_chain_free(chain); - return -1; - } - - wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)", - (unsigned long) idx, (unsigned long) cert_len); - - if (idx == 0) { - crypto_public_key_free(conn->client_rsa_key); - if (tls_parse_cert(pos, cert_len, - &conn->client_rsa_key)) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " - "the certificate"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_BAD_CERTIFICATE); - x509_certificate_chain_free(chain); - return -1; - } - } - - cert = x509_certificate_parse(pos, cert_len); - if (cert == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " - "the certificate"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_BAD_CERTIFICATE); - x509_certificate_chain_free(chain); - return -1; - } - - if (last == NULL) - chain = cert; - else - last->next = cert; - last = cert; - - idx++; - pos += cert_len; - } - - if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain, - &reason, 0) < 0) { - int tls_reason; - wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain " - "validation failed (reason=%d)", reason); - switch (reason) { - case X509_VALIDATE_BAD_CERTIFICATE: - tls_reason = TLS_ALERT_BAD_CERTIFICATE; - break; - case X509_VALIDATE_UNSUPPORTED_CERTIFICATE: - tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE; - break; - case X509_VALIDATE_CERTIFICATE_REVOKED: - tls_reason = TLS_ALERT_CERTIFICATE_REVOKED; - break; - case X509_VALIDATE_CERTIFICATE_EXPIRED: - tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED; - break; - case X509_VALIDATE_CERTIFICATE_UNKNOWN: - tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN; - break; - case X509_VALIDATE_UNKNOWN_CA: - tls_reason = TLS_ALERT_UNKNOWN_CA; - break; - default: - tls_reason = TLS_ALERT_BAD_CERTIFICATE; - break; - } - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason); - x509_certificate_chain_free(chain); - return -1; - } - - x509_certificate_chain_free(chain); - - *in_len = end - in_data; - - conn->state = CLIENT_KEY_EXCHANGE; - - return 0; -} - - -static int tls_process_client_key_exchange_rsa( - struct tlsv1_server *conn, const u8 *pos, const u8 *end) -{ - u8 *out; - size_t outlen, outbuflen; - u16 encr_len; - int res; - int use_random = 0; - - if (end - pos < 2) { - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - 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 ? - outlen : TLS_PRE_MASTER_SECRET_LEN); - if (out == NULL) { - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - /* - * struct { - * ProtocolVersion client_version; - * opaque random[46]; - * } PreMasterSecret; - * - * struct { - * public-key-encrypted PreMasterSecret pre_master_secret; - * } EncryptedPreMasterSecret; - */ - - /* - * Note: To avoid Bleichenbacher attack, we do not report decryption or - * parsing errors from EncryptedPreMasterSecret processing to the - * client. Instead, a random pre-master secret is used to force the - * handshake to fail. - */ - - if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key, - pos, encr_len, - out, &outlen) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt " - "PreMasterSecret (encr_len=%u outlen=%lu)", - encr_len, (unsigned long) outlen); - use_random = 1; - } - - 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 (!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"); - use_random = 1; - } - - if (use_random) { - wpa_printf(MSG_DEBUG, "TLSv1: Using random premaster secret " - "to avoid revealing information about private key"); - outlen = TLS_PRE_MASTER_SECRET_LEN; - if (os_get_random(out, outlen)) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " - "data"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(out); - return -1; - } - } - - res = tlsv1_server_derive_keys(conn, out, outlen); - - /* Clear the pre-master secret since it is not needed anymore */ - os_memset(out, 0, outbuflen); - os_free(out); - - if (res) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - return 0; -} - - -static int tls_process_client_key_exchange_dh_anon( - struct tlsv1_server *conn, const u8 *pos, const u8 *end) -{ - const u8 *dh_yc; - u16 dh_yc_len; - u8 *shared; - size_t shared_len; - int res; - - /* - * struct { - * select (PublicValueEncoding) { - * case implicit: struct { }; - * case explicit: opaque dh_Yc<1..2^16-1>; - * } dh_public; - * } ClientDiffieHellmanPublic; - */ - - wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic", - pos, end - pos); - - if (end == pos) { - wpa_printf(MSG_DEBUG, "TLSv1: Implicit public value encoding " - "not supported"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - if (end - pos < 3) { - wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value " - "length"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - dh_yc_len = WPA_GET_BE16(pos); - dh_yc = pos + 2; - - if (dh_yc + dh_yc_len > end) { - wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow " - "(length %d)", dh_yc_len); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)", - dh_yc, dh_yc_len); - - if (conn->cred == NULL || conn->cred->dh_p == NULL || - conn->dh_secret == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - shared_len = conn->cred->dh_p_len; - shared = os_malloc(shared_len); - if (shared == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for " - "DH"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - /* shared = Yc^secret mod p */ - if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret, - conn->dh_secret_len, - conn->cred->dh_p, conn->cred->dh_p_len, - shared, &shared_len)) { - os_free(shared); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange", - shared, shared_len); - - os_memset(conn->dh_secret, 0, conn->dh_secret_len); - os_free(conn->dh_secret); - conn->dh_secret = NULL; - - res = tlsv1_server_derive_keys(conn, shared, shared_len); - - /* Clear the pre-master secret since it is not needed anymore */ - os_memset(shared, 0, shared_len); - os_free(shared); - - if (res) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - return 0; -} - - -static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct, - const u8 *in_data, size_t *in_len) -{ - const u8 *pos, *end; - size_t left, len; - u8 type; - tls_key_exchange keyx; - const struct tls_cipher_suite *suite; - - if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " - "received content type 0x%x", ct); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - if (left < 4) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange " - "(Left=%lu)", (unsigned long) left); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - type = *pos++; - len = WPA_GET_BE24(pos); - pos += 3; - left -= 4; - - if (len > left) { - wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange " - "length (len=%lu != left=%lu)", - (unsigned long) len, (unsigned long) left); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - end = pos + len; - - if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) { - wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " - "message %d (expected ClientKeyExchange)", type); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange"); - - wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len); - - suite = tls_get_cipher_suite(conn->rl.cipher_suite); - if (suite == NULL) - keyx = TLS_KEY_X_NULL; - else - keyx = suite->key_exchange; - - if (keyx == TLS_KEY_X_DH_anon && - tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0) - return -1; - - if (keyx != TLS_KEY_X_DH_anon && - tls_process_client_key_exchange_rsa(conn, pos, end) < 0) - return -1; - - *in_len = end - in_data; - - conn->state = CERTIFICATE_VERIFY; - - return 0; -} - - -static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct, - const u8 *in_data, size_t *in_len) -{ - const u8 *pos, *end; - size_t left, len; - u8 type; - size_t hlen, buflen; - u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf; - enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; - u16 slen; - - if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { - if (conn->verify_peer) { - wpa_printf(MSG_DEBUG, "TLSv1: Client did not include " - "CertificateVerify"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - return tls_process_change_cipher_spec(conn, ct, in_data, - in_len); - } - - if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " - "received content type 0x%x", ct); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - if (left < 4) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify " - "message (len=%lu)", (unsigned long) left); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - type = *pos++; - len = WPA_GET_BE24(pos); - pos += 3; - left -= 4; - - if (len > left) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify " - "message length (len=%lu != left=%lu)", - (unsigned long) len, (unsigned long) left); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - end = pos + len; - - if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) { - wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " - "message %d (expected CertificateVerify)", type); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify"); - - /* - * struct { - * Signature signature; - * } CertificateVerify; - */ - - 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 || - crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) - { - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - conn->verify.md5_cert = NULL; - crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); - conn->verify.sha1_cert = NULL; - return -1; - } - hpos += MD5_MAC_LEN; - } else - crypto_hash_finish(conn->verify.md5_cert, NULL, NULL); - - conn->verify.md5_cert = NULL; - hlen = SHA1_MAC_LEN; - if (conn->verify.sha1_cert == NULL || - crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) { - conn->verify.sha1_cert = NULL; - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - conn->verify.sha1_cert = NULL; - - 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) { - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - slen = WPA_GET_BE16(pos); - pos += 2; - if (end - pos < slen) { - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos); - if (conn->client_rsa_key == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify " - "signature"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - buflen = end - pos; - buf = os_malloc(end - pos); - if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key, - pos, end - pos, buf, &buflen) < 0) - { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature"); - os_free(buf); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECRYPT_ERROR); - return -1; - } - - 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 " - "hash"); - os_free(buf); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECRYPT_ERROR); - return -1; - } - - os_free(buf); - - *in_len = end - in_data; - - conn->state = CHANGE_CIPHER_SPEC; - - return 0; -} - - -static int tls_process_change_cipher_spec(struct tlsv1_server *conn, - u8 ct, const u8 *in_data, - size_t *in_len) -{ - const u8 *pos; - size_t left; - - if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " - "received content type 0x%x", ct); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - if (left < 1) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - if (*pos != TLS_CHANGE_CIPHER_SPEC) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " - "received data 0x%x", *pos); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec"); - if (tlsv1_record_change_read_cipher(&conn->rl) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher " - "for record layer"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - *in_len = pos + 1 - in_data; - - conn->state = CLIENT_FINISHED; - - return 0; -} - - -static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct, - const u8 *in_data, size_t *in_len) -{ - const u8 *pos, *end; - size_t left, len, hlen; - u8 verify_data[TLS_VERIFY_DATA_LEN]; - u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; - - if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; " - "received content type 0x%x", ct); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - pos = in_data; - left = *in_len; - - if (left < 4) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for " - "Finished", - (unsigned long) left); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - - if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) { - wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received " - "type 0x%x", pos[0]); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_UNEXPECTED_MESSAGE); - return -1; - } - - len = WPA_GET_BE24(pos + 1); - - pos += 4; - left -= 4; - - if (len > left) { - wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished " - "(len=%lu > left=%lu)", - (unsigned long) len, (unsigned long) left); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - end = pos + len; - if (len != TLS_VERIFY_DATA_LEN) { - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length " - "in Finished: %lu (expected %d)", - (unsigned long) len, TLS_VERIFY_DATA_LEN); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_DECODE_ERROR); - return -1; - } - 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) { - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - conn->verify.md5_client = NULL; - crypto_hash_finish(conn->verify.sha1_client, NULL, NULL); - conn->verify.sha1_client = NULL; - return -1; - } - conn->verify.md5_client = NULL; - hlen = SHA1_MAC_LEN; - if (conn->verify.sha1_client == NULL || - crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN, - &hlen) < 0) { - conn->verify.sha1_client = NULL; - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - conn->verify.sha1_client = NULL; - hlen = MD5_MAC_LEN + SHA1_MAC_LEN; - -#ifdef CONFIG_TLSV12 - } -#endif /* CONFIG_TLSV12 */ - - 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, - TLS_ALERT_DECRYPT_ERROR); - return -1; - } - wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", - verify_data, TLS_VERIFY_DATA_LEN); - - if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { - wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data"); - return -1; - } - - wpa_printf(MSG_DEBUG, "TLSv1: Received Finished"); - - *in_len = end - in_data; - - if (conn->use_session_ticket) { - /* Abbreviated handshake using session ticket; RFC 4507 */ - wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed " - "successfully"); - conn->state = ESTABLISHED; - } else { - /* Full handshake */ - conn->state = SERVER_CHANGE_CIPHER_SPEC; - } - - return 0; -} - - -int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct, - const u8 *buf, size_t *len) -{ - if (ct == TLS_CONTENT_TYPE_ALERT) { - if (*len < 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", - buf[0], buf[1]); - *len = 2; - conn->state = FAILED; - return -1; - } - - switch (conn->state) { - case CLIENT_HELLO: - if (tls_process_client_hello(conn, ct, buf, len)) - return -1; - break; - case CLIENT_CERTIFICATE: - if (tls_process_certificate(conn, ct, buf, len)) - return -1; - break; - case CLIENT_KEY_EXCHANGE: - if (tls_process_client_key_exchange(conn, ct, buf, len)) - return -1; - break; - case CERTIFICATE_VERIFY: - if (tls_process_certificate_verify(conn, ct, buf, len)) - return -1; - break; - case CHANGE_CIPHER_SPEC: - if (tls_process_change_cipher_spec(conn, ct, buf, len)) - return -1; - break; - case CLIENT_FINISHED: - if (tls_process_client_finished(conn, ct, buf, len)) - return -1; - break; - default: - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d " - "while processing received message", - conn->state); - return -1; - } - - if (ct == TLS_CONTENT_TYPE_HANDSHAKE) - tls_verify_hash_add(&conn->verify, buf, *len); - - return 0; -} diff --git a/contrib/hostapd/src/tls/tlsv1_server_write.c b/contrib/hostapd/src/tls/tlsv1_server_write.c deleted file mode 100644 index 6d8e55ed49..0000000000 --- a/contrib/hostapd/src/tls/tlsv1_server_write.c +++ /dev/null @@ -1,801 +0,0 @@ -/* - * TLSv1 server - write handshake message - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/md5.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "crypto/tls.h" -#include "crypto/random.h" -#include "x509v3.h" -#include "tlsv1_common.h" -#include "tlsv1_record.h" -#include "tlsv1_server.h" -#include "tlsv1_server_i.h" - - -static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn) -{ - size_t len = 0; - struct x509_certificate *cert; - - cert = conn->cred->cert; - while (cert) { - len += 3 + cert->cert_len; - if (x509_certificate_self_signed(cert)) - break; - cert = x509_certificate_get_subject(conn->cred->trusted_certs, - &cert->issuer); - } - - return len; -} - - -static int tls_write_server_hello(struct tlsv1_server *conn, - u8 **msgpos, u8 *end) -{ - u8 *pos, *rhdr, *hs_start, *hs_length; - struct os_time now; - size_t rlen; - - pos = *msgpos; - - wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello"); - rhdr = pos; - pos += TLS_RECORD_HEADER_LEN; - - os_get_time(&now); - WPA_PUT_BE32(conn->server_random, now.sec); - if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) { - wpa_printf(MSG_ERROR, "TLSv1: Could not generate " - "server_random"); - return -1; - } - wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random", - conn->server_random, TLS_RANDOM_LEN); - - conn->session_id_len = TLS_SESSION_ID_MAX_LEN; - if (random_get_bytes(conn->session_id, conn->session_id_len)) { - wpa_printf(MSG_ERROR, "TLSv1: Could not generate " - "session_id"); - return -1; - } - wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id", - conn->session_id, conn->session_id_len); - - /* opaque fragment[TLSPlaintext.length] */ - - /* Handshake */ - hs_start = pos; - /* HandshakeType msg_type */ - *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO; - /* uint24 length (to be filled) */ - hs_length = pos; - pos += 3; - /* body - ServerHello */ - /* ProtocolVersion server_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); - pos += TLS_RANDOM_LEN; - /* SessionID session_id */ - *pos++ = conn->session_id_len; - os_memcpy(pos, conn->session_id, conn->session_id_len); - pos += conn->session_id_len; - /* CipherSuite cipher_suite */ - WPA_PUT_BE16(pos, conn->cipher_suite); - pos += 2; - /* CompressionMethod compression_method */ - *pos++ = TLS_COMPRESSION_NULL; - - if (conn->session_ticket && conn->session_ticket_cb) { - int res = conn->session_ticket_cb( - conn->session_ticket_cb_ctx, - conn->session_ticket, conn->session_ticket_len, - conn->client_random, conn->server_random, - conn->master_secret); - if (res < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback " - "indicated failure"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_HANDSHAKE_FAILURE); - return -1; - } - conn->use_session_ticket = res; - - if (conn->use_session_ticket) { - if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to " - "derive keys"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - } - - /* - * RFC 4507 specifies that server would include an empty - * SessionTicket extension in ServerHello and a - * NewSessionTicket message after the ServerHello. However, - * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket - * extension at the moment, does not use such extensions. - * - * TODO: Add support for configuring RFC 4507 behavior and make - * EAP-FAST disable it. - */ - } - - 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, 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); - return -1; - } - pos = rhdr + rlen; - - *msgpos = pos; - - return 0; -} - - -static int tls_write_server_certificate(struct tlsv1_server *conn, - u8 **msgpos, u8 *end) -{ - u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start; - size_t rlen; - struct x509_certificate *cert; - const struct tls_cipher_suite *suite; - - suite = tls_get_cipher_suite(conn->rl.cipher_suite); - if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) { - wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when " - "using anonymous DH"); - return 0; - } - - pos = *msgpos; - - wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate"); - rhdr = pos; - pos += TLS_RECORD_HEADER_LEN; - - /* opaque fragment[TLSPlaintext.length] */ - - /* Handshake */ - hs_start = pos; - /* HandshakeType msg_type */ - *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE; - /* uint24 length (to be filled) */ - hs_length = pos; - pos += 3; - /* body - Certificate */ - /* uint24 length (to be filled) */ - cert_start = pos; - pos += 3; - cert = conn->cred->cert; - while (cert) { - if (pos + 3 + cert->cert_len > end) { - wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space " - "for Certificate (cert_len=%lu left=%lu)", - (unsigned long) cert->cert_len, - (unsigned long) (end - pos)); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - WPA_PUT_BE24(pos, cert->cert_len); - pos += 3; - os_memcpy(pos, cert->cert_start, cert->cert_len); - pos += cert->cert_len; - - if (x509_certificate_self_signed(cert)) - break; - cert = x509_certificate_get_subject(conn->cred->trusted_certs, - &cert->issuer); - } - if (cert == conn->cred->cert || cert == NULL) { - /* - * Server was not configured with all the needed certificates - * to form a full certificate chain. The client may fail to - * validate the chain unless it is configured with all the - * missing CA certificates. - */ - wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain " - "not configured - validation may fail"); - } - WPA_PUT_BE24(cert_start, pos - cert_start - 3); - - WPA_PUT_BE24(hs_length, pos - hs_length - 3); - - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - 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); - return -1; - } - pos = rhdr + rlen; - - tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); - - *msgpos = pos; - - return 0; -} - - -static int tls_write_server_key_exchange(struct tlsv1_server *conn, - u8 **msgpos, u8 *end) -{ - tls_key_exchange keyx; - const struct tls_cipher_suite *suite; - u8 *pos, *rhdr, *hs_start, *hs_length; - size_t rlen; - u8 *dh_ys; - size_t dh_ys_len; - - suite = tls_get_cipher_suite(conn->rl.cipher_suite); - if (suite == NULL) - keyx = TLS_KEY_X_NULL; - else - keyx = suite->key_exchange; - - if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) { - wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed"); - return 0; - } - - if (keyx != TLS_KEY_X_DH_anon) { - /* TODO? */ - wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet " - "supported with key exchange type %d", keyx); - return -1; - } - - if (conn->cred == NULL || conn->cred->dh_p == NULL || - conn->cred->dh_g == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for " - "ServerKeyExhcange"); - return -1; - } - - os_free(conn->dh_secret); - conn->dh_secret_len = conn->cred->dh_p_len; - conn->dh_secret = os_malloc(conn->dh_secret_len); - if (conn->dh_secret == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " - "memory for secret (Diffie-Hellman)"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - if (random_get_bytes(conn->dh_secret, conn->dh_secret_len)) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " - "data for Diffie-Hellman"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(conn->dh_secret); - conn->dh_secret = NULL; - return -1; - } - - if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) > - 0) - conn->dh_secret[0] = 0; /* make sure secret < p */ - - pos = conn->dh_secret; - while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0) - pos++; - if (pos != conn->dh_secret) { - os_memmove(conn->dh_secret, pos, - conn->dh_secret_len - (pos - conn->dh_secret)); - conn->dh_secret_len -= pos - conn->dh_secret; - } - wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value", - conn->dh_secret, conn->dh_secret_len); - - /* Ys = g^secret mod p */ - dh_ys_len = conn->cred->dh_p_len; - dh_ys = os_malloc(dh_ys_len); - if (dh_ys == NULL) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for " - "Diffie-Hellman"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len, - conn->dh_secret, conn->dh_secret_len, - conn->cred->dh_p, conn->cred->dh_p_len, - dh_ys, &dh_ys_len)) { - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(dh_ys); - return -1; - } - - wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)", - dh_ys, dh_ys_len); - - /* - * struct { - * select (KeyExchangeAlgorithm) { - * case diffie_hellman: - * ServerDHParams params; - * Signature signed_params; - * case rsa: - * ServerRSAParams params; - * Signature signed_params; - * }; - * } ServerKeyExchange; - * - * struct { - * opaque dh_p<1..2^16-1>; - * opaque dh_g<1..2^16-1>; - * opaque dh_Ys<1..2^16-1>; - * } ServerDHParams; - */ - - pos = *msgpos; - - wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange"); - rhdr = pos; - pos += TLS_RECORD_HEADER_LEN; - - /* opaque fragment[TLSPlaintext.length] */ - - /* Handshake */ - hs_start = pos; - /* HandshakeType msg_type */ - *pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE; - /* uint24 length (to be filled) */ - hs_length = pos; - pos += 3; - - /* body - ServerDHParams */ - /* dh_p */ - if (pos + 2 + conn->cred->dh_p_len > end) { - wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " - "dh_p"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(dh_ys); - return -1; - } - WPA_PUT_BE16(pos, conn->cred->dh_p_len); - pos += 2; - os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len); - pos += conn->cred->dh_p_len; - - /* dh_g */ - if (pos + 2 + conn->cred->dh_g_len > end) { - wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " - "dh_g"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(dh_ys); - return -1; - } - WPA_PUT_BE16(pos, conn->cred->dh_g_len); - pos += 2; - os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len); - pos += conn->cred->dh_g_len; - - /* dh_Ys */ - if (pos + 2 + dh_ys_len > end) { - wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " - "dh_Ys"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - os_free(dh_ys); - return -1; - } - WPA_PUT_BE16(pos, dh_ys_len); - pos += 2; - os_memcpy(pos, dh_ys, dh_ys_len); - pos += dh_ys_len; - os_free(dh_ys); - - WPA_PUT_BE24(hs_length, pos - hs_length - 3); - - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - 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); - return -1; - } - pos = rhdr + rlen; - - tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); - - *msgpos = pos; - - return 0; -} - - -static int tls_write_server_certificate_request(struct tlsv1_server *conn, - u8 **msgpos, u8 *end) -{ - u8 *pos, *rhdr, *hs_start, *hs_length; - size_t rlen; - - if (!conn->verify_peer) { - wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed"); - return 0; - } - - pos = *msgpos; - - wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest"); - rhdr = pos; - pos += TLS_RECORD_HEADER_LEN; - - /* opaque fragment[TLSPlaintext.length] */ - - /* Handshake */ - hs_start = pos; - /* HandshakeType msg_type */ - *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST; - /* uint24 length (to be filled) */ - hs_length = pos; - pos += 3; - /* body - CertificateRequest */ - - /* - * enum { - * rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), - * (255) - * } ClientCertificateType; - * ClientCertificateType certificate_types<1..2^8-1> - */ - *pos++ = 1; - *pos++ = 1; /* rsa_sign */ - - /* - * opaque DistinguishedName<1..2^16-1> - * DistinguishedName certificate_authorities<3..2^16-1> - */ - /* TODO: add support for listing DNs for trusted CAs */ - WPA_PUT_BE16(pos, 0); - pos += 2; - - WPA_PUT_BE24(hs_length, pos - hs_length - 3); - - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - 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); - return -1; - } - pos = rhdr + rlen; - - tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); - - *msgpos = pos; - - return 0; -} - - -static int tls_write_server_hello_done(struct tlsv1_server *conn, - u8 **msgpos, u8 *end) -{ - u8 *pos; - size_t rlen; - u8 payload[4]; - - wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone"); - - /* opaque fragment[TLSPlaintext.length] */ - - /* Handshake */ - pos = payload; - /* HandshakeType msg_type */ - *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE; - /* uint24 length */ - WPA_PUT_BE24(pos, 0); - pos += 3; - /* body - ServerHelloDone (empty) */ - - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - *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; - } - - tls_verify_hash_add(&conn->verify, payload, pos - payload); - - *msgpos += rlen; - - return 0; -} - - -static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn, - u8 **msgpos, u8 *end) -{ - size_t rlen; - u8 payload[1]; - - wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec"); - - payload[0] = TLS_CHANGE_CIPHER_SPEC; - - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC, - *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); - return -1; - } - - if (tlsv1_record_change_write_cipher(&conn->rl) < 0) { - wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for " - "record layer"); - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - - *msgpos += rlen; - - return 0; -} - - -static int tls_write_server_finished(struct tlsv1_server *conn, - u8 **msgpos, u8 *end) -{ - u8 *pos, *hs_start; - size_t rlen, hlen; - 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_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) { - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - conn->verify.md5_server = NULL; - crypto_hash_finish(conn->verify.sha1_server, NULL, NULL); - conn->verify.sha1_server = NULL; - return -1; - } - conn->verify.md5_server = NULL; - hlen = SHA1_MAC_LEN; - if (conn->verify.sha1_server == NULL || - crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN, - &hlen) < 0) { - conn->verify.sha1_server = NULL; - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - return -1; - } - conn->verify.sha1_server = NULL; - hlen = MD5_MAC_LEN + SHA1_MAC_LEN; - -#ifdef CONFIG_TLSV12 - } -#endif /* CONFIG_TLSV12 */ - - 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 + 1 + 3, TLS_VERIFY_DATA_LEN); - - /* Handshake */ - pos = hs_start = verify_data; - /* HandshakeType msg_type */ - *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; - /* uint24 length */ - WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN); - pos += 3; - pos += TLS_VERIFY_DATA_LEN; - tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); - - if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, - *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; - } - - *msgpos += rlen; - - return 0; -} - - -static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len) -{ - u8 *msg, *end, *pos; - size_t msglen; - - *out_len = 0; - - msglen = 1000 + tls_server_cert_chain_der_len(conn); - - msg = os_malloc(msglen); - if (msg == NULL) - return NULL; - - pos = msg; - end = msg + msglen; - - if (tls_write_server_hello(conn, &pos, end) < 0) { - os_free(msg); - return NULL; - } - - if (conn->use_session_ticket) { - /* Abbreviated handshake using session ticket; RFC 4507 */ - if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 || - tls_write_server_finished(conn, &pos, end) < 0) { - os_free(msg); - return NULL; - } - - *out_len = pos - msg; - - conn->state = CHANGE_CIPHER_SPEC; - - return msg; - } - - /* Full handshake */ - if (tls_write_server_certificate(conn, &pos, end) < 0 || - tls_write_server_key_exchange(conn, &pos, end) < 0 || - tls_write_server_certificate_request(conn, &pos, end) < 0 || - tls_write_server_hello_done(conn, &pos, end) < 0) { - os_free(msg); - return NULL; - } - - *out_len = pos - msg; - - conn->state = CLIENT_CERTIFICATE; - - return msg; -} - - -static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn, - size_t *out_len) -{ - u8 *msg, *end, *pos; - - *out_len = 0; - - msg = os_malloc(1000); - if (msg == NULL) - return NULL; - - pos = msg; - end = msg + 1000; - - if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 || - tls_write_server_finished(conn, &pos, end) < 0) { - os_free(msg); - return NULL; - } - - *out_len = pos - msg; - - wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully"); - conn->state = ESTABLISHED; - - return msg; -} - - -u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len) -{ - switch (conn->state) { - case SERVER_HELLO: - return tls_send_server_hello(conn, out_len); - case SERVER_CHANGE_CIPHER_SPEC: - return tls_send_change_cipher_spec(conn, out_len); - default: - if (conn->state == ESTABLISHED && conn->use_session_ticket) { - /* Abbreviated handshake was already completed. */ - return NULL; - } - wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while " - "generating reply", conn->state); - return NULL; - } -} - - -u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level, - u8 description, size_t *out_len) -{ - u8 *alert, *pos, *length; - - wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description); - *out_len = 0; - - alert = os_malloc(10); - if (alert == NULL) - return NULL; - - pos = alert; - - /* TLSPlaintext */ - /* ContentType type */ - *pos++ = TLS_CONTENT_TYPE_ALERT; - /* ProtocolVersion version */ - WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version : - TLS_VERSION); - pos += 2; - /* uint16 length (to be filled) */ - length = pos; - pos += 2; - /* opaque fragment[TLSPlaintext.length] */ - - /* Alert */ - /* AlertLevel level */ - *pos++ = level; - /* AlertDescription description */ - *pos++ = description; - - WPA_PUT_BE16(length, pos - length - 2); - *out_len = pos - alert; - - return alert; -} diff --git a/contrib/hostapd/src/tls/x509v3.c b/contrib/hostapd/src/tls/x509v3.c deleted file mode 100644 index 06540bffd6..0000000000 --- a/contrib/hostapd/src/tls/x509v3.c +++ /dev/null @@ -1,1979 +0,0 @@ -/* - * X.509v3 certificate parsing and processing (RFC 3280 profile) - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/crypto.h" -#include "asn1.h" -#include "x509v3.h" - - -static void x509_free_name(struct x509_name *name) -{ - size_t i; - - for (i = 0; i < name->num_attr; i++) { - os_free(name->attr[i].value); - name->attr[i].value = NULL; - name->attr[i].type = X509_NAME_ATTR_NOT_USED; - } - name->num_attr = 0; - os_free(name->email); - name->email = NULL; - - os_free(name->alt_email); - os_free(name->dns); - os_free(name->uri); - os_free(name->ip); - name->alt_email = name->dns = name->uri = NULL; - name->ip = NULL; - name->ip_len = 0; - os_memset(&name->rid, 0, sizeof(name->rid)); -} - - -/** - * x509_certificate_free - Free an X.509 certificate - * @cert: Certificate to be freed - */ -void x509_certificate_free(struct x509_certificate *cert) -{ - if (cert == NULL) - return; - if (cert->next) { - wpa_printf(MSG_DEBUG, "X509: x509_certificate_free: cer=%p " - "was still on a list (next=%p)\n", - cert, cert->next); - } - x509_free_name(&cert->issuer); - x509_free_name(&cert->subject); - os_free(cert->public_key); - os_free(cert->sign_value); - os_free(cert); -} - - -/** - * x509_certificate_free - Free an X.509 certificate chain - * @cert: Pointer to the first certificate in the chain - */ -void x509_certificate_chain_free(struct x509_certificate *cert) -{ - struct x509_certificate *next; - - while (cert) { - next = cert->next; - cert->next = NULL; - x509_certificate_free(cert); - cert = next; - } -} - - -static int x509_whitespace(char c) -{ - return c == ' ' || c == '\t'; -} - - -static void x509_str_strip_whitespace(char *a) -{ - char *ipos, *opos; - int remove_whitespace = 1; - - ipos = opos = a; - - while (*ipos) { - if (remove_whitespace && x509_whitespace(*ipos)) - ipos++; - else { - remove_whitespace = x509_whitespace(*ipos); - *opos++ = *ipos++; - } - } - - *opos-- = '\0'; - if (opos > a && x509_whitespace(*opos)) - *opos = '\0'; -} - - -static int x509_str_compare(const char *a, const char *b) -{ - char *aa, *bb; - int ret; - - if (!a && b) - return -1; - if (a && !b) - return 1; - if (!a && !b) - return 0; - - aa = os_strdup(a); - bb = os_strdup(b); - - if (aa == NULL || bb == NULL) { - os_free(aa); - os_free(bb); - return os_strcasecmp(a, b); - } - - x509_str_strip_whitespace(aa); - x509_str_strip_whitespace(bb); - - ret = os_strcasecmp(aa, bb); - - os_free(aa); - os_free(bb); - - return ret; -} - - -/** - * x509_name_compare - Compare X.509 certificate names - * @a: Certificate name - * @b: Certificate name - * Returns: <0, 0, or >0 based on whether a is less than, equal to, or - * greater than b - */ -int x509_name_compare(struct x509_name *a, struct x509_name *b) -{ - int res; - size_t i; - - if (!a && b) - return -1; - if (a && !b) - return 1; - if (!a && !b) - return 0; - if (a->num_attr < b->num_attr) - return -1; - if (a->num_attr > b->num_attr) - return 1; - - for (i = 0; i < a->num_attr; i++) { - if (a->attr[i].type < b->attr[i].type) - return -1; - if (a->attr[i].type > b->attr[i].type) - return -1; - res = x509_str_compare(a->attr[i].value, b->attr[i].value); - if (res) - return res; - } - res = x509_str_compare(a->email, b->email); - if (res) - return res; - - return 0; -} - - -static int x509_parse_algorithm_identifier( - const u8 *buf, size_t len, - struct x509_algorithm_identifier *id, const u8 **next) -{ - struct asn1_hdr hdr; - const u8 *pos, *end; - - /* - * AlgorithmIdentifier ::= SEQUENCE { - * algorithm OBJECT IDENTIFIER, - * parameters ANY DEFINED BY algorithm OPTIONAL - * } - */ - - if (asn1_get_next(buf, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " - "(AlgorithmIdentifier) - found class %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - pos = hdr.payload; - end = pos + hdr.length; - - if (end > buf + len) - return -1; - - *next = end; - - if (asn1_get_oid(pos, end - pos, &id->oid, &pos)) - return -1; - - /* TODO: optional parameters */ - - return 0; -} - - -static int x509_parse_public_key(const u8 *buf, size_t len, - struct x509_certificate *cert, - const u8 **next) -{ - struct asn1_hdr hdr; - const u8 *pos, *end; - - /* - * SubjectPublicKeyInfo ::= SEQUENCE { - * algorithm AlgorithmIdentifier, - * subjectPublicKey BIT STRING - * } - */ - - pos = buf; - end = buf + len; - - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " - "(SubjectPublicKeyInfo) - found class %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - pos = hdr.payload; - - if (pos + hdr.length > end) - return -1; - end = pos + hdr.length; - *next = end; - - if (x509_parse_algorithm_identifier(pos, end - pos, - &cert->public_key_alg, &pos)) - return -1; - - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_BITSTRING) { - wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING " - "(subjectPublicKey) - found class %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - if (hdr.length < 1) - return -1; - pos = hdr.payload; - if (*pos) { - wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits", - *pos); - /* - * TODO: should this be rejected? X.509 certificates are - * unlikely to use such a construction. Now we would end up - * including the extra bits in the buffer which may also be - * ok. - */ - } - os_free(cert->public_key); - cert->public_key = os_malloc(hdr.length - 1); - if (cert->public_key == NULL) { - wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for " - "public key"); - return -1; - } - os_memcpy(cert->public_key, pos + 1, hdr.length - 1); - cert->public_key_len = hdr.length - 1; - wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey", - cert->public_key, cert->public_key_len); - - return 0; -} - - -static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, - const u8 **next) -{ - struct asn1_hdr hdr; - const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end; - struct asn1_oid oid; - char *val; - - /* - * Name ::= CHOICE { RDNSequence } - * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName - * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue - * AttributeTypeAndValue ::= SEQUENCE { - * type AttributeType, - * value AttributeValue - * } - * AttributeType ::= OBJECT IDENTIFIER - * AttributeValue ::= ANY DEFINED BY AttributeType - */ - - if (asn1_get_next(buf, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " - "(Name / RDNSequencer) - found class %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - pos = hdr.payload; - - if (pos + hdr.length > buf + len) - return -1; - - end = *next = pos + hdr.length; - - while (pos < end) { - enum x509_name_attr_type type; - - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SET) { - wpa_printf(MSG_DEBUG, "X509: Expected SET " - "(RelativeDistinguishedName) - found class " - "%d tag 0x%x", hdr.class, hdr.tag); - x509_free_name(name); - return -1; - } - - set_pos = hdr.payload; - pos = set_end = hdr.payload + hdr.length; - - if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " - "(AttributeTypeAndValue) - found class %d " - "tag 0x%x", hdr.class, hdr.tag); - x509_free_name(name); - return -1; - } - - seq_pos = hdr.payload; - seq_end = hdr.payload + hdr.length; - - if (asn1_get_oid(seq_pos, seq_end - seq_pos, &oid, &seq_pos)) { - x509_free_name(name); - return -1; - } - - if (asn1_get_next(seq_pos, seq_end - seq_pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL) { - wpa_printf(MSG_DEBUG, "X509: Failed to parse " - "AttributeValue"); - x509_free_name(name); - return -1; - } - - /* RFC 3280: - * MUST: country, organization, organizational-unit, - * distinguished name qualifier, state or province name, - * common name, serial number. - * SHOULD: locality, title, surname, given name, initials, - * pseudonym, generation qualifier. - * MUST: domainComponent (RFC 2247). - */ - type = X509_NAME_ATTR_NOT_USED; - if (oid.len == 4 && - oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) { - /* id-at ::= 2.5.4 */ - switch (oid.oid[3]) { - case 3: - /* commonName */ - type = X509_NAME_ATTR_CN; - break; - case 6: - /* countryName */ - type = X509_NAME_ATTR_C; - break; - case 7: - /* localityName */ - type = X509_NAME_ATTR_L; - break; - case 8: - /* stateOrProvinceName */ - type = X509_NAME_ATTR_ST; - break; - case 10: - /* organizationName */ - type = X509_NAME_ATTR_O; - break; - case 11: - /* organizationalUnitName */ - type = X509_NAME_ATTR_OU; - break; - } - } else if (oid.len == 7 && - oid.oid[0] == 1 && oid.oid[1] == 2 && - oid.oid[2] == 840 && oid.oid[3] == 113549 && - oid.oid[4] == 1 && oid.oid[5] == 9 && - oid.oid[6] == 1) { - /* 1.2.840.113549.1.9.1 - e-mailAddress */ - os_free(name->email); - name->email = os_malloc(hdr.length + 1); - if (name->email == NULL) { - x509_free_name(name); - return -1; - } - os_memcpy(name->email, hdr.payload, hdr.length); - name->email[hdr.length] = '\0'; - continue; - } else if (oid.len == 7 && - oid.oid[0] == 0 && oid.oid[1] == 9 && - oid.oid[2] == 2342 && oid.oid[3] == 19200300 && - oid.oid[4] == 100 && oid.oid[5] == 1 && - oid.oid[6] == 25) { - /* 0.9.2342.19200300.100.1.25 - domainComponent */ - type = X509_NAME_ATTR_DC; - } - - if (type == X509_NAME_ATTR_NOT_USED) { - wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID", - (u8 *) oid.oid, - oid.len * sizeof(oid.oid[0])); - wpa_hexdump_ascii(MSG_MSGDUMP, "X509: Attribute Data", - hdr.payload, hdr.length); - continue; - } - - if (name->num_attr == X509_MAX_NAME_ATTRIBUTES) { - wpa_printf(MSG_INFO, "X509: Too many Name attributes"); - x509_free_name(name); - return -1; - } - - val = dup_binstr(hdr.payload, hdr.length); - if (val == NULL) { - x509_free_name(name); - return -1; - } - if (os_strlen(val) != hdr.length) { - wpa_printf(MSG_INFO, "X509: Reject certificate with " - "embedded NUL byte in a string (%s[NUL])", - val); - os_free(val); - x509_free_name(name); - return -1; - } - - name->attr[name->num_attr].type = type; - name->attr[name->num_attr].value = val; - name->num_attr++; - } - - return 0; -} - - -static char * x509_name_attr_str(enum x509_name_attr_type type) -{ - switch (type) { - case X509_NAME_ATTR_NOT_USED: - return "[N/A]"; - case X509_NAME_ATTR_DC: - return "DC"; - case X509_NAME_ATTR_CN: - return "CN"; - case X509_NAME_ATTR_C: - return "C"; - case X509_NAME_ATTR_L: - return "L"; - case X509_NAME_ATTR_ST: - return "ST"; - case X509_NAME_ATTR_O: - return "O"; - case X509_NAME_ATTR_OU: - return "OU"; - } - return "?"; -} - - -/** - * x509_name_string - Convert an X.509 certificate name into a string - * @name: Name to convert - * @buf: Buffer for the string - * @len: Maximum buffer length - */ -void x509_name_string(struct x509_name *name, char *buf, size_t len) -{ - char *pos, *end; - int ret; - size_t i; - - if (len == 0) - return; - - pos = buf; - end = buf + len; - - for (i = 0; i < name->num_attr; i++) { - ret = os_snprintf(pos, end - pos, "%s=%s, ", - x509_name_attr_str(name->attr[i].type), - name->attr[i].value); - if (ret < 0 || ret >= end - pos) - goto done; - pos += ret; - } - - if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') { - pos--; - *pos = '\0'; - pos--; - *pos = '\0'; - } - - if (name->email) { - ret = os_snprintf(pos, end - pos, "/emailAddress=%s", - name->email); - if (ret < 0 || ret >= end - pos) - goto done; - pos += ret; - } - -done: - end[-1] = '\0'; -} - - -static int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, - os_time_t *val) -{ - const char *pos; - int year, month, day, hour, min, sec; - - /* - * Time ::= CHOICE { - * utcTime UTCTime, - * generalTime GeneralizedTime - * } - * - * UTCTime: YYMMDDHHMMSSZ - * GeneralizedTime: YYYYMMDDHHMMSSZ - */ - - pos = (const char *) buf; - - switch (asn1_tag) { - case ASN1_TAG_UTCTIME: - if (len != 13 || buf[12] != 'Z') { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " - "UTCTime format", buf, len); - return -1; - } - if (sscanf(pos, "%02d", &year) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " - "UTCTime year", buf, len); - return -1; - } - if (year < 50) - year += 2000; - else - year += 1900; - pos += 2; - break; - case ASN1_TAG_GENERALIZEDTIME: - if (len != 15 || buf[14] != 'Z') { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " - "GeneralizedTime format", buf, len); - return -1; - } - if (sscanf(pos, "%04d", &year) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " - "GeneralizedTime year", buf, len); - return -1; - } - pos += 4; - break; - default: - wpa_printf(MSG_DEBUG, "X509: Expected UTCTime or " - "GeneralizedTime - found tag 0x%x", asn1_tag); - return -1; - } - - if (sscanf(pos, "%02d", &month) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " - "(month)", buf, len); - return -1; - } - pos += 2; - - if (sscanf(pos, "%02d", &day) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " - "(day)", buf, len); - return -1; - } - pos += 2; - - if (sscanf(pos, "%02d", &hour) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " - "(hour)", buf, len); - return -1; - } - pos += 2; - - if (sscanf(pos, "%02d", &min) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " - "(min)", buf, len); - return -1; - } - pos += 2; - - if (sscanf(pos, "%02d", &sec) != 1) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " - "(sec)", buf, len); - return -1; - } - - if (os_mktime(year, month, day, hour, min, sec, val) < 0) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time", - buf, len); - if (year < 1970) { - /* - * At least some test certificates have been configured - * to use dates prior to 1970. Set the date to - * beginning of 1970 to handle these case. - */ - wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - " - "assume epoch as the time", year); - *val = 0; - return 0; - } - return -1; - } - - return 0; -} - - -static int x509_parse_validity(const u8 *buf, size_t len, - struct x509_certificate *cert, const u8 **next) -{ - struct asn1_hdr hdr; - const u8 *pos; - size_t plen; - - /* - * Validity ::= SEQUENCE { - * notBefore Time, - * notAfter Time - * } - * - * RFC 3280, 4.1.2.5: - * CAs conforming to this profile MUST always encode certificate - * validity dates through the year 2049 as UTCTime; certificate - * validity dates in 2050 or later MUST be encoded as GeneralizedTime. - */ - - if (asn1_get_next(buf, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " - "(Validity) - found class %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - pos = hdr.payload; - plen = hdr.length; - - if (pos + plen > buf + len) - return -1; - - *next = pos + plen; - - if (asn1_get_next(pos, plen, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - x509_parse_time(hdr.payload, hdr.length, hdr.tag, - &cert->not_before) < 0) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notBefore " - "Time", hdr.payload, hdr.length); - return -1; - } - - pos = hdr.payload + hdr.length; - plen = *next - pos; - - if (asn1_get_next(pos, plen, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - x509_parse_time(hdr.payload, hdr.length, hdr.tag, - &cert->not_after) < 0) { - wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notAfter " - "Time", hdr.payload, hdr.length); - return -1; - } - - wpa_printf(MSG_MSGDUMP, "X509: Validity: notBefore: %lu notAfter: %lu", - (unsigned long) cert->not_before, - (unsigned long) cert->not_after); - - return 0; -} - - -static int x509_id_ce_oid(struct asn1_oid *oid) -{ - /* id-ce arc from X.509 for standard X.509v3 extensions */ - return oid->len >= 4 && - oid->oid[0] == 2 /* joint-iso-ccitt */ && - oid->oid[1] == 5 /* ds */ && - oid->oid[2] == 29 /* id-ce */; -} - - -static int x509_parse_ext_key_usage(struct x509_certificate *cert, - const u8 *pos, size_t len) -{ - struct asn1_hdr hdr; - - /* - * KeyUsage ::= BIT STRING { - * digitalSignature (0), - * nonRepudiation (1), - * keyEncipherment (2), - * dataEncipherment (3), - * keyAgreement (4), - * keyCertSign (5), - * cRLSign (6), - * encipherOnly (7), - * decipherOnly (8) } - */ - - if (asn1_get_next(pos, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_BITSTRING || - hdr.length < 1) { - wpa_printf(MSG_DEBUG, "X509: Expected BIT STRING in " - "KeyUsage; found %d tag 0x%x len %d", - hdr.class, hdr.tag, hdr.length); - return -1; - } - - cert->extensions_present |= X509_EXT_KEY_USAGE; - cert->key_usage = asn1_bit_string_to_long(hdr.payload, hdr.length); - - wpa_printf(MSG_DEBUG, "X509: KeyUsage 0x%lx", cert->key_usage); - - return 0; -} - - -static int x509_parse_ext_basic_constraints(struct x509_certificate *cert, - const u8 *pos, size_t len) -{ - struct asn1_hdr hdr; - unsigned long value; - size_t left; - - /* - * BasicConstraints ::= SEQUENCE { - * cA BOOLEAN DEFAULT FALSE, - * pathLenConstraint INTEGER (0..MAX) OPTIONAL } - */ - - if (asn1_get_next(pos, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " - "BasicConstraints; found %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - - cert->extensions_present |= X509_EXT_BASIC_CONSTRAINTS; - - if (hdr.length == 0) - return 0; - - if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL) { - wpa_printf(MSG_DEBUG, "X509: Failed to parse " - "BasicConstraints"); - return -1; - } - - if (hdr.tag == ASN1_TAG_BOOLEAN) { - if (hdr.length != 1) { - wpa_printf(MSG_DEBUG, "X509: Unexpected " - "Boolean length (%u) in BasicConstraints", - hdr.length); - return -1; - } - cert->ca = hdr.payload[0]; - - if (hdr.payload + hdr.length == pos + len) { - wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d", - cert->ca); - return 0; - } - - if (asn1_get_next(hdr.payload + hdr.length, len - hdr.length, - &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL) { - wpa_printf(MSG_DEBUG, "X509: Failed to parse " - "BasicConstraints"); - return -1; - } - } - - if (hdr.tag != ASN1_TAG_INTEGER) { - wpa_printf(MSG_DEBUG, "X509: Expected INTEGER in " - "BasicConstraints; found class %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - - pos = hdr.payload; - left = hdr.length; - value = 0; - while (left) { - value <<= 8; - value |= *pos++; - left--; - } - - cert->path_len_constraint = value; - cert->extensions_present |= X509_EXT_PATH_LEN_CONSTRAINT; - - wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d " - "pathLenConstraint=%lu", - cert->ca, cert->path_len_constraint); - - return 0; -} - - -static int x509_parse_alt_name_rfc8222(struct x509_name *name, - const u8 *pos, size_t len) -{ - /* rfc822Name IA5String */ - wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - rfc822Name", pos, len); - os_free(name->alt_email); - name->alt_email = os_zalloc(len + 1); - if (name->alt_email == NULL) - return -1; - os_memcpy(name->alt_email, pos, len); - if (os_strlen(name->alt_email) != len) { - wpa_printf(MSG_INFO, "X509: Reject certificate with " - "embedded NUL byte in rfc822Name (%s[NUL])", - name->alt_email); - os_free(name->alt_email); - name->alt_email = NULL; - return -1; - } - return 0; -} - - -static int x509_parse_alt_name_dns(struct x509_name *name, - const u8 *pos, size_t len) -{ - /* dNSName IA5String */ - wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - dNSName", pos, len); - os_free(name->dns); - name->dns = os_zalloc(len + 1); - if (name->dns == NULL) - return -1; - os_memcpy(name->dns, pos, len); - if (os_strlen(name->dns) != len) { - wpa_printf(MSG_INFO, "X509: Reject certificate with " - "embedded NUL byte in dNSName (%s[NUL])", - name->dns); - os_free(name->dns); - name->dns = NULL; - return -1; - } - return 0; -} - - -static int x509_parse_alt_name_uri(struct x509_name *name, - const u8 *pos, size_t len) -{ - /* uniformResourceIdentifier IA5String */ - wpa_hexdump_ascii(MSG_MSGDUMP, - "X509: altName - uniformResourceIdentifier", - pos, len); - os_free(name->uri); - name->uri = os_zalloc(len + 1); - if (name->uri == NULL) - return -1; - os_memcpy(name->uri, pos, len); - if (os_strlen(name->uri) != len) { - wpa_printf(MSG_INFO, "X509: Reject certificate with " - "embedded NUL byte in uniformResourceIdentifier " - "(%s[NUL])", name->uri); - os_free(name->uri); - name->uri = NULL; - return -1; - } - return 0; -} - - -static int x509_parse_alt_name_ip(struct x509_name *name, - const u8 *pos, size_t len) -{ - /* iPAddress OCTET STRING */ - wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len); - os_free(name->ip); - name->ip = os_malloc(len); - if (name->ip == NULL) - return -1; - os_memcpy(name->ip, pos, len); - name->ip_len = len; - return 0; -} - - -static int x509_parse_alt_name_rid(struct x509_name *name, - const u8 *pos, size_t len) -{ - char buf[80]; - - /* registeredID OBJECT IDENTIFIER */ - if (asn1_parse_oid(pos, len, &name->rid) < 0) - return -1; - - asn1_oid_to_str(&name->rid, buf, sizeof(buf)); - wpa_printf(MSG_MSGDUMP, "X509: altName - registeredID: %s", buf); - - return 0; -} - - -static int x509_parse_ext_alt_name(struct x509_name *name, - const u8 *pos, size_t len) -{ - struct asn1_hdr hdr; - const u8 *p, *end; - - /* - * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName - * - * GeneralName ::= CHOICE { - * otherName [0] OtherName, - * rfc822Name [1] IA5String, - * dNSName [2] IA5String, - * x400Address [3] ORAddress, - * directoryName [4] Name, - * ediPartyName [5] EDIPartyName, - * uniformResourceIdentifier [6] IA5String, - * iPAddress [7] OCTET STRING, - * registeredID [8] OBJECT IDENTIFIER } - * - * OtherName ::= SEQUENCE { - * type-id OBJECT IDENTIFIER, - * value [0] EXPLICIT ANY DEFINED BY type-id } - * - * EDIPartyName ::= SEQUENCE { - * nameAssigner [0] DirectoryString OPTIONAL, - * partyName [1] DirectoryString } - */ - - for (p = pos, end = pos + len; p < end; p = hdr.payload + hdr.length) { - int res; - - if (asn1_get_next(p, end - p, &hdr) < 0) { - wpa_printf(MSG_DEBUG, "X509: Failed to parse " - "SubjectAltName item"); - return -1; - } - - if (hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) - continue; - - switch (hdr.tag) { - case 1: - res = x509_parse_alt_name_rfc8222(name, hdr.payload, - hdr.length); - break; - case 2: - res = x509_parse_alt_name_dns(name, hdr.payload, - hdr.length); - break; - case 6: - res = x509_parse_alt_name_uri(name, hdr.payload, - hdr.length); - break; - case 7: - res = x509_parse_alt_name_ip(name, hdr.payload, - hdr.length); - break; - case 8: - res = x509_parse_alt_name_rid(name, hdr.payload, - hdr.length); - break; - case 0: /* TODO: otherName */ - case 3: /* TODO: x500Address */ - case 4: /* TODO: directoryName */ - case 5: /* TODO: ediPartyName */ - default: - res = 0; - break; - } - if (res < 0) - return res; - } - - return 0; -} - - -static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert, - const u8 *pos, size_t len) -{ - struct asn1_hdr hdr; - - /* SubjectAltName ::= GeneralNames */ - - if (asn1_get_next(pos, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " - "SubjectAltName; found %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - - wpa_printf(MSG_DEBUG, "X509: SubjectAltName"); - cert->extensions_present |= X509_EXT_SUBJECT_ALT_NAME; - - if (hdr.length == 0) - return 0; - - return x509_parse_ext_alt_name(&cert->subject, hdr.payload, - hdr.length); -} - - -static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert, - const u8 *pos, size_t len) -{ - struct asn1_hdr hdr; - - /* IssuerAltName ::= GeneralNames */ - - if (asn1_get_next(pos, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " - "IssuerAltName; found %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - - wpa_printf(MSG_DEBUG, "X509: IssuerAltName"); - cert->extensions_present |= X509_EXT_ISSUER_ALT_NAME; - - if (hdr.length == 0) - return 0; - - return x509_parse_ext_alt_name(&cert->issuer, hdr.payload, - hdr.length); -} - - -static int x509_parse_extension_data(struct x509_certificate *cert, - struct asn1_oid *oid, - const u8 *pos, size_t len) -{ - if (!x509_id_ce_oid(oid)) - return 1; - - /* TODO: add other extensions required by RFC 3280, Ch 4.2: - * certificate policies (section 4.2.1.5) - * name constraints (section 4.2.1.11) - * policy constraints (section 4.2.1.12) - * extended key usage (section 4.2.1.13) - * inhibit any-policy (section 4.2.1.15) - */ - switch (oid->oid[3]) { - case 15: /* id-ce-keyUsage */ - return x509_parse_ext_key_usage(cert, pos, len); - case 17: /* id-ce-subjectAltName */ - return x509_parse_ext_subject_alt_name(cert, pos, len); - case 18: /* id-ce-issuerAltName */ - return x509_parse_ext_issuer_alt_name(cert, pos, len); - case 19: /* id-ce-basicConstraints */ - return x509_parse_ext_basic_constraints(cert, pos, len); - default: - return 1; - } -} - - -static int x509_parse_extension(struct x509_certificate *cert, - const u8 *pos, size_t len, const u8 **next) -{ - const u8 *end; - struct asn1_hdr hdr; - struct asn1_oid oid; - int critical_ext = 0, res; - char buf[80]; - - /* - * Extension ::= SEQUENCE { - * extnID OBJECT IDENTIFIER, - * critical BOOLEAN DEFAULT FALSE, - * extnValue OCTET STRING - * } - */ - - if (asn1_get_next(pos, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in " - "Extensions: class %d tag 0x%x; expected SEQUENCE", - hdr.class, hdr.tag); - return -1; - } - pos = hdr.payload; - *next = end = pos + hdr.length; - - if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) { - wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data for " - "Extension (expected OID)"); - return -1; - } - - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - (hdr.tag != ASN1_TAG_BOOLEAN && - hdr.tag != ASN1_TAG_OCTETSTRING)) { - wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in " - "Extensions: class %d tag 0x%x; expected BOOLEAN " - "or OCTET STRING", hdr.class, hdr.tag); - return -1; - } - - if (hdr.tag == ASN1_TAG_BOOLEAN) { - if (hdr.length != 1) { - wpa_printf(MSG_DEBUG, "X509: Unexpected " - "Boolean length (%u)", hdr.length); - return -1; - } - critical_ext = hdr.payload[0]; - pos = hdr.payload; - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - (hdr.class != ASN1_CLASS_UNIVERSAL && - hdr.class != ASN1_CLASS_PRIVATE) || - hdr.tag != ASN1_TAG_OCTETSTRING) { - wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header " - "in Extensions: class %d tag 0x%x; " - "expected OCTET STRING", - hdr.class, hdr.tag); - return -1; - } - } - - asn1_oid_to_str(&oid, buf, sizeof(buf)); - wpa_printf(MSG_DEBUG, "X509: Extension: extnID=%s critical=%d", - buf, critical_ext); - wpa_hexdump(MSG_MSGDUMP, "X509: extnValue", hdr.payload, hdr.length); - - res = x509_parse_extension_data(cert, &oid, hdr.payload, hdr.length); - if (res < 0) - return res; - if (res == 1 && critical_ext) { - wpa_printf(MSG_INFO, "X509: Unknown critical extension %s", - buf); - return -1; - } - - return 0; -} - - -static int x509_parse_extensions(struct x509_certificate *cert, - const u8 *pos, size_t len) -{ - const u8 *end; - struct asn1_hdr hdr; - - /* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */ - - if (asn1_get_next(pos, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data " - "for Extensions: class %d tag 0x%x; " - "expected SEQUENCE", hdr.class, hdr.tag); - return -1; - } - - pos = hdr.payload; - end = pos + hdr.length; - - while (pos < end) { - if (x509_parse_extension(cert, pos, end - pos, &pos) - < 0) - return -1; - } - - return 0; -} - - -static int x509_parse_tbs_certificate(const u8 *buf, size_t len, - struct x509_certificate *cert, - const u8 **next) -{ - struct asn1_hdr hdr; - const u8 *pos, *end; - size_t left; - char sbuf[128]; - unsigned long value; - - /* tbsCertificate TBSCertificate ::= SEQUENCE */ - if (asn1_get_next(buf, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: tbsCertificate did not start " - "with a valid SEQUENCE - found class %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - pos = hdr.payload; - end = *next = pos + hdr.length; - - /* - * version [0] EXPLICIT Version DEFAULT v1 - * Version ::= INTEGER { v1(0), v2(1), v3(2) } - */ - if (asn1_get_next(pos, end - pos, &hdr) < 0) - return -1; - pos = hdr.payload; - - if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC) { - if (asn1_get_next(pos, end - pos, &hdr) < 0) - return -1; - - if (hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_INTEGER) { - wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for " - "version field - found class %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - if (hdr.length != 1) { - wpa_printf(MSG_DEBUG, "X509: Unexpected version field " - "length %u (expected 1)", hdr.length); - return -1; - } - pos = hdr.payload; - left = hdr.length; - value = 0; - while (left) { - value <<= 8; - value |= *pos++; - left--; - } - - cert->version = value; - if (cert->version != X509_CERT_V1 && - cert->version != X509_CERT_V2 && - cert->version != X509_CERT_V3) { - wpa_printf(MSG_DEBUG, "X509: Unsupported version %d", - cert->version + 1); - return -1; - } - - if (asn1_get_next(pos, end - pos, &hdr) < 0) - return -1; - } else - cert->version = X509_CERT_V1; - wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1); - - /* serialNumber CertificateSerialNumber ::= INTEGER */ - if (hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_INTEGER) { - wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for " - "serialNumber; class=%d tag=0x%x", - hdr.class, hdr.tag); - return -1; - } - - pos = hdr.payload; - left = hdr.length; - while (left) { - cert->serial_number <<= 8; - cert->serial_number |= *pos++; - left--; - } - wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number); - - /* signature AlgorithmIdentifier */ - if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature, - &pos)) - return -1; - - /* issuer Name */ - if (x509_parse_name(pos, end - pos, &cert->issuer, &pos)) - return -1; - x509_name_string(&cert->issuer, sbuf, sizeof(sbuf)); - wpa_printf(MSG_MSGDUMP, "X509: issuer %s", sbuf); - - /* validity Validity */ - if (x509_parse_validity(pos, end - pos, cert, &pos)) - return -1; - - /* subject Name */ - if (x509_parse_name(pos, end - pos, &cert->subject, &pos)) - return -1; - x509_name_string(&cert->subject, sbuf, sizeof(sbuf)); - wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf); - - /* subjectPublicKeyInfo SubjectPublicKeyInfo */ - if (x509_parse_public_key(pos, end - pos, cert, &pos)) - return -1; - - if (pos == end) - return 0; - - if (cert->version == X509_CERT_V1) - return 0; - - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { - wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" - " tag to parse optional tbsCertificate " - "field(s); parsed class %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - - if (hdr.tag == 1) { - /* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL */ - wpa_printf(MSG_DEBUG, "X509: issuerUniqueID"); - /* TODO: parse UniqueIdentifier ::= BIT STRING */ - - if (hdr.payload + hdr.length == end) - return 0; - - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { - wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" - " tag to parse optional tbsCertificate " - "field(s); parsed class %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - } - - if (hdr.tag == 2) { - /* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL */ - wpa_printf(MSG_DEBUG, "X509: subjectUniqueID"); - /* TODO: parse UniqueIdentifier ::= BIT STRING */ - - if (hdr.payload + hdr.length == end) - return 0; - - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { - wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" - " tag to parse optional tbsCertificate " - "field(s); parsed class %d tag 0x%x", - hdr.class, hdr.tag); - return -1; - } - } - - if (hdr.tag != 3) { - wpa_printf(MSG_DEBUG, "X509: Ignored unexpected " - "Context-Specific tag %d in optional " - "tbsCertificate fields", hdr.tag); - return 0; - } - - /* extensions [3] EXPLICIT Extensions OPTIONAL */ - - if (cert->version != X509_CERT_V3) { - wpa_printf(MSG_DEBUG, "X509: X.509%d certificate and " - "Extensions data which are only allowed for " - "version 3", cert->version + 1); - return -1; - } - - if (x509_parse_extensions(cert, hdr.payload, hdr.length) < 0) - return -1; - - pos = hdr.payload + hdr.length; - if (pos < end) { - wpa_hexdump(MSG_DEBUG, - "X509: Ignored extra tbsCertificate data", - pos, end - pos); - } - - return 0; -} - - -static int x509_rsadsi_oid(struct asn1_oid *oid) -{ - return oid->len >= 4 && - oid->oid[0] == 1 /* iso */ && - oid->oid[1] == 2 /* member-body */ && - oid->oid[2] == 840 /* us */ && - oid->oid[3] == 113549 /* rsadsi */; -} - - -static int x509_pkcs_oid(struct asn1_oid *oid) -{ - return oid->len >= 5 && - x509_rsadsi_oid(oid) && - oid->oid[4] == 1 /* pkcs */; -} - - -static int x509_digest_oid(struct asn1_oid *oid) -{ - return oid->len >= 5 && - x509_rsadsi_oid(oid) && - oid->oid[4] == 2 /* digestAlgorithm */; -} - - -static int x509_sha1_oid(struct asn1_oid *oid) -{ - return oid->len == 6 && - oid->oid[0] == 1 /* iso */ && - oid->oid[1] == 3 /* identified-organization */ && - oid->oid[2] == 14 /* oiw */ && - oid->oid[3] == 3 /* secsig */ && - oid->oid[4] == 2 /* algorithms */ && - oid->oid[5] == 26 /* id-sha1 */; -} - - -static int x509_sha256_oid(struct asn1_oid *oid) -{ - return oid->len == 9 && - oid->oid[0] == 2 /* joint-iso-itu-t */ && - oid->oid[1] == 16 /* country */ && - oid->oid[2] == 840 /* us */ && - oid->oid[3] == 1 /* organization */ && - oid->oid[4] == 101 /* gov */ && - oid->oid[5] == 3 /* csor */ && - oid->oid[6] == 4 /* nistAlgorithm */ && - oid->oid[7] == 2 /* hashAlgs */ && - oid->oid[8] == 1 /* sha256 */; -} - - -/** - * x509_certificate_parse - Parse a X.509 certificate in DER format - * @buf: Pointer to the X.509 certificate in DER format - * @len: Buffer length - * Returns: Pointer to the parsed certificate or %NULL on failure - * - * Caller is responsible for freeing the returned certificate by calling - * x509_certificate_free(). - */ -struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len) -{ - struct asn1_hdr hdr; - const u8 *pos, *end, *hash_start; - struct x509_certificate *cert; - - cert = os_zalloc(sizeof(*cert) + len); - if (cert == NULL) - return NULL; - os_memcpy(cert + 1, buf, len); - cert->cert_start = (u8 *) (cert + 1); - cert->cert_len = len; - - pos = buf; - end = buf + len; - - /* RFC 3280 - X.509 v3 certificate / ASN.1 DER */ - - /* Certificate ::= SEQUENCE */ - if (asn1_get_next(pos, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: Certificate did not start with " - "a valid SEQUENCE - found class %d tag 0x%x", - hdr.class, hdr.tag); - x509_certificate_free(cert); - return NULL; - } - pos = hdr.payload; - - if (pos + hdr.length > end) { - x509_certificate_free(cert); - return NULL; - } - - if (pos + hdr.length < end) { - wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER " - "encoded certificate", - pos + hdr.length, end - pos + hdr.length); - end = pos + hdr.length; - } - - hash_start = pos; - cert->tbs_cert_start = cert->cert_start + (hash_start - buf); - if (x509_parse_tbs_certificate(pos, end - pos, cert, &pos)) { - x509_certificate_free(cert); - return NULL; - } - cert->tbs_cert_len = pos - hash_start; - - /* signatureAlgorithm AlgorithmIdentifier */ - if (x509_parse_algorithm_identifier(pos, end - pos, - &cert->signature_alg, &pos)) { - x509_certificate_free(cert); - return NULL; - } - - /* signatureValue BIT STRING */ - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_BITSTRING) { - wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING " - "(signatureValue) - found class %d tag 0x%x", - hdr.class, hdr.tag); - x509_certificate_free(cert); - return NULL; - } - if (hdr.length < 1) { - x509_certificate_free(cert); - return NULL; - } - pos = hdr.payload; - if (*pos) { - wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits", - *pos); - /* PKCS #1 v1.5 10.2.1: - * It is an error if the length in bits of the signature S is - * not a multiple of eight. - */ - x509_certificate_free(cert); - return NULL; - } - os_free(cert->sign_value); - cert->sign_value = os_malloc(hdr.length - 1); - if (cert->sign_value == NULL) { - wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for " - "signatureValue"); - x509_certificate_free(cert); - return NULL; - } - os_memcpy(cert->sign_value, pos + 1, hdr.length - 1); - cert->sign_value_len = hdr.length - 1; - wpa_hexdump(MSG_MSGDUMP, "X509: signature", - cert->sign_value, cert->sign_value_len); - - return cert; -} - - -/** - * x509_certificate_check_signature - Verify certificate signature - * @issuer: Issuer certificate - * @cert: Certificate to be verified - * Returns: 0 if cert has a valid signature that was signed by the issuer, - * -1 if not - */ -int x509_certificate_check_signature(struct x509_certificate *issuer, - struct x509_certificate *cert) -{ - struct crypto_public_key *pk; - u8 *data; - const u8 *pos, *end, *next, *da_end; - size_t data_len; - struct asn1_hdr hdr; - struct asn1_oid oid; - u8 hash[32]; - size_t hash_len; - - if (!x509_pkcs_oid(&cert->signature.oid) || - cert->signature.oid.len != 7 || - cert->signature.oid.oid[5] != 1 /* pkcs-1 */) { - wpa_printf(MSG_DEBUG, "X509: Unrecognized signature " - "algorithm"); - return -1; - } - - pk = crypto_public_key_import(issuer->public_key, - issuer->public_key_len); - if (pk == NULL) - return -1; - - data_len = cert->sign_value_len; - data = os_malloc(data_len); - if (data == NULL) { - crypto_public_key_free(pk); - return -1; - } - - if (crypto_public_key_decrypt_pkcs1(pk, cert->sign_value, - cert->sign_value_len, data, - &data_len) < 0) { - wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature"); - crypto_public_key_free(pk); - os_free(data); - return -1; - } - crypto_public_key_free(pk); - - wpa_hexdump(MSG_MSGDUMP, "X509: Signature data D", data, data_len); - - /* - * PKCS #1 v1.5, 10.1.2: - * - * DigestInfo ::= SEQUENCE { - * digestAlgorithm DigestAlgorithmIdentifier, - * digest Digest - * } - * - * DigestAlgorithmIdentifier ::= AlgorithmIdentifier - * - * Digest ::= OCTET STRING - * - */ - if (asn1_get_next(data, data_len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " - "(DigestInfo) - found class %d tag 0x%x", - hdr.class, hdr.tag); - os_free(data); - return -1; - } - - pos = hdr.payload; - end = pos + hdr.length; - - /* - * X.509: - * AlgorithmIdentifier ::= SEQUENCE { - * algorithm OBJECT IDENTIFIER, - * parameters ANY DEFINED BY algorithm OPTIONAL - * } - */ - - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " - "(AlgorithmIdentifier) - found class %d tag 0x%x", - hdr.class, hdr.tag); - os_free(data); - return -1; - } - da_end = hdr.payload + hdr.length; - - if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) { - wpa_printf(MSG_DEBUG, "X509: Failed to parse digestAlgorithm"); - os_free(data); - return -1; - } - - if (x509_sha1_oid(&oid)) { - if (cert->signature.oid.oid[6] != - 5 /* sha-1WithRSAEncryption */) { - wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 " - "does not match with certificate " - "signatureAlgorithm (%lu)", - cert->signature.oid.oid[6]); - os_free(data); - return -1; - } - goto skip_digest_oid; - } - - if (x509_sha256_oid(&oid)) { - if (cert->signature.oid.oid[6] != - 11 /* sha2561WithRSAEncryption */) { - wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA256 " - "does not match with certificate " - "signatureAlgorithm (%lu)", - cert->signature.oid.oid[6]); - os_free(data); - return -1; - } - goto skip_digest_oid; - } - - if (!x509_digest_oid(&oid)) { - wpa_printf(MSG_DEBUG, "X509: Unrecognized digestAlgorithm"); - os_free(data); - return -1; - } - switch (oid.oid[5]) { - case 5: /* md5 */ - if (cert->signature.oid.oid[6] != 4 /* md5WithRSAEncryption */) - { - wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does " - "not match with certificate " - "signatureAlgorithm (%lu)", - cert->signature.oid.oid[6]); - os_free(data); - return -1; - } - break; - case 2: /* md2 */ - case 4: /* md4 */ - default: - wpa_printf(MSG_DEBUG, "X509: Unsupported digestAlgorithm " - "(%lu)", oid.oid[5]); - os_free(data); - return -1; - } - -skip_digest_oid: - /* Digest ::= OCTET STRING */ - pos = da_end; - end = data + data_len; - - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_OCTETSTRING) { - wpa_printf(MSG_DEBUG, "X509: Expected OCTETSTRING " - "(Digest) - found class %d tag 0x%x", - hdr.class, hdr.tag); - os_free(data); - return -1; - } - wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest", - hdr.payload, hdr.length); - - switch (cert->signature.oid.oid[6]) { - case 4: /* md5WithRSAEncryption */ - md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, - hash); - hash_len = 16; - wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)", - hash, hash_len); - break; - case 5: /* sha-1WithRSAEncryption */ - sha1_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, - hash); - hash_len = 20; - wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)", - hash, hash_len); - break; - case 11: /* sha256WithRSAEncryption */ - sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, - hash); - hash_len = 32; - wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)", - hash, hash_len); - break; - case 2: /* md2WithRSAEncryption */ - case 12: /* sha384WithRSAEncryption */ - case 13: /* sha512WithRSAEncryption */ - default: - wpa_printf(MSG_INFO, "X509: Unsupported certificate signature " - "algorithm (%lu)", cert->signature.oid.oid[6]); - os_free(data); - return -1; - } - - if (hdr.length != hash_len || - os_memcmp(hdr.payload, hash, hdr.length) != 0) { - wpa_printf(MSG_INFO, "X509: Certificate Digest does not match " - "with calculated tbsCertificate hash"); - os_free(data); - return -1; - } - - os_free(data); - - wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with " - "calculated tbsCertificate hash"); - - return 0; -} - - -static int x509_valid_issuer(const struct x509_certificate *cert) -{ - if ((cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS) && - !cert->ca) { - wpa_printf(MSG_DEBUG, "X509: Non-CA certificate used as an " - "issuer"); - return -1; - } - - if (cert->version == X509_CERT_V3 && - !(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) { - wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not " - "include BasicConstraints extension"); - return -1; - } - - if ((cert->extensions_present & X509_EXT_KEY_USAGE) && - !(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) { - wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have " - "keyCertSign bit in Key Usage"); - return -1; - } - - return 0; -} - - -/** - * x509_certificate_chain_validate - Validate X.509 certificate chain - * @trusted: List of trusted certificates - * @chain: Certificate chain to be validated (first chain must be issued by - * signed by the second certificate in the chain and so on) - * @reason: Buffer for returning failure reason (X509_VALIDATE_*) - * Returns: 0 if chain is valid, -1 if not - */ -int x509_certificate_chain_validate(struct x509_certificate *trusted, - struct x509_certificate *chain, - int *reason, int disable_time_checks) -{ - long unsigned idx; - int chain_trusted = 0; - struct x509_certificate *cert, *trust; - char buf[128]; - struct os_time now; - - *reason = X509_VALIDATE_OK; - - wpa_printf(MSG_DEBUG, "X509: Validate certificate chain"); - os_get_time(&now); - - for (cert = chain, idx = 0; cert; cert = cert->next, idx++) { - x509_name_string(&cert->subject, buf, sizeof(buf)); - wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf); - - if (chain_trusted) - continue; - - if (!disable_time_checks && - ((unsigned long) now.sec < - (unsigned long) cert->not_before || - (unsigned long) now.sec > - (unsigned long) cert->not_after)) { - wpa_printf(MSG_INFO, "X509: Certificate not valid " - "(now=%lu not_before=%lu not_after=%lu)", - now.sec, cert->not_before, cert->not_after); - *reason = X509_VALIDATE_CERTIFICATE_EXPIRED; - return -1; - } - - if (cert->next) { - if (x509_name_compare(&cert->issuer, - &cert->next->subject) != 0) { - wpa_printf(MSG_DEBUG, "X509: Certificate " - "chain issuer name mismatch"); - x509_name_string(&cert->issuer, buf, - sizeof(buf)); - wpa_printf(MSG_DEBUG, "X509: cert issuer: %s", - buf); - x509_name_string(&cert->next->subject, buf, - sizeof(buf)); - wpa_printf(MSG_DEBUG, "X509: next cert " - "subject: %s", buf); - *reason = X509_VALIDATE_CERTIFICATE_UNKNOWN; - return -1; - } - - if (x509_valid_issuer(cert->next) < 0) { - *reason = X509_VALIDATE_BAD_CERTIFICATE; - return -1; - } - - if ((cert->next->extensions_present & - X509_EXT_PATH_LEN_CONSTRAINT) && - idx > cert->next->path_len_constraint) { - wpa_printf(MSG_DEBUG, "X509: pathLenConstraint" - " not met (idx=%lu issuer " - "pathLenConstraint=%lu)", idx, - cert->next->path_len_constraint); - *reason = X509_VALIDATE_BAD_CERTIFICATE; - return -1; - } - - if (x509_certificate_check_signature(cert->next, cert) - < 0) { - wpa_printf(MSG_DEBUG, "X509: Invalid " - "certificate signature within " - "chain"); - *reason = X509_VALIDATE_BAD_CERTIFICATE; - return -1; - } - } - - for (trust = trusted; trust; trust = trust->next) { - if (x509_name_compare(&cert->issuer, &trust->subject) - == 0) - break; - } - - if (trust) { - wpa_printf(MSG_DEBUG, "X509: Found issuer from the " - "list of trusted certificates"); - if (x509_valid_issuer(trust) < 0) { - *reason = X509_VALIDATE_BAD_CERTIFICATE; - return -1; - } - - if (x509_certificate_check_signature(trust, cert) < 0) - { - wpa_printf(MSG_DEBUG, "X509: Invalid " - "certificate signature"); - *reason = X509_VALIDATE_BAD_CERTIFICATE; - return -1; - } - - wpa_printf(MSG_DEBUG, "X509: Trusted certificate " - "found to complete the chain"); - chain_trusted = 1; - } - } - - if (!chain_trusted) { - wpa_printf(MSG_DEBUG, "X509: Did not find any of the issuers " - "from the list of trusted certificates"); - if (trusted) { - *reason = X509_VALIDATE_UNKNOWN_CA; - return -1; - } - wpa_printf(MSG_DEBUG, "X509: Certificate chain validation " - "disabled - ignore unknown CA issue"); - } - - wpa_printf(MSG_DEBUG, "X509: Certificate chain valid"); - - return 0; -} - - -/** - * x509_certificate_get_subject - Get a certificate based on Subject name - * @chain: Certificate chain to search through - * @name: Subject name to search for - * Returns: Pointer to the certificate with the given Subject name or - * %NULL on failure - */ -struct x509_certificate * -x509_certificate_get_subject(struct x509_certificate *chain, - struct x509_name *name) -{ - struct x509_certificate *cert; - - for (cert = chain; cert; cert = cert->next) { - if (x509_name_compare(&cert->subject, name) == 0) - return cert; - } - return NULL; -} - - -/** - * x509_certificate_self_signed - Is the certificate self-signed? - * @cert: Certificate - * Returns: 1 if certificate is self-signed, 0 if not - */ -int x509_certificate_self_signed(struct x509_certificate *cert) -{ - return x509_name_compare(&cert->issuer, &cert->subject) == 0; -} diff --git a/contrib/hostapd/src/tls/x509v3.h b/contrib/hostapd/src/tls/x509v3.h deleted file mode 100644 index 91a35baf92..0000000000 --- a/contrib/hostapd/src/tls/x509v3.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * X.509v3 certificate parsing and processing - * Copyright (c) 2006-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef X509V3_H -#define X509V3_H - -#include "asn1.h" - -struct x509_algorithm_identifier { - struct asn1_oid oid; -}; - -struct x509_name_attr { - enum x509_name_attr_type { - X509_NAME_ATTR_NOT_USED, - X509_NAME_ATTR_DC, - X509_NAME_ATTR_CN, - X509_NAME_ATTR_C, - X509_NAME_ATTR_L, - X509_NAME_ATTR_ST, - X509_NAME_ATTR_O, - X509_NAME_ATTR_OU - } type; - char *value; -}; - -#define X509_MAX_NAME_ATTRIBUTES 20 - -struct x509_name { - struct x509_name_attr attr[X509_MAX_NAME_ATTRIBUTES]; - size_t num_attr; - char *email; /* emailAddress */ - - /* from alternative name extension */ - char *alt_email; /* rfc822Name */ - char *dns; /* dNSName */ - char *uri; /* uniformResourceIdentifier */ - u8 *ip; /* iPAddress */ - size_t ip_len; /* IPv4: 4, IPv6: 16 */ - struct asn1_oid rid; /* registeredID */ -}; - -struct x509_certificate { - struct x509_certificate *next; - enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version; - unsigned long serial_number; - struct x509_algorithm_identifier signature; - struct x509_name issuer; - struct x509_name subject; - os_time_t not_before; - os_time_t not_after; - struct x509_algorithm_identifier public_key_alg; - u8 *public_key; - size_t public_key_len; - struct x509_algorithm_identifier signature_alg; - u8 *sign_value; - size_t sign_value_len; - - /* Extensions */ - unsigned int extensions_present; -#define X509_EXT_BASIC_CONSTRAINTS (1 << 0) -#define X509_EXT_PATH_LEN_CONSTRAINT (1 << 1) -#define X509_EXT_KEY_USAGE (1 << 2) -#define X509_EXT_SUBJECT_ALT_NAME (1 << 3) -#define X509_EXT_ISSUER_ALT_NAME (1 << 4) - - /* BasicConstraints */ - int ca; /* cA */ - unsigned long path_len_constraint; /* pathLenConstraint */ - - /* KeyUsage */ - unsigned long key_usage; -#define X509_KEY_USAGE_DIGITAL_SIGNATURE (1 << 0) -#define X509_KEY_USAGE_NON_REPUDIATION (1 << 1) -#define X509_KEY_USAGE_KEY_ENCIPHERMENT (1 << 2) -#define X509_KEY_USAGE_DATA_ENCIPHERMENT (1 << 3) -#define X509_KEY_USAGE_KEY_AGREEMENT (1 << 4) -#define X509_KEY_USAGE_KEY_CERT_SIGN (1 << 5) -#define X509_KEY_USAGE_CRL_SIGN (1 << 6) -#define X509_KEY_USAGE_ENCIPHER_ONLY (1 << 7) -#define X509_KEY_USAGE_DECIPHER_ONLY (1 << 8) - - /* - * The DER format certificate follows struct x509_certificate. These - * pointers point to that buffer. - */ - const u8 *cert_start; - size_t cert_len; - const u8 *tbs_cert_start; - size_t tbs_cert_len; -}; - -enum { - X509_VALIDATE_OK, - X509_VALIDATE_BAD_CERTIFICATE, - X509_VALIDATE_UNSUPPORTED_CERTIFICATE, - X509_VALIDATE_CERTIFICATE_REVOKED, - X509_VALIDATE_CERTIFICATE_EXPIRED, - X509_VALIDATE_CERTIFICATE_UNKNOWN, - X509_VALIDATE_UNKNOWN_CA -}; - -void x509_certificate_free(struct x509_certificate *cert); -struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len); -void x509_name_string(struct x509_name *name, char *buf, size_t len); -int x509_name_compare(struct x509_name *a, struct x509_name *b); -void x509_certificate_chain_free(struct x509_certificate *cert); -int x509_certificate_check_signature(struct x509_certificate *issuer, - struct x509_certificate *cert); -int x509_certificate_chain_validate(struct x509_certificate *trusted, - struct x509_certificate *chain, - int *reason, int disable_time_checks); -struct x509_certificate * -x509_certificate_get_subject(struct x509_certificate *chain, - struct x509_name *name); -int x509_certificate_self_signed(struct x509_certificate *cert); - -#endif /* X509V3_H */ diff --git a/contrib/hostapd/src/utils/base64.c b/contrib/hostapd/src/utils/base64.c deleted file mode 100644 index af1307fc4e..0000000000 --- a/contrib/hostapd/src/utils/base64.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Base64 encoding/decoding (RFC1341) - * Copyright (c) 2005-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "os.h" -#include "base64.h" - -static const unsigned char base64_table[65] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/** - * base64_encode - Base64 encode - * @src: Data to be encoded - * @len: Length of the data to be encoded - * @out_len: Pointer to output length variable, or %NULL if not used - * Returns: Allocated buffer of out_len bytes of encoded data, - * or %NULL on failure - * - * Caller is responsible for freeing the returned buffer. Returned buffer is - * nul terminated to make it easier to use as a C string. The nul terminator is - * not included in out_len. - */ -unsigned char * base64_encode(const unsigned char *src, size_t len, - size_t *out_len) -{ - unsigned char *out, *pos; - const unsigned char *end, *in; - size_t olen; - int line_len; - - olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ - olen += olen / 72; /* line feeds */ - olen++; /* nul termination */ - if (olen < len) - return NULL; /* integer overflow */ - out = os_malloc(olen); - if (out == NULL) - return NULL; - - end = src + len; - in = src; - pos = out; - line_len = 0; - while (end - in >= 3) { - *pos++ = base64_table[in[0] >> 2]; - *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; - *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; - *pos++ = base64_table[in[2] & 0x3f]; - in += 3; - line_len += 4; - if (line_len >= 72) { - *pos++ = '\n'; - line_len = 0; - } - } - - if (end - in) { - *pos++ = base64_table[in[0] >> 2]; - if (end - in == 1) { - *pos++ = base64_table[(in[0] & 0x03) << 4]; - *pos++ = '='; - } else { - *pos++ = base64_table[((in[0] & 0x03) << 4) | - (in[1] >> 4)]; - *pos++ = base64_table[(in[1] & 0x0f) << 2]; - } - *pos++ = '='; - line_len += 4; - } - - if (line_len) - *pos++ = '\n'; - - *pos = '\0'; - if (out_len) - *out_len = pos - out; - return out; -} - - -/** - * base64_decode - Base64 decode - * @src: Data to be decoded - * @len: Length of the data to be decoded - * @out_len: Pointer to output length variable - * Returns: Allocated buffer of out_len bytes of decoded data, - * or %NULL on failure - * - * Caller is responsible for freeing the returned buffer. - */ -unsigned char * base64_decode(const unsigned char *src, size_t len, - size_t *out_len) -{ - 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++) - dtable[base64_table[i]] = (unsigned char) i; - dtable['='] = 0; - - count = 0; - for (i = 0; i < len; i++) { - if (dtable[src[i]] != 0x80) - count++; - } - - if (count == 0 || count % 4) - return NULL; - - olen = count / 4 * 3; - pos = out = os_malloc(olen); - if (out == NULL) - return NULL; - - count = 0; - for (i = 0; i < len; i++) { - tmp = dtable[src[i]]; - if (tmp == 0x80) - continue; - - if (src[i] == '=') - pad++; - block[count] = tmp; - count++; - if (count == 4) { - *pos++ = (block[0] << 2) | (block[1] >> 4); - *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; - } - } - } - - *out_len = pos - out; - return out; -} diff --git a/contrib/hostapd/src/utils/base64.h b/contrib/hostapd/src/utils/base64.h deleted file mode 100644 index aa21fd0fc1..0000000000 --- a/contrib/hostapd/src/utils/base64.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Base64 encoding/decoding (RFC1341) - * Copyright (c) 2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef BASE64_H -#define BASE64_H - -unsigned char * base64_encode(const unsigned char *src, size_t len, - size_t *out_len); -unsigned char * base64_decode(const unsigned char *src, size_t len, - size_t *out_len); - -#endif /* BASE64_H */ diff --git a/contrib/hostapd/src/utils/bitfield.c b/contrib/hostapd/src/utils/bitfield.c deleted file mode 100644 index f90e4beb61..0000000000 --- a/contrib/hostapd/src/utils/bitfield.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Bitfield - * Copyright (c) 2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "bitfield.h" - - -struct bitfield { - u8 *bits; - size_t max_bits; -}; - - -struct bitfield * bitfield_alloc(size_t max_bits) -{ - struct bitfield *bf; - - bf = os_zalloc(sizeof(*bf) + (max_bits + 7) / 8); - if (bf == NULL) - return NULL; - bf->bits = (u8 *) (bf + 1); - bf->max_bits = max_bits; - return bf; -} - - -void bitfield_free(struct bitfield *bf) -{ - os_free(bf); -} - - -void bitfield_set(struct bitfield *bf, size_t bit) -{ - if (bit >= bf->max_bits) - return; - bf->bits[bit / 8] |= BIT(bit % 8); -} - - -void bitfield_clear(struct bitfield *bf, size_t bit) -{ - if (bit >= bf->max_bits) - return; - bf->bits[bit / 8] &= ~BIT(bit % 8); -} - - -int bitfield_is_set(struct bitfield *bf, size_t bit) -{ - if (bit >= bf->max_bits) - return 0; - return !!(bf->bits[bit / 8] & BIT(bit % 8)); -} - - -static int first_zero(u8 val) -{ - int i; - for (i = 0; i < 8; i++) { - if (!(val & 0x01)) - return i; - val >>= 1; - } - return -1; -} - - -int bitfield_get_first_zero(struct bitfield *bf) -{ - size_t i; - for (i = 0; i <= (bf->max_bits + 7) / 8; i++) { - if (bf->bits[i] != 0xff) - break; - } - if (i > (bf->max_bits + 7) / 8) - return -1; - i = i * 8 + first_zero(bf->bits[i]); - if (i >= bf->max_bits) - return -1; - return i; -} diff --git a/contrib/hostapd/src/utils/bitfield.h b/contrib/hostapd/src/utils/bitfield.h deleted file mode 100644 index 7050a208c8..0000000000 --- a/contrib/hostapd/src/utils/bitfield.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Bitfield - * Copyright (c) 2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef BITFIELD_H -#define BITFIELD_H - -struct bitfield; - -struct bitfield * bitfield_alloc(size_t max_bits); -void bitfield_free(struct bitfield *bf); -void bitfield_set(struct bitfield *bf, size_t bit); -void bitfield_clear(struct bitfield *bf, size_t bit); -int bitfield_is_set(struct bitfield *bf, size_t bit); -int bitfield_get_first_zero(struct bitfield *bf); - -#endif /* BITFIELD_H */ diff --git a/contrib/hostapd/src/utils/build_config.h b/contrib/hostapd/src/utils/build_config.h deleted file mode 100644 index c6f4e4379a..0000000000 --- a/contrib/hostapd/src/utils/build_config.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * wpa_supplicant/hostapd - Build time configuration defines - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This header file can be used to define configuration defines that were - * originally defined in Makefile. This is mainly meant for IDE use or for - * systems that do not have suitable 'make' tool. In these cases, it may be - * easier to have a single place for defining all the needed C pre-processor - * defines. - */ - -#ifndef BUILD_CONFIG_H -#define BUILD_CONFIG_H - -/* Insert configuration defines, e.g., #define EAP_MD5, here, if needed. */ - -#ifdef CONFIG_WIN32_DEFAULTS -#define CONFIG_NATIVE_WINDOWS -#define CONFIG_ANSI_C_EXTRA -#define CONFIG_WINPCAP -#define IEEE8021X_EAPOL -#define PKCS12_FUNCS -#define PCSC_FUNCS -#define CONFIG_CTRL_IFACE -#define CONFIG_CTRL_IFACE_NAMED_PIPE -#define CONFIG_DRIVER_NDIS -#define CONFIG_NDIS_EVENTS_INTEGRATED -#define CONFIG_DEBUG_FILE -#define EAP_MD5 -#define EAP_TLS -#define EAP_MSCHAPv2 -#define EAP_PEAP -#define EAP_TTLS -#define EAP_GTC -#define EAP_OTP -#define EAP_LEAP -#define EAP_TNC -#define _CRT_SECURE_NO_DEPRECATE - -#ifdef USE_INTERNAL_CRYPTO -#define CONFIG_TLS_INTERNAL_CLIENT -#define CONFIG_INTERNAL_LIBTOMMATH -#define CONFIG_CRYPTO_INTERNAL -#endif /* USE_INTERNAL_CRYPTO */ -#endif /* CONFIG_WIN32_DEFAULTS */ - -#endif /* BUILD_CONFIG_H */ diff --git a/contrib/hostapd/src/utils/common.c b/contrib/hostapd/src/utils/common.c deleted file mode 100644 index 39751d408d..0000000000 --- a/contrib/hostapd/src/utils/common.c +++ /dev/null @@ -1,829 +0,0 @@ -/* - * wpa_supplicant/hostapd / common helper functions, etc. - * Copyright (c) 2002-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" - - -static int hex2num(char c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - return -1; -} - - -int hex2byte(const char *hex) -{ - int a, b; - a = hex2num(*hex++); - if (a < 0) - return -1; - b = hex2num(*hex++); - if (b < 0) - return -1; - return (a << 4) | b; -} - - -/** - * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format) - * @txt: MAC address as a string (e.g., "00:11:22:33:44:55") - * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) - * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) - */ -int hwaddr_aton(const char *txt, u8 *addr) -{ - int i; - - for (i = 0; i < 6; i++) { - int a, b; - - a = hex2num(*txt++); - if (a < 0) - return -1; - b = hex2num(*txt++); - if (b < 0) - return -1; - *addr++ = (a << 4) | b; - if (i < 5 && *txt++ != ':') - return -1; - } - - return 0; -} - -/** - * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format) - * @txt: MAC address as a string (e.g., "001122334455") - * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) - * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) - */ -int hwaddr_compact_aton(const char *txt, u8 *addr) -{ - int i; - - for (i = 0; i < 6; i++) { - int a, b; - - a = hex2num(*txt++); - if (a < 0) - return -1; - b = hex2num(*txt++); - if (b < 0) - return -1; - *addr++ = (a << 4) | b; - } - - return 0; -} - -/** - * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format) - * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455) - * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) - * Returns: Characters used (> 0) on success, -1 on failure - */ -int hwaddr_aton2(const char *txt, u8 *addr) -{ - int i; - const char *pos = txt; - - for (i = 0; i < 6; i++) { - int a, b; - - while (*pos == ':' || *pos == '.' || *pos == '-') - pos++; - - a = hex2num(*pos++); - if (a < 0) - return -1; - b = hex2num(*pos++); - if (b < 0) - return -1; - *addr++ = (a << 4) | b; - } - - return pos - txt; -} - - -/** - * hexstr2bin - Convert ASCII hex string into binary data - * @hex: ASCII hex string (e.g., "01ab") - * @buf: Buffer for the binary data - * @len: Length of the text to convert in bytes (of buf); hex will be double - * this size - * Returns: 0 on success, -1 on failure (invalid hex string) - */ -int hexstr2bin(const char *hex, u8 *buf, size_t len) -{ - size_t i; - int a; - const char *ipos = hex; - u8 *opos = buf; - - for (i = 0; i < len; i++) { - a = hex2byte(ipos); - if (a < 0) - return -1; - *opos++ = a; - ipos += 2; - } - return 0; -} - - -/** - * inc_byte_array - Increment arbitrary length byte array by one - * @counter: Pointer to byte array - * @len: Length of the counter in bytes - * - * This function increments the last byte of the counter by one and continues - * rolling over to more significant bytes if the byte was incremented from - * 0xff to 0x00. - */ -void inc_byte_array(u8 *counter, size_t len) -{ - int pos = len - 1; - while (pos >= 0) { - counter[pos]++; - if (counter[pos] != 0) - break; - pos--; - } -} - - -void wpa_get_ntp_timestamp(u8 *buf) -{ - struct os_time now; - u32 sec, usec; - be32 tmp; - - /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */ - os_get_time(&now); - sec = now.sec + 2208988800U; /* Epoch to 1900 */ - /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */ - usec = now.usec; - usec = 4295 * usec - (usec >> 5) - (usec >> 9); - tmp = host_to_be32(sec); - os_memcpy(buf, (u8 *) &tmp, 4); - tmp = host_to_be32(usec); - os_memcpy(buf + 4, (u8 *) &tmp, 4); -} - - -static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, - size_t len, int uppercase) -{ - size_t i; - char *pos = buf, *end = buf + buf_size; - int ret; - if (buf_size == 0) - return 0; - for (i = 0; i < len; i++) { - ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x", - data[i]); - if (ret < 0 || ret >= end - pos) { - end[-1] = '\0'; - return pos - buf; - } - pos += ret; - } - end[-1] = '\0'; - return pos - buf; -} - -/** - * wpa_snprintf_hex - Print data as a hex string into a buffer - * @buf: Memory area to use as the output buffer - * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) - * @data: Data to be printed - * @len: Length of data in bytes - * Returns: Number of bytes written - */ -int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) -{ - return _wpa_snprintf_hex(buf, buf_size, data, len, 0); -} - - -/** - * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf - * @buf: Memory area to use as the output buffer - * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) - * @data: Data to be printed - * @len: Length of data in bytes - * Returns: Number of bytes written - */ -int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, - size_t len) -{ - return _wpa_snprintf_hex(buf, buf_size, data, len, 1); -} - - -#ifdef CONFIG_ANSI_C_EXTRA - -#ifdef _WIN32_WCE -void perror(const char *s) -{ - wpa_printf(MSG_ERROR, "%s: GetLastError: %d", - s, (int) GetLastError()); -} -#endif /* _WIN32_WCE */ - - -int optind = 1; -int optopt; -char *optarg; - -int getopt(int argc, char *const argv[], const char *optstring) -{ - static int optchr = 1; - char *cp; - - if (optchr == 1) { - if (optind >= argc) { - /* all arguments processed */ - return EOF; - } - - if (argv[optind][0] != '-' || argv[optind][1] == '\0') { - /* no option characters */ - return EOF; - } - } - - if (os_strcmp(argv[optind], "--") == 0) { - /* no more options */ - optind++; - return EOF; - } - - optopt = argv[optind][optchr]; - cp = os_strchr(optstring, optopt); - if (cp == NULL || optopt == ':') { - if (argv[optind][++optchr] == '\0') { - optchr = 1; - optind++; - } - return '?'; - } - - if (cp[1] == ':') { - /* Argument required */ - optchr = 1; - if (argv[optind][optchr + 1]) { - /* No space between option and argument */ - optarg = &argv[optind++][optchr + 1]; - } else if (++optind >= argc) { - /* option requires an argument */ - return '?'; - } else { - /* Argument in the next argv */ - optarg = argv[optind++]; - } - } else { - /* No argument */ - if (argv[optind][++optchr] == '\0') { - optchr = 1; - optind++; - } - optarg = NULL; - } - return *cp; -} -#endif /* CONFIG_ANSI_C_EXTRA */ - - -#ifdef CONFIG_NATIVE_WINDOWS -/** - * wpa_unicode2ascii_inplace - Convert unicode string into ASCII - * @str: Pointer to string to convert - * - * This function converts a unicode string to ASCII using the same - * buffer for output. If UNICODE is not set, the buffer is not - * modified. - */ -void wpa_unicode2ascii_inplace(TCHAR *str) -{ -#ifdef UNICODE - char *dst = (char *) str; - while (*str) - *dst++ = (char) *str++; - *dst = '\0'; -#endif /* UNICODE */ -} - - -TCHAR * wpa_strdup_tchar(const char *str) -{ -#ifdef UNICODE - TCHAR *buf; - buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR)); - if (buf == NULL) - return NULL; - wsprintf(buf, L"%S", str); - return buf; -#else /* UNICODE */ - return os_strdup(str); -#endif /* UNICODE */ -} -#endif /* CONFIG_NATIVE_WINDOWS */ - - -void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len) -{ - char *end = txt + maxlen; - size_t i; - - for (i = 0; i < len; i++) { - if (txt + 4 > end) - break; - - switch (data[i]) { - case '\"': - *txt++ = '\\'; - *txt++ = '\"'; - break; - case '\\': - *txt++ = '\\'; - *txt++ = '\\'; - break; - case '\e': - *txt++ = '\\'; - *txt++ = 'e'; - break; - case '\n': - *txt++ = '\\'; - *txt++ = 'n'; - break; - case '\r': - *txt++ = '\\'; - *txt++ = 'r'; - break; - case '\t': - *txt++ = '\\'; - *txt++ = 't'; - break; - default: - if (data[i] >= 32 && data[i] <= 127) { - *txt++ = data[i]; - } else { - txt += os_snprintf(txt, end - txt, "\\x%02x", - data[i]); - } - break; - } - } - - *txt = '\0'; -} - - -size_t printf_decode(u8 *buf, size_t maxlen, const char *str) -{ - const char *pos = str; - size_t len = 0; - int val; - - while (*pos) { - if (len + 1 >= maxlen) - break; - switch (*pos) { - case '\\': - pos++; - switch (*pos) { - case '\\': - buf[len++] = '\\'; - pos++; - break; - case '"': - buf[len++] = '"'; - pos++; - break; - case 'n': - buf[len++] = '\n'; - pos++; - break; - case 'r': - buf[len++] = '\r'; - pos++; - break; - case 't': - buf[len++] = '\t'; - pos++; - break; - case 'e': - buf[len++] = '\e'; - pos++; - break; - case 'x': - pos++; - val = hex2byte(pos); - if (val < 0) { - val = hex2num(*pos); - if (val < 0) - break; - buf[len++] = val; - pos++; - } else { - buf[len++] = val; - pos += 2; - } - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - val = *pos++ - '0'; - if (*pos >= '0' && *pos <= '7') - val = val * 8 + (*pos++ - '0'); - if (*pos >= '0' && *pos <= '7') - val = val * 8 + (*pos++ - '0'); - buf[len++] = val; - break; - default: - break; - } - break; - default: - buf[len++] = *pos++; - break; - } - } - if (maxlen > len) - buf[len] = '\0'; - - return len; -} - - -/** - * wpa_ssid_txt - Convert SSID to a printable string - * @ssid: SSID (32-octet string) - * @ssid_len: Length of ssid in octets - * Returns: Pointer to a printable string - * - * This function can be used to convert SSIDs into printable form. In most - * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard - * does not limit the used character set, so anything could be used in an SSID. - * - * This function uses a static buffer, so only one call can be used at the - * time, i.e., this is not re-entrant and the returned buffer must be used - * before calling this again. - */ -const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len) -{ - static char ssid_txt[32 * 4 + 1]; - - if (ssid == NULL) { - ssid_txt[0] = '\0'; - return ssid_txt; - } - - printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len); - return ssid_txt; -} - - -void * __hide_aliasing_typecast(void *foo) -{ - return foo; -} - - -char * wpa_config_parse_string(const char *value, size_t *len) -{ - if (*value == '"') { - const char *pos; - char *str; - value++; - pos = os_strrchr(value, '"'); - if (pos == NULL || pos[1] != '\0') - return NULL; - *len = pos - value; - str = dup_binstr(value, *len); - if (str == NULL) - return NULL; - return str; - } else if (*value == 'P' && value[1] == '"') { - const char *pos; - char *tstr, *str; - size_t tlen; - value += 2; - pos = os_strrchr(value, '"'); - if (pos == NULL || pos[1] != '\0') - return NULL; - tlen = pos - value; - tstr = dup_binstr(value, tlen); - if (tstr == NULL) - return NULL; - - str = os_malloc(tlen + 1); - if (str == NULL) { - os_free(tstr); - return NULL; - } - - *len = printf_decode((u8 *) str, tlen + 1, tstr); - os_free(tstr); - - return str; - } else { - u8 *str; - size_t tlen, hlen = os_strlen(value); - if (hlen & 1) - return NULL; - tlen = hlen / 2; - str = os_malloc(tlen + 1); - if (str == NULL) - return NULL; - if (hexstr2bin(value, str, tlen)) { - os_free(str); - return NULL; - } - str[tlen] = '\0'; - *len = tlen; - return (char *) str; - } -} - - -int is_hex(const u8 *data, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) { - if (data[i] < 32 || data[i] >= 127) - return 1; - } - return 0; -} - - -int find_first_bit(u32 value) -{ - int pos = 0; - - while (value) { - if (value & 0x1) - return pos; - value >>= 1; - pos++; - } - - return -1; -} - - -size_t merge_byte_arrays(u8 *res, size_t res_len, - const u8 *src1, size_t src1_len, - const u8 *src2, size_t src2_len) -{ - size_t len = 0; - - os_memset(res, 0, res_len); - - if (src1) { - if (src1_len >= res_len) { - os_memcpy(res, src1, res_len); - return res_len; - } - - os_memcpy(res, src1, src1_len); - len += src1_len; - } - - if (src2) { - if (len + src2_len >= res_len) { - os_memcpy(res + len, src2, res_len - len); - return res_len; - } - - os_memcpy(res + len, src2, src2_len); - len += src2_len; - } - - return len; -} - - -char * dup_binstr(const void *src, size_t len) -{ - char *res; - - if (src == NULL) - return NULL; - res = os_malloc(len + 1); - if (res == NULL) - return NULL; - os_memcpy(res, src, len); - res[len] = '\0'; - - return res; -} - - -int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value) -{ - struct wpa_freq_range *freq = NULL, *n; - unsigned int count = 0; - const char *pos, *pos2, *pos3; - - /* - * Comma separated list of frequency ranges. - * For example: 2412-2432,2462,5000-6000 - */ - pos = value; - while (pos && pos[0]) { - n = os_realloc_array(freq, count + 1, - sizeof(struct wpa_freq_range)); - if (n == NULL) { - os_free(freq); - return -1; - } - freq = n; - freq[count].min = atoi(pos); - pos2 = os_strchr(pos, '-'); - pos3 = os_strchr(pos, ','); - if (pos2 && (!pos3 || pos2 < pos3)) { - pos2++; - freq[count].max = atoi(pos2); - } else - freq[count].max = freq[count].min; - pos = pos3; - if (pos) - pos++; - count++; - } - - os_free(res->range); - res->range = freq; - res->num = count; - - return 0; -} - - -int freq_range_list_includes(const struct wpa_freq_range_list *list, - unsigned int freq) -{ - unsigned int i; - - if (list == NULL) - return 0; - - for (i = 0; i < list->num; i++) { - if (freq >= list->range[i].min && freq <= list->range[i].max) - return 1; - } - - return 0; -} - - -char * freq_range_list_str(const struct wpa_freq_range_list *list) -{ - char *buf, *pos, *end; - size_t maxlen; - unsigned int i; - int res; - - if (list->num == 0) - return NULL; - - maxlen = list->num * 30; - buf = os_malloc(maxlen); - if (buf == NULL) - return NULL; - pos = buf; - end = buf + maxlen; - - for (i = 0; i < list->num; i++) { - struct wpa_freq_range *range = &list->range[i]; - - if (range->min == range->max) - res = os_snprintf(pos, end - pos, "%s%u", - i == 0 ? "" : ",", range->min); - else - res = os_snprintf(pos, end - pos, "%s%u-%u", - i == 0 ? "" : ",", - range->min, range->max); - if (res < 0 || res > end - pos) { - os_free(buf); - return NULL; - } - pos += res; - } - - return buf; -} - - -int int_array_len(const int *a) -{ - int i; - for (i = 0; a && a[i]; i++) - ; - return i; -} - - -void int_array_concat(int **res, const int *a) -{ - int reslen, alen, i; - int *n; - - reslen = int_array_len(*res); - alen = int_array_len(a); - - n = os_realloc_array(*res, reslen + alen + 1, sizeof(int)); - if (n == NULL) { - os_free(*res); - *res = NULL; - return; - } - for (i = 0; i <= alen; i++) - n[reslen + i] = a[i]; - *res = n; -} - - -static int freq_cmp(const void *a, const void *b) -{ - int _a = *(int *) a; - int _b = *(int *) b; - - if (_a == 0) - return 1; - if (_b == 0) - return -1; - return _a - _b; -} - - -void int_array_sort_unique(int *a) -{ - int alen; - int i, j; - - if (a == NULL) - return; - - alen = int_array_len(a); - qsort(a, alen, sizeof(int), freq_cmp); - - i = 0; - j = 1; - while (a[i] && a[j]) { - if (a[i] == a[j]) { - j++; - continue; - } - a[++i] = a[j++]; - } - if (a[i]) - i++; - a[i] = 0; -} - - -void int_array_add_unique(int **res, int a) -{ - int reslen; - int *n; - - for (reslen = 0; *res && (*res)[reslen]; reslen++) { - if ((*res)[reslen] == a) - return; /* already in the list */ - } - - n = os_realloc_array(*res, reslen + 2, sizeof(int)); - if (n == NULL) { - os_free(*res); - *res = NULL; - return; - } - - n[reslen] = a; - n[reslen + 1] = 0; - - *res = n; -} diff --git a/contrib/hostapd/src/utils/common.h b/contrib/hostapd/src/utils/common.h deleted file mode 100644 index a85cc159df..0000000000 --- a/contrib/hostapd/src/utils/common.h +++ /dev/null @@ -1,557 +0,0 @@ -/* - * wpa_supplicant/hostapd / common helper functions, etc. - * Copyright (c) 2002-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef COMMON_H -#define COMMON_H - -#include "os.h" - -#if defined(__linux__) || defined(__GLIBC__) -#include -#include -#endif /* __linux__ */ - -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ - defined(__OpenBSD__) -#include -#include -#define __BYTE_ORDER _BYTE_ORDER -#define __LITTLE_ENDIAN _LITTLE_ENDIAN -#define __BIG_ENDIAN _BIG_ENDIAN -#ifdef __OpenBSD__ -#define bswap_16 swap16 -#define bswap_32 swap32 -#define bswap_64 swap64 -#else /* __OpenBSD__ */ -#define bswap_16 bswap16 -#define bswap_32 bswap32 -#define bswap_64 bswap64 -#endif /* __OpenBSD__ */ -#endif /* defined(__FreeBSD__) || defined(__NetBSD__) || - * defined(__DragonFly__) || defined(__OpenBSD__) */ - -#ifdef __APPLE__ -#include -#include -#define __BYTE_ORDER _BYTE_ORDER -#define __LITTLE_ENDIAN _LITTLE_ENDIAN -#define __BIG_ENDIAN _BIG_ENDIAN -static inline unsigned short bswap_16(unsigned short v) -{ - return ((v & 0xff) << 8) | (v >> 8); -} - -static inline unsigned int bswap_32(unsigned int v) -{ - return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | - ((v & 0xff0000) >> 8) | (v >> 24); -} -#endif /* __APPLE__ */ - -#ifdef CONFIG_TI_COMPILER -#define __BIG_ENDIAN 4321 -#define __LITTLE_ENDIAN 1234 -#ifdef __big_endian__ -#define __BYTE_ORDER __BIG_ENDIAN -#else -#define __BYTE_ORDER __LITTLE_ENDIAN -#endif -#endif /* CONFIG_TI_COMPILER */ - -#ifdef CONFIG_NATIVE_WINDOWS -#include - -typedef int socklen_t; - -#ifndef MSG_DONTWAIT -#define MSG_DONTWAIT 0 /* not supported */ -#endif - -#endif /* CONFIG_NATIVE_WINDOWS */ - -#ifdef _MSC_VER -#define inline __inline - -#undef vsnprintf -#define vsnprintf _vsnprintf -#undef close -#define close closesocket -#endif /* _MSC_VER */ - - -/* Define platform specific integer types */ - -#ifdef _MSC_VER -typedef UINT64 u64; -typedef UINT32 u32; -typedef UINT16 u16; -typedef UINT8 u8; -typedef INT64 s64; -typedef INT32 s32; -typedef INT16 s16; -typedef INT8 s8; -#define WPA_TYPES_DEFINED -#endif /* _MSC_VER */ - -#ifdef __vxworks -typedef unsigned long long u64; -typedef UINT32 u32; -typedef UINT16 u16; -typedef UINT8 u8; -typedef long long s64; -typedef INT32 s32; -typedef INT16 s16; -typedef INT8 s8; -#define WPA_TYPES_DEFINED -#endif /* __vxworks */ - -#ifdef CONFIG_TI_COMPILER -#ifdef _LLONG_AVAILABLE -typedef unsigned long long u64; -#else -/* - * TODO: 64-bit variable not available. Using long as a workaround to test the - * build, but this will likely not work for all operations. - */ -typedef unsigned long u64; -#endif -typedef unsigned int u32; -typedef unsigned short u16; -typedef unsigned char u8; -#define WPA_TYPES_DEFINED -#endif /* CONFIG_TI_COMPILER */ - -#ifndef WPA_TYPES_DEFINED -#ifdef CONFIG_USE_INTTYPES_H -#include -#else -#include -#endif -typedef uint64_t u64; -typedef uint32_t u32; -typedef uint16_t u16; -typedef uint8_t u8; -typedef int64_t s64; -typedef int32_t s32; -typedef int16_t s16; -typedef int8_t s8; -#define WPA_TYPES_DEFINED -#endif /* !WPA_TYPES_DEFINED */ - - -/* Define platform specific byte swapping macros */ - -#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) - -static inline unsigned short wpa_swap_16(unsigned short v) -{ - return ((v & 0xff) << 8) | (v >> 8); -} - -static inline unsigned int wpa_swap_32(unsigned int v) -{ - return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | - ((v & 0xff0000) >> 8) | (v >> 24); -} - -#define le_to_host16(n) (n) -#define host_to_le16(n) (n) -#define be_to_host16(n) wpa_swap_16(n) -#define host_to_be16(n) wpa_swap_16(n) -#define le_to_host32(n) (n) -#define be_to_host32(n) wpa_swap_32(n) -#define host_to_be32(n) wpa_swap_32(n) - -#define WPA_BYTE_SWAP_DEFINED - -#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */ - - -#ifndef WPA_BYTE_SWAP_DEFINED - -#ifndef __BYTE_ORDER -#ifndef __LITTLE_ENDIAN -#ifndef __BIG_ENDIAN -#define __LITTLE_ENDIAN 1234 -#define __BIG_ENDIAN 4321 -#if defined(sparc) -#define __BYTE_ORDER __BIG_ENDIAN -#endif -#endif /* __BIG_ENDIAN */ -#endif /* __LITTLE_ENDIAN */ -#endif /* __BYTE_ORDER */ - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define le_to_host16(n) ((__force u16) (le16) (n)) -#define host_to_le16(n) ((__force le16) (u16) (n)) -#define be_to_host16(n) bswap_16((__force u16) (be16) (n)) -#define host_to_be16(n) ((__force be16) bswap_16((n))) -#define le_to_host32(n) ((__force u32) (le32) (n)) -#define host_to_le32(n) ((__force le32) (u32) (n)) -#define be_to_host32(n) bswap_32((__force u32) (be32) (n)) -#define host_to_be32(n) ((__force be32) bswap_32((n))) -#define le_to_host64(n) ((__force u64) (le64) (n)) -#define host_to_le64(n) ((__force le64) (u64) (n)) -#define be_to_host64(n) bswap_64((__force u64) (be64) (n)) -#define host_to_be64(n) ((__force be64) bswap_64((n))) -#elif __BYTE_ORDER == __BIG_ENDIAN -#define le_to_host16(n) bswap_16(n) -#define host_to_le16(n) bswap_16(n) -#define be_to_host16(n) (n) -#define host_to_be16(n) (n) -#define le_to_host32(n) bswap_32(n) -#define host_to_le32(n) bswap_32(n) -#define be_to_host32(n) (n) -#define host_to_be32(n) (n) -#define le_to_host64(n) bswap_64(n) -#define host_to_le64(n) bswap_64(n) -#define be_to_host64(n) (n) -#define host_to_be64(n) (n) -#ifndef WORDS_BIGENDIAN -#define WORDS_BIGENDIAN -#endif -#else -#error Could not determine CPU byte order -#endif - -#define WPA_BYTE_SWAP_DEFINED -#endif /* !WPA_BYTE_SWAP_DEFINED */ - - -/* Macros for handling unaligned memory accesses */ - -static inline u16 WPA_GET_BE16(const u8 *a) -{ - return (a[0] << 8) | a[1]; -} - -static inline void WPA_PUT_BE16(u8 *a, u16 val) -{ - a[0] = val >> 8; - a[1] = val & 0xff; -} - -static inline u16 WPA_GET_LE16(const u8 *a) -{ - return (a[1] << 8) | a[0]; -} - -static inline void WPA_PUT_LE16(u8 *a, u16 val) -{ - a[1] = val >> 8; - a[0] = val & 0xff; -} - -static inline u32 WPA_GET_BE24(const u8 *a) -{ - return (a[0] << 16) | (a[1] << 8) | a[2]; -} - -static inline void WPA_PUT_BE24(u8 *a, u32 val) -{ - a[0] = (val >> 16) & 0xff; - a[1] = (val >> 8) & 0xff; - a[2] = val & 0xff; -} - -static inline u32 WPA_GET_BE32(const u8 *a) -{ - return (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]; -} - -static inline void WPA_PUT_BE32(u8 *a, u32 val) -{ - a[0] = (val >> 24) & 0xff; - a[1] = (val >> 16) & 0xff; - a[2] = (val >> 8) & 0xff; - a[3] = val & 0xff; -} - -static inline u32 WPA_GET_LE32(const u8 *a) -{ - return (a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]; -} - -static inline void WPA_PUT_LE32(u8 *a, u32 val) -{ - a[3] = (val >> 24) & 0xff; - a[2] = (val >> 16) & 0xff; - a[1] = (val >> 8) & 0xff; - a[0] = val & 0xff; -} - -static inline u64 WPA_GET_BE64(const u8 *a) -{ - return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) | - (((u64) a[2]) << 40) | (((u64) a[3]) << 32) | - (((u64) a[4]) << 24) | (((u64) a[5]) << 16) | - (((u64) a[6]) << 8) | ((u64) a[7]); -} - -static inline void WPA_PUT_BE64(u8 *a, u64 val) -{ - a[0] = val >> 56; - a[1] = val >> 48; - a[2] = val >> 40; - a[3] = val >> 32; - a[4] = val >> 24; - a[5] = val >> 16; - a[6] = val >> 8; - a[7] = val & 0xff; -} - -static inline u64 WPA_GET_LE64(const u8 *a) -{ - return (((u64) a[7]) << 56) | (((u64) a[6]) << 48) | - (((u64) a[5]) << 40) | (((u64) a[4]) << 32) | - (((u64) a[3]) << 24) | (((u64) a[2]) << 16) | - (((u64) a[1]) << 8) | ((u64) a[0]); -} - -static inline void WPA_PUT_LE64(u8 *a, u64 val) -{ - a[7] = val >> 56; - a[6] = val >> 48; - a[5] = val >> 40; - a[4] = val >> 32; - a[3] = val >> 24; - a[2] = val >> 16; - a[1] = val >> 8; - a[0] = val & 0xff; -} - - -#ifndef ETH_ALEN -#define ETH_ALEN 6 -#endif -#ifndef IFNAMSIZ -#define IFNAMSIZ 16 -#endif -#ifndef ETH_P_ALL -#define ETH_P_ALL 0x0003 -#endif -#ifndef ETH_P_80211_ENCAP -#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */ -#endif -#ifndef ETH_P_PAE -#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ -#endif /* ETH_P_PAE */ -#ifndef ETH_P_EAPOL -#define ETH_P_EAPOL ETH_P_PAE -#endif /* ETH_P_EAPOL */ -#ifndef ETH_P_RSN_PREAUTH -#define ETH_P_RSN_PREAUTH 0x88c7 -#endif /* ETH_P_RSN_PREAUTH */ -#ifndef ETH_P_RRB -#define ETH_P_RRB 0x890D -#endif /* ETH_P_RRB */ - - -#ifdef __GNUC__ -#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) -#define STRUCT_PACKED __attribute__ ((packed)) -#else -#define PRINTF_FORMAT(a,b) -#define STRUCT_PACKED -#endif - - -#ifdef CONFIG_ANSI_C_EXTRA - -#if !defined(_MSC_VER) || _MSC_VER < 1400 -/* snprintf - used in number of places; sprintf() is _not_ a good replacement - * due to possible buffer overflow; see, e.g., - * http://www.ijs.si/software/snprintf/ for portable implementation of - * snprintf. */ -int snprintf(char *str, size_t size, const char *format, ...); - -/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */ -int vsnprintf(char *str, size_t size, const char *format, va_list ap); -#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */ - -/* getopt - only used in main.c */ -int getopt(int argc, char *const argv[], const char *optstring); -extern char *optarg; -extern int optind; - -#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF -#ifndef __socklen_t_defined -typedef int socklen_t; -#endif -#endif - -/* inline - define as __inline or just define it to be empty, if needed */ -#ifdef CONFIG_NO_INLINE -#define inline -#else -#define inline __inline -#endif - -#ifndef __func__ -#define __func__ "__func__ not defined" -#endif - -#ifndef bswap_16 -#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) -#endif - -#ifndef bswap_32 -#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ - (((u32) (a) << 8) & 0xff0000) | \ - (((u32) (a) >> 8) & 0xff00) | \ - (((u32) (a) >> 24) & 0xff)) -#endif - -#ifndef MSG_DONTWAIT -#define MSG_DONTWAIT 0 -#endif - -#ifdef _WIN32_WCE -void perror(const char *s); -#endif /* _WIN32_WCE */ - -#endif /* CONFIG_ANSI_C_EXTRA */ - -#ifndef MAC2STR -#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" - -/* - * Compact form for string representation of MAC address - * To be used, e.g., for constructing dbus paths for P2P Devices - */ -#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x" -#endif - -#ifndef BIT -#define BIT(x) (1 << (x)) -#endif - -/* - * Definitions for sparse validation - * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) - */ -#ifdef __CHECKER__ -#define __force __attribute__((force)) -#define __bitwise __attribute__((bitwise)) -#else -#define __force -#define __bitwise -#endif - -typedef u16 __bitwise be16; -typedef u16 __bitwise le16; -typedef u32 __bitwise be32; -typedef u32 __bitwise le32; -typedef u64 __bitwise be64; -typedef u64 __bitwise le64; - -#ifndef __must_check -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -#define __must_check __attribute__((__warn_unused_result__)) -#else -#define __must_check -#endif /* __GNUC__ */ -#endif /* __must_check */ - -#ifndef __maybe_unused -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -#define __maybe_unused __attribute__((unused)) -#else -#define __maybe_unused -#endif /* __GNUC__ */ -#endif /* __must_check */ - -int hwaddr_aton(const char *txt, u8 *addr); -int hwaddr_compact_aton(const char *txt, u8 *addr); -int hwaddr_aton2(const char *txt, u8 *addr); -int hex2byte(const char *hex); -int hexstr2bin(const char *hex, u8 *buf, size_t len); -void inc_byte_array(u8 *counter, size_t len); -void wpa_get_ntp_timestamp(u8 *buf); -int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); -int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, - size_t len); - -#ifdef CONFIG_NATIVE_WINDOWS -void wpa_unicode2ascii_inplace(TCHAR *str); -TCHAR * wpa_strdup_tchar(const char *str); -#else /* CONFIG_NATIVE_WINDOWS */ -#define wpa_unicode2ascii_inplace(s) do { } while (0) -#define wpa_strdup_tchar(s) strdup((s)) -#endif /* CONFIG_NATIVE_WINDOWS */ - -void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len); -size_t printf_decode(u8 *buf, size_t maxlen, const char *str); - -const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); - -char * wpa_config_parse_string(const char *value, size_t *len); -int is_hex(const u8 *data, size_t len); -int find_first_bit(u32 value); -size_t merge_byte_arrays(u8 *res, size_t res_len, - const u8 *src1, size_t src1_len, - const u8 *src2, size_t src2_len); -char * dup_binstr(const void *src, size_t len); - -static inline int is_zero_ether_addr(const u8 *a) -{ - return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); -} - -static inline int is_broadcast_ether_addr(const u8 *a) -{ - return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff; -} - -#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff" - -#include "wpa_debug.h" - - -struct wpa_freq_range_list { - struct wpa_freq_range { - unsigned int min; - unsigned int max; - } *range; - unsigned int num; -}; - -int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value); -int freq_range_list_includes(const struct wpa_freq_range_list *list, - unsigned int freq); -char * freq_range_list_str(const struct wpa_freq_range_list *list); - -int int_array_len(const int *a); -void int_array_concat(int **res, const int *a); -void int_array_sort_unique(int *a); -void int_array_add_unique(int **res, int a); - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - - -/* - * gcc 4.4 ends up generating strict-aliasing warnings about some very common - * networking socket uses that do not really result in a real problem and - * cannot be easily avoided with union-based type-punning due to struct - * definitions including another struct in system header files. To avoid having - * to fully disable strict-aliasing warnings, provide a mechanism to hide the - * typecast from aliasing for now. A cleaner solution will hopefully be found - * in the future to handle these cases. - */ -void * __hide_aliasing_typecast(void *foo); -#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) - -#ifdef CONFIG_VALGRIND -#include -#define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) -#else /* CONFIG_VALGRIND */ -#define WPA_MEM_DEFINED(ptr, len) do { } while (0) -#endif /* CONFIG_VALGRIND */ - -#endif /* COMMON_H */ diff --git a/contrib/hostapd/src/utils/edit.c b/contrib/hostapd/src/utils/edit.c deleted file mode 100644 index 177ecf41d4..0000000000 --- a/contrib/hostapd/src/utils/edit.c +++ /dev/null @@ -1,1174 +0,0 @@ -/* - * Command line editing and history - * Copyright (c) 2010-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "eloop.h" -#include "list.h" -#include "edit.h" - -#define CMD_BUF_LEN 256 -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; -static const char *ps2 = NULL; - -#define HISTORY_MAX 100 - -struct edit_history { - struct dl_list list; - char str[1]; -}; - -static struct dl_list history_list; -static struct edit_history *history_curr; - -static void *edit_cb_ctx; -static void (*edit_cmd_cb)(void *ctx, char *cmd); -static void (*edit_eof_cb)(void *ctx); -static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) = - NULL; - -static struct termios prevt, newt; - - -#define CLEAR_END_LINE "\e[K" - - -void edit_clear_line(void) -{ - int i; - putchar('\r'); - for (i = 0; i < cmdbuf_len + 2 + (ps2 ? (int) os_strlen(ps2) : 0); i++) - putchar(' '); -} - - -static void move_start(void) -{ - cmdbuf_pos = 0; - edit_redraw(); -} - - -static void move_end(void) -{ - cmdbuf_pos = cmdbuf_len; - edit_redraw(); -} - - -static void move_left(void) -{ - if (cmdbuf_pos > 0) { - cmdbuf_pos--; - edit_redraw(); - } -} - - -static void move_right(void) -{ - if (cmdbuf_pos < cmdbuf_len) { - cmdbuf_pos++; - edit_redraw(); - } -} - - -static void move_word_left(void) -{ - while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] == ' ') - cmdbuf_pos--; - while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] != ' ') - cmdbuf_pos--; - edit_redraw(); -} - - -static void move_word_right(void) -{ - while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] == ' ') - cmdbuf_pos++; - while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] != ' ') - cmdbuf_pos++; - edit_redraw(); -} - - -static void delete_left(void) -{ - if (cmdbuf_pos == 0) - return; - - edit_clear_line(); - os_memmove(cmdbuf + cmdbuf_pos - 1, cmdbuf + cmdbuf_pos, - cmdbuf_len - cmdbuf_pos); - cmdbuf_pos--; - cmdbuf_len--; - edit_redraw(); -} - - -static void delete_current(void) -{ - if (cmdbuf_pos == cmdbuf_len) - return; - - edit_clear_line(); - os_memmove(cmdbuf + cmdbuf_pos, cmdbuf + cmdbuf_pos + 1, - cmdbuf_len - cmdbuf_pos); - cmdbuf_len--; - edit_redraw(); -} - - -static void delete_word(void) -{ - int pos; - - edit_clear_line(); - pos = cmdbuf_pos; - while (pos > 0 && cmdbuf[pos - 1] == ' ') - pos--; - while (pos > 0 && cmdbuf[pos - 1] != ' ') - pos--; - os_memmove(cmdbuf + pos, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos); - cmdbuf_len -= cmdbuf_pos - pos; - cmdbuf_pos = pos; - edit_redraw(); -} - - -static void clear_left(void) -{ - if (cmdbuf_pos == 0) - return; - - edit_clear_line(); - os_memmove(cmdbuf, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos); - cmdbuf_len -= cmdbuf_pos; - cmdbuf_pos = 0; - edit_redraw(); -} - - -static void clear_right(void) -{ - if (cmdbuf_pos == cmdbuf_len) - return; - - edit_clear_line(); - cmdbuf_len = cmdbuf_pos; - edit_redraw(); -} - - -static void history_add(const char *str) -{ - struct edit_history *h, *match = NULL, *last = NULL; - size_t len, count = 0; - - if (str[0] == '\0') - return; - - dl_list_for_each(h, &history_list, struct edit_history, list) { - if (os_strcmp(str, h->str) == 0) { - match = h; - break; - } - last = h; - count++; - } - - if (match) { - dl_list_del(&h->list); - dl_list_add(&history_list, &h->list); - history_curr = h; - return; - } - - if (count >= HISTORY_MAX && last) { - dl_list_del(&last->list); - os_free(last); - } - - len = os_strlen(str); - h = os_zalloc(sizeof(*h) + len); - if (h == NULL) - return; - dl_list_add(&history_list, &h->list); - os_strlcpy(h->str, str, len + 1); - history_curr = h; -} - - -static void history_use(void) -{ - edit_clear_line(); - cmdbuf_len = cmdbuf_pos = os_strlen(history_curr->str); - os_memcpy(cmdbuf, history_curr->str, cmdbuf_len); - edit_redraw(); -} - - -static void history_prev(void) -{ - if (history_curr == NULL) - return; - - if (history_curr == - dl_list_first(&history_list, struct edit_history, list)) { - if (!currbuf_valid) { - cmdbuf[cmdbuf_len] = '\0'; - os_memcpy(currbuf, cmdbuf, cmdbuf_len + 1); - currbuf_valid = 1; - history_use(); - return; - } - } - - 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(); -} - - -static void history_next(void) -{ - if (history_curr == NULL || - history_curr == - 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); - history_use(); -} - - -static void history_read(const char *fname) -{ - FILE *f; - char buf[CMD_BUF_LEN], *pos; - - f = fopen(fname, "r"); - if (f == NULL) - return; - - while (fgets(buf, CMD_BUF_LEN, f)) { - for (pos = buf; *pos; pos++) { - if (*pos == '\r' || *pos == '\n') { - *pos = '\0'; - break; - } - } - history_add(buf); - } - - fclose(f); -} - - -static void history_write(const char *fname, - int (*filter_cb)(void *ctx, const char *cmd)) -{ - FILE *f; - struct edit_history *h; - - f = fopen(fname, "w"); - if (f == NULL) - return; - - dl_list_for_each_reverse(h, &history_list, struct edit_history, list) { - if (filter_cb && filter_cb(edit_cb_ctx, h->str)) - continue; - fprintf(f, "%s\n", h->str); - } - - fclose(f); -} - - -static void history_debug_dump(void) -{ - struct edit_history *h; - edit_clear_line(); - 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(); -} - - -static void insert_char(int c) -{ - if (cmdbuf_len >= (int) sizeof(cmdbuf) - 1) - return; - if (cmdbuf_len == cmdbuf_pos) { - cmdbuf[cmdbuf_pos++] = c; - cmdbuf_len++; - putchar(c); - fflush(stdout); - } else { - os_memmove(cmdbuf + cmdbuf_pos + 1, cmdbuf + cmdbuf_pos, - cmdbuf_len - cmdbuf_pos); - cmdbuf[cmdbuf_pos++] = c; - cmdbuf_len++; - edit_redraw(); - } -} - - -static void process_cmd(void) -{ - currbuf_valid = 0; - if (cmdbuf_len == 0) { - printf("\n%s> ", ps2 ? ps2 : ""); - fflush(stdout); - return; - } - printf("\n"); - cmdbuf[cmdbuf_len] = '\0'; - history_add(cmdbuf); - cmdbuf_pos = 0; - cmdbuf_len = 0; - edit_cmd_cb(edit_cb_ctx, cmdbuf); - printf("%s> ", ps2 ? ps2 : ""); - fflush(stdout); -} - - -static void free_completions(char **c) -{ - int i; - if (c == NULL) - return; - for (i = 0; c[i]; i++) - os_free(c[i]); - os_free(c); -} - - -static int filter_strings(char **c, char *str, size_t len) -{ - int i, j; - - for (i = 0, j = 0; c[j]; j++) { - if (os_strncasecmp(c[j], str, len) == 0) { - if (i != j) { - c[i] = c[j]; - c[j] = NULL; - } - i++; - } else { - os_free(c[j]); - c[j] = NULL; - } - } - c[i] = NULL; - return i; -} - - -static int common_len(const char *a, const char *b) -{ - int len = 0; - while (a[len] && a[len] == b[len]) - len++; - return len; -} - - -static int max_common_length(char **c) -{ - int len, i; - - len = os_strlen(c[0]); - for (i = 1; c[i]; i++) { - int same = common_len(c[0], c[i]); - if (same < len) - len = same; - } - - return len; -} - - -static int cmp_str(const void *a, const void *b) -{ - return os_strcmp(* (const char **) a, * (const char **) b); -} - -static void complete(int list) -{ - char **c; - int i, len, count; - int start, end; - int room, plen, add_space; - - if (edit_completion_cb == NULL) - return; - - cmdbuf[cmdbuf_len] = '\0'; - c = edit_completion_cb(edit_cb_ctx, cmdbuf, cmdbuf_pos); - if (c == NULL) - return; - - end = cmdbuf_pos; - start = end; - while (start > 0 && cmdbuf[start - 1] != ' ') - start--; - plen = end - start; - - count = filter_strings(c, &cmdbuf[start], plen); - if (count == 0) { - free_completions(c); - return; - } - - len = max_common_length(c); - if (len <= plen && count > 1) { - if (list) { - qsort(c, count, sizeof(char *), cmp_str); - edit_clear_line(); - printf("\r"); - for (i = 0; c[i]; i++) - printf("%s%s", i > 0 ? " " : "", c[i]); - printf("\n"); - edit_redraw(); - } - free_completions(c); - return; - } - len -= plen; - - room = sizeof(cmdbuf) - 1 - cmdbuf_len; - if (room < len) - len = room; - add_space = count == 1 && len < room; - - os_memmove(cmdbuf + cmdbuf_pos + len + add_space, cmdbuf + cmdbuf_pos, - cmdbuf_len - cmdbuf_pos); - os_memcpy(&cmdbuf[cmdbuf_pos - plen], c[0], plen + len); - if (add_space) - cmdbuf[cmdbuf_pos + len] = ' '; - - cmdbuf_pos += len + add_space; - cmdbuf_len += len + add_space; - - edit_redraw(); - - free_completions(c); -} - - -enum edit_key_code { - EDIT_KEY_NONE = 256, - EDIT_KEY_TAB, - EDIT_KEY_UP, - EDIT_KEY_DOWN, - EDIT_KEY_RIGHT, - EDIT_KEY_LEFT, - EDIT_KEY_ENTER, - EDIT_KEY_BACKSPACE, - EDIT_KEY_INSERT, - EDIT_KEY_DELETE, - EDIT_KEY_HOME, - EDIT_KEY_END, - EDIT_KEY_PAGE_UP, - EDIT_KEY_PAGE_DOWN, - EDIT_KEY_F1, - EDIT_KEY_F2, - EDIT_KEY_F3, - EDIT_KEY_F4, - EDIT_KEY_F5, - EDIT_KEY_F6, - EDIT_KEY_F7, - EDIT_KEY_F8, - EDIT_KEY_F9, - EDIT_KEY_F10, - EDIT_KEY_F11, - EDIT_KEY_F12, - EDIT_KEY_CTRL_UP, - EDIT_KEY_CTRL_DOWN, - EDIT_KEY_CTRL_RIGHT, - EDIT_KEY_CTRL_LEFT, - EDIT_KEY_CTRL_A, - EDIT_KEY_CTRL_B, - EDIT_KEY_CTRL_D, - EDIT_KEY_CTRL_E, - EDIT_KEY_CTRL_F, - EDIT_KEY_CTRL_G, - EDIT_KEY_CTRL_H, - EDIT_KEY_CTRL_J, - EDIT_KEY_CTRL_K, - EDIT_KEY_CTRL_L, - EDIT_KEY_CTRL_N, - EDIT_KEY_CTRL_O, - EDIT_KEY_CTRL_P, - EDIT_KEY_CTRL_R, - EDIT_KEY_CTRL_T, - EDIT_KEY_CTRL_U, - EDIT_KEY_CTRL_V, - EDIT_KEY_CTRL_W, - EDIT_KEY_ALT_UP, - EDIT_KEY_ALT_DOWN, - EDIT_KEY_ALT_RIGHT, - EDIT_KEY_ALT_LEFT, - EDIT_KEY_SHIFT_UP, - EDIT_KEY_SHIFT_DOWN, - EDIT_KEY_SHIFT_RIGHT, - EDIT_KEY_SHIFT_LEFT, - EDIT_KEY_ALT_SHIFT_UP, - EDIT_KEY_ALT_SHIFT_DOWN, - EDIT_KEY_ALT_SHIFT_RIGHT, - EDIT_KEY_ALT_SHIFT_LEFT, - EDIT_KEY_EOF -}; - -static void show_esc_buf(const char *esc_buf, char c, int i) -{ - edit_clear_line(); - printf("\rESC buffer '%s' c='%c' [%d]\n", esc_buf, c, i); - edit_redraw(); -} - - -static enum edit_key_code esc_seq_to_key1_no(char last) -{ - switch (last) { - case 'A': - return EDIT_KEY_UP; - case 'B': - return EDIT_KEY_DOWN; - case 'C': - return EDIT_KEY_RIGHT; - case 'D': - return EDIT_KEY_LEFT; - default: - return EDIT_KEY_NONE; - } -} - - -static enum edit_key_code esc_seq_to_key1_shift(char last) -{ - switch (last) { - case 'A': - return EDIT_KEY_SHIFT_UP; - case 'B': - return EDIT_KEY_SHIFT_DOWN; - case 'C': - return EDIT_KEY_SHIFT_RIGHT; - case 'D': - return EDIT_KEY_SHIFT_LEFT; - default: - return EDIT_KEY_NONE; - } -} - - -static enum edit_key_code esc_seq_to_key1_alt(char last) -{ - switch (last) { - case 'A': - return EDIT_KEY_ALT_UP; - case 'B': - return EDIT_KEY_ALT_DOWN; - case 'C': - return EDIT_KEY_ALT_RIGHT; - case 'D': - return EDIT_KEY_ALT_LEFT; - default: - return EDIT_KEY_NONE; - } -} - - -static enum edit_key_code esc_seq_to_key1_alt_shift(char last) -{ - switch (last) { - case 'A': - return EDIT_KEY_ALT_SHIFT_UP; - case 'B': - return EDIT_KEY_ALT_SHIFT_DOWN; - case 'C': - return EDIT_KEY_ALT_SHIFT_RIGHT; - case 'D': - return EDIT_KEY_ALT_SHIFT_LEFT; - default: - return EDIT_KEY_NONE; - } -} - - -static enum edit_key_code esc_seq_to_key1_ctrl(char last) -{ - switch (last) { - case 'A': - return EDIT_KEY_CTRL_UP; - case 'B': - return EDIT_KEY_CTRL_DOWN; - case 'C': - return EDIT_KEY_CTRL_RIGHT; - case 'D': - return EDIT_KEY_CTRL_LEFT; - default: - return EDIT_KEY_NONE; - } -} - - -static enum edit_key_code esc_seq_to_key1(int param1, int param2, char last) -{ - /* ESC-[; */ - - if (param1 < 0 && param2 < 0) - return esc_seq_to_key1_no(last); - - if (param1 == 1 && param2 == 2) - return esc_seq_to_key1_shift(last); - - if (param1 == 1 && param2 == 3) - return esc_seq_to_key1_alt(last); - - if (param1 == 1 && param2 == 4) - return esc_seq_to_key1_alt_shift(last); - - if (param1 == 1 && param2 == 5) - return esc_seq_to_key1_ctrl(last); - - if (param2 < 0) { - if (last != '~') - return EDIT_KEY_NONE; - switch (param1) { - case 2: - return EDIT_KEY_INSERT; - case 3: - return EDIT_KEY_DELETE; - case 5: - return EDIT_KEY_PAGE_UP; - case 6: - return EDIT_KEY_PAGE_DOWN; - case 15: - return EDIT_KEY_F5; - case 17: - return EDIT_KEY_F6; - case 18: - return EDIT_KEY_F7; - case 19: - return EDIT_KEY_F8; - case 20: - return EDIT_KEY_F9; - case 21: - return EDIT_KEY_F10; - case 23: - return EDIT_KEY_F11; - case 24: - return EDIT_KEY_F12; - } - } - - return EDIT_KEY_NONE; -} - - -static enum edit_key_code esc_seq_to_key2(int param1, int param2, char last) -{ - /* ESC-O; */ - - if (param1 >= 0 || param2 >= 0) - return EDIT_KEY_NONE; - - switch (last) { - case 'F': - return EDIT_KEY_END; - case 'H': - return EDIT_KEY_HOME; - case 'P': - return EDIT_KEY_F1; - case 'Q': - return EDIT_KEY_F2; - case 'R': - return EDIT_KEY_F3; - case 'S': - return EDIT_KEY_F4; - default: - return EDIT_KEY_NONE; - } -} - - -static enum edit_key_code esc_seq_to_key(char *seq) -{ - char last, *pos; - int param1 = -1, param2 = -1; - enum edit_key_code ret = EDIT_KEY_NONE; - - last = '\0'; - for (pos = seq; *pos; pos++) - last = *pos; - - if (seq[1] >= '0' && seq[1] <= '9') { - param1 = atoi(&seq[1]); - pos = os_strchr(seq, ';'); - if (pos) - param2 = atoi(pos + 1); - } - - if (seq[0] == '[') - ret = esc_seq_to_key1(param1, param2, last); - else if (seq[0] == 'O') - ret = esc_seq_to_key2(param1, param2, last); - - if (ret != EDIT_KEY_NONE) - return ret; - - edit_clear_line(); - printf("\rUnknown escape sequence '%s'\n", seq); - edit_redraw(); - return EDIT_KEY_NONE; -} - - -static enum edit_key_code edit_read_key(int sock) -{ - int c; - unsigned char buf[1]; - int res; - static int esc = -1; - static char esc_buf[7]; - - res = read(sock, buf, 1); - if (res < 0) - perror("read"); - if (res <= 0) - return EDIT_KEY_EOF; - - c = buf[0]; - - if (esc >= 0) { - if (c == 27 /* ESC */) { - esc = 0; - return EDIT_KEY_NONE; - } - - if (esc == 6) { - show_esc_buf(esc_buf, c, 0); - esc = -1; - } else { - esc_buf[esc++] = c; - esc_buf[esc] = '\0'; - } - } - - if (esc == 1) { - if (esc_buf[0] != '[' && esc_buf[0] != 'O') { - show_esc_buf(esc_buf, c, 1); - esc = -1; - return EDIT_KEY_NONE; - } else - return EDIT_KEY_NONE; /* Escape sequence continues */ - } - - if (esc > 1) { - if ((c >= '0' && c <= '9') || c == ';') - return EDIT_KEY_NONE; /* Escape sequence continues */ - - if (c == '~' || (c >= 'A' && c <= 'Z')) { - esc = -1; - return esc_seq_to_key(esc_buf); - } - - show_esc_buf(esc_buf, c, 2); - esc = -1; - return EDIT_KEY_NONE; - } - - switch (c) { - case 1: - return EDIT_KEY_CTRL_A; - case 2: - return EDIT_KEY_CTRL_B; - case 4: - return EDIT_KEY_CTRL_D; - case 5: - return EDIT_KEY_CTRL_E; - case 6: - return EDIT_KEY_CTRL_F; - case 7: - return EDIT_KEY_CTRL_G; - case 8: - return EDIT_KEY_CTRL_H; - case 9: - return EDIT_KEY_TAB; - case 10: - return EDIT_KEY_CTRL_J; - case 13: /* CR */ - return EDIT_KEY_ENTER; - case 11: - return EDIT_KEY_CTRL_K; - case 12: - return EDIT_KEY_CTRL_L; - case 14: - return EDIT_KEY_CTRL_N; - case 15: - return EDIT_KEY_CTRL_O; - case 16: - return EDIT_KEY_CTRL_P; - case 18: - return EDIT_KEY_CTRL_R; - case 20: - return EDIT_KEY_CTRL_T; - case 21: - return EDIT_KEY_CTRL_U; - case 22: - return EDIT_KEY_CTRL_V; - case 23: - return EDIT_KEY_CTRL_W; - case 27: /* ESC */ - esc = 0; - return EDIT_KEY_NONE; - case 127: - return EDIT_KEY_BACKSPACE; - default: - return c; - } -} - - -static char search_buf[21]; -static int search_skip; - -static char * search_find(void) -{ - struct edit_history *h; - size_t len = os_strlen(search_buf); - int skip = search_skip; - - if (len == 0) - return NULL; - - dl_list_for_each(h, &history_list, struct edit_history, list) { - if (os_strstr(h->str, search_buf)) { - if (skip == 0) - return h->str; - skip--; - } - } - - search_skip = 0; - return NULL; -} - - -static void search_redraw(void) -{ - char *match = search_find(); - printf("\rsearch '%s': %s" CLEAR_END_LINE, - search_buf, match ? match : ""); - printf("\rsearch '%s", search_buf); - fflush(stdout); -} - - -static void search_start(void) -{ - edit_clear_line(); - search_buf[0] = '\0'; - search_skip = 0; - search_redraw(); -} - - -static void search_clear(void) -{ - search_redraw(); - printf("\r" CLEAR_END_LINE); -} - - -static void search_stop(void) -{ - char *match = search_find(); - search_buf[0] = '\0'; - search_clear(); - if (match) { - os_strlcpy(cmdbuf, match, CMD_BUF_LEN); - cmdbuf_len = os_strlen(cmdbuf); - cmdbuf_pos = cmdbuf_len; - } - edit_redraw(); -} - - -static void search_cancel(void) -{ - search_buf[0] = '\0'; - search_clear(); - edit_redraw(); -} - - -static void search_backspace(void) -{ - size_t len; - len = os_strlen(search_buf); - if (len == 0) - return; - search_buf[len - 1] = '\0'; - search_skip = 0; - search_redraw(); -} - - -static void search_next(void) -{ - search_skip++; - search_find(); - search_redraw(); -} - - -static void search_char(char c) -{ - size_t len; - len = os_strlen(search_buf); - if (len == sizeof(search_buf) - 1) - return; - search_buf[len] = c; - search_buf[len + 1] = '\0'; - search_skip = 0; - search_redraw(); -} - - -static enum edit_key_code search_key(enum edit_key_code c) -{ - switch (c) { - case EDIT_KEY_ENTER: - case EDIT_KEY_CTRL_J: - case EDIT_KEY_LEFT: - case EDIT_KEY_RIGHT: - case EDIT_KEY_HOME: - case EDIT_KEY_END: - case EDIT_KEY_CTRL_A: - case EDIT_KEY_CTRL_E: - search_stop(); - return c; - case EDIT_KEY_DOWN: - case EDIT_KEY_UP: - search_cancel(); - return EDIT_KEY_EOF; - case EDIT_KEY_CTRL_H: - case EDIT_KEY_BACKSPACE: - search_backspace(); - break; - case EDIT_KEY_CTRL_R: - search_next(); - break; - default: - if (c >= 32 && c <= 255) - search_char(c); - break; - } - - return EDIT_KEY_NONE; -} - - -static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx) -{ - static int last_tab = 0; - static int search = 0; - enum edit_key_code c; - - c = edit_read_key(sock); - - if (search) { - c = search_key(c); - if (c == EDIT_KEY_NONE) - return; - search = 0; - if (c == EDIT_KEY_EOF) - return; - } - - if (c != EDIT_KEY_TAB && c != EDIT_KEY_NONE) - last_tab = 0; - - switch (c) { - case EDIT_KEY_NONE: - break; - case EDIT_KEY_EOF: - edit_eof_cb(edit_cb_ctx); - break; - case EDIT_KEY_TAB: - complete(last_tab); - last_tab = 1; - break; - case EDIT_KEY_UP: - case EDIT_KEY_CTRL_P: - history_prev(); - break; - case EDIT_KEY_DOWN: - case EDIT_KEY_CTRL_N: - history_next(); - break; - case EDIT_KEY_RIGHT: - case EDIT_KEY_CTRL_F: - move_right(); - break; - case EDIT_KEY_LEFT: - case EDIT_KEY_CTRL_B: - move_left(); - break; - case EDIT_KEY_CTRL_RIGHT: - move_word_right(); - break; - case EDIT_KEY_CTRL_LEFT: - move_word_left(); - break; - case EDIT_KEY_DELETE: - delete_current(); - break; - case EDIT_KEY_END: - move_end(); - break; - case EDIT_KEY_HOME: - case EDIT_KEY_CTRL_A: - move_start(); - break; - case EDIT_KEY_F2: - history_debug_dump(); - break; - case EDIT_KEY_CTRL_D: - if (cmdbuf_len > 0) { - delete_current(); - return; - } - printf("\n"); - edit_eof_cb(edit_cb_ctx); - break; - case EDIT_KEY_CTRL_E: - move_end(); - break; - case EDIT_KEY_CTRL_H: - case EDIT_KEY_BACKSPACE: - delete_left(); - break; - case EDIT_KEY_ENTER: - case EDIT_KEY_CTRL_J: - process_cmd(); - break; - case EDIT_KEY_CTRL_K: - clear_right(); - break; - case EDIT_KEY_CTRL_L: - edit_clear_line(); - edit_redraw(); - break; - case EDIT_KEY_CTRL_R: - search = 1; - search_start(); - break; - case EDIT_KEY_CTRL_U: - clear_left(); - break; - case EDIT_KEY_CTRL_W: - delete_word(); - break; - default: - if (c >= 32 && c <= 255) - insert_char(c); - break; - } -} - - -int edit_init(void (*cmd_cb)(void *ctx, char *cmd), - void (*eof_cb)(void *ctx), - char ** (*completion_cb)(void *ctx, const char *cmd, int pos), - void *ctx, const char *history_file, const char *ps) -{ - currbuf[0] = '\0'; - dl_list_init(&history_list); - history_curr = NULL; - if (history_file) - history_read(history_file); - - edit_cb_ctx = ctx; - edit_cmd_cb = cmd_cb; - edit_eof_cb = eof_cb; - edit_completion_cb = completion_cb; - - tcgetattr(STDIN_FILENO, &prevt); - newt = prevt; - newt.c_lflag &= ~(ICANON | ECHO); - tcsetattr(STDIN_FILENO, TCSANOW, &newt); - - eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL); - - ps2 = ps; - printf("%s> ", ps2 ? ps2 : ""); - fflush(stdout); - - return 0; -} - - -void edit_deinit(const char *history_file, - int (*filter_cb)(void *ctx, const char *cmd)) -{ - struct edit_history *h; - if (history_file) - history_write(history_file, filter_cb); - while ((h = dl_list_first(&history_list, struct edit_history, list))) { - dl_list_del(&h->list); - os_free(h); - } - edit_clear_line(); - putchar('\r'); - fflush(stdout); - eloop_unregister_read_sock(STDIN_FILENO); - tcsetattr(STDIN_FILENO, TCSANOW, &prevt); -} - - -void edit_redraw(void) -{ - char tmp; - cmdbuf[cmdbuf_len] = '\0'; - printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf); - if (cmdbuf_pos != cmdbuf_len) { - tmp = cmdbuf[cmdbuf_pos]; - cmdbuf[cmdbuf_pos] = '\0'; - printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf); - cmdbuf[cmdbuf_pos] = tmp; - } - fflush(stdout); -} diff --git a/contrib/hostapd/src/utils/edit.h b/contrib/hostapd/src/utils/edit.h deleted file mode 100644 index ad27f1c7a4..0000000000 --- a/contrib/hostapd/src/utils/edit.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Command line editing and history - * Copyright (c) 2010, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EDIT_H -#define EDIT_H - -int edit_init(void (*cmd_cb)(void *ctx, char *cmd), - void (*eof_cb)(void *ctx), - char ** (*completion_cb)(void *ctx, const char *cmd, int pos), - void *ctx, const char *history_file, const char *ps); -void edit_deinit(const char *history_file, - int (*filter_cb)(void *ctx, const char *cmd)); -void edit_clear_line(void); -void edit_redraw(void); - -#endif /* EDIT_H */ diff --git a/contrib/hostapd/src/utils/edit_readline.c b/contrib/hostapd/src/utils/edit_readline.c deleted file mode 100644 index c2a5bcaa17..0000000000 --- a/contrib/hostapd/src/utils/edit_readline.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Command line editing and history wrapper for readline - * Copyright (c) 2010, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include -#include - -#include "common.h" -#include "eloop.h" -#include "edit.h" - - -static void *edit_cb_ctx; -static void (*edit_cmd_cb)(void *ctx, char *cmd); -static void (*edit_eof_cb)(void *ctx); -static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) = - NULL; - -static char **pending_completions = NULL; - - -static void readline_free_completions(void) -{ - int i; - if (pending_completions == NULL) - return; - for (i = 0; pending_completions[i]; i++) - os_free(pending_completions[i]); - os_free(pending_completions); - pending_completions = NULL; -} - - -static char * readline_completion_func(const char *text, int state) -{ - static int pos = 0; - static size_t len = 0; - - if (pending_completions == NULL) { - rl_attempted_completion_over = 1; - return NULL; - } - - if (state == 0) { - pos = 0; - len = os_strlen(text); - } - for (; pending_completions[pos]; pos++) { - if (strncmp(pending_completions[pos], text, len) == 0) - return strdup(pending_completions[pos++]); - } - - rl_attempted_completion_over = 1; - return NULL; -} - - -static char ** readline_completion(const char *text, int start, int end) -{ - readline_free_completions(); - if (edit_completion_cb) - pending_completions = edit_completion_cb(edit_cb_ctx, - rl_line_buffer, end); - return rl_completion_matches(text, readline_completion_func); -} - - -static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx) -{ - rl_callback_read_char(); -} - - -static void trunc_nl(char *str) -{ - char *pos = str; - while (*pos != '\0') { - if (*pos == '\n') { - *pos = '\0'; - break; - } - pos++; - } -} - - -static void readline_cmd_handler(char *cmd) -{ - if (cmd && *cmd) { - HIST_ENTRY *h; - while (next_history()) - ; - h = previous_history(); - if (h == NULL || os_strcmp(cmd, h->line) != 0) - add_history(cmd); - next_history(); - } - if (cmd == NULL) { - edit_eof_cb(edit_cb_ctx); - return; - } - trunc_nl(cmd); - edit_cmd_cb(edit_cb_ctx, cmd); -} - - -int edit_init(void (*cmd_cb)(void *ctx, char *cmd), - void (*eof_cb)(void *ctx), - char ** (*completion_cb)(void *ctx, const char *cmd, int pos), - void *ctx, const char *history_file, const char *ps) -{ - edit_cb_ctx = ctx; - edit_cmd_cb = cmd_cb; - edit_eof_cb = eof_cb; - edit_completion_cb = completion_cb; - - rl_attempted_completion_function = readline_completion; - if (history_file) { - read_history(history_file); - stifle_history(100); - } - - eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL); - - if (ps) { - size_t blen = os_strlen(ps) + 3; - char *ps2 = os_malloc(blen); - if (ps2) { - os_snprintf(ps2, blen, "%s> ", ps); - rl_callback_handler_install(ps2, readline_cmd_handler); - os_free(ps2); - return 0; - } - } - - rl_callback_handler_install("> ", readline_cmd_handler); - - return 0; -} - - -void edit_deinit(const char *history_file, - int (*filter_cb)(void *ctx, const char *cmd)) -{ - rl_set_prompt(""); - rl_replace_line("", 0); - rl_redisplay(); - rl_callback_handler_remove(); - readline_free_completions(); - - eloop_unregister_read_sock(STDIN_FILENO); - - if (history_file) { - /* Save command history, excluding lines that may contain - * passwords. */ - HIST_ENTRY *h; - history_set_pos(0); - while ((h = current_history())) { - char *p = h->line; - while (*p == ' ' || *p == '\t') - p++; - if (filter_cb && filter_cb(edit_cb_ctx, p)) { - h = remove_history(where_history()); - if (h) { - free(h->line); - free(h->data); - free(h); - } else - next_history(); - } else - next_history(); - } - write_history(history_file); - } -} - - -void edit_clear_line(void) -{ -} - - -void edit_redraw(void) -{ - rl_on_new_line(); - rl_redisplay(); -} diff --git a/contrib/hostapd/src/utils/edit_simple.c b/contrib/hostapd/src/utils/edit_simple.c deleted file mode 100644 index a095ea6abe..0000000000 --- a/contrib/hostapd/src/utils/edit_simple.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Minimal command line editing - * Copyright (c) 2010, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eloop.h" -#include "edit.h" - - -#define CMD_BUF_LEN 256 -static char cmdbuf[CMD_BUF_LEN]; -static int cmdbuf_pos = 0; -static const char *ps2 = NULL; - -static void *edit_cb_ctx; -static void (*edit_cmd_cb)(void *ctx, char *cmd); -static void (*edit_eof_cb)(void *ctx); - - -static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx) -{ - int c; - unsigned char buf[1]; - int res; - - res = read(sock, buf, 1); - if (res < 0) - perror("read"); - if (res <= 0) { - edit_eof_cb(edit_cb_ctx); - return; - } - c = buf[0]; - - if (c == '\r' || c == '\n') { - cmdbuf[cmdbuf_pos] = '\0'; - cmdbuf_pos = 0; - edit_cmd_cb(edit_cb_ctx, cmdbuf); - printf("%s> ", ps2 ? ps2 : ""); - fflush(stdout); - return; - } - - if (c >= 32 && c <= 255) { - if (cmdbuf_pos < (int) sizeof(cmdbuf) - 1) { - cmdbuf[cmdbuf_pos++] = c; - } - } -} - - -int edit_init(void (*cmd_cb)(void *ctx, char *cmd), - void (*eof_cb)(void *ctx), - char ** (*completion_cb)(void *ctx, const char *cmd, int pos), - void *ctx, const char *history_file, const char *ps) -{ - edit_cb_ctx = ctx; - edit_cmd_cb = cmd_cb; - edit_eof_cb = eof_cb; - eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL); - ps2 = ps; - - printf("%s> ", ps2 ? ps2 : ""); - fflush(stdout); - - return 0; -} - - -void edit_deinit(const char *history_file, - int (*filter_cb)(void *ctx, const char *cmd)) -{ - eloop_unregister_read_sock(STDIN_FILENO); -} - - -void edit_clear_line(void) -{ -} - - -void edit_redraw(void) -{ - cmdbuf[cmdbuf_pos] = '\0'; - printf("\r> %s", cmdbuf); -} diff --git a/contrib/hostapd/src/utils/eloop.c b/contrib/hostapd/src/utils/eloop.c deleted file mode 100644 index f83a2327ae..0000000000 --- a/contrib/hostapd/src/utils/eloop.c +++ /dev/null @@ -1,950 +0,0 @@ -/* - * Event loop based on select() loop - * Copyright (c) 2002-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "trace.h" -#include "list.h" -#include "eloop.h" - -#ifdef CONFIG_ELOOP_POLL -#include -#include -#endif /* CONFIG_ELOOP_POLL */ - - -struct eloop_sock { - int sock; - void *eloop_data; - void *user_data; - eloop_sock_handler handler; - WPA_TRACE_REF(eloop); - WPA_TRACE_REF(user); - WPA_TRACE_INFO -}; - -struct eloop_timeout { - struct dl_list list; - struct os_reltime time; - void *eloop_data; - void *user_data; - eloop_timeout_handler handler; - WPA_TRACE_REF(eloop); - WPA_TRACE_REF(user); - WPA_TRACE_INFO -}; - -struct eloop_signal { - int sig; - void *user_data; - eloop_signal_handler handler; - int signaled; -}; - -struct eloop_sock_table { - int count; - struct eloop_sock *table; - int changed; -}; - -struct eloop_data { - int max_sock; - - int count; /* sum of all table counts */ -#ifdef CONFIG_ELOOP_POLL - int max_pollfd_map; /* number of pollfds_map currently allocated */ - int max_poll_fds; /* number of pollfds currently allocated */ - struct pollfd *pollfds; - struct pollfd **pollfds_map; -#endif /* CONFIG_ELOOP_POLL */ - struct eloop_sock_table readers; - struct eloop_sock_table writers; - struct eloop_sock_table exceptions; - - struct dl_list timeout; - - int signal_count; - struct eloop_signal *signals; - int signaled; - int pending_terminate; - - int terminate; - int reader_table_changed; -}; - -static struct eloop_data eloop; - - -#ifdef WPA_TRACE - -static void eloop_sigsegv_handler(int sig) -{ - wpa_trace_show("eloop SIGSEGV"); - abort(); -} - -static void eloop_trace_sock_add_ref(struct eloop_sock_table *table) -{ - int i; - if (table == NULL || table->table == NULL) - return; - for (i = 0; i < table->count; i++) { - wpa_trace_add_ref(&table->table[i], eloop, - table->table[i].eloop_data); - wpa_trace_add_ref(&table->table[i], user, - table->table[i].user_data); - } -} - - -static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table) -{ - int i; - if (table == NULL || table->table == NULL) - return; - for (i = 0; i < table->count; i++) { - wpa_trace_remove_ref(&table->table[i], eloop, - table->table[i].eloop_data); - wpa_trace_remove_ref(&table->table[i], user, - table->table[i].user_data); - } -} - -#else /* WPA_TRACE */ - -#define eloop_trace_sock_add_ref(table) do { } while (0) -#define eloop_trace_sock_remove_ref(table) do { } while (0) - -#endif /* WPA_TRACE */ - - -int eloop_init(void) -{ - os_memset(&eloop, 0, sizeof(eloop)); - dl_list_init(&eloop.timeout); -#ifdef WPA_TRACE - signal(SIGSEGV, eloop_sigsegv_handler); -#endif /* WPA_TRACE */ - return 0; -} - - -static int eloop_sock_table_add_sock(struct eloop_sock_table *table, - int sock, eloop_sock_handler handler, - void *eloop_data, void *user_data) -{ - struct eloop_sock *tmp; - int new_max_sock; - - if (sock > eloop.max_sock) - new_max_sock = sock; - else - new_max_sock = eloop.max_sock; - - if (table == NULL) - return -1; - -#ifdef CONFIG_ELOOP_POLL - if (new_max_sock >= eloop.max_pollfd_map) { - struct pollfd **nmap; - nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50, - sizeof(struct pollfd *)); - if (nmap == NULL) - return -1; - - eloop.max_pollfd_map = new_max_sock + 50; - eloop.pollfds_map = nmap; - } - - if (eloop.count + 1 > eloop.max_poll_fds) { - struct pollfd *n; - int nmax = eloop.count + 1 + 50; - n = os_realloc_array(eloop.pollfds, nmax, - sizeof(struct pollfd)); - if (n == NULL) - return -1; - - eloop.max_poll_fds = nmax; - eloop.pollfds = n; - } -#endif /* CONFIG_ELOOP_POLL */ - - eloop_trace_sock_remove_ref(table); - tmp = os_realloc_array(table->table, table->count + 1, - sizeof(struct eloop_sock)); - if (tmp == NULL) - return -1; - - tmp[table->count].sock = sock; - tmp[table->count].eloop_data = eloop_data; - tmp[table->count].user_data = user_data; - tmp[table->count].handler = handler; - wpa_trace_record(&tmp[table->count]); - table->count++; - table->table = tmp; - eloop.max_sock = new_max_sock; - eloop.count++; - table->changed = 1; - eloop_trace_sock_add_ref(table); - - return 0; -} - - -static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, - int sock) -{ - int i; - - if (table == NULL || table->table == NULL || table->count == 0) - return; - - for (i = 0; i < table->count; i++) { - if (table->table[i].sock == sock) - break; - } - if (i == table->count) - return; - eloop_trace_sock_remove_ref(table); - if (i != table->count - 1) { - os_memmove(&table->table[i], &table->table[i + 1], - (table->count - i - 1) * - sizeof(struct eloop_sock)); - } - table->count--; - eloop.count--; - table->changed = 1; - eloop_trace_sock_add_ref(table); -} - - -#ifdef CONFIG_ELOOP_POLL - -static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx) -{ - if (fd < mx && fd >= 0) - return pollfds_map[fd]; - return NULL; -} - - -static int eloop_sock_table_set_fds(struct eloop_sock_table *readers, - struct eloop_sock_table *writers, - struct eloop_sock_table *exceptions, - struct pollfd *pollfds, - struct pollfd **pollfds_map, - int max_pollfd_map) -{ - int i; - int nxt = 0; - int fd; - struct pollfd *pfd; - - /* Clear pollfd lookup map. It will be re-populated below. */ - os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map); - - if (readers && readers->table) { - for (i = 0; i < readers->count; i++) { - fd = readers->table[i].sock; - assert(fd >= 0 && fd < max_pollfd_map); - pollfds[nxt].fd = fd; - pollfds[nxt].events = POLLIN; - pollfds[nxt].revents = 0; - pollfds_map[fd] = &(pollfds[nxt]); - nxt++; - } - } - - if (writers && writers->table) { - for (i = 0; i < writers->count; i++) { - /* - * See if we already added this descriptor, update it - * if so. - */ - fd = writers->table[i].sock; - assert(fd >= 0 && fd < max_pollfd_map); - pfd = pollfds_map[fd]; - if (!pfd) { - pfd = &(pollfds[nxt]); - pfd->events = 0; - pfd->fd = fd; - pollfds[i].revents = 0; - pollfds_map[fd] = pfd; - nxt++; - } - pfd->events |= POLLOUT; - } - } - - /* - * Exceptions are always checked when using poll, but I suppose it's - * possible that someone registered a socket *only* for exception - * handling. Set the POLLIN bit in this case. - */ - if (exceptions && exceptions->table) { - for (i = 0; i < exceptions->count; i++) { - /* - * See if we already added this descriptor, just use it - * if so. - */ - fd = exceptions->table[i].sock; - assert(fd >= 0 && fd < max_pollfd_map); - pfd = pollfds_map[fd]; - if (!pfd) { - pfd = &(pollfds[nxt]); - pfd->events = POLLIN; - pfd->fd = fd; - pollfds[i].revents = 0; - pollfds_map[fd] = pfd; - nxt++; - } - } - } - - return nxt; -} - - -static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table, - struct pollfd **pollfds_map, - int max_pollfd_map, - short int revents) -{ - int i; - struct pollfd *pfd; - - if (!table || !table->table) - return 0; - - table->changed = 0; - for (i = 0; i < table->count; i++) { - pfd = find_pollfd(pollfds_map, table->table[i].sock, - max_pollfd_map); - if (!pfd) - continue; - - if (!(pfd->revents & revents)) - continue; - - table->table[i].handler(table->table[i].sock, - table->table[i].eloop_data, - table->table[i].user_data); - if (table->changed) - return 1; - } - - return 0; -} - - -static void eloop_sock_table_dispatch(struct eloop_sock_table *readers, - struct eloop_sock_table *writers, - struct eloop_sock_table *exceptions, - struct pollfd **pollfds_map, - int max_pollfd_map) -{ - if (eloop_sock_table_dispatch_table(readers, pollfds_map, - max_pollfd_map, POLLIN | POLLERR | - POLLHUP)) - return; /* pollfds may be invalid at this point */ - - if (eloop_sock_table_dispatch_table(writers, pollfds_map, - max_pollfd_map, POLLOUT)) - return; /* pollfds may be invalid at this point */ - - eloop_sock_table_dispatch_table(exceptions, pollfds_map, - max_pollfd_map, POLLERR | POLLHUP); -} - -#else /* CONFIG_ELOOP_POLL */ - -static void eloop_sock_table_set_fds(struct eloop_sock_table *table, - fd_set *fds) -{ - int i; - - FD_ZERO(fds); - - if (table->table == NULL) - return; - - for (i = 0; i < table->count; i++) - FD_SET(table->table[i].sock, fds); -} - - -static void eloop_sock_table_dispatch(struct eloop_sock_table *table, - fd_set *fds) -{ - int i; - - if (table == NULL || table->table == NULL) - return; - - table->changed = 0; - for (i = 0; i < table->count; i++) { - if (FD_ISSET(table->table[i].sock, fds)) { - table->table[i].handler(table->table[i].sock, - table->table[i].eloop_data, - table->table[i].user_data); - if (table->changed) - break; - } - } -} - -#endif /* CONFIG_ELOOP_POLL */ - - -static void eloop_sock_table_destroy(struct eloop_sock_table *table) -{ - if (table) { - int i; - for (i = 0; i < table->count && table->table; i++) { - wpa_printf(MSG_INFO, "ELOOP: remaining socket: " - "sock=%d eloop_data=%p user_data=%p " - "handler=%p", - table->table[i].sock, - table->table[i].eloop_data, - table->table[i].user_data, - table->table[i].handler); - wpa_trace_dump_funcname("eloop unregistered socket " - "handler", - table->table[i].handler); - wpa_trace_dump("eloop sock", &table->table[i]); - } - os_free(table->table); - } -} - - -int eloop_register_read_sock(int sock, eloop_sock_handler handler, - void *eloop_data, void *user_data) -{ - return eloop_register_sock(sock, EVENT_TYPE_READ, handler, - eloop_data, user_data); -} - - -void eloop_unregister_read_sock(int sock) -{ - eloop_unregister_sock(sock, EVENT_TYPE_READ); -} - - -static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type) -{ - switch (type) { - case EVENT_TYPE_READ: - return &eloop.readers; - case EVENT_TYPE_WRITE: - return &eloop.writers; - case EVENT_TYPE_EXCEPTION: - return &eloop.exceptions; - } - - return NULL; -} - - -int eloop_register_sock(int sock, eloop_event_type type, - eloop_sock_handler handler, - void *eloop_data, void *user_data) -{ - struct eloop_sock_table *table; - - table = eloop_get_sock_table(type); - return eloop_sock_table_add_sock(table, sock, handler, - eloop_data, user_data); -} - - -void eloop_unregister_sock(int sock, eloop_event_type type) -{ - struct eloop_sock_table *table; - - table = eloop_get_sock_table(type); - eloop_sock_table_remove_sock(table, sock); -} - - -int eloop_register_timeout(unsigned int secs, unsigned int usecs, - eloop_timeout_handler handler, - void *eloop_data, void *user_data) -{ - struct eloop_timeout *timeout, *tmp; - os_time_t now_sec; - - timeout = os_zalloc(sizeof(*timeout)); - if (timeout == NULL) - return -1; - if (os_get_reltime(&timeout->time) < 0) { - os_free(timeout); - return -1; - } - now_sec = timeout->time.sec; - timeout->time.sec += secs; - if (timeout->time.sec < now_sec) { - /* - * Integer overflow - assume long enough timeout to be assumed - * to be infinite, i.e., the timeout would never happen. - */ - wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to " - "ever happen - ignore it", secs); - os_free(timeout); - return 0; - } - timeout->time.usec += usecs; - while (timeout->time.usec >= 1000000) { - timeout->time.sec++; - timeout->time.usec -= 1000000; - } - timeout->eloop_data = eloop_data; - timeout->user_data = user_data; - timeout->handler = handler; - wpa_trace_add_ref(timeout, eloop, eloop_data); - wpa_trace_add_ref(timeout, user, user_data); - wpa_trace_record(timeout); - - /* Maintain timeouts in order of increasing time */ - dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { - if (os_reltime_before(&timeout->time, &tmp->time)) { - dl_list_add(tmp->list.prev, &timeout->list); - return 0; - } - } - dl_list_add_tail(&eloop.timeout, &timeout->list); - - return 0; -} - - -static void eloop_remove_timeout(struct eloop_timeout *timeout) -{ - dl_list_del(&timeout->list); - wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data); - wpa_trace_remove_ref(timeout, user, timeout->user_data); - os_free(timeout); -} - - -int eloop_cancel_timeout(eloop_timeout_handler handler, - void *eloop_data, void *user_data) -{ - struct eloop_timeout *timeout, *prev; - int removed = 0; - - dl_list_for_each_safe(timeout, prev, &eloop.timeout, - struct eloop_timeout, list) { - if (timeout->handler == handler && - (timeout->eloop_data == eloop_data || - eloop_data == ELOOP_ALL_CTX) && - (timeout->user_data == user_data || - user_data == ELOOP_ALL_CTX)) { - eloop_remove_timeout(timeout); - removed++; - } - } - - return removed; -} - - -int eloop_cancel_timeout_one(eloop_timeout_handler handler, - void *eloop_data, void *user_data, - struct os_reltime *remaining) -{ - struct eloop_timeout *timeout, *prev; - int removed = 0; - struct os_reltime now; - - os_get_reltime(&now); - remaining->sec = remaining->usec = 0; - - dl_list_for_each_safe(timeout, prev, &eloop.timeout, - struct eloop_timeout, list) { - if (timeout->handler == handler && - (timeout->eloop_data == eloop_data) && - (timeout->user_data == user_data)) { - removed = 1; - if (os_reltime_before(&now, &timeout->time)) - os_reltime_sub(&timeout->time, &now, remaining); - eloop_remove_timeout(timeout); - break; - } - } - return removed; -} - - -int eloop_is_timeout_registered(eloop_timeout_handler handler, - void *eloop_data, void *user_data) -{ - struct eloop_timeout *tmp; - - dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { - if (tmp->handler == handler && - tmp->eloop_data == eloop_data && - tmp->user_data == user_data) - return 1; - } - - return 0; -} - - -int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs, - eloop_timeout_handler handler, void *eloop_data, - void *user_data) -{ - struct os_reltime now, requested, remaining; - struct eloop_timeout *tmp; - - dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { - if (tmp->handler == handler && - tmp->eloop_data == eloop_data && - tmp->user_data == user_data) { - requested.sec = req_secs; - requested.usec = req_usecs; - os_get_reltime(&now); - os_reltime_sub(&tmp->time, &now, &remaining); - if (os_reltime_before(&requested, &remaining)) { - eloop_cancel_timeout(handler, eloop_data, - user_data); - eloop_register_timeout(requested.sec, - requested.usec, - handler, eloop_data, - user_data); - return 1; - } - return 0; - } - } - - return -1; -} - - -int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, - eloop_timeout_handler handler, void *eloop_data, - void *user_data) -{ - struct os_reltime now, requested, remaining; - struct eloop_timeout *tmp; - - dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { - if (tmp->handler == handler && - tmp->eloop_data == eloop_data && - tmp->user_data == user_data) { - requested.sec = req_secs; - requested.usec = req_usecs; - os_get_reltime(&now); - os_reltime_sub(&tmp->time, &now, &remaining); - if (os_reltime_before(&remaining, &requested)) { - eloop_cancel_timeout(handler, eloop_data, - user_data); - eloop_register_timeout(requested.sec, - requested.usec, - handler, eloop_data, - user_data); - return 1; - } - return 0; - } - } - - return -1; -} - - -#ifndef CONFIG_NATIVE_WINDOWS -static void eloop_handle_alarm(int sig) -{ - wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in " - "two seconds. Looks like there\n" - "is a bug that ends up in a busy loop that " - "prevents clean shutdown.\n" - "Killing program forcefully.\n"); - exit(1); -} -#endif /* CONFIG_NATIVE_WINDOWS */ - - -static void eloop_handle_signal(int sig) -{ - int i; - -#ifndef CONFIG_NATIVE_WINDOWS - if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { - /* Use SIGALRM to break out from potential busy loops that - * would not allow the program to be killed. */ - eloop.pending_terminate = 1; - signal(SIGALRM, eloop_handle_alarm); - alarm(2); - } -#endif /* CONFIG_NATIVE_WINDOWS */ - - eloop.signaled++; - for (i = 0; i < eloop.signal_count; i++) { - if (eloop.signals[i].sig == sig) { - eloop.signals[i].signaled++; - break; - } - } -} - - -static void eloop_process_pending_signals(void) -{ - int i; - - if (eloop.signaled == 0) - return; - eloop.signaled = 0; - - if (eloop.pending_terminate) { -#ifndef CONFIG_NATIVE_WINDOWS - alarm(0); -#endif /* CONFIG_NATIVE_WINDOWS */ - eloop.pending_terminate = 0; - } - - for (i = 0; i < eloop.signal_count; i++) { - if (eloop.signals[i].signaled) { - eloop.signals[i].signaled = 0; - eloop.signals[i].handler(eloop.signals[i].sig, - eloop.signals[i].user_data); - } - } -} - - -int eloop_register_signal(int sig, eloop_signal_handler handler, - void *user_data) -{ - struct eloop_signal *tmp; - - tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1, - sizeof(struct eloop_signal)); - if (tmp == NULL) - return -1; - - tmp[eloop.signal_count].sig = sig; - tmp[eloop.signal_count].user_data = user_data; - tmp[eloop.signal_count].handler = handler; - tmp[eloop.signal_count].signaled = 0; - eloop.signal_count++; - eloop.signals = tmp; - signal(sig, eloop_handle_signal); - - return 0; -} - - -int eloop_register_signal_terminate(eloop_signal_handler handler, - void *user_data) -{ - int ret = eloop_register_signal(SIGINT, handler, user_data); - if (ret == 0) - ret = eloop_register_signal(SIGTERM, handler, user_data); - return ret; -} - - -int eloop_register_signal_reconfig(eloop_signal_handler handler, - void *user_data) -{ -#ifdef CONFIG_NATIVE_WINDOWS - return 0; -#else /* CONFIG_NATIVE_WINDOWS */ - return eloop_register_signal(SIGHUP, handler, user_data); -#endif /* CONFIG_NATIVE_WINDOWS */ -} - - -void eloop_run(void) -{ -#ifdef CONFIG_ELOOP_POLL - int num_poll_fds; - int timeout_ms = 0; -#else /* CONFIG_ELOOP_POLL */ - fd_set *rfds, *wfds, *efds; - struct timeval _tv; -#endif /* CONFIG_ELOOP_POLL */ - int res; - struct os_reltime tv, now; - -#ifndef CONFIG_ELOOP_POLL - rfds = os_malloc(sizeof(*rfds)); - wfds = os_malloc(sizeof(*wfds)); - efds = os_malloc(sizeof(*efds)); - if (rfds == NULL || wfds == NULL || efds == NULL) - goto out; -#endif /* CONFIG_ELOOP_POLL */ - - while (!eloop.terminate && - (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || - eloop.writers.count > 0 || eloop.exceptions.count > 0)) { - struct eloop_timeout *timeout; - timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, - list); - if (timeout) { - os_get_reltime(&now); - if (os_reltime_before(&now, &timeout->time)) - os_reltime_sub(&timeout->time, &now, &tv); - else - tv.sec = tv.usec = 0; -#ifdef CONFIG_ELOOP_POLL - timeout_ms = tv.sec * 1000 + tv.usec / 1000; -#else /* CONFIG_ELOOP_POLL */ - _tv.tv_sec = tv.sec; - _tv.tv_usec = tv.usec; -#endif /* CONFIG_ELOOP_POLL */ - } - -#ifdef CONFIG_ELOOP_POLL - num_poll_fds = eloop_sock_table_set_fds( - &eloop.readers, &eloop.writers, &eloop.exceptions, - eloop.pollfds, eloop.pollfds_map, - eloop.max_pollfd_map); - res = poll(eloop.pollfds, num_poll_fds, - timeout ? timeout_ms : -1); - - if (res < 0 && errno != EINTR && errno != 0) { - wpa_printf(MSG_INFO, "eloop: poll: %s", - strerror(errno)); - goto out; - } -#else /* CONFIG_ELOOP_POLL */ - eloop_sock_table_set_fds(&eloop.readers, rfds); - eloop_sock_table_set_fds(&eloop.writers, wfds); - eloop_sock_table_set_fds(&eloop.exceptions, efds); - res = select(eloop.max_sock + 1, rfds, wfds, efds, - timeout ? &_tv : NULL); - if (res < 0 && errno != EINTR && errno != 0) { - wpa_printf(MSG_INFO, "eloop: select: %s", - strerror(errno)); - goto out; - } -#endif /* CONFIG_ELOOP_POLL */ - eloop_process_pending_signals(); - - /* check if some registered timeouts have occurred */ - timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, - list); - if (timeout) { - os_get_reltime(&now); - if (!os_reltime_before(&now, &timeout->time)) { - void *eloop_data = timeout->eloop_data; - void *user_data = timeout->user_data; - eloop_timeout_handler handler = - timeout->handler; - eloop_remove_timeout(timeout); - handler(eloop_data, user_data); - } - - } - - if (res <= 0) - continue; - -#ifdef CONFIG_ELOOP_POLL - eloop_sock_table_dispatch(&eloop.readers, &eloop.writers, - &eloop.exceptions, eloop.pollfds_map, - eloop.max_pollfd_map); -#else /* CONFIG_ELOOP_POLL */ - eloop_sock_table_dispatch(&eloop.readers, rfds); - eloop_sock_table_dispatch(&eloop.writers, wfds); - eloop_sock_table_dispatch(&eloop.exceptions, efds); -#endif /* CONFIG_ELOOP_POLL */ - } - - eloop.terminate = 0; -out: -#ifndef CONFIG_ELOOP_POLL - os_free(rfds); - os_free(wfds); - os_free(efds); -#endif /* CONFIG_ELOOP_POLL */ - return; -} - - -void eloop_terminate(void) -{ - eloop.terminate = 1; -} - - -void eloop_destroy(void) -{ - struct eloop_timeout *timeout, *prev; - struct os_reltime now; - - os_get_reltime(&now); - dl_list_for_each_safe(timeout, prev, &eloop.timeout, - struct eloop_timeout, list) { - int sec, usec; - sec = timeout->time.sec - now.sec; - usec = timeout->time.usec - now.usec; - if (timeout->time.usec < now.usec) { - sec--; - usec += 1000000; - } - wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d " - "eloop_data=%p user_data=%p handler=%p", - sec, usec, timeout->eloop_data, timeout->user_data, - timeout->handler); - wpa_trace_dump_funcname("eloop unregistered timeout handler", - timeout->handler); - wpa_trace_dump("eloop timeout", timeout); - eloop_remove_timeout(timeout); - } - eloop_sock_table_destroy(&eloop.readers); - eloop_sock_table_destroy(&eloop.writers); - eloop_sock_table_destroy(&eloop.exceptions); - os_free(eloop.signals); - -#ifdef CONFIG_ELOOP_POLL - os_free(eloop.pollfds); - os_free(eloop.pollfds_map); -#endif /* CONFIG_ELOOP_POLL */ -} - - -int eloop_terminated(void) -{ - return eloop.terminate; -} - - -void eloop_wait_for_read_sock(int sock) -{ -#ifdef CONFIG_ELOOP_POLL - struct pollfd pfd; - - if (sock < 0) - return; - - os_memset(&pfd, 0, sizeof(pfd)); - pfd.fd = sock; - pfd.events = POLLIN; - - poll(&pfd, 1, -1); -#else /* CONFIG_ELOOP_POLL */ - fd_set rfds; - - if (sock < 0) - return; - - FD_ZERO(&rfds); - FD_SET(sock, &rfds); - select(sock + 1, &rfds, NULL, NULL, NULL); -#endif /* CONFIG_ELOOP_POLL */ -} diff --git a/contrib/hostapd/src/utils/eloop.h b/contrib/hostapd/src/utils/eloop.h deleted file mode 100644 index 07b8c0dc33..0000000000 --- a/contrib/hostapd/src/utils/eloop.h +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Event loop - * Copyright (c) 2002-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file defines an event loop interface that supports processing events - * from registered timeouts (i.e., do something after N seconds), sockets - * (e.g., a new packet available for reading), and signals. eloop.c is an - * implementation of this interface using select() and sockets. This is - * suitable for most UNIX/POSIX systems. When porting to other operating - * systems, it may be necessary to replace that implementation with OS specific - * mechanisms. - */ - -#ifndef ELOOP_H -#define ELOOP_H - -/** - * ELOOP_ALL_CTX - eloop_cancel_timeout() magic number to match all timeouts - */ -#define ELOOP_ALL_CTX (void *) -1 - -/** - * eloop_event_type - eloop socket event type for eloop_register_sock() - * @EVENT_TYPE_READ: Socket has data available for reading - * @EVENT_TYPE_WRITE: Socket has room for new data to be written - * @EVENT_TYPE_EXCEPTION: An exception has been reported - */ -typedef enum { - EVENT_TYPE_READ = 0, - EVENT_TYPE_WRITE, - EVENT_TYPE_EXCEPTION -} eloop_event_type; - -/** - * eloop_sock_handler - eloop socket event callback type - * @sock: File descriptor number for the socket - * @eloop_ctx: Registered callback context data (eloop_data) - * @sock_ctx: Registered callback context data (user_data) - */ -typedef void (*eloop_sock_handler)(int sock, void *eloop_ctx, void *sock_ctx); - -/** - * eloop_event_handler - eloop generic event callback type - * @eloop_ctx: Registered callback context data (eloop_data) - * @sock_ctx: Registered callback context data (user_data) - */ -typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx); - -/** - * eloop_timeout_handler - eloop timeout event callback type - * @eloop_ctx: Registered callback context data (eloop_data) - * @sock_ctx: Registered callback context data (user_data) - */ -typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx); - -/** - * eloop_signal_handler - eloop signal event callback type - * @sig: Signal number - * @signal_ctx: Registered callback context data (user_data from - * eloop_register_signal(), eloop_register_signal_terminate(), or - * eloop_register_signal_reconfig() call) - */ -typedef void (*eloop_signal_handler)(int sig, void *signal_ctx); - -/** - * eloop_init() - Initialize global event loop data - * Returns: 0 on success, -1 on failure - * - * This function must be called before any other eloop_* function. - */ -int eloop_init(void); - -/** - * eloop_register_read_sock - Register handler for read events - * @sock: File descriptor number for the socket - * @handler: Callback function to be called when data is available for reading - * @eloop_data: Callback context data (eloop_ctx) - * @user_data: Callback context data (sock_ctx) - * Returns: 0 on success, -1 on failure - * - * Register a read socket notifier for the given file descriptor. The handler - * function will be called whenever data is available for reading from the - * socket. The handler function is responsible for clearing the event after - * having processed it in order to avoid eloop from calling the handler again - * for the same event. - */ -int eloop_register_read_sock(int sock, eloop_sock_handler handler, - void *eloop_data, void *user_data); - -/** - * eloop_unregister_read_sock - Unregister handler for read events - * @sock: File descriptor number for the socket - * - * Unregister a read socket notifier that was previously registered with - * eloop_register_read_sock(). - */ -void eloop_unregister_read_sock(int sock); - -/** - * eloop_register_sock - Register handler for socket events - * @sock: File descriptor number for the socket - * @type: Type of event to wait for - * @handler: Callback function to be called when the event is triggered - * @eloop_data: Callback context data (eloop_ctx) - * @user_data: Callback context data (sock_ctx) - * Returns: 0 on success, -1 on failure - * - * Register an event notifier for the given socket's file descriptor. The - * handler function will be called whenever the that event is triggered for the - * socket. The handler function is responsible for clearing the event after - * having processed it in order to avoid eloop from calling the handler again - * for the same event. - */ -int eloop_register_sock(int sock, eloop_event_type type, - eloop_sock_handler handler, - void *eloop_data, void *user_data); - -/** - * eloop_unregister_sock - Unregister handler for socket events - * @sock: File descriptor number for the socket - * @type: Type of event for which sock was registered - * - * Unregister a socket event notifier that was previously registered with - * eloop_register_sock(). - */ -void eloop_unregister_sock(int sock, eloop_event_type type); - -/** - * eloop_register_event - Register handler for generic events - * @event: Event to wait (eloop implementation specific) - * @event_size: Size of event data - * @handler: Callback function to be called when event is triggered - * @eloop_data: Callback context data (eloop_data) - * @user_data: Callback context data (user_data) - * 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 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 - * function is responsible for clearing the event after having processed it in - * order to avoid eloop from calling the handler again for the same event. - * - * In case of Windows implementation (eloop_win.c), event pointer is of HANDLE - * type, i.e., void*. The callers are likely to have 'HANDLE h' type variable, - * and they would call this function with eloop_register_event(h, sizeof(h), - * ...). - */ -int eloop_register_event(void *event, size_t event_size, - eloop_event_handler handler, - void *eloop_data, void *user_data); - -/** - * eloop_unregister_event - Unregister handler for a generic event - * @event: Event to cancel (eloop implementation specific) - * @event_size: Size of event data - * - * Unregister a generic event notifier that was previously registered with - * eloop_register_event(). - */ -void eloop_unregister_event(void *event, size_t event_size); - -/** - * eloop_register_timeout - Register timeout - * @secs: Number of seconds to the timeout - * @usecs: Number of microseconds to the timeout - * @handler: Callback function to be called when timeout occurs - * @eloop_data: Callback context data (eloop_ctx) - * @user_data: Callback context data (sock_ctx) - * Returns: 0 on success, -1 on failure - * - * Register a timeout that will cause the handler function to be called after - * given time. - */ -int eloop_register_timeout(unsigned int secs, unsigned int usecs, - eloop_timeout_handler handler, - void *eloop_data, void *user_data); - -/** - * eloop_cancel_timeout - Cancel timeouts - * @handler: Matching callback function - * @eloop_data: Matching eloop_data or %ELOOP_ALL_CTX to match all - * @user_data: Matching user_data or %ELOOP_ALL_CTX to match all - * Returns: Number of cancelled timeouts - * - * Cancel matching timeouts registered with - * eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for - * cancelling all timeouts regardless of eloop_data/user_data. - */ -int eloop_cancel_timeout(eloop_timeout_handler handler, - void *eloop_data, void *user_data); - -/** - * eloop_cancel_timeout_one - Cancel a single timeout - * @handler: Matching callback function - * @eloop_data: Matching eloop_data - * @user_data: Matching user_data - * @remaining: Time left on the cancelled timer - * Returns: Number of cancelled timeouts - * - * Cancel matching timeout registered with - * eloop_register_timeout() and return the remaining time left. - */ -int eloop_cancel_timeout_one(eloop_timeout_handler handler, - void *eloop_data, void *user_data, - struct os_reltime *remaining); - -/** - * eloop_is_timeout_registered - Check if a timeout is already registered - * @handler: Matching callback function - * @eloop_data: Matching eloop_data - * @user_data: Matching user_data - * Returns: 1 if the timeout is registered, 0 if the timeout is not registered - * - * Determine if a matching timeout is registered - * with eloop_register_timeout(). - */ -int eloop_is_timeout_registered(eloop_timeout_handler handler, - void *eloop_data, void *user_data); - -/** - * eloop_deplete_timeout - Deplete a timeout that is already registered - * @req_secs: Requested number of seconds to the timeout - * @req_usecs: Requested number of microseconds to the timeout - * @handler: Matching callback function - * @eloop_data: Matching eloop_data - * @user_data: Matching user_data - * Returns: 1 if the timeout is depleted, 0 if no change is made, -1 if no - * timeout matched - * - * Find a registered matching timeout. If found, - * deplete the timeout if remaining time is more than the requested time. - */ -int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs, - eloop_timeout_handler handler, void *eloop_data, - void *user_data); - -/** - * eloop_replenish_timeout - Replenish a timeout that is already registered - * @req_secs: Requested number of seconds to the timeout - * @req_usecs: Requested number of microseconds to the timeout - * @handler: Matching callback function - * @eloop_data: Matching eloop_data - * @user_data: Matching user_data - * Returns: 1 if the timeout is replenished, 0 if no change is made, -1 if no - * timeout matched - * - * Find a registered matching timeout. If found, - * replenish the timeout if remaining time is less than the requested time. - */ -int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, - eloop_timeout_handler handler, void *eloop_data, - void *user_data); - -/** - * eloop_register_signal - Register handler for signals - * @sig: Signal number (e.g., SIGHUP) - * @handler: Callback function to be called when the signal is received - * @user_data: Callback context data (signal_ctx) - * Returns: 0 on success, -1 on failure - * - * Register a callback function that will be called when a signal is received. - * The callback function is actually called only after the system signal - * handler has returned. This means that the normal limits for sighandlers - * (i.e., only "safe functions" allowed) do not apply for the registered - * callback. - */ -int eloop_register_signal(int sig, eloop_signal_handler handler, - void *user_data); - -/** - * eloop_register_signal_terminate - Register handler for terminate signals - * @handler: Callback function to be called when the signal is received - * @user_data: Callback context data (signal_ctx) - * Returns: 0 on success, -1 on failure - * - * Register a callback function that will be called when a process termination - * signal is received. The callback function is actually called only after the - * system signal handler has returned. This means that the normal limits for - * sighandlers (i.e., only "safe functions" allowed) do not apply for the - * registered callback. - * - * This function is a more portable version of eloop_register_signal() since - * the knowledge of exact details of the signals is hidden in eloop - * implementation. In case of operating systems using signal(), this function - * registers handlers for SIGINT and SIGTERM. - */ -int eloop_register_signal_terminate(eloop_signal_handler handler, - void *user_data); - -/** - * eloop_register_signal_reconfig - Register handler for reconfig signals - * @handler: Callback function to be called when the signal is received - * @user_data: Callback context data (signal_ctx) - * Returns: 0 on success, -1 on failure - * - * Register a callback function that will be called when a reconfiguration / - * hangup signal is received. The callback function is actually called only - * after the system signal handler has returned. This means that the normal - * limits for sighandlers (i.e., only "safe functions" allowed) do not apply - * for the registered callback. - * - * This function is a more portable version of eloop_register_signal() since - * the knowledge of exact details of the signals is hidden in eloop - * implementation. In case of operating systems using signal(), this function - * registers a handler for SIGHUP. - */ -int eloop_register_signal_reconfig(eloop_signal_handler handler, - void *user_data); - -/** - * eloop_run - Start the event loop - * - * Start the event loop and continue running as long as there are any - * registered event handlers. This function is run after event loop has been - * initialized with event_init() and one or more events have been registered. - */ -void eloop_run(void); - -/** - * eloop_terminate - Terminate event loop - * - * Terminate event loop even if there are registered events. This can be used - * to request the program to be terminated cleanly. - */ -void eloop_terminate(void); - -/** - * eloop_destroy - Free any resources allocated for the event loop - * - * After calling eloop_destroy(), other eloop_* functions must not be called - * before re-running eloop_init(). - */ -void eloop_destroy(void); - -/** - * eloop_terminated - Check whether event loop has been terminated - * Returns: 1 = event loop terminate, 0 = event loop still running - * - * This function can be used to check whether eloop_terminate() has been called - * to request termination of the event loop. This is normally used to abort - * operations that may still be queued to be run when eloop_terminate() was - * called. - */ -int eloop_terminated(void); - -/** - * eloop_wait_for_read_sock - Wait for a single reader - * @sock: File descriptor number for the socket - * - * Do a blocking wait for a single read socket. - */ -void eloop_wait_for_read_sock(int sock); - -#endif /* ELOOP_H */ diff --git a/contrib/hostapd/src/utils/eloop_win.c b/contrib/hostapd/src/utils/eloop_win.c deleted file mode 100644 index de47fb2183..0000000000 --- a/contrib/hostapd/src/utils/eloop_win.c +++ /dev/null @@ -1,694 +0,0 @@ -/* - * Event loop based on Windows events and WaitForMultipleObjects - * Copyright (c) 2002-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "list.h" -#include "eloop.h" - - -struct eloop_sock { - int sock; - void *eloop_data; - void *user_data; - eloop_sock_handler handler; - WSAEVENT event; -}; - -struct eloop_event { - void *eloop_data; - void *user_data; - eloop_event_handler handler; - HANDLE event; -}; - -struct eloop_timeout { - struct dl_list list; - struct os_reltime time; - void *eloop_data; - void *user_data; - eloop_timeout_handler handler; -}; - -struct eloop_signal { - int sig; - void *user_data; - eloop_signal_handler handler; - int signaled; -}; - -struct eloop_data { - int max_sock; - size_t reader_count; - struct eloop_sock *readers; - - size_t event_count; - struct eloop_event *events; - - struct dl_list timeout; - - int signal_count; - struct eloop_signal *signals; - int signaled; - int pending_terminate; - - int terminate; - int reader_table_changed; - - struct eloop_signal term_signal; - HANDLE term_event; - - HANDLE *handles; - size_t num_handles; -}; - -static struct eloop_data eloop; - - -int eloop_init(void) -{ - os_memset(&eloop, 0, sizeof(eloop)); - dl_list_init(&eloop.timeout); - eloop.num_handles = 1; - eloop.handles = os_malloc(eloop.num_handles * - sizeof(eloop.handles[0])); - if (eloop.handles == NULL) - return -1; - - eloop.term_event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (eloop.term_event == NULL) { - printf("CreateEvent() failed: %d\n", - (int) GetLastError()); - os_free(eloop.handles); - return -1; - } - - return 0; -} - - -static int eloop_prepare_handles(void) -{ - HANDLE *n; - - if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8) - return 0; - n = os_realloc_array(eloop.handles, eloop.num_handles * 2, - sizeof(eloop.handles[0])); - if (n == NULL) - return -1; - eloop.handles = n; - eloop.num_handles *= 2; - return 0; -} - - -int eloop_register_read_sock(int sock, eloop_sock_handler handler, - void *eloop_data, void *user_data) -{ - WSAEVENT event; - struct eloop_sock *tmp; - - if (eloop_prepare_handles()) - return -1; - - event = WSACreateEvent(); - if (event == WSA_INVALID_EVENT) { - printf("WSACreateEvent() failed: %d\n", WSAGetLastError()); - return -1; - } - - if (WSAEventSelect(sock, event, FD_READ)) { - printf("WSAEventSelect() failed: %d\n", WSAGetLastError()); - WSACloseEvent(event); - return -1; - } - tmp = os_realloc_array(eloop.readers, eloop.reader_count + 1, - sizeof(struct eloop_sock)); - if (tmp == NULL) { - WSAEventSelect(sock, event, 0); - WSACloseEvent(event); - return -1; - } - - tmp[eloop.reader_count].sock = sock; - tmp[eloop.reader_count].eloop_data = eloop_data; - tmp[eloop.reader_count].user_data = user_data; - tmp[eloop.reader_count].handler = handler; - tmp[eloop.reader_count].event = event; - eloop.reader_count++; - eloop.readers = tmp; - if (sock > eloop.max_sock) - eloop.max_sock = sock; - eloop.reader_table_changed = 1; - - return 0; -} - - -void eloop_unregister_read_sock(int sock) -{ - size_t i; - - if (eloop.readers == NULL || eloop.reader_count == 0) - return; - - for (i = 0; i < eloop.reader_count; i++) { - if (eloop.readers[i].sock == sock) - break; - } - if (i == eloop.reader_count) - return; - - WSAEventSelect(eloop.readers[i].sock, eloop.readers[i].event, 0); - WSACloseEvent(eloop.readers[i].event); - - if (i != eloop.reader_count - 1) { - os_memmove(&eloop.readers[i], &eloop.readers[i + 1], - (eloop.reader_count - i - 1) * - sizeof(struct eloop_sock)); - } - eloop.reader_count--; - eloop.reader_table_changed = 1; -} - - -int eloop_register_event(void *event, size_t event_size, - eloop_event_handler handler, - void *eloop_data, void *user_data) -{ - struct eloop_event *tmp; - HANDLE h = event; - - if (event_size != sizeof(HANDLE) || h == INVALID_HANDLE_VALUE) - return -1; - - if (eloop_prepare_handles()) - return -1; - - tmp = os_realloc_array(eloop.events, eloop.event_count + 1, - sizeof(struct eloop_event)); - if (tmp == NULL) - return -1; - - tmp[eloop.event_count].eloop_data = eloop_data; - tmp[eloop.event_count].user_data = user_data; - tmp[eloop.event_count].handler = handler; - tmp[eloop.event_count].event = h; - eloop.event_count++; - eloop.events = tmp; - - return 0; -} - - -void eloop_unregister_event(void *event, size_t event_size) -{ - size_t i; - HANDLE h = event; - - if (eloop.events == NULL || eloop.event_count == 0 || - event_size != sizeof(HANDLE)) - return; - - for (i = 0; i < eloop.event_count; i++) { - if (eloop.events[i].event == h) - break; - } - if (i == eloop.event_count) - return; - - if (i != eloop.event_count - 1) { - os_memmove(&eloop.events[i], &eloop.events[i + 1], - (eloop.event_count - i - 1) * - sizeof(struct eloop_event)); - } - eloop.event_count--; -} - - -int eloop_register_timeout(unsigned int secs, unsigned int usecs, - eloop_timeout_handler handler, - void *eloop_data, void *user_data) -{ - struct eloop_timeout *timeout, *tmp; - os_time_t now_sec; - - timeout = os_zalloc(sizeof(*timeout)); - if (timeout == NULL) - return -1; - if (os_get_reltime(&timeout->time) < 0) { - os_free(timeout); - return -1; - } - now_sec = timeout->time.sec; - timeout->time.sec += secs; - if (timeout->time.sec < now_sec) { - /* - * Integer overflow - assume long enough timeout to be assumed - * to be infinite, i.e., the timeout would never happen. - */ - wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to " - "ever happen - ignore it", secs); - os_free(timeout); - return 0; - } - timeout->time.usec += usecs; - while (timeout->time.usec >= 1000000) { - timeout->time.sec++; - timeout->time.usec -= 1000000; - } - timeout->eloop_data = eloop_data; - timeout->user_data = user_data; - timeout->handler = handler; - - /* Maintain timeouts in order of increasing time */ - dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { - if (os_reltime_before(&timeout->time, &tmp->time)) { - dl_list_add(tmp->list.prev, &timeout->list); - return 0; - } - } - dl_list_add_tail(&eloop.timeout, &timeout->list); - - return 0; -} - - -static void eloop_remove_timeout(struct eloop_timeout *timeout) -{ - dl_list_del(&timeout->list); - os_free(timeout); -} - - -int eloop_cancel_timeout(eloop_timeout_handler handler, - void *eloop_data, void *user_data) -{ - struct eloop_timeout *timeout, *prev; - int removed = 0; - - dl_list_for_each_safe(timeout, prev, &eloop.timeout, - struct eloop_timeout, list) { - if (timeout->handler == handler && - (timeout->eloop_data == eloop_data || - eloop_data == ELOOP_ALL_CTX) && - (timeout->user_data == user_data || - user_data == ELOOP_ALL_CTX)) { - eloop_remove_timeout(timeout); - removed++; - } - } - - return removed; -} - - -int eloop_cancel_timeout_one(eloop_timeout_handler handler, - void *eloop_data, void *user_data, - struct os_reltime *remaining) -{ - struct eloop_timeout *timeout, *prev; - int removed = 0; - struct os_reltime now; - - os_get_reltime(&now); - remaining->sec = remaining->usec = 0; - - dl_list_for_each_safe(timeout, prev, &eloop.timeout, - struct eloop_timeout, list) { - if (timeout->handler == handler && - (timeout->eloop_data == eloop_data) && - (timeout->user_data == user_data)) { - removed = 1; - if (os_reltime_before(&now, &timeout->time)) - os_reltime_sub(&timeout->time, &now, remaining); - eloop_remove_timeout(timeout); - break; - } - } - return removed; -} - - -int eloop_is_timeout_registered(eloop_timeout_handler handler, - void *eloop_data, void *user_data) -{ - struct eloop_timeout *tmp; - - dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { - if (tmp->handler == handler && - tmp->eloop_data == eloop_data && - tmp->user_data == user_data) - return 1; - } - - return 0; -} - - -int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs, - eloop_timeout_handler handler, void *eloop_data, - void *user_data) -{ - struct os_reltime now, requested, remaining; - struct eloop_timeout *tmp; - - dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { - if (tmp->handler == handler && - tmp->eloop_data == eloop_data && - tmp->user_data == user_data) { - requested.sec = req_secs; - requested.usec = req_usecs; - os_get_reltime(&now); - os_reltime_sub(&tmp->time, &now, &remaining); - if (os_reltime_before(&requested, &remaining)) { - eloop_cancel_timeout(handler, eloop_data, - user_data); - eloop_register_timeout(requested.sec, - requested.usec, - handler, eloop_data, - user_data); - return 1; - } - return 0; - } - } - - return -1; -} - - -int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, - eloop_timeout_handler handler, void *eloop_data, - void *user_data) -{ - struct os_reltime now, requested, remaining; - struct eloop_timeout *tmp; - - dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { - if (tmp->handler == handler && - tmp->eloop_data == eloop_data && - tmp->user_data == user_data) { - requested.sec = req_secs; - requested.usec = req_usecs; - os_get_reltime(&now); - os_reltime_sub(&tmp->time, &now, &remaining); - if (os_reltime_before(&remaining, &requested)) { - eloop_cancel_timeout(handler, eloop_data, - user_data); - eloop_register_timeout(requested.sec, - requested.usec, - handler, eloop_data, - user_data); - return 1; - } - return 0; - } - } - - return -1; -} - - -/* TODO: replace with suitable signal handler */ -#if 0 -static void eloop_handle_signal(int sig) -{ - int i; - - eloop.signaled++; - for (i = 0; i < eloop.signal_count; i++) { - if (eloop.signals[i].sig == sig) { - eloop.signals[i].signaled++; - break; - } - } -} -#endif - - -static void eloop_process_pending_signals(void) -{ - int i; - - if (eloop.signaled == 0) - return; - eloop.signaled = 0; - - if (eloop.pending_terminate) { - eloop.pending_terminate = 0; - } - - for (i = 0; i < eloop.signal_count; i++) { - if (eloop.signals[i].signaled) { - eloop.signals[i].signaled = 0; - eloop.signals[i].handler(eloop.signals[i].sig, - eloop.signals[i].user_data); - } - } - - if (eloop.term_signal.signaled) { - eloop.term_signal.signaled = 0; - eloop.term_signal.handler(eloop.term_signal.sig, - eloop.term_signal.user_data); - } -} - - -int eloop_register_signal(int sig, eloop_signal_handler handler, - void *user_data) -{ - struct eloop_signal *tmp; - - tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1, - sizeof(struct eloop_signal)); - if (tmp == NULL) - return -1; - - tmp[eloop.signal_count].sig = sig; - tmp[eloop.signal_count].user_data = user_data; - tmp[eloop.signal_count].handler = handler; - tmp[eloop.signal_count].signaled = 0; - eloop.signal_count++; - eloop.signals = tmp; - - /* TODO: register signal handler */ - - return 0; -} - - -#ifndef _WIN32_WCE -static BOOL eloop_handle_console_ctrl(DWORD type) -{ - switch (type) { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - eloop.signaled++; - eloop.term_signal.signaled++; - SetEvent(eloop.term_event); - return TRUE; - default: - return FALSE; - } -} -#endif /* _WIN32_WCE */ - - -int eloop_register_signal_terminate(eloop_signal_handler handler, - void *user_data) -{ -#ifndef _WIN32_WCE - if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) eloop_handle_console_ctrl, - TRUE) == 0) { - printf("SetConsoleCtrlHandler() failed: %d\n", - (int) GetLastError()); - return -1; - } -#endif /* _WIN32_WCE */ - - eloop.term_signal.handler = handler; - eloop.term_signal.user_data = user_data; - - return 0; -} - - -int eloop_register_signal_reconfig(eloop_signal_handler handler, - void *user_data) -{ - /* TODO */ - return 0; -} - - -void eloop_run(void) -{ - struct os_reltime tv, now; - DWORD count, ret, timeout_val, err; - size_t i; - - while (!eloop.terminate && - (!dl_list_empty(&eloop.timeout) || eloop.reader_count > 0 || - eloop.event_count > 0)) { - struct eloop_timeout *timeout; - tv.sec = tv.usec = 0; - timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, - list); - if (timeout) { - os_get_reltime(&now); - if (os_reltime_before(&now, &timeout->time)) - os_reltime_sub(&timeout->time, &now, &tv); - } - - count = 0; - for (i = 0; i < eloop.event_count; i++) - eloop.handles[count++] = eloop.events[i].event; - - for (i = 0; i < eloop.reader_count; i++) - eloop.handles[count++] = eloop.readers[i].event; - - if (eloop.term_event) - eloop.handles[count++] = eloop.term_event; - - if (timeout) - timeout_val = tv.sec * 1000 + tv.usec / 1000; - else - timeout_val = INFINITE; - - if (count > MAXIMUM_WAIT_OBJECTS) { - printf("WaitForMultipleObjects: Too many events: " - "%d > %d (ignoring extra events)\n", - (int) count, MAXIMUM_WAIT_OBJECTS); - count = MAXIMUM_WAIT_OBJECTS; - } -#ifdef _WIN32_WCE - ret = WaitForMultipleObjects(count, eloop.handles, FALSE, - timeout_val); -#else /* _WIN32_WCE */ - ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE, - timeout_val, TRUE); -#endif /* _WIN32_WCE */ - err = GetLastError(); - - eloop_process_pending_signals(); - - /* check if some registered timeouts have occurred */ - timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, - list); - if (timeout) { - os_get_reltime(&now); - if (!os_reltime_before(&now, &timeout->time)) { - void *eloop_data = timeout->eloop_data; - void *user_data = timeout->user_data; - eloop_timeout_handler handler = - timeout->handler; - eloop_remove_timeout(timeout); - handler(eloop_data, user_data); - } - - } - - if (ret == WAIT_FAILED) { - printf("WaitForMultipleObjects(count=%d) failed: %d\n", - (int) count, (int) err); - os_sleep(1, 0); - continue; - } - -#ifndef _WIN32_WCE - if (ret == WAIT_IO_COMPLETION) - continue; -#endif /* _WIN32_WCE */ - - if (ret == WAIT_TIMEOUT) - continue; - - while (ret >= WAIT_OBJECT_0 && - ret < WAIT_OBJECT_0 + eloop.event_count) { - eloop.events[ret].handler( - eloop.events[ret].eloop_data, - eloop.events[ret].user_data); - ret = WaitForMultipleObjects(eloop.event_count, - eloop.handles, FALSE, 0); - } - - eloop.reader_table_changed = 0; - for (i = 0; i < eloop.reader_count; i++) { - WSANETWORKEVENTS events; - if (WSAEnumNetworkEvents(eloop.readers[i].sock, - eloop.readers[i].event, - &events) == 0 && - (events.lNetworkEvents & FD_READ)) { - eloop.readers[i].handler( - eloop.readers[i].sock, - eloop.readers[i].eloop_data, - eloop.readers[i].user_data); - if (eloop.reader_table_changed) - break; - } - } - } -} - - -void eloop_terminate(void) -{ - eloop.terminate = 1; - SetEvent(eloop.term_event); -} - - -void eloop_destroy(void) -{ - struct eloop_timeout *timeout, *prev; - - dl_list_for_each_safe(timeout, prev, &eloop.timeout, - struct eloop_timeout, list) { - eloop_remove_timeout(timeout); - } - os_free(eloop.readers); - os_free(eloop.signals); - if (eloop.term_event) - CloseHandle(eloop.term_event); - os_free(eloop.handles); - eloop.handles = NULL; - os_free(eloop.events); - eloop.events = NULL; -} - - -int eloop_terminated(void) -{ - return eloop.terminate; -} - - -void eloop_wait_for_read_sock(int sock) -{ - WSAEVENT event; - - event = WSACreateEvent(); - if (event == WSA_INVALID_EVENT) { - printf("WSACreateEvent() failed: %d\n", WSAGetLastError()); - return; - } - - if (WSAEventSelect(sock, event, FD_READ)) { - printf("WSAEventSelect() failed: %d\n", WSAGetLastError()); - WSACloseEvent(event); - return ; - } - - WaitForSingleObject(event, INFINITE); - WSAEventSelect(sock, event, 0); - WSACloseEvent(event); -} diff --git a/contrib/hostapd/src/utils/ext_password.c b/contrib/hostapd/src/utils/ext_password.c deleted file mode 100644 index 06131197a3..0000000000 --- a/contrib/hostapd/src/utils/ext_password.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * External password backend - * Copyright (c) 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#ifdef __linux__ -#include -#endif /* __linux__ */ - -#include "common.h" -#include "ext_password_i.h" - - -#ifdef CONFIG_EXT_PASSWORD_TEST -extern struct ext_password_backend ext_password_test; -#endif /* CONFIG_EXT_PASSWORD_TEST */ - -static const struct ext_password_backend *backends[] = { -#ifdef CONFIG_EXT_PASSWORD_TEST - &ext_password_test, -#endif /* CONFIG_EXT_PASSWORD_TEST */ - NULL -}; - -struct ext_password_data { - const struct ext_password_backend *backend; - void *priv; -}; - - -struct ext_password_data * ext_password_init(const char *backend, - const char *params) -{ - struct ext_password_data *data; - int i; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - - for (i = 0; backends[i]; i++) { - if (os_strcmp(backends[i]->name, backend) == 0) { - data->backend = backends[i]; - break; - } - } - - if (!data->backend) { - os_free(data); - return NULL; - } - - data->priv = data->backend->init(params); - if (data->priv == NULL) { - os_free(data); - return NULL; - } - - return data; -} - - -void ext_password_deinit(struct ext_password_data *data) -{ - if (data && data->backend && data->priv) - data->backend->deinit(data->priv); - os_free(data); -} - - -struct wpabuf * ext_password_get(struct ext_password_data *data, - const char *name) -{ - if (data == NULL) - return NULL; - return data->backend->get(data->priv, name); -} - - -struct wpabuf * ext_password_alloc(size_t len) -{ - struct wpabuf *buf; - - buf = wpabuf_alloc(len); - if (buf == NULL) - return NULL; - -#ifdef __linux__ - if (mlock(wpabuf_head(buf), wpabuf_len(buf)) < 0) { - wpa_printf(MSG_ERROR, "EXT PW: mlock failed: %s", - strerror(errno)); - } -#endif /* __linux__ */ - - return buf; -} - - -void ext_password_free(struct wpabuf *pw) -{ - if (pw == NULL) - return; - os_memset(wpabuf_mhead(pw), 0, wpabuf_len(pw)); -#ifdef __linux__ - if (munlock(wpabuf_head(pw), wpabuf_len(pw)) < 0) { - wpa_printf(MSG_ERROR, "EXT PW: munlock failed: %s", - strerror(errno)); - } -#endif /* __linux__ */ - wpabuf_free(pw); -} diff --git a/contrib/hostapd/src/utils/ext_password.h b/contrib/hostapd/src/utils/ext_password.h deleted file mode 100644 index e3e46ea084..0000000000 --- a/contrib/hostapd/src/utils/ext_password.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * External password backend - * Copyright (c) 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EXT_PASSWORD_H -#define EXT_PASSWORD_H - -struct ext_password_data; - -#ifdef CONFIG_EXT_PASSWORD - -struct ext_password_data * ext_password_init(const char *backend, - const char *params); -void ext_password_deinit(struct ext_password_data *data); - -struct wpabuf * ext_password_get(struct ext_password_data *data, - const char *name); -void ext_password_free(struct wpabuf *pw); - -#else /* CONFIG_EXT_PASSWORD */ - -#define ext_password_init(b, p) ((void *) 1) -#define ext_password_deinit(d) do { } while (0) -#define ext_password_get(d, n) (NULL) -#define ext_password_free(p) do { } while (0) - -#endif /* CONFIG_EXT_PASSWORD */ - -#endif /* EXT_PASSWORD_H */ diff --git a/contrib/hostapd/src/utils/ext_password_i.h b/contrib/hostapd/src/utils/ext_password_i.h deleted file mode 100644 index 043e7312c6..0000000000 --- a/contrib/hostapd/src/utils/ext_password_i.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * External password backend - internal definitions - * Copyright (c) 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EXT_PASSWORD_I_H -#define EXT_PASSWORD_I_H - -#include "ext_password.h" - -struct ext_password_backend { - const char *name; - void * (*init)(const char *params); - void (*deinit)(void *ctx); - struct wpabuf * (*get)(void *ctx, const char *name); -}; - -struct wpabuf * ext_password_alloc(size_t len); - -#endif /* EXT_PASSWORD_I_H */ diff --git a/contrib/hostapd/src/utils/ext_password_test.c b/contrib/hostapd/src/utils/ext_password_test.c deleted file mode 100644 index 3801bb8544..0000000000 --- a/contrib/hostapd/src/utils/ext_password_test.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * External password backend - * Copyright (c) 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "ext_password_i.h" - - -struct ext_password_test_data { - char *params; -}; - - -static void * ext_password_test_init(const char *params) -{ - struct ext_password_test_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - - if (params) - data->params = os_strdup(params); - - return data; -} - - -static void ext_password_test_deinit(void *ctx) -{ - struct ext_password_test_data *data = ctx; - - os_free(data->params); - os_free(data); -} - - -static struct wpabuf * ext_password_test_get(void *ctx, const char *name) -{ - struct ext_password_test_data *data = ctx; - char *pos, *pos2; - size_t nlen; - - wpa_printf(MSG_DEBUG, "EXT PW TEST: get(%s)", name); - - pos = data->params; - if (pos == NULL) - return NULL; - nlen = os_strlen(name); - - while (pos && *pos) { - if (os_strncmp(pos, name, nlen) == 0 && pos[nlen] == '=') { - struct wpabuf *buf; - pos += nlen + 1; - pos2 = pos; - while (*pos2 != '|' && *pos2 != '\0') - pos2++; - buf = ext_password_alloc(pos2 - pos); - if (buf == NULL) - return NULL; - wpabuf_put_data(buf, pos, pos2 - pos); - wpa_hexdump_ascii_key(MSG_DEBUG, "EXT PW TEST: value", - wpabuf_head(buf), - wpabuf_len(buf)); - return buf; - } - - pos = os_strchr(pos + 1, '|'); - if (pos) - pos++; - } - - wpa_printf(MSG_DEBUG, "EXT PW TEST: get(%s) - not found", name); - - return NULL; -} - - -const struct ext_password_backend ext_password_test = { - .name = "test", - .init = ext_password_test_init, - .deinit = ext_password_test_deinit, - .get = ext_password_test_get, -}; diff --git a/contrib/hostapd/src/utils/includes.h b/contrib/hostapd/src/utils/includes.h deleted file mode 100644 index 6c6ec87d0e..0000000000 --- a/contrib/hostapd/src/utils/includes.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * wpa_supplicant/hostapd - Default include files - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This header file is included into all C files so that commonly used header - * files can be selected with OS specific ifdef blocks in one place instead of - * having to have OS/C library specific selection in many files. - */ - -#ifndef INCLUDES_H -#define INCLUDES_H - -/* Include possible build time configuration before including anything else */ -#include "build_config.h" - -#include -#include -#include -#include -#ifndef _WIN32_WCE -#ifndef CONFIG_TI_COMPILER -#include -#include -#endif /* CONFIG_TI_COMPILER */ -#include -#endif /* _WIN32_WCE */ -#include - -#ifndef CONFIG_TI_COMPILER -#ifndef _MSC_VER -#include -#endif /* _MSC_VER */ -#endif /* CONFIG_TI_COMPILER */ - -#ifndef CONFIG_NATIVE_WINDOWS -#ifndef CONFIG_TI_COMPILER -#include -#include -#include -#ifndef __vxworks -#include -#include -#endif /* __vxworks */ -#endif /* CONFIG_TI_COMPILER */ -#endif /* CONFIG_NATIVE_WINDOWS */ - -#endif /* INCLUDES_H */ diff --git a/contrib/hostapd/src/utils/ip_addr.c b/contrib/hostapd/src/utils/ip_addr.c deleted file mode 100644 index 3647c764e6..0000000000 --- a/contrib/hostapd/src/utils/ip_addr.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * IP address processing - * Copyright (c) 2003-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "ip_addr.h" - -const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf, - size_t buflen) -{ - if (buflen == 0 || addr == NULL) - return NULL; - - if (addr->af == AF_INET) { - os_strlcpy(buf, inet_ntoa(addr->u.v4), buflen); - } else { - buf[0] = '\0'; - } -#ifdef CONFIG_IPV6 - if (addr->af == AF_INET6) { - if (inet_ntop(AF_INET6, &addr->u.v6, buf, buflen) == NULL) - buf[0] = '\0'; - } -#endif /* CONFIG_IPV6 */ - - return buf; -} - - -int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b) -{ - if (a == NULL && b == NULL) - return 0; - if (a == NULL || b == NULL) - return 1; - - switch (a->af) { - case AF_INET: - if (a->u.v4.s_addr != b->u.v4.s_addr) - return 1; - break; -#ifdef CONFIG_IPV6 - case AF_INET6: - if (os_memcmp(&a->u.v6, &b->u.v6, sizeof(a->u.v6)) != 0) - return 1; - break; -#endif /* CONFIG_IPV6 */ - } - - return 0; -} - - -int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr) -{ -#ifndef CONFIG_NATIVE_WINDOWS - if (inet_aton(txt, &addr->u.v4)) { - addr->af = AF_INET; - return 0; - } - -#ifdef CONFIG_IPV6 - if (inet_pton(AF_INET6, txt, &addr->u.v6) > 0) { - addr->af = AF_INET6; - return 0; - } -#endif /* CONFIG_IPV6 */ -#endif /* CONFIG_NATIVE_WINDOWS */ - - return -1; -} diff --git a/contrib/hostapd/src/utils/ip_addr.h b/contrib/hostapd/src/utils/ip_addr.h deleted file mode 100644 index 79ac20cdbd..0000000000 --- a/contrib/hostapd/src/utils/ip_addr.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * IP address processing - * Copyright (c) 2003-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef IP_ADDR_H -#define IP_ADDR_H - -struct hostapd_ip_addr { - int af; /* AF_INET / AF_INET6 */ - union { - struct in_addr v4; -#ifdef CONFIG_IPV6 - struct in6_addr v6; -#endif /* CONFIG_IPV6 */ - u8 max_len[16]; - } u; -}; - -const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf, - size_t buflen); -int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b); -int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr); - -#endif /* IP_ADDR_H */ diff --git a/contrib/hostapd/src/utils/list.h b/contrib/hostapd/src/utils/list.h deleted file mode 100644 index 6881130957..0000000000 --- a/contrib/hostapd/src/utils/list.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Doubly-linked list - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef LIST_H -#define LIST_H - -/** - * struct dl_list - Doubly-linked list - */ -struct dl_list { - struct dl_list *next; - struct dl_list *prev; -}; - -static inline void dl_list_init(struct dl_list *list) -{ - list->next = list; - list->prev = list; -} - -static inline void dl_list_add(struct dl_list *list, struct dl_list *item) -{ - item->next = list->next; - item->prev = list; - list->next->prev = item; - list->next = item; -} - -static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item) -{ - dl_list_add(list->prev, item); -} - -static inline void dl_list_del(struct dl_list *item) -{ - item->next->prev = item->prev; - item->prev->next = item->next; - item->next = NULL; - item->prev = NULL; -} - -static inline int dl_list_empty(struct dl_list *list) -{ - return list->next == list; -} - -static inline unsigned int dl_list_len(struct dl_list *list) -{ - struct dl_list *item; - int count = 0; - for (item = list->next; item != list; item = item->next) - count++; - return count; -} - -#ifndef offsetof -#define offsetof(type, member) ((long) &((type *) 0)->member) -#endif - -#define dl_list_entry(item, type, member) \ - ((type *) ((char *) item - offsetof(type, member))) - -#define dl_list_first(list, type, member) \ - (dl_list_empty((list)) ? NULL : \ - dl_list_entry((list)->next, type, member)) - -#define dl_list_last(list, type, member) \ - (dl_list_empty((list)) ? NULL : \ - dl_list_entry((list)->prev, type, member)) - -#define dl_list_for_each(item, list, type, member) \ - for (item = dl_list_entry((list)->next, type, member); \ - &item->member != (list); \ - item = dl_list_entry(item->member.next, type, member)) - -#define dl_list_for_each_safe(item, n, list, type, member) \ - for (item = dl_list_entry((list)->next, type, member), \ - n = dl_list_entry(item->member.next, type, member); \ - &item->member != (list); \ - item = n, n = dl_list_entry(n->member.next, type, member)) - -#define dl_list_for_each_reverse(item, list, type, member) \ - for (item = dl_list_entry((list)->prev, type, member); \ - &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/contrib/hostapd/src/utils/os.h b/contrib/hostapd/src/utils/os.h deleted file mode 100644 index 2e2350a783..0000000000 --- a/contrib/hostapd/src/utils/os.h +++ /dev/null @@ -1,595 +0,0 @@ -/* - * OS specific functions - * Copyright (c) 2005-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef OS_H -#define OS_H - -typedef long os_time_t; - -/** - * os_sleep - Sleep (sec, usec) - * @sec: Number of seconds to sleep - * @usec: Number of microseconds to sleep - */ -void os_sleep(os_time_t sec, os_time_t usec); - -struct os_time { - os_time_t sec; - os_time_t usec; -}; - -struct os_reltime { - os_time_t sec; - os_time_t usec; -}; - -/** - * os_get_time - Get current time (sec, usec) - * @t: Pointer to buffer for the time - * Returns: 0 on success, -1 on failure - */ -int os_get_time(struct os_time *t); - -/** - * os_get_reltime - Get relative time (sec, usec) - * @t: Pointer to buffer for the time - * Returns: 0 on success, -1 on failure - */ -int os_get_reltime(struct os_reltime *t); - - -/* Helpers for handling struct os_time */ - -static inline int os_time_before(struct os_time *a, struct os_time *b) -{ - return (a->sec < b->sec) || - (a->sec == b->sec && a->usec < b->usec); -} - - -static inline void os_time_sub(struct os_time *a, struct os_time *b, - struct os_time *res) -{ - res->sec = a->sec - b->sec; - res->usec = a->usec - b->usec; - if (res->usec < 0) { - res->sec--; - res->usec += 1000000; - } -} - - -/* Helpers for handling struct os_reltime */ - -static inline int os_reltime_before(struct os_reltime *a, - struct os_reltime *b) -{ - return (a->sec < b->sec) || - (a->sec == b->sec && a->usec < b->usec); -} - - -static inline void os_reltime_sub(struct os_reltime *a, struct os_reltime *b, - struct os_reltime *res) -{ - res->sec = a->sec - b->sec; - res->usec = a->usec - b->usec; - if (res->usec < 0) { - res->sec--; - res->usec += 1000000; - } -} - - -static inline void os_reltime_age(struct os_reltime *start, - struct os_reltime *age) -{ - struct os_reltime now; - - os_get_reltime(&now); - os_reltime_sub(&now, start, age); -} - - -static inline int os_reltime_expired(struct os_reltime *now, - struct os_reltime *ts, - os_time_t timeout_secs) -{ - struct os_reltime age; - - os_reltime_sub(now, ts, &age); - return (age.sec > timeout_secs) || - (age.sec == timeout_secs && age.usec > 0); -} - - -static inline int os_reltime_initialized(struct os_reltime *t) -{ - return t->sec != 0 || t->usec != 0; -} - - -/** - * os_mktime - Convert broken-down time into seconds since 1970-01-01 - * @year: Four digit year - * @month: Month (1 .. 12) - * @day: Day of month (1 .. 31) - * @hour: Hour (0 .. 23) - * @min: Minute (0 .. 59) - * @sec: Second (0 .. 60) - * @t: Buffer for returning calendar time representation (seconds since - * 1970-01-01 00:00:00) - * Returns: 0 on success, -1 on failure - * - * Note: The result is in seconds from Epoch, i.e., in UTC, not in local time - * which is used by POSIX mktime(). - */ -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) - * @pid_file: File name to write the process ID to or %NULL to skip this - * Returns: 0 on success, -1 on failure - */ -int os_daemonize(const char *pid_file); - -/** - * os_daemonize_terminate - Stop running in the background (remove pid file) - * @pid_file: File name to write the process ID to or %NULL to skip this - */ -void os_daemonize_terminate(const char *pid_file); - -/** - * os_get_random - Get cryptographically strong pseudo random data - * @buf: Buffer for pseudo random data - * @len: Length of the buffer - * Returns: 0 on success, -1 on failure - */ -int os_get_random(unsigned char *buf, size_t len); - -/** - * os_random - Get pseudo random value (not necessarily very strong) - * Returns: Pseudo random value - */ -unsigned long os_random(void); - -/** - * os_rel2abs_path - Get an absolute path for a file - * @rel_path: Relative path to a file - * Returns: Absolute path for the file or %NULL on failure - * - * This function tries to convert a relative path of a file to an absolute path - * in order for the file to be found even if current working directory has - * changed. The returned value is allocated and caller is responsible for - * freeing it. It is acceptable to just return the same path in an allocated - * buffer, e.g., return strdup(rel_path). This function is only used to find - * configuration files when os_daemonize() may have changed the current working - * directory and relative path would be pointing to a different location. - */ -char * os_rel2abs_path(const char *rel_path); - -/** - * os_program_init - Program initialization (called at start) - * Returns: 0 on success, -1 on failure - * - * This function is called when a programs starts. If there are any OS specific - * processing that is needed, it can be placed here. It is also acceptable to - * just return 0 if not special processing is needed. - */ -int os_program_init(void); - -/** - * os_program_deinit - Program deinitialization (called just before exit) - * - * This function is called just before a program exists. If there are any OS - * specific processing, e.g., freeing resourced allocated in os_program_init(), - * it should be done here. It is also acceptable for this function to do - * nothing. - */ -void os_program_deinit(void); - -/** - * os_setenv - Set environment variable - * @name: Name of the variable - * @value: Value to set to the variable - * @overwrite: Whether existing variable should be overwritten - * Returns: 0 on success, -1 on error - * - * This function is only used for wpa_cli action scripts. OS wrapper does not - * need to implement this if such functionality is not needed. - */ -int os_setenv(const char *name, const char *value, int overwrite); - -/** - * os_unsetenv - Delete environent variable - * @name: Name of the variable - * Returns: 0 on success, -1 on error - * - * This function is only used for wpa_cli action scripts. OS wrapper does not - * need to implement this if such functionality is not needed. - */ -int os_unsetenv(const char *name); - -/** - * os_readfile - Read a file to an allocated memory buffer - * @name: Name of the file to read - * @len: For returning the length of the allocated buffer - * Returns: Pointer to the allocated buffer or %NULL on failure - * - * This function allocates memory and reads the given file to this buffer. Both - * binary and text files can be read with this function. The caller is - * responsible for freeing the returned buffer with os_free(). - */ -char * os_readfile(const char *name, size_t *len); - -/** - * os_zalloc - Allocate and zero memory - * @size: Number of bytes to allocate - * Returns: Pointer to allocated and zeroed memory or %NULL on failure - * - * Caller is responsible for freeing the returned buffer with os_free(). - */ -void * os_zalloc(size_t size); - -/** - * os_calloc - Allocate and zero memory for an array - * @nmemb: Number of members in the array - * @size: Number of bytes in each member - * Returns: Pointer to allocated and zeroed memory or %NULL on failure - * - * This function can be used as a wrapper for os_zalloc(nmemb * size) when an - * allocation is used for an array. The main benefit over os_zalloc() is in - * having an extra check to catch integer overflows in multiplication. - * - * Caller is responsible for freeing the returned buffer with os_free(). - */ -static inline void * os_calloc(size_t nmemb, size_t size) -{ - if (size && nmemb > (~(size_t) 0) / size) - return NULL; - return os_zalloc(nmemb * size); -} - - -/* - * The following functions are wrapper for standard ANSI C or POSIX functions. - * By default, they are just defined to use the standard function name and no - * os_*.c implementation is needed for them. This avoids extra function calls - * by allowing the C pre-processor take care of the function name mapping. - * - * If the target system uses a C library that does not provide these functions, - * build_config.h can be used to define the wrappers to use a different - * function name. This can be done on function-by-function basis since the - * defines here are only used if build_config.h does not define the os_* name. - * If needed, os_*.c file can be used to implement the functions that are not - * included in the C library on the target system. Alternatively, - * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case - * these functions need to be implemented in os_*.c file for the target system. - */ - -#ifdef OS_NO_C_LIB_DEFINES - -/** - * os_malloc - Allocate dynamic memory - * @size: Size of the buffer to allocate - * Returns: Allocated buffer or %NULL on failure - * - * Caller is responsible for freeing the returned buffer with os_free(). - */ -void * os_malloc(size_t size); - -/** - * os_realloc - Re-allocate dynamic memory - * @ptr: Old buffer from os_malloc() or os_realloc() - * @size: Size of the new buffer - * Returns: Allocated buffer or %NULL on failure - * - * Caller is responsible for freeing the returned buffer with os_free(). - * If re-allocation fails, %NULL is returned and the original buffer (ptr) is - * not freed and caller is still responsible for freeing it. - */ -void * os_realloc(void *ptr, size_t size); - -/** - * os_free - Free dynamic memory - * @ptr: Old buffer from os_malloc() or os_realloc(); can be %NULL - */ -void os_free(void *ptr); - -/** - * os_memcpy - Copy memory area - * @dest: Destination - * @src: Source - * @n: Number of bytes to copy - * Returns: dest - * - * The memory areas src and dst must not overlap. os_memmove() can be used with - * overlapping memory. - */ -void * os_memcpy(void *dest, const void *src, size_t n); - -/** - * os_memmove - Copy memory area - * @dest: Destination - * @src: Source - * @n: Number of bytes to copy - * Returns: dest - * - * The memory areas src and dst may overlap. - */ -void * os_memmove(void *dest, const void *src, size_t n); - -/** - * os_memset - Fill memory with a constant byte - * @s: Memory area to be filled - * @c: Constant byte - * @n: Number of bytes started from s to fill with c - * Returns: s - */ -void * os_memset(void *s, int c, size_t n); - -/** - * os_memcmp - Compare memory areas - * @s1: First buffer - * @s2: Second buffer - * @n: Maximum numbers of octets to compare - * Returns: An integer less than, equal to, or greater than zero if s1 is - * found to be less than, to match, or be greater than s2. Only first n - * characters will be compared. - */ -int os_memcmp(const void *s1, const void *s2, size_t n); - -/** - * os_strdup - Duplicate a string - * @s: Source string - * Returns: Allocated buffer with the string copied into it or %NULL on failure - * - * Caller is responsible for freeing the returned buffer with os_free(). - */ -char * os_strdup(const char *s); - -/** - * os_strlen - Calculate the length of a string - * @s: '\0' terminated string - * Returns: Number of characters in s (not counting the '\0' terminator) - */ -size_t os_strlen(const char *s); - -/** - * os_strcasecmp - Compare two strings ignoring case - * @s1: First string - * @s2: Second string - * Returns: An integer less than, equal to, or greater than zero if s1 is - * found to be less than, to match, or be greatred than s2 - */ -int os_strcasecmp(const char *s1, const char *s2); - -/** - * os_strncasecmp - Compare two strings ignoring case - * @s1: First string - * @s2: Second string - * @n: Maximum numbers of characters to compare - * Returns: An integer less than, equal to, or greater than zero if s1 is - * found to be less than, to match, or be greater than s2. Only first n - * characters will be compared. - */ -int os_strncasecmp(const char *s1, const char *s2, size_t n); - -/** - * os_strchr - Locate the first occurrence of a character in string - * @s: String - * @c: Character to search for - * Returns: Pointer to the matched character or %NULL if not found - */ -char * os_strchr(const char *s, int c); - -/** - * os_strrchr - Locate the last occurrence of a character in string - * @s: String - * @c: Character to search for - * Returns: Pointer to the matched character or %NULL if not found - */ -char * os_strrchr(const char *s, int c); - -/** - * os_strcmp - Compare two strings - * @s1: First string - * @s2: Second string - * Returns: An integer less than, equal to, or greater than zero if s1 is - * found to be less than, to match, or be greatred than s2 - */ -int os_strcmp(const char *s1, const char *s2); - -/** - * os_strncmp - Compare two strings - * @s1: First string - * @s2: Second string - * @n: Maximum numbers of characters to compare - * Returns: An integer less than, equal to, or greater than zero if s1 is - * found to be less than, to match, or be greater than s2. Only first n - * characters will be compared. - */ -int os_strncmp(const char *s1, const char *s2, size_t n); - -/** - * os_strstr - Locate a substring - * @haystack: String (haystack) to search from - * @needle: Needle to search from haystack - * Returns: Pointer to the beginning of the substring or %NULL if not found - */ -char * os_strstr(const char *haystack, const char *needle); - -/** - * os_snprintf - Print to a memory buffer - * @str: Memory buffer to print into - * @size: Maximum length of the str buffer - * @format: printf format - * Returns: Number of characters printed (not including trailing '\0'). - * - * If the output buffer is truncated, number of characters which would have - * been written is returned. Since some C libraries return -1 in such a case, - * the caller must be prepared on that value, too, to indicate truncation. - * - * Note: Some C library implementations of snprintf() may not guarantee null - * termination in case the output is truncated. The OS wrapper function of - * os_snprintf() should provide this guarantee, i.e., to null terminate the - * output buffer if a C library version of the function is used and if that - * function does not guarantee null termination. - * - * If the target system does not include snprintf(), see, e.g., - * http://www.ijs.si/software/snprintf/ for an example of a portable - * implementation of snprintf. - */ -int os_snprintf(char *str, size_t size, const char *format, ...); - -#else /* OS_NO_C_LIB_DEFINES */ - -#ifdef WPA_TRACE -void * os_malloc(size_t size); -void * os_realloc(void *ptr, size_t size); -void os_free(void *ptr); -char * os_strdup(const char *s); -#else /* WPA_TRACE */ -#ifndef os_malloc -#define os_malloc(s) malloc((s)) -#endif -#ifndef os_realloc -#define os_realloc(p, s) realloc((p), (s)) -#endif -#ifndef os_free -#define os_free(p) free((p)) -#endif -#ifndef os_strdup -#ifdef _MSC_VER -#define os_strdup(s) _strdup(s) -#else -#define os_strdup(s) strdup(s) -#endif -#endif -#endif /* WPA_TRACE */ - -#ifndef os_memcpy -#define os_memcpy(d, s, n) memcpy((d), (s), (n)) -#endif -#ifndef os_memmove -#define os_memmove(d, s, n) memmove((d), (s), (n)) -#endif -#ifndef os_memset -#define os_memset(s, c, n) memset(s, c, n) -#endif -#ifndef os_memcmp -#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n)) -#endif - -#ifndef os_strlen -#define os_strlen(s) strlen(s) -#endif -#ifndef os_strcasecmp -#ifdef _MSC_VER -#define os_strcasecmp(s1, s2) _stricmp((s1), (s2)) -#else -#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2)) -#endif -#endif -#ifndef os_strncasecmp -#ifdef _MSC_VER -#define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n)) -#else -#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n)) -#endif -#endif -#ifndef os_strchr -#define os_strchr(s, c) strchr((s), (c)) -#endif -#ifndef os_strcmp -#define os_strcmp(s1, s2) strcmp((s1), (s2)) -#endif -#ifndef os_strncmp -#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n)) -#endif -#ifndef os_strrchr -#define os_strrchr(s, c) strrchr((s), (c)) -#endif -#ifndef os_strstr -#define os_strstr(h, n) strstr((h), (n)) -#endif - -#ifndef os_snprintf -#ifdef _MSC_VER -#define os_snprintf _snprintf -#else -#define os_snprintf snprintf -#endif -#endif - -#endif /* OS_NO_C_LIB_DEFINES */ - - -static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size) -{ - if (size && nmemb > (~(size_t) 0) / size) - return NULL; - return os_realloc(ptr, nmemb * size); -} - - -/** - * os_strlcpy - Copy a string with size bound and NUL-termination - * @dest: Destination - * @src: Source - * @siz: Size of the target buffer - * Returns: Total length of the target string (length of src) (not including - * NUL-termination) - * - * This function matches in behavior with the strlcpy(3) function in OpenBSD. - */ -size_t os_strlcpy(char *dest, const char *src, size_t siz); - - -#ifdef OS_REJECT_C_LIB_FUNCTIONS -#define malloc OS_DO_NOT_USE_malloc -#define realloc OS_DO_NOT_USE_realloc -#define free OS_DO_NOT_USE_free -#define memcpy OS_DO_NOT_USE_memcpy -#define memmove OS_DO_NOT_USE_memmove -#define memset OS_DO_NOT_USE_memset -#define memcmp OS_DO_NOT_USE_memcmp -#undef strdup -#define strdup OS_DO_NOT_USE_strdup -#define strlen OS_DO_NOT_USE_strlen -#define strcasecmp OS_DO_NOT_USE_strcasecmp -#define strncasecmp OS_DO_NOT_USE_strncasecmp -#undef strchr -#define strchr OS_DO_NOT_USE_strchr -#undef strcmp -#define strcmp OS_DO_NOT_USE_strcmp -#undef strncmp -#define strncmp OS_DO_NOT_USE_strncmp -#undef strncpy -#define strncpy OS_DO_NOT_USE_strncpy -#define strrchr OS_DO_NOT_USE_strrchr -#define strstr OS_DO_NOT_USE_strstr -#undef snprintf -#define snprintf OS_DO_NOT_USE_snprintf - -#define strcpy OS_DO_NOT_USE_strcpy -#endif /* OS_REJECT_C_LIB_FUNCTIONS */ - -#endif /* OS_H */ diff --git a/contrib/hostapd/src/utils/os_internal.c b/contrib/hostapd/src/utils/os_internal.c deleted file mode 100644 index 2cb0d1262d..0000000000 --- a/contrib/hostapd/src/utils/os_internal.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * wpa_supplicant/hostapd / Internal implementation of OS specific functions - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file is an example of operating system specific wrapper functions. - * This version implements many of the functions internally, so it can be used - * to fill in missing functions from the target system C libraries. - * - * Some of the functions are using standard C library calls in order to keep - * this file in working condition to allow the functions to be tested on a - * Linux target. Please note that OS_NO_C_LIB_DEFINES needs to be defined for - * this file to work correctly. Note that these implementations are only - * examples and are not optimized for speed. - */ - -#include "includes.h" - -#undef OS_REJECT_C_LIB_FUNCTIONS -#include "os.h" - -void os_sleep(os_time_t sec, os_time_t usec) -{ - if (sec) - sleep(sec); - if (usec) - usleep(usec); -} - - -int os_get_time(struct os_time *t) -{ - int res; - struct timeval tv; - res = gettimeofday(&tv, NULL); - t->sec = tv.tv_sec; - t->usec = tv.tv_usec; - return res; -} - - -int os_get_reltime(struct os_reltime *t) -{ - int res; - struct timeval tv; - res = gettimeofday(&tv, NULL); - t->sec = tv.tv_sec; - t->usec = tv.tv_usec; - return res; -} - - -int os_mktime(int year, int month, int day, int hour, int min, int sec, - os_time_t *t) -{ - struct tm tm; - - if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || - hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || - sec > 60) - return -1; - - os_memset(&tm, 0, sizeof(tm)); - tm.tm_year = year - 1900; - tm.tm_mon = month - 1; - tm.tm_mday = day; - tm.tm_hour = hour; - tm.tm_min = min; - tm.tm_sec = sec; - - *t = (os_time_t) mktime(&tm); - return 0; -} - - -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)) { - perror("daemon"); - return -1; - } - - if (pid_file) { - FILE *f = fopen(pid_file, "w"); - if (f) { - fprintf(f, "%u\n", getpid()); - fclose(f); - } - } - - return -0; -} - - -void os_daemonize_terminate(const char *pid_file) -{ - if (pid_file) - unlink(pid_file); -} - - -int os_get_random(unsigned char *buf, size_t len) -{ - FILE *f; - size_t rc; - - f = fopen("/dev/urandom", "rb"); - if (f == NULL) { - printf("Could not open /dev/urandom.\n"); - return -1; - } - - rc = fread(buf, 1, len, f); - fclose(f); - - return rc != len ? -1 : 0; -} - - -unsigned long os_random(void) -{ - return random(); -} - - -char * os_rel2abs_path(const char *rel_path) -{ - char *buf = NULL, *cwd, *ret; - size_t len = 128, cwd_len, rel_len, ret_len; - - if (rel_path[0] == '/') - return os_strdup(rel_path); - - for (;;) { - buf = os_malloc(len); - if (buf == NULL) - return NULL; - cwd = getcwd(buf, len); - if (cwd == NULL) { - os_free(buf); - if (errno != ERANGE) { - return NULL; - } - len *= 2; - } else { - break; - } - } - - cwd_len = strlen(cwd); - rel_len = strlen(rel_path); - ret_len = cwd_len + 1 + rel_len + 1; - ret = os_malloc(ret_len); - if (ret) { - os_memcpy(ret, cwd, cwd_len); - ret[cwd_len] = '/'; - os_memcpy(ret + cwd_len + 1, rel_path, rel_len); - ret[ret_len - 1] = '\0'; - } - os_free(buf); - return ret; -} - - -int os_program_init(void) -{ - return 0; -} - - -void os_program_deinit(void) -{ -} - - -int os_setenv(const char *name, const char *value, int overwrite) -{ - return setenv(name, value, overwrite); -} - - -int os_unsetenv(const char *name) -{ -#if defined(__FreeBSD__) || defined(__NetBSD__) - unsetenv(name); - return 0; -#else - return unsetenv(name); -#endif -} - - -char * os_readfile(const char *name, size_t *len) -{ - FILE *f; - char *buf; - - f = fopen(name, "rb"); - if (f == NULL) - return NULL; - - fseek(f, 0, SEEK_END); - *len = ftell(f); - fseek(f, 0, SEEK_SET); - - buf = os_malloc(*len); - if (buf == NULL) { - fclose(f); - return NULL; - } - - if (fread(buf, 1, *len, f) != *len) { - fclose(f); - os_free(buf); - return NULL; - } - - fclose(f); - - return buf; -} - - -void * os_zalloc(size_t size) -{ - void *n = os_malloc(size); - if (n) - os_memset(n, 0, size); - return n; -} - - -void * os_malloc(size_t size) -{ - return malloc(size); -} - - -void * os_realloc(void *ptr, size_t size) -{ - return realloc(ptr, size); -} - - -void os_free(void *ptr) -{ - free(ptr); -} - - -void * os_memcpy(void *dest, const void *src, size_t n) -{ - char *d = dest; - const char *s = src; - while (n--) - *d++ = *s++; - return dest; -} - - -void * os_memmove(void *dest, const void *src, size_t n) -{ - if (dest < src) - os_memcpy(dest, src, n); - else { - /* overlapping areas */ - char *d = (char *) dest + n; - const char *s = (const char *) src + n; - while (n--) - *--d = *--s; - } - return dest; -} - - -void * os_memset(void *s, int c, size_t n) -{ - char *p = s; - while (n--) - *p++ = c; - return s; -} - - -int os_memcmp(const void *s1, const void *s2, size_t n) -{ - const unsigned char *p1 = s1, *p2 = s2; - - if (n == 0) - return 0; - - while (*p1 == *p2) { - p1++; - p2++; - n--; - if (n == 0) - return 0; - } - - return *p1 - *p2; -} - - -char * os_strdup(const char *s) -{ - char *res; - size_t len; - if (s == NULL) - return NULL; - len = os_strlen(s); - res = os_malloc(len + 1); - if (res) - os_memcpy(res, s, len + 1); - return res; -} - - -size_t os_strlen(const char *s) -{ - const char *p = s; - while (*p) - p++; - return p - s; -} - - -int os_strcasecmp(const char *s1, const char *s2) -{ - /* - * Ignoring case is not required for main functionality, so just use - * the case sensitive version of the function. - */ - return os_strcmp(s1, s2); -} - - -int os_strncasecmp(const char *s1, const char *s2, size_t n) -{ - /* - * Ignoring case is not required for main functionality, so just use - * the case sensitive version of the function. - */ - return os_strncmp(s1, s2, n); -} - - -char * os_strchr(const char *s, int c) -{ - while (*s) { - if (*s == c) - return (char *) s; - s++; - } - return NULL; -} - - -char * os_strrchr(const char *s, int c) -{ - const char *p = s; - while (*p) - p++; - p--; - while (p >= s) { - if (*p == c) - return (char *) p; - p--; - } - return NULL; -} - - -int os_strcmp(const char *s1, const char *s2) -{ - while (*s1 == *s2) { - if (*s1 == '\0') - break; - s1++; - s2++; - } - - return *s1 - *s2; -} - - -int os_strncmp(const char *s1, const char *s2, size_t n) -{ - if (n == 0) - return 0; - - while (*s1 == *s2) { - if (*s1 == '\0') - break; - s1++; - s2++; - n--; - if (n == 0) - return 0; - } - - return *s1 - *s2; -} - - -char * os_strncpy(char *dest, const char *src, size_t n) -{ - char *d = dest; - - while (n--) { - *d = *src; - if (*src == '\0') - break; - d++; - src++; - } - - return dest; -} - - -size_t os_strlcpy(char *dest, const char *src, size_t siz) -{ - const char *s = src; - size_t left = siz; - - if (left) { - /* Copy string up to the maximum size of the dest buffer */ - while (--left != 0) { - if ((*dest++ = *s++) == '\0') - break; - } - } - - if (left == 0) { - /* Not enough room for the string; force NUL-termination */ - if (siz != 0) - *dest = '\0'; - while (*s++) - ; /* determine total src string length */ - } - - return s - src - 1; -} - - -char * os_strstr(const char *haystack, const char *needle) -{ - size_t len = os_strlen(needle); - while (*haystack) { - if (os_strncmp(haystack, needle, len) == 0) - return (char *) haystack; - haystack++; - } - - return NULL; -} - - -int os_snprintf(char *str, size_t size, const char *format, ...) -{ - va_list ap; - int ret; - - /* See http://www.ijs.si/software/snprintf/ for portable - * implementation of snprintf. - */ - - va_start(ap, format); - ret = vsnprintf(str, size, format, ap); - va_end(ap); - if (size > 0) - str[size - 1] = '\0'; - return ret; -} diff --git a/contrib/hostapd/src/utils/os_none.c b/contrib/hostapd/src/utils/os_none.c deleted file mode 100644 index 228c4724cd..0000000000 --- a/contrib/hostapd/src/utils/os_none.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * wpa_supplicant/hostapd / Empty OS specific functions - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file can be used as a starting point when adding a new OS target. The - * functions here do not really work as-is since they are just empty or only - * return an error value. os_internal.c can be used as another starting point - * or reference since it has example implementation of many of these functions. - */ - -#include "includes.h" - -#include "os.h" - -void os_sleep(os_time_t sec, os_time_t usec) -{ -} - - -int os_get_time(struct os_time *t) -{ - return -1; -} - - -int os_get_reltime(struct os_reltime *t) -{ - return -1; -} - - -int os_mktime(int year, int month, int day, int hour, int min, int sec, - os_time_t *t) -{ - return -1; -} - -int os_gmtime(os_time_t t, struct os_tm *tm) -{ - return -1; -} - - -int os_daemonize(const char *pid_file) -{ - return -1; -} - - -void os_daemonize_terminate(const char *pid_file) -{ -} - - -int os_get_random(unsigned char *buf, size_t len) -{ - return -1; -} - - -unsigned long os_random(void) -{ - return 0; -} - - -char * os_rel2abs_path(const char *rel_path) -{ - return NULL; /* strdup(rel_path) can be used here */ -} - - -int os_program_init(void) -{ - return 0; -} - - -void os_program_deinit(void) -{ -} - - -int os_setenv(const char *name, const char *value, int overwrite) -{ - return -1; -} - - -int os_unsetenv(const char *name) -{ - return -1; -} - - -char * os_readfile(const char *name, size_t *len) -{ - return NULL; -} - - -void * os_zalloc(size_t size) -{ - return NULL; -} - - -#ifdef OS_NO_C_LIB_DEFINES -void * os_malloc(size_t size) -{ - return NULL; -} - - -void * os_realloc(void *ptr, size_t size) -{ - return NULL; -} - - -void os_free(void *ptr) -{ -} - - -void * os_memcpy(void *dest, const void *src, size_t n) -{ - return dest; -} - - -void * os_memmove(void *dest, const void *src, size_t n) -{ - return dest; -} - - -void * os_memset(void *s, int c, size_t n) -{ - return s; -} - - -int os_memcmp(const void *s1, const void *s2, size_t n) -{ - return 0; -} - - -char * os_strdup(const char *s) -{ - return NULL; -} - - -size_t os_strlen(const char *s) -{ - return 0; -} - - -int os_strcasecmp(const char *s1, const char *s2) -{ - /* - * Ignoring case is not required for main functionality, so just use - * the case sensitive version of the function. - */ - return os_strcmp(s1, s2); -} - - -int os_strncasecmp(const char *s1, const char *s2, size_t n) -{ - /* - * Ignoring case is not required for main functionality, so just use - * the case sensitive version of the function. - */ - return os_strncmp(s1, s2, n); -} - - -char * os_strchr(const char *s, int c) -{ - return NULL; -} - - -char * os_strrchr(const char *s, int c) -{ - return NULL; -} - - -int os_strcmp(const char *s1, const char *s2) -{ - return 0; -} - - -int os_strncmp(const char *s1, const char *s2, size_t n) -{ - return 0; -} - - -char * os_strncpy(char *dest, const char *src, size_t n) -{ - return dest; -} - - -size_t os_strlcpy(char *dest, const char *src, size_t size) -{ - return 0; -} - - -char * os_strstr(const char *haystack, const char *needle) -{ - return NULL; -} - - -int os_snprintf(char *str, size_t size, const char *format, ...) -{ - return 0; -} -#endif /* OS_NO_C_LIB_DEFINES */ diff --git a/contrib/hostapd/src/utils/os_unix.c b/contrib/hostapd/src/utils/os_unix.c deleted file mode 100644 index fa67fdfb68..0000000000 --- a/contrib/hostapd/src/utils/os_unix.c +++ /dev/null @@ -1,532 +0,0 @@ -/* - * OS specific functions for UNIX/POSIX systems - * Copyright (c) 2005-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include - -#ifdef ANDROID -#include -#include -#include -#endif /* ANDROID */ - -#include "os.h" -#include "common.h" - -#ifdef WPA_TRACE - -#include "wpa_debug.h" -#include "trace.h" -#include "list.h" - -static struct dl_list alloc_list; - -#define ALLOC_MAGIC 0xa84ef1b2 -#define FREED_MAGIC 0x67fd487a - -struct os_alloc_trace { - unsigned int magic; - struct dl_list list; - size_t len; - WPA_TRACE_INFO -}; - -#endif /* WPA_TRACE */ - - -void os_sleep(os_time_t sec, os_time_t usec) -{ - if (sec) - sleep(sec); - if (usec) - usleep(usec); -} - - -int os_get_time(struct os_time *t) -{ - int res; - struct timeval tv; - res = gettimeofday(&tv, NULL); - t->sec = tv.tv_sec; - t->usec = tv.tv_usec; - return res; -} - - -int os_get_reltime(struct os_reltime *t) -{ -#if defined(CLOCK_BOOTTIME) - static clockid_t clock_id = CLOCK_BOOTTIME; -#elif defined(CLOCK_MONOTONIC) - static clockid_t clock_id = CLOCK_MONOTONIC; -#else - static clockid_t clock_id = CLOCK_REALTIME; -#endif - struct timespec ts; - int res; - - while (1) { - res = clock_gettime(clock_id, &ts); - if (res == 0) { - t->sec = ts.tv_sec; - t->usec = ts.tv_nsec / 1000; - return 0; - } - switch (clock_id) { -#ifdef CLOCK_BOOTTIME - case CLOCK_BOOTTIME: - clock_id = CLOCK_MONOTONIC; - break; -#endif -#ifdef CLOCK_MONOTONIC - case CLOCK_MONOTONIC: - clock_id = CLOCK_REALTIME; - break; -#endif - case CLOCK_REALTIME: - return -1; - } - } -} - - -int os_mktime(int year, int month, int day, int hour, int min, int sec, - os_time_t *t) -{ - struct tm tm, *tm1; - time_t t_local, t1, t2; - os_time_t tz_offset; - - if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || - hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || - sec > 60) - return -1; - - memset(&tm, 0, sizeof(tm)); - tm.tm_year = year - 1900; - tm.tm_mon = month - 1; - tm.tm_mday = day; - tm.tm_hour = hour; - tm.tm_min = min; - tm.tm_sec = sec; - - t_local = mktime(&tm); - - /* figure out offset to UTC */ - tm1 = localtime(&t_local); - if (tm1) { - t1 = mktime(tm1); - tm1 = gmtime(&t_local); - if (tm1) { - t2 = mktime(tm1); - tz_offset = t2 - t1; - } else - tz_offset = 0; - } else - tz_offset = 0; - - *t = (os_time_t) t_local - tz_offset; - return 0; -} - - -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 -static int os_daemon(int nochdir, int noclose) -{ - int devnull; - - if (chdir("/") < 0) - return -1; - - devnull = open("/dev/null", O_RDWR); - if (devnull < 0) - return -1; - - if (dup2(devnull, STDIN_FILENO) < 0) { - close(devnull); - return -1; - } - - if (dup2(devnull, STDOUT_FILENO) < 0) { - close(devnull); - return -1; - } - - if (dup2(devnull, STDERR_FILENO) < 0) { - close(devnull); - return -1; - } - - return 0; -} -#else /* __APPLE__ */ -#define os_daemon daemon -#endif /* __APPLE__ */ - - -int os_daemonize(const char *pid_file) -{ -#if defined(__uClinux__) || defined(__sun__) - return -1; -#else /* defined(__uClinux__) || defined(__sun__) */ - if (os_daemon(0, 0)) { - perror("daemon"); - return -1; - } - - if (pid_file) { - FILE *f = fopen(pid_file, "w"); - if (f) { - fprintf(f, "%u\n", getpid()); - fclose(f); - } - } - - return -0; -#endif /* defined(__uClinux__) || defined(__sun__) */ -} - - -void os_daemonize_terminate(const char *pid_file) -{ - if (pid_file) - unlink(pid_file); -} - - -int os_get_random(unsigned char *buf, size_t len) -{ - FILE *f; - size_t rc; - - f = fopen("/dev/urandom", "rb"); - if (f == NULL) { - printf("Could not open /dev/urandom.\n"); - return -1; - } - - rc = fread(buf, 1, len, f); - fclose(f); - - return rc != len ? -1 : 0; -} - - -unsigned long os_random(void) -{ - return random(); -} - - -char * os_rel2abs_path(const char *rel_path) -{ - char *buf = NULL, *cwd, *ret; - size_t len = 128, cwd_len, rel_len, ret_len; - int last_errno; - - if (!rel_path) - return NULL; - - if (rel_path[0] == '/') - return os_strdup(rel_path); - - for (;;) { - buf = os_malloc(len); - if (buf == NULL) - return NULL; - cwd = getcwd(buf, len); - if (cwd == NULL) { - last_errno = errno; - os_free(buf); - if (last_errno != ERANGE) - return NULL; - len *= 2; - if (len > 2000) - return NULL; - } else { - buf[len - 1] = '\0'; - break; - } - } - - cwd_len = os_strlen(cwd); - rel_len = os_strlen(rel_path); - ret_len = cwd_len + 1 + rel_len + 1; - ret = os_malloc(ret_len); - if (ret) { - os_memcpy(ret, cwd, cwd_len); - ret[cwd_len] = '/'; - os_memcpy(ret + cwd_len + 1, rel_path, rel_len); - ret[ret_len - 1] = '\0'; - } - os_free(buf); - return ret; -} - - -int os_program_init(void) -{ -#ifdef ANDROID - /* - * We ignore errors here since errors are normal if we - * are already running as non-root. - */ -#ifdef ANDROID_SETGROUPS_OVERRIDE - gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE }; -#else /* ANDROID_SETGROUPS_OVERRIDE */ - gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE }; -#endif /* ANDROID_SETGROUPS_OVERRIDE */ - struct __user_cap_header_struct header; - struct __user_cap_data_struct cap; - - setgroups(ARRAY_SIZE(groups), groups); - - prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); - - setgid(AID_WIFI); - setuid(AID_WIFI); - - header.version = _LINUX_CAPABILITY_VERSION; - header.pid = 0; - cap.effective = cap.permitted = - (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW); - cap.inheritable = 0; - capset(&header, &cap); -#endif /* ANDROID */ - -#ifdef WPA_TRACE - dl_list_init(&alloc_list); -#endif /* WPA_TRACE */ - return 0; -} - - -void os_program_deinit(void) -{ -#ifdef WPA_TRACE - struct os_alloc_trace *a; - unsigned long total = 0; - dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) { - total += a->len; - if (a->magic != ALLOC_MAGIC) { - wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x " - "len %lu", - a, a->magic, (unsigned long) a->len); - continue; - } - wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu", - a, (unsigned long) a->len); - wpa_trace_dump("memleak", a); - } - if (total) - wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", - (unsigned long) total); -#endif /* WPA_TRACE */ -} - - -int os_setenv(const char *name, const char *value, int overwrite) -{ - return setenv(name, value, overwrite); -} - - -int os_unsetenv(const char *name) -{ -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \ - defined(__OpenBSD__) - unsetenv(name); - return 0; -#else - return unsetenv(name); -#endif -} - - -char * os_readfile(const char *name, size_t *len) -{ - FILE *f; - char *buf; - long pos; - - f = fopen(name, "rb"); - if (f == NULL) - return NULL; - - if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) { - fclose(f); - return NULL; - } - *len = pos; - if (fseek(f, 0, SEEK_SET) < 0) { - fclose(f); - return NULL; - } - - buf = os_malloc(*len); - if (buf == NULL) { - fclose(f); - return NULL; - } - - if (fread(buf, 1, *len, f) != *len) { - fclose(f); - os_free(buf); - return NULL; - } - - fclose(f); - - return buf; -} - - -#ifndef WPA_TRACE -void * os_zalloc(size_t size) -{ - return calloc(1, size); -} -#endif /* WPA_TRACE */ - - -size_t os_strlcpy(char *dest, const char *src, size_t siz) -{ - const char *s = src; - size_t left = siz; - - if (left) { - /* Copy string up to the maximum size of the dest buffer */ - while (--left != 0) { - if ((*dest++ = *s++) == '\0') - break; - } - } - - if (left == 0) { - /* Not enough room for the string; force NUL-termination */ - if (siz != 0) - *dest = '\0'; - while (*s++) - ; /* determine total src string length */ - } - - return s - src - 1; -} - - -#ifdef WPA_TRACE - -void * os_malloc(size_t size) -{ - struct os_alloc_trace *a; - a = malloc(sizeof(*a) + size); - if (a == NULL) - return NULL; - a->magic = ALLOC_MAGIC; - dl_list_add(&alloc_list, &a->list); - a->len = size; - wpa_trace_record(a); - return a + 1; -} - - -void * os_realloc(void *ptr, size_t size) -{ - struct os_alloc_trace *a; - size_t copy_len; - void *n; - - if (ptr == NULL) - return os_malloc(size); - - a = (struct os_alloc_trace *) ptr - 1; - if (a->magic != ALLOC_MAGIC) { - wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s", - a, a->magic, - a->magic == FREED_MAGIC ? " (already freed)" : ""); - wpa_trace_show("Invalid os_realloc() call"); - abort(); - } - n = os_malloc(size); - if (n == NULL) - return NULL; - copy_len = a->len; - if (copy_len > size) - copy_len = size; - os_memcpy(n, a + 1, copy_len); - os_free(ptr); - return n; -} - - -void os_free(void *ptr) -{ - struct os_alloc_trace *a; - - if (ptr == NULL) - return; - a = (struct os_alloc_trace *) ptr - 1; - if (a->magic != ALLOC_MAGIC) { - wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s", - a, a->magic, - a->magic == FREED_MAGIC ? " (already freed)" : ""); - wpa_trace_show("Invalid os_free() call"); - abort(); - } - dl_list_del(&a->list); - a->magic = FREED_MAGIC; - - wpa_trace_check_ref(ptr); - free(a); -} - - -void * os_zalloc(size_t size) -{ - void *ptr = os_malloc(size); - if (ptr) - os_memset(ptr, 0, size); - return ptr; -} - - -char * os_strdup(const char *s) -{ - size_t len; - char *d; - len = os_strlen(s); - d = os_malloc(len + 1); - if (d == NULL) - return NULL; - os_memcpy(d, s, len); - d[len] = '\0'; - return d; -} - -#endif /* WPA_TRACE */ diff --git a/contrib/hostapd/src/utils/os_win32.c b/contrib/hostapd/src/utils/os_win32.c deleted file mode 100644 index 1cfa7a5f81..0000000000 --- a/contrib/hostapd/src/utils/os_win32.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * wpa_supplicant/hostapd / OS specific functions for Win32 systems - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include -#include -#include - -#include "os.h" - -void os_sleep(os_time_t sec, os_time_t usec) -{ - if (sec) - Sleep(sec * 1000); - if (usec) - Sleep(usec / 1000); -} - - -int os_get_time(struct os_time *t) -{ -#define EPOCHFILETIME (116444736000000000ULL) - FILETIME ft; - LARGE_INTEGER li; - ULONGLONG tt; - -#ifdef _WIN32_WCE - SYSTEMTIME st; - - GetSystemTime(&st); - SystemTimeToFileTime(&st, &ft); -#else /* _WIN32_WCE */ - GetSystemTimeAsFileTime(&ft); -#endif /* _WIN32_WCE */ - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - tt = (li.QuadPart - EPOCHFILETIME) / 10; - t->sec = (os_time_t) (tt / 1000000); - t->usec = (os_time_t) (tt % 1000000); - - return 0; -} - - -int os_get_reltime(struct os_reltime *t) -{ - /* consider using performance counters or so instead */ - struct os_time now; - int res = os_get_time(&now); - t->sec = now.sec; - t->usec = now.usec; - return res; -} - - -int os_mktime(int year, int month, int day, int hour, int min, int sec, - os_time_t *t) -{ - struct tm tm, *tm1; - time_t t_local, t1, t2; - os_time_t tz_offset; - - if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || - hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || - sec > 60) - return -1; - - memset(&tm, 0, sizeof(tm)); - tm.tm_year = year - 1900; - tm.tm_mon = month - 1; - tm.tm_mday = day; - tm.tm_hour = hour; - tm.tm_min = min; - tm.tm_sec = sec; - - t_local = mktime(&tm); - - /* figure out offset to UTC */ - tm1 = localtime(&t_local); - if (tm1) { - t1 = mktime(tm1); - tm1 = gmtime(&t_local); - if (tm1) { - t2 = mktime(tm1); - tz_offset = t2 - t1; - } else - tz_offset = 0; - } else - tz_offset = 0; - - *t = (os_time_t) t_local - tz_offset; - return 0; -} - - -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 */ - return -1; -} - - -void os_daemonize_terminate(const char *pid_file) -{ -} - - -int os_get_random(unsigned char *buf, size_t len) -{ - HCRYPTPROV prov; - BOOL ret; - - if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) - return -1; - - ret = CryptGenRandom(prov, len, buf); - CryptReleaseContext(prov, 0); - - return ret ? 0 : -1; -} - - -unsigned long os_random(void) -{ - return rand(); -} - - -char * os_rel2abs_path(const char *rel_path) -{ - return _strdup(rel_path); -} - - -int os_program_init(void) -{ -#ifdef CONFIG_NATIVE_WINDOWS - WSADATA wsaData; - if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { - printf("Could not find a usable WinSock.dll\n"); - return -1; - } -#endif /* CONFIG_NATIVE_WINDOWS */ - return 0; -} - - -void os_program_deinit(void) -{ -#ifdef CONFIG_NATIVE_WINDOWS - WSACleanup(); -#endif /* CONFIG_NATIVE_WINDOWS */ -} - - -int os_setenv(const char *name, const char *value, int overwrite) -{ - return -1; -} - - -int os_unsetenv(const char *name) -{ - return -1; -} - - -char * os_readfile(const char *name, size_t *len) -{ - FILE *f; - char *buf; - - f = fopen(name, "rb"); - if (f == NULL) - return NULL; - - fseek(f, 0, SEEK_END); - *len = ftell(f); - fseek(f, 0, SEEK_SET); - - buf = malloc(*len); - if (buf == NULL) { - fclose(f); - return NULL; - } - - fread(buf, 1, *len, f); - fclose(f); - - return buf; -} - - -void * os_zalloc(size_t size) -{ - return calloc(1, size); -} - - -size_t os_strlcpy(char *dest, const char *src, size_t siz) -{ - const char *s = src; - size_t left = siz; - - if (left) { - /* Copy string up to the maximum size of the dest buffer */ - while (--left != 0) { - if ((*dest++ = *s++) == '\0') - break; - } - } - - if (left == 0) { - /* Not enough room for the string; force NUL-termination */ - if (siz != 0) - *dest = '\0'; - while (*s++) - ; /* determine total src string length */ - } - - return s - src - 1; -} diff --git a/contrib/hostapd/src/utils/pcsc_funcs.c b/contrib/hostapd/src/utils/pcsc_funcs.c deleted file mode 100644 index ee90d25e79..0000000000 --- a/contrib/hostapd/src/utils/pcsc_funcs.c +++ /dev/null @@ -1,1419 +0,0 @@ -/* - * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM - * Copyright (c) 2004-2007, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM - * cards through PC/SC smartcard library. These functions are used to implement - * authentication routines for EAP-SIM and EAP-AKA. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "pcsc_funcs.h" - - -/* See ETSI GSM 11.11 and ETSI TS 102 221 for details. - * SIM commands: - * Command APDU: CLA INS P1 P2 P3 Data - * CLA (class of instruction): A0 for GSM, 00 for USIM - * INS (instruction) - * P1 P2 P3 (parameters, P3 = length of Data) - * Response APDU: Data SW1 SW2 - * SW1 SW2 (Status words) - * Commands (INS P1 P2 P3): - * SELECT: A4 00 00 02 - * GET RESPONSE: C0 00 00 - * RUN GSM ALG: 88 00 00 00 - * RUN UMTS ALG: 88 00 81 data: 0x10 | RAND | 0x10 | AUTN - * P1 = ID of alg in card - * P2 = ID of secret key - * READ BINARY: B0 - * READ RECORD: B2 - * P2 (mode) = '02' (next record), '03' (previous record), - * '04' (absolute mode) - * VERIFY CHV: 20 00 08 - * CHANGE CHV: 24 00 10 - * DISABLE CHV: 26 00 01 08 - * ENABLE CHV: 28 00 01 08 - * UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10 - * SLEEP: FA 00 00 00 - */ - -/* GSM SIM commands */ -#define SIM_CMD_SELECT 0xa0, 0xa4, 0x00, 0x00, 0x02 -#define SIM_CMD_RUN_GSM_ALG 0xa0, 0x88, 0x00, 0x00, 0x10 -#define SIM_CMD_GET_RESPONSE 0xa0, 0xc0, 0x00, 0x00 -#define SIM_CMD_READ_BIN 0xa0, 0xb0, 0x00, 0x00 -#define SIM_CMD_READ_RECORD 0xa0, 0xb2, 0x00, 0x00 -#define SIM_CMD_VERIFY_CHV1 0xa0, 0x20, 0x00, 0x01, 0x08 - -/* USIM commands */ -#define USIM_CLA 0x00 -#define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22 -#define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00 - -#define SIM_RECORD_MODE_ABSOLUTE 0x04 - -#define USIM_FSP_TEMPL_TAG 0x62 - -#define USIM_TLV_FILE_DESC 0x82 -#define USIM_TLV_FILE_ID 0x83 -#define USIM_TLV_DF_NAME 0x84 -#define USIM_TLV_PROPR_INFO 0xA5 -#define USIM_TLV_LIFE_CYCLE_STATUS 0x8A -#define USIM_TLV_FILE_SIZE 0x80 -#define USIM_TLV_TOTAL_FILE_SIZE 0x81 -#define USIM_TLV_PIN_STATUS_TEMPLATE 0xC6 -#define USIM_TLV_SHORT_FILE_ID 0x88 -#define USIM_TLV_SECURITY_ATTR_8B 0x8B -#define USIM_TLV_SECURITY_ATTR_8C 0x8C -#define USIM_TLV_SECURITY_ATTR_AB 0xAB - -#define USIM_PS_DO_TAG 0x90 - -#define AKA_RAND_LEN 16 -#define AKA_AUTN_LEN 16 -#define AKA_AUTS_LEN 14 -#define RES_MAX_LEN 16 -#define IK_LEN 16 -#define CK_LEN 16 - - -/* GSM files - * File type in first octet: - * 3F = Master File - * 7F = Dedicated File - * 2F = Elementary File under the Master File - * 6F = Elementary File under a Dedicated File - */ -#define SCARD_FILE_MF 0x3F00 -#define SCARD_FILE_GSM_DF 0x7F20 -#define SCARD_FILE_UMTS_DF 0x7F50 -#define SCARD_FILE_GSM_EF_IMSI 0x6F07 -#define SCARD_FILE_GSM_EF_AD 0x6FAD -#define SCARD_FILE_EF_DIR 0x2F00 -#define SCARD_FILE_EF_ICCID 0x2FE2 -#define SCARD_FILE_EF_CK 0x6FE1 -#define SCARD_FILE_EF_IK 0x6FE2 - -#define SCARD_CHV1_OFFSET 13 -#define SCARD_CHV1_FLAG 0x80 - - -typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types; - -struct scard_data { - SCARDCONTEXT ctx; - SCARDHANDLE card; - DWORD protocol; - sim_types sim_type; - int pin1_required; -}; - -#ifdef __MINGW32_VERSION -/* MinGW does not yet support WinScard, so load the needed functions - * dynamically from winscard.dll for now. */ - -static HINSTANCE dll = NULL; /* winscard.dll */ - -static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci; -#undef SCARD_PCI_T0 -#define SCARD_PCI_T0 (dll_g_rgSCardT0Pci) -#undef SCARD_PCI_T1 -#define SCARD_PCI_T1 (dll_g_rgSCardT1Pci) - - -static WINSCARDAPI LONG WINAPI -(*dll_SCardEstablishContext)(IN DWORD dwScope, - IN LPCVOID pvReserved1, - IN LPCVOID pvReserved2, - OUT LPSCARDCONTEXT phContext); -#define SCardEstablishContext dll_SCardEstablishContext - -static long (*dll_SCardReleaseContext)(long hContext); -#define SCardReleaseContext dll_SCardReleaseContext - -static WINSCARDAPI LONG WINAPI -(*dll_SCardListReadersA)(IN SCARDCONTEXT hContext, - IN LPCSTR mszGroups, - OUT LPSTR mszReaders, - IN OUT LPDWORD pcchReaders); -#undef SCardListReaders -#define SCardListReaders dll_SCardListReadersA - -static WINSCARDAPI LONG WINAPI -(*dll_SCardConnectA)(IN SCARDCONTEXT hContext, - IN LPCSTR szReader, - IN DWORD dwShareMode, - IN DWORD dwPreferredProtocols, - OUT LPSCARDHANDLE phCard, - OUT LPDWORD pdwActiveProtocol); -#undef SCardConnect -#define SCardConnect dll_SCardConnectA - -static WINSCARDAPI LONG WINAPI -(*dll_SCardDisconnect)(IN SCARDHANDLE hCard, - IN DWORD dwDisposition); -#define SCardDisconnect dll_SCardDisconnect - -static WINSCARDAPI LONG WINAPI -(*dll_SCardTransmit)(IN SCARDHANDLE hCard, - IN LPCSCARD_IO_REQUEST pioSendPci, - IN LPCBYTE pbSendBuffer, - IN DWORD cbSendLength, - IN OUT LPSCARD_IO_REQUEST pioRecvPci, - OUT LPBYTE pbRecvBuffer, - IN OUT LPDWORD pcbRecvLength); -#define SCardTransmit dll_SCardTransmit - -static WINSCARDAPI LONG WINAPI -(*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard); -#define SCardBeginTransaction dll_SCardBeginTransaction - -static WINSCARDAPI LONG WINAPI -(*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition); -#define SCardEndTransaction dll_SCardEndTransaction - - -static int mingw_load_symbols(void) -{ - char *sym; - - if (dll) - return 0; - - dll = LoadLibrary("winscard"); - if (dll == NULL) { - wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll " - "library"); - return -1; - } - -#define LOADSYM(s) \ - sym = #s; \ - dll_ ## s = (void *) GetProcAddress(dll, sym); \ - if (dll_ ## s == NULL) \ - goto fail; - - LOADSYM(SCardEstablishContext); - LOADSYM(SCardReleaseContext); - LOADSYM(SCardListReadersA); - LOADSYM(SCardConnectA); - LOADSYM(SCardDisconnect); - LOADSYM(SCardTransmit); - LOADSYM(SCardBeginTransaction); - LOADSYM(SCardEndTransaction); - LOADSYM(g_rgSCardT0Pci); - LOADSYM(g_rgSCardT1Pci); - -#undef LOADSYM - - return 0; - -fail: - wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from " - "winscard.dll", sym); - FreeLibrary(dll); - dll = NULL; - return -1; -} - - -static void mingw_unload_symbols(void) -{ - if (dll == NULL) - return; - - FreeLibrary(dll); - dll = NULL; -} - -#else /* __MINGW32_VERSION */ - -#define mingw_load_symbols() 0 -#define mingw_unload_symbols() do { } while (0) - -#endif /* __MINGW32_VERSION */ - - -static int _scard_select_file(struct scard_data *scard, unsigned short file_id, - unsigned char *buf, size_t *buf_len, - sim_types sim_type, unsigned char *aid, - size_t aidlen); -static int scard_select_file(struct scard_data *scard, unsigned short file_id, - unsigned char *buf, size_t *buf_len); -static int scard_verify_pin(struct scard_data *scard, const char *pin); -static int scard_get_record_len(struct scard_data *scard, - unsigned char recnum, unsigned char mode); -static int scard_read_record(struct scard_data *scard, - unsigned char *data, size_t len, - unsigned char recnum, unsigned char mode); - - -static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len, - int *ps_do, int *file_len) -{ - unsigned char *pos, *end; - - if (ps_do) - *ps_do = -1; - if (file_len) - *file_len = -1; - - pos = buf; - end = pos + buf_len; - if (*pos != USIM_FSP_TEMPL_TAG) { - wpa_printf(MSG_DEBUG, "SCARD: file header did not " - "start with FSP template tag"); - return -1; - } - pos++; - if (pos >= end) - return -1; - if ((pos + pos[0]) < end) - end = pos + 1 + pos[0]; - pos++; - wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template", - pos, end - pos); - - while (pos + 1 < end) { - wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV 0x%02x len=%d", - pos[0], pos[1]); - if (pos + 2 + pos[1] > end) - break; - - switch (pos[0]) { - case USIM_TLV_FILE_DESC: - wpa_hexdump(MSG_MSGDUMP, "SCARD: File Descriptor TLV", - pos + 2, pos[1]); - break; - case USIM_TLV_FILE_ID: - wpa_hexdump(MSG_MSGDUMP, "SCARD: File Identifier TLV", - pos + 2, pos[1]); - break; - case USIM_TLV_DF_NAME: - wpa_hexdump(MSG_MSGDUMP, "SCARD: DF name (AID) TLV", - pos + 2, pos[1]); - break; - case USIM_TLV_PROPR_INFO: - wpa_hexdump(MSG_MSGDUMP, "SCARD: Proprietary " - "information TLV", pos + 2, pos[1]); - break; - case USIM_TLV_LIFE_CYCLE_STATUS: - wpa_hexdump(MSG_MSGDUMP, "SCARD: Life Cycle Status " - "Integer TLV", pos + 2, pos[1]); - break; - case USIM_TLV_FILE_SIZE: - wpa_hexdump(MSG_MSGDUMP, "SCARD: File size TLV", - pos + 2, pos[1]); - if ((pos[1] == 1 || pos[1] == 2) && file_len) { - if (pos[1] == 1) - *file_len = (int) pos[2]; - else - *file_len = ((int) pos[2] << 8) | - (int) pos[3]; - wpa_printf(MSG_DEBUG, "SCARD: file_size=%d", - *file_len); - } - break; - case USIM_TLV_TOTAL_FILE_SIZE: - wpa_hexdump(MSG_MSGDUMP, "SCARD: Total file size TLV", - pos + 2, pos[1]); - break; - case USIM_TLV_PIN_STATUS_TEMPLATE: - wpa_hexdump(MSG_MSGDUMP, "SCARD: PIN Status Template " - "DO TLV", pos + 2, pos[1]); - if (pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG && - pos[3] >= 1 && ps_do) { - wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x", - pos[4]); - *ps_do = (int) pos[4]; - } - break; - case USIM_TLV_SHORT_FILE_ID: - wpa_hexdump(MSG_MSGDUMP, "SCARD: Short File " - "Identifier (SFI) TLV", pos + 2, pos[1]); - break; - case USIM_TLV_SECURITY_ATTR_8B: - case USIM_TLV_SECURITY_ATTR_8C: - case USIM_TLV_SECURITY_ATTR_AB: - wpa_hexdump(MSG_MSGDUMP, "SCARD: Security attribute " - "TLV", pos + 2, pos[1]); - break; - default: - wpa_hexdump(MSG_MSGDUMP, "SCARD: Unrecognized TLV", - pos, 2 + pos[1]); - break; - } - - pos += 2 + pos[1]; - - if (pos == end) - return 0; - } - return -1; -} - - -static int scard_pin_needed(struct scard_data *scard, - unsigned char *hdr, size_t hlen) -{ - if (scard->sim_type == SCARD_GSM_SIM) { - if (hlen > SCARD_CHV1_OFFSET && - !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG)) - return 1; - return 0; - } - - if (scard->sim_type == SCARD_USIM) { - int ps_do; - if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL)) - return -1; - /* TODO: there could be more than one PS_DO entry because of - * multiple PINs in key reference.. */ - if (ps_do > 0 && (ps_do & 0x80)) - return 1; - return 0; - } - - return -1; -} - - -static int scard_get_aid(struct scard_data *scard, unsigned char *aid, - size_t maxlen) -{ - int rlen, rec; - struct efdir { - unsigned char appl_template_tag; /* 0x61 */ - unsigned char appl_template_len; - unsigned char appl_id_tag; /* 0x4f */ - unsigned char aid_len; - unsigned char rid[5]; - unsigned char appl_code[2]; /* 0x1002 for 3G USIM */ - } *efdir; - unsigned char buf[127]; - size_t blen; - - efdir = (struct efdir *) buf; - blen = sizeof(buf); - if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) { - wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR"); - return -1; - } - wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen); - - for (rec = 1; rec < 10; rec++) { - rlen = scard_get_record_len(scard, rec, - SIM_RECORD_MODE_ABSOLUTE); - if (rlen < 0) { - wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR " - "record length"); - return -1; - } - blen = sizeof(buf); - if (rlen > (int) blen) { - wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record"); - return -1; - } - if (scard_read_record(scard, buf, rlen, rec, - SIM_RECORD_MODE_ABSOLUTE) < 0) { - wpa_printf(MSG_DEBUG, "SCARD: Failed to read " - "EF_DIR record %d", rec); - return -1; - } - wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen); - - if (efdir->appl_template_tag != 0x61) { - wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " - "template tag 0x%x", - efdir->appl_template_tag); - continue; - } - - if (efdir->appl_template_len > rlen - 2) { - wpa_printf(MSG_DEBUG, "SCARD: Too long application " - "template (len=%d rlen=%d)", - efdir->appl_template_len, rlen); - continue; - } - - if (efdir->appl_id_tag != 0x4f) { - wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " - "identifier tag 0x%x", efdir->appl_id_tag); - continue; - } - - if (efdir->aid_len < 1 || efdir->aid_len > 16) { - wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d", - efdir->aid_len); - continue; - } - - wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record", - efdir->rid, efdir->aid_len); - - if (efdir->appl_code[0] == 0x10 && - efdir->appl_code[1] == 0x02) { - wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from " - "EF_DIR record %d", rec); - break; - } - } - - if (rec >= 10) { - wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found " - "from EF_DIR records"); - return -1; - } - - if (efdir->aid_len > maxlen) { - wpa_printf(MSG_DEBUG, "SCARD: Too long AID"); - return -1; - } - - os_memcpy(aid, efdir->rid, efdir->aid_len); - - return efdir->aid_len; -} - - -/** - * scard_init - Initialize SIM/USIM connection using PC/SC - * @reader: Reader name prefix to search for - * Returns: Pointer to private data structure, or %NULL on failure - * - * This function is used to initialize SIM/USIM connection. PC/SC is used to - * open connection to the SIM/USIM card. In addition, local flag is set if a - * PIN is needed to access some of the card functions. Once the connection is - * not needed anymore, scard_deinit() can be used to close it. - */ -struct scard_data * scard_init(const char *reader) -{ - long ret; - unsigned long len, pos; - struct scard_data *scard; -#ifdef CONFIG_NATIVE_WINDOWS - TCHAR *readers = NULL; -#else /* CONFIG_NATIVE_WINDOWS */ - char *readers = NULL; -#endif /* CONFIG_NATIVE_WINDOWS */ - unsigned char buf[100]; - size_t blen; - int transaction = 0; - int pin_needed; - - wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface"); - if (mingw_load_symbols()) - return NULL; - scard = os_zalloc(sizeof(*scard)); - if (scard == NULL) - return NULL; - - ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, - &scard->ctx); - if (ret != SCARD_S_SUCCESS) { - wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card " - "context (err=%ld)", ret); - goto failed; - } - - ret = SCardListReaders(scard->ctx, NULL, NULL, &len); - if (ret != SCARD_S_SUCCESS) { - wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed " - "(err=%ld)", ret); - goto failed; - } - -#ifdef UNICODE - len *= 2; -#endif /* UNICODE */ - readers = os_malloc(len); - if (readers == NULL) { - wpa_printf(MSG_INFO, "SCARD: malloc failed\n"); - goto failed; - } - - ret = SCardListReaders(scard->ctx, NULL, readers, &len); - if (ret != SCARD_S_SUCCESS) { - wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) " - "(err=%ld)", ret); - goto failed; - } - if (len < 3) { - wpa_printf(MSG_WARNING, "SCARD: No smart card readers " - "available."); - goto failed; - } - wpa_hexdump_ascii(MSG_DEBUG, "SCARD: Readers", (u8 *) readers, len); - /* - * readers is a list of available readers. The last entry is terminated - * with double null. - */ - pos = 0; -#ifdef UNICODE - /* TODO */ -#else /* UNICODE */ - while (pos < len) { - if (reader == NULL || - os_strncmp(&readers[pos], reader, os_strlen(reader)) == 0) - break; - while (pos < len && readers[pos]) - pos++; - pos++; /* skip separating null */ - if (pos < len && readers[pos] == '\0') - pos = len; /* double null terminates list */ - } -#endif /* UNICODE */ - if (pos >= len) { - wpa_printf(MSG_WARNING, "SCARD: No reader with prefix '%s' " - "found", reader); - goto failed; - } - -#ifdef UNICODE - wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", &readers[pos]); -#else /* UNICODE */ - wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", &readers[pos]); -#endif /* UNICODE */ - - ret = SCardConnect(scard->ctx, &readers[pos], SCARD_SHARE_SHARED, - SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, - &scard->card, &scard->protocol); - if (ret != SCARD_S_SUCCESS) { - if (ret == (long) SCARD_E_NO_SMARTCARD) - wpa_printf(MSG_INFO, "No smart card inserted."); - else - wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret); - goto failed; - } - - os_free(readers); - readers = NULL; - - wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)", - (unsigned int) scard->card, scard->protocol, - scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1"); - - ret = SCardBeginTransaction(scard->card); - if (ret != SCARD_S_SUCCESS) { - wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: " - "0x%x", (unsigned int) ret); - goto failed; - } - transaction = 1; - - blen = sizeof(buf); - - wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support"); - if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen, - SCARD_USIM, NULL, 0)) { - wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported. Trying to use GSM SIM"); - scard->sim_type = SCARD_GSM_SIM; - } else { - wpa_printf(MSG_DEBUG, "SCARD: USIM is supported"); - scard->sim_type = SCARD_USIM; - } - - if (scard->sim_type == SCARD_GSM_SIM) { - blen = sizeof(buf); - if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) { - wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF"); - goto failed; - } - - blen = sizeof(buf); - if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) { - wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF"); - goto failed; - } - } else { - unsigned char aid[32]; - int aid_len; - - aid_len = scard_get_aid(scard, aid, sizeof(aid)); - if (aid_len < 0) { - wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for " - "3G USIM app - try to use standard 3G RID"); - os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5); - aid_len = 5; - } - wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len); - - /* Select based on AID = 3G RID from EF_DIR. This is usually - * starting with A0 00 00 00 87. */ - blen = sizeof(buf); - if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type, - aid, aid_len)) { - wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM " - "app"); - wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID", - aid, aid_len); - goto failed; - } - } - - /* Verify whether CHV1 (PIN1) is needed to access the card. */ - pin_needed = scard_pin_needed(scard, buf, blen); - if (pin_needed < 0) { - wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN " - "is needed"); - goto failed; - } - if (pin_needed) { - scard->pin1_required = 1; - wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access (retry " - "counter=%d)", scard_get_pin_retry_counter(scard)); - } - - ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); - if (ret != SCARD_S_SUCCESS) { - wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: " - "0x%x", (unsigned int) ret); - } - - return scard; - -failed: - if (transaction) - SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); - os_free(readers); - scard_deinit(scard); - return NULL; -} - - -/** - * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands - * @scard: Pointer to private data from scard_init() - * @pin: PIN code as an ASCII string (e.g., "1234") - * Returns: 0 on success, -1 on failure - */ -int scard_set_pin(struct scard_data *scard, const char *pin) -{ - if (scard == NULL) - return -1; - - /* Verify whether CHV1 (PIN1) is needed to access the card. */ - if (scard->pin1_required) { - if (pin == NULL) { - wpa_printf(MSG_DEBUG, "No PIN configured for SIM " - "access"); - return -1; - } - if (scard_verify_pin(scard, pin)) { - wpa_printf(MSG_INFO, "PIN verification failed for " - "SIM access"); - return -1; - } - } - - return 0; -} - - -/** - * scard_deinit - Deinitialize SIM/USIM connection - * @scard: Pointer to private data from scard_init() - * - * This function closes the SIM/USIM connect opened with scard_init(). - */ -void scard_deinit(struct scard_data *scard) -{ - long ret; - - if (scard == NULL) - return; - - wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface"); - if (scard->card) { - ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD); - if (ret != SCARD_S_SUCCESS) { - wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect " - "smart card (err=%ld)", ret); - } - } - - if (scard->ctx) { - ret = SCardReleaseContext(scard->ctx); - if (ret != SCARD_S_SUCCESS) { - wpa_printf(MSG_DEBUG, "Failed to release smart card " - "context (err=%ld)", ret); - } - } - os_free(scard); - mingw_unload_symbols(); -} - - -static long scard_transmit(struct scard_data *scard, - unsigned char *_send, size_t send_len, - unsigned char *_recv, size_t *recv_len) -{ - long ret; - unsigned long rlen; - - wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send", - _send, send_len); - rlen = *recv_len; - ret = SCardTransmit(scard->card, - scard->protocol == SCARD_PROTOCOL_T1 ? - SCARD_PCI_T1 : SCARD_PCI_T0, - _send, (unsigned long) send_len, - NULL, _recv, &rlen); - *recv_len = rlen; - if (ret == SCARD_S_SUCCESS) { - wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv", - _recv, rlen); - } else { - wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed " - "(err=0x%lx)", ret); - } - return ret; -} - - -static int _scard_select_file(struct scard_data *scard, unsigned short file_id, - unsigned char *buf, size_t *buf_len, - sim_types sim_type, unsigned char *aid, - size_t aidlen) -{ - long ret; - unsigned char resp[3]; - unsigned char cmd[50] = { SIM_CMD_SELECT }; - int cmdlen; - unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE }; - size_t len, rlen; - - if (sim_type == SCARD_USIM) { - cmd[0] = USIM_CLA; - cmd[3] = 0x04; - get_resp[0] = USIM_CLA; - } - - wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id); - if (aid) { - wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID", - aid, aidlen); - if (5 + aidlen > sizeof(cmd)) - return -1; - cmd[2] = 0x04; /* Select by AID */ - cmd[4] = aidlen; /* len */ - os_memcpy(cmd + 5, aid, aidlen); - cmdlen = 5 + aidlen; - } else { - cmd[5] = file_id >> 8; - cmd[6] = file_id & 0xff; - cmdlen = 7; - } - len = sizeof(resp); - ret = scard_transmit(scard, cmd, cmdlen, resp, &len); - if (ret != SCARD_S_SUCCESS) { - wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed " - "(err=0x%lx)", ret); - return -1; - } - - if (len != 2) { - wpa_printf(MSG_WARNING, "SCARD: unexpected resp len " - "%d (expected 2)", (int) len); - return -1; - } - - if (resp[0] == 0x98 && resp[1] == 0x04) { - /* Security status not satisfied (PIN_WLAN) */ - wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied " - "(PIN_WLAN)"); - return -1; - } - - if (resp[0] == 0x6e) { - wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported"); - return -1; - } - - if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) { - wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x " - "(expected 0x61, 0x6c, or 0x9f)", resp[0]); - return -1; - } - /* Normal ending of command; resp[1] bytes available */ - get_resp[4] = resp[1]; - wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)", - resp[1]); - - rlen = *buf_len; - ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen); - if (ret == SCARD_S_SUCCESS) { - *buf_len = resp[1] < rlen ? resp[1] : rlen; - return 0; - } - - wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret); - return -1; -} - - -static int scard_select_file(struct scard_data *scard, unsigned short file_id, - unsigned char *buf, size_t *buf_len) -{ - return _scard_select_file(scard, file_id, buf, buf_len, - scard->sim_type, NULL, 0); -} - - -static int scard_get_record_len(struct scard_data *scard, unsigned char recnum, - unsigned char mode) -{ - unsigned char buf[255]; - unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; - size_t blen; - long ret; - - if (scard->sim_type == SCARD_USIM) - cmd[0] = USIM_CLA; - cmd[2] = recnum; - cmd[3] = mode; - cmd[4] = sizeof(buf); - - blen = sizeof(buf); - ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); - if (ret != SCARD_S_SUCCESS) { - wpa_printf(MSG_DEBUG, "SCARD: failed to determine file " - "length for record %d", recnum); - return -1; - } - - wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response", - buf, blen); - - if (blen < 2 || (buf[0] != 0x6c && buf[0] != 0x67)) { - wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file " - "length determination"); - return -1; - } - - return buf[1]; -} - - -static int scard_read_record(struct scard_data *scard, - unsigned char *data, size_t len, - unsigned char recnum, unsigned char mode) -{ - unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; - size_t blen = len + 3; - unsigned char *buf; - long ret; - - if (scard->sim_type == SCARD_USIM) - cmd[0] = USIM_CLA; - cmd[2] = recnum; - cmd[3] = mode; - cmd[4] = len; - - buf = os_malloc(blen); - if (buf == NULL) - return -1; - - ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); - if (ret != SCARD_S_SUCCESS) { - os_free(buf); - return -2; - } - if (blen != len + 2) { - wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " - "length %ld (expected %ld)", - (long) blen, (long) len + 2); - os_free(buf); - return -3; - } - - if (buf[len] != 0x90 || buf[len + 1] != 0x00) { - wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " - "status %02x %02x (expected 90 00)", - buf[len], buf[len + 1]); - os_free(buf); - return -4; - } - - os_memcpy(data, buf, len); - os_free(buf); - - return 0; -} - - -static int scard_read_file(struct scard_data *scard, - unsigned char *data, size_t len) -{ - unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ }; - size_t blen = len + 3; - unsigned char *buf; - long ret; - - cmd[4] = len; - - buf = os_malloc(blen); - if (buf == NULL) - return -1; - - if (scard->sim_type == SCARD_USIM) - cmd[0] = USIM_CLA; - ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); - if (ret != SCARD_S_SUCCESS) { - os_free(buf); - return -2; - } - if (blen != len + 2) { - wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " - "length %ld (expected %ld)", - (long) blen, (long) len + 2); - os_free(buf); - return -3; - } - - if (buf[len] != 0x90 || buf[len + 1] != 0x00) { - wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " - "status %02x %02x (expected 90 00)", - buf[len], buf[len + 1]); - os_free(buf); - return -4; - } - - os_memcpy(data, buf, len); - os_free(buf); - - return 0; -} - - -static int scard_verify_pin(struct scard_data *scard, const char *pin) -{ - long ret; - unsigned char resp[3]; - unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 }; - size_t len; - - wpa_printf(MSG_DEBUG, "SCARD: verifying PIN"); - - if (pin == NULL || os_strlen(pin) > 8) - return -1; - - if (scard->sim_type == SCARD_USIM) - cmd[0] = USIM_CLA; - os_memcpy(cmd + 5, pin, os_strlen(pin)); - os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin)); - - len = sizeof(resp); - ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); - if (ret != SCARD_S_SUCCESS) - return -2; - - if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) { - wpa_printf(MSG_WARNING, "SCARD: PIN verification failed"); - return -1; - } - - wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully"); - return 0; -} - - -int scard_get_pin_retry_counter(struct scard_data *scard) -{ - long ret; - unsigned char resp[3]; - unsigned char cmd[5] = { SIM_CMD_VERIFY_CHV1 }; - size_t len; - u16 val; - - wpa_printf(MSG_DEBUG, "SCARD: fetching PIN retry counter"); - - if (scard->sim_type == SCARD_USIM) - cmd[0] = USIM_CLA; - cmd[4] = 0; /* Empty data */ - - len = sizeof(resp); - ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); - if (ret != SCARD_S_SUCCESS) - return -2; - - if (len != 2) { - wpa_printf(MSG_WARNING, "SCARD: failed to fetch PIN retry " - "counter"); - return -1; - } - - val = WPA_GET_BE16(resp); - if (val == 0x63c0 || val == 0x6983) { - wpa_printf(MSG_DEBUG, "SCARD: PIN has been blocked"); - return 0; - } - - if (val >= 0x63c0 && val <= 0x63cf) - return val & 0x000f; - - wpa_printf(MSG_DEBUG, "SCARD: Unexpected PIN retry counter response " - "value 0x%x", val); - return 0; -} - - -/** - * scard_get_imsi - Read IMSI from SIM/USIM card - * @scard: Pointer to private data from scard_init() - * @imsi: Buffer for IMSI - * @len: Length of imsi buffer; set to IMSI length on success - * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file - * selection returns invalid result code, -3 if parsing FSP template file fails - * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set - * to needed length), -5 if reading IMSI file fails. - * - * This function can be used to read IMSI from the SIM/USIM card. If the IMSI - * file is PIN protected, scard_set_pin() must have been used to set the - * correct PIN code before calling scard_get_imsi(). - */ -int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len) -{ - unsigned char buf[100]; - size_t blen, imsilen, i; - char *pos; - - wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI"); - blen = sizeof(buf); - if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen)) - return -1; - if (blen < 4) { - wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI " - "header (len=%ld)", (long) blen); - return -2; - } - - if (scard->sim_type == SCARD_GSM_SIM) { - blen = (buf[2] << 8) | buf[3]; - } else { - int file_size; - if (scard_parse_fsp_templ(buf, blen, NULL, &file_size)) - return -3; - blen = file_size; - } - if (blen < 2 || blen > sizeof(buf)) { - wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%ld", - (long) blen); - return -3; - } - - imsilen = (blen - 2) * 2 + 1; - wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%ld imsilen=%ld", - (long) blen, (long) imsilen); - if (blen < 2 || imsilen > *len) { - *len = imsilen; - return -4; - } - - if (scard_read_file(scard, buf, blen)) - return -5; - - pos = imsi; - *pos++ = '0' + (buf[1] >> 4 & 0x0f); - for (i = 2; i < blen; i++) { - unsigned char digit; - - digit = buf[i] & 0x0f; - if (digit < 10) - *pos++ = '0' + digit; - else - imsilen--; - - digit = buf[i] >> 4 & 0x0f; - if (digit < 10) - *pos++ = '0' + digit; - else - imsilen--; - } - *len = imsilen; - - return 0; -} - - -/** - * scard_get_mnc_len - Read length of MNC in the IMSI from SIM/USIM card - * @scard: Pointer to private data from scard_init() - * Returns: length (>0) on success, -1 if administrative data file cannot be - * selected, -2 if administrative data file selection returns invalid result - * code, -3 if parsing FSP template file fails (USIM only), -4 if length of - * the file is unexpected, -5 if reading file fails, -6 if MNC length is not - * in range (i.e. 2 or 3), -7 if MNC length is not available. - * - */ -int scard_get_mnc_len(struct scard_data *scard) -{ - unsigned char buf[100]; - size_t blen; - int file_size; - - wpa_printf(MSG_DEBUG, "SCARD: reading MNC len from (GSM) EF-AD"); - blen = sizeof(buf); - if (scard_select_file(scard, SCARD_FILE_GSM_EF_AD, buf, &blen)) - return -1; - if (blen < 4) { - wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-AD " - "header (len=%ld)", (long) blen); - return -2; - } - - if (scard->sim_type == SCARD_GSM_SIM) { - file_size = (buf[2] << 8) | buf[3]; - } else { - if (scard_parse_fsp_templ(buf, blen, NULL, &file_size)) - return -3; - } - if (file_size == 3) { - wpa_printf(MSG_DEBUG, "SCARD: MNC length not available"); - return -7; - } - if (file_size < 4 || file_size > (int) sizeof(buf)) { - wpa_printf(MSG_DEBUG, "SCARD: invalid file length=%ld", - (long) file_size); - return -4; - } - - if (scard_read_file(scard, buf, file_size)) - return -5; - buf[3] = buf[3] & 0x0f; /* upper nibble reserved for future use */ - if (buf[3] < 2 || buf[3] > 3) { - wpa_printf(MSG_DEBUG, "SCARD: invalid MNC length=%ld", - (long) buf[3]); - return -6; - } - wpa_printf(MSG_DEBUG, "SCARD: MNC length=%ld", (long) buf[3]); - return buf[3]; -} - - -/** - * scard_gsm_auth - Run GSM authentication command on SIM card - * @scard: Pointer to private data from scard_init() - * @_rand: 16-byte RAND value from HLR/AuC - * @sres: 4-byte buffer for SRES - * @kc: 8-byte buffer for Kc - * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized, - * -2 if authentication command execution fails, -3 if unknown response code - * for authentication command is received, -4 if reading of response fails, - * -5 if if response data is of unexpected length - * - * This function performs GSM authentication using SIM/USIM card and the - * provided RAND value from HLR/AuC. If authentication command can be completed - * successfully, SRES and Kc values will be written into sres and kc buffers. - */ -int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand, - unsigned char *sres, unsigned char *kc) -{ - unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG }; - int cmdlen; - unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE }; - unsigned char resp[3], buf[12 + 3 + 2]; - size_t len; - long ret; - - if (scard == NULL) - return -1; - - wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16); - if (scard->sim_type == SCARD_GSM_SIM) { - cmdlen = 5 + 16; - os_memcpy(cmd + 5, _rand, 16); - } else { - cmdlen = 5 + 1 + 16; - cmd[0] = USIM_CLA; - cmd[3] = 0x80; - cmd[4] = 17; - cmd[5] = 16; - os_memcpy(cmd + 6, _rand, 16); - } - len = sizeof(resp); - ret = scard_transmit(scard, cmd, cmdlen, resp, &len); - if (ret != SCARD_S_SUCCESS) - return -2; - - if ((scard->sim_type == SCARD_GSM_SIM && - (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) || - (scard->sim_type == SCARD_USIM && - (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) { - wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM " - "auth request (len=%ld resp=%02x %02x)", - (long) len, resp[0], resp[1]); - return -3; - } - get_resp[4] = resp[1]; - - len = sizeof(buf); - ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len); - if (ret != SCARD_S_SUCCESS) - return -4; - - if (scard->sim_type == SCARD_GSM_SIM) { - if (len != 4 + 8 + 2) { - wpa_printf(MSG_WARNING, "SCARD: unexpected data " - "length for GSM auth (len=%ld, expected 14)", - (long) len); - return -5; - } - os_memcpy(sres, buf, 4); - os_memcpy(kc, buf + 4, 8); - } else { - if (len != 1 + 4 + 1 + 8 + 2) { - wpa_printf(MSG_WARNING, "SCARD: unexpected data " - "length for USIM auth (len=%ld, " - "expected 16)", (long) len); - return -5; - } - if (buf[0] != 4 || buf[5] != 8) { - wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc " - "length (%d %d, expected 4 8)", - buf[0], buf[5]); - } - os_memcpy(sres, buf + 1, 4); - os_memcpy(kc, buf + 6, 8); - } - - wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4); - wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8); - - return 0; -} - - -/** - * scard_umts_auth - Run UMTS authentication command on USIM card - * @scard: Pointer to private data from scard_init() - * @_rand: 16-byte RAND value from HLR/AuC - * @autn: 16-byte AUTN value from HLR/AuC - * @res: 16-byte buffer for RES - * @res_len: Variable that will be set to RES length - * @ik: 16-byte buffer for IK - * @ck: 16-byte buffer for CK - * @auts: 14-byte buffer for AUTS - * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization - * failure - * - * This function performs AKA authentication using USIM card and the provided - * RAND and AUTN values from HLR/AuC. If authentication command can be - * completed successfully, RES, IK, and CK values will be written into provided - * buffers and res_len is set to length of received RES value. If USIM reports - * synchronization failure, the received AUTS value will be written into auts - * buffer. In this case, RES, IK, and CK are not valid. - */ -int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, - const unsigned char *autn, - unsigned char *res, size_t *res_len, - unsigned char *ik, unsigned char *ck, unsigned char *auts) -{ - unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] = - { USIM_CMD_RUN_UMTS_ALG }; - unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE }; - unsigned char resp[3], buf[64], *pos, *end; - size_t len; - long ret; - - if (scard == NULL) - return -1; - - if (scard->sim_type == SCARD_GSM_SIM) { - wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS " - "auth"); - return -1; - } - - wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN); - wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN); - cmd[5] = AKA_RAND_LEN; - os_memcpy(cmd + 6, _rand, AKA_RAND_LEN); - cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN; - os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN); - - len = sizeof(resp); - ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); - if (ret != SCARD_S_SUCCESS) - return -1; - - if (len <= sizeof(resp)) - wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len); - - if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) { - wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - " - "MAC != XMAC"); - return -1; - } else if (len != 2 || resp[0] != 0x61) { - wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS " - "auth request (len=%ld resp=%02x %02x)", - (long) len, resp[0], resp[1]); - return -1; - } - get_resp[4] = resp[1]; - - len = sizeof(buf); - ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len); - if (ret != SCARD_S_SUCCESS || len > sizeof(buf)) - return -1; - - wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len); - if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc && - buf[1] == AKA_AUTS_LEN) { - wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure"); - os_memcpy(auts, buf + 2, AKA_AUTS_LEN); - wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN); - return -2; - } else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) { - pos = buf + 1; - end = buf + len; - - /* RES */ - if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) { - wpa_printf(MSG_DEBUG, "SCARD: Invalid RES"); - return -1; - } - *res_len = *pos++; - os_memcpy(res, pos, *res_len); - pos += *res_len; - wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len); - - /* CK */ - if (pos[0] != CK_LEN || pos + CK_LEN > end) { - wpa_printf(MSG_DEBUG, "SCARD: Invalid CK"); - return -1; - } - pos++; - os_memcpy(ck, pos, CK_LEN); - pos += CK_LEN; - wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN); - - /* IK */ - if (pos[0] != IK_LEN || pos + IK_LEN > end) { - wpa_printf(MSG_DEBUG, "SCARD: Invalid IK"); - return -1; - } - pos++; - os_memcpy(ik, pos, IK_LEN); - pos += IK_LEN; - wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN); - - return 0; - } - - wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response"); - return -1; -} - - -int scard_supports_umts(struct scard_data *scard) -{ - return scard->sim_type == SCARD_USIM; -} diff --git a/contrib/hostapd/src/utils/pcsc_funcs.h b/contrib/hostapd/src/utils/pcsc_funcs.h deleted file mode 100644 index eacd2a2d70..0000000000 --- a/contrib/hostapd/src/utils/pcsc_funcs.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM - * Copyright (c) 2004-2006, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef PCSC_FUNCS_H -#define PCSC_FUNCS_H - -#ifdef PCSC_FUNCS -struct scard_data * scard_init(const char *reader); -void scard_deinit(struct scard_data *scard); - -int scard_set_pin(struct scard_data *scard, const char *pin); -int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len); -int scard_get_mnc_len(struct scard_data *scard); -int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand, - unsigned char *sres, unsigned char *kc); -int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, - const unsigned char *autn, - unsigned char *res, size_t *res_len, - unsigned char *ik, unsigned char *ck, unsigned char *auts); -int scard_get_pin_retry_counter(struct scard_data *scard); -int scard_supports_umts(struct scard_data *scard); - -#else /* PCSC_FUNCS */ - -#define scard_init(r) NULL -#define scard_deinit(s) do { } while (0) -#define scard_set_pin(s, p) -1 -#define scard_get_imsi(s, i, l) -1 -#define scard_get_mnc_len(s) -1 -#define scard_gsm_auth(s, r, s2, k) -1 -#define scard_umts_auth(s, r, a, r2, rl, i, c, a2) -1 -#define scard_get_pin_retry_counter(s) -1 -#define scard_supports_umts(s) 0 - -#endif /* PCSC_FUNCS */ - -#endif /* PCSC_FUNCS_H */ diff --git a/contrib/hostapd/src/utils/radiotap.c b/contrib/hostapd/src/utils/radiotap.c deleted file mode 100644 index 804473fa4b..0000000000 --- a/contrib/hostapd/src/utils/radiotap.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Radiotap parser - * - * Copyright 2007 Andy Green - * - * 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. - * - * - * Modified for userspace by Johannes Berg - * I only modified some things on top to ease syncing should bugs be found. - */ - -#include "includes.h" - -#include "common.h" -#include "radiotap_iter.h" - -#define le16_to_cpu le_to_host16 -#define le32_to_cpu le_to_host32 -#define __le32 uint32_t -#define ulong unsigned long -#define unlikely(cond) (cond) -#define get_unaligned(p) \ -({ \ - struct packed_dummy_struct { \ - typeof(*(p)) __val; \ - } __attribute__((packed)) *__ptr = (void *) (p); \ - \ - __ptr->__val; \ -}) - -/* function prototypes and related defs are in radiotap_iter.h */ - -/** - * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization - * @iterator: radiotap_iterator to initialize - * @radiotap_header: radiotap header to parse - * @max_length: total length we can parse into (eg, whole packet length) - * - * Returns: 0 or a negative error code if there is a problem. - * - * This function initializes an opaque iterator struct which can then - * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap - * argument which is present in the header. It knows about extended - * present headers and handles them. - * - * How to use: - * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator - * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) - * checking for a good 0 return code. Then loop calling - * __ieee80211_radiotap_iterator_next()... it returns either 0, - * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. - * The iterator's @this_arg member points to the start of the argument - * associated with the current argument index that is present, which can be - * found in the iterator's @this_arg_index member. This arg index corresponds - * to the IEEE80211_RADIOTAP_... defines. - * - * Radiotap header length: - * You can find the CPU-endian total radiotap header length in - * iterator->max_length after executing ieee80211_radiotap_iterator_init() - * successfully. - * - * Alignment Gotcha: - * You must take care when dereferencing iterator.this_arg - * for multibyte types... the pointer is not aligned. Use - * get_unaligned((type *)iterator.this_arg) to dereference - * iterator.this_arg for type "type" safely on all arches. - * - * Example code: - * See Documentation/networking/radiotap-headers.txt - */ - -int ieee80211_radiotap_iterator_init( - struct ieee80211_radiotap_iterator *iterator, - struct ieee80211_radiotap_header *radiotap_header, - int max_length) -{ - /* Linux only supports version 0 radiotap format */ - if (radiotap_header->it_version) - return -EINVAL; - - /* sanity check for allowed length and radiotap length field */ - if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len))) - return -EINVAL; - - iterator->rtheader = radiotap_header; - iterator->max_length = le16_to_cpu(get_unaligned( - &radiotap_header->it_len)); - iterator->arg_index = 0; - iterator->bitmap_shifter = le32_to_cpu(get_unaligned( - &radiotap_header->it_present)); - iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); - iterator->this_arg = NULL; - - /* find payload start allowing for extended bitmap(s) */ - - if (unlikely(iterator->bitmap_shifter & (1<arg)) & - (1<arg += sizeof(u32); - - /* - * check for insanity where the present bitmaps - * keep claiming to extend up to or even beyond the - * stated radiotap header length - */ - - if (((ulong)iterator->arg - (ulong)iterator->rtheader) - > (ulong)iterator->max_length) - return -EINVAL; - } - - iterator->arg += sizeof(u32); - - /* - * no need to check again for blowing past stated radiotap - * header length, because ieee80211_radiotap_iterator_next - * checks it before it is dereferenced - */ - } - - /* we are all initialized happily */ - - return 0; -} - - -/** - * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg - * @iterator: radiotap_iterator to move to next arg (if any) - * - * Returns: 0 if there is an argument to handle, - * -ENOENT if there are no more args or -EINVAL - * if there is something else wrong. - * - * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) - * in @this_arg_index and sets @this_arg to point to the - * payload for the field. It takes care of alignment handling and extended - * present fields. @this_arg can be changed by the caller (eg, - * incremented to move inside a compound argument like - * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in - * little-endian format whatever the endianess of your CPU. - * - * Alignment Gotcha: - * You must take care when dereferencing iterator.this_arg - * for multibyte types... the pointer is not aligned. Use - * get_unaligned((type *)iterator.this_arg) to dereference - * iterator.this_arg for type "type" safely on all arches. - */ - -int ieee80211_radiotap_iterator_next( - struct ieee80211_radiotap_iterator *iterator) -{ - - /* - * small length lookup table for all radiotap types we heard of - * starting from b0 in the bitmap, so we can walk the payload - * area of the radiotap header - * - * There is a requirement to pad args, so that args - * of a given length must begin at a boundary of that length - * -- but note that compound args are allowed (eg, 2 x u16 - * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not - * a reliable indicator of alignment requirement. - * - * upper nybble: content alignment for arg - * lower nybble: content length for arg - */ - - static const u8 rt_sizes[] = { - [IEEE80211_RADIOTAP_TSFT] = 0x88, - [IEEE80211_RADIOTAP_FLAGS] = 0x11, - [IEEE80211_RADIOTAP_RATE] = 0x11, - [IEEE80211_RADIOTAP_CHANNEL] = 0x24, - [IEEE80211_RADIOTAP_FHSS] = 0x22, - [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, - [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, - [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, - [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, - [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, - [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, - [IEEE80211_RADIOTAP_ANTENNA] = 0x11, - [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, - [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, - [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, - [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, - [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, - [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11, - /* - * add more here as they are defined in - * include/net/ieee80211_radiotap.h - */ - }; - - /* - * for every radiotap entry we can at - * least skip (by knowing the length)... - */ - - while (iterator->arg_index < (int) sizeof(rt_sizes)) { - int hit = 0; - int pad; - - if (!(iterator->bitmap_shifter & 1)) - goto next_entry; /* arg not present */ - - /* - * arg is present, account for alignment padding - * 8-bit args can be at any alignment - * 16-bit args must start on 16-bit boundary - * 32-bit args must start on 32-bit boundary - * 64-bit args must start on 64-bit boundary - * - * note that total arg size can differ from alignment of - * elements inside arg, so we use upper nybble of length - * table to base alignment on - * - * also note: these alignments are ** relative to the - * start of the radiotap header **. There is no guarantee - * that the radiotap header itself is aligned on any - * kind of boundary. - * - * the above is why get_unaligned() is used to dereference - * multibyte elements from the radiotap area - */ - - pad = (((ulong)iterator->arg) - - ((ulong)iterator->rtheader)) & - ((rt_sizes[iterator->arg_index] >> 4) - 1); - - if (pad) - iterator->arg += - (rt_sizes[iterator->arg_index] >> 4) - pad; - - /* - * this is what we will return to user, but we need to - * move on first so next call has something fresh to test - */ - iterator->this_arg_index = iterator->arg_index; - iterator->this_arg = iterator->arg; - hit = 1; - - /* internally move on the size of this arg */ - iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; - - /* - * check for insanity where we are given a bitmap that - * claims to have more arg content than the length of the - * radiotap section. We will normally end up equalling this - * max_length on the last arg, never exceeding it. - */ - - if (((ulong)iterator->arg - (ulong)iterator->rtheader) > - (ulong) iterator->max_length) - return -EINVAL; - - next_entry: - iterator->arg_index++; - if (unlikely((iterator->arg_index & 31) == 0)) { - /* completed current u32 bitmap */ - if (iterator->bitmap_shifter & 1) { - /* b31 was set, there is more */ - /* move to next u32 bitmap */ - iterator->bitmap_shifter = le32_to_cpu( - get_unaligned(iterator->next_bitmap)); - iterator->next_bitmap++; - } else - /* no more bitmaps: end */ - iterator->arg_index = sizeof(rt_sizes); - } else /* just try the next bit */ - iterator->bitmap_shifter >>= 1; - - /* if we found a valid arg earlier, return it now */ - if (hit) - return 0; - } - - /* we don't know how to handle any more args, we're done */ - return -ENOENT; -} diff --git a/contrib/hostapd/src/utils/radiotap.h b/contrib/hostapd/src/utils/radiotap.h deleted file mode 100644 index 137288f9a1..0000000000 --- a/contrib/hostapd/src/utils/radiotap.h +++ /dev/null @@ -1,243 +0,0 @@ -/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ -/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */ - -/*- - * Copyright (c) 2003, 2004 David Young. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of David Young may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID - * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -/* - * Modifications to fit into the linux IEEE 802.11 stack, - * Mike Kershaw (dragorn@kismetwireless.net) - */ - -#ifndef IEEE80211RADIOTAP_H -#define IEEE80211RADIOTAP_H - -#include - -/* Base version of the radiotap packet header data */ -#define PKTHDR_RADIOTAP_VERSION 0 - -/* A generic radio capture format is desirable. There is one for - * Linux, but it is neither rigidly defined (there were not even - * units given for some fields) nor easily extensible. - * - * I suggest the following extensible radio capture format. It is - * based on a bitmap indicating which fields are present. - * - * I am trying to describe precisely what the application programmer - * should expect in the following, and for that reason I tell the - * units and origin of each measurement (where it applies), or else I - * use sufficiently weaselly language ("is a monotonically nondecreasing - * function of...") that I cannot set false expectations for lawyerly - * readers. - */ - -/* The radio capture header precedes the 802.11 header. - * All data in the header is little endian on all platforms. - */ -struct ieee80211_radiotap_header { - uint8_t it_version; /* Version 0. Only increases - * for drastic changes, - * introduction of compatible - * new fields does not count. - */ - uint8_t it_pad; - uint16_t it_len; /* length of the whole - * header in bytes, including - * it_version, it_pad, - * it_len, and data fields. - */ - uint32_t it_present; /* A bitmap telling which - * fields are present. Set bit 31 - * (0x80000000) to extend the - * bitmap by another 32 bits. - * Additional extensions are made - * by setting bit 31. - */ -}; - -/* Name Data type Units - * ---- --------- ----- - * - * IEEE80211_RADIOTAP_TSFT __le64 microseconds - * - * Value in microseconds of the MAC's 64-bit 802.11 Time - * Synchronization Function timer when the first bit of the - * MPDU arrived at the MAC. For received frames, only. - * - * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap - * - * Tx/Rx frequency in MHz, followed by flags (see below). - * - * IEEE80211_RADIOTAP_FHSS uint16_t see below - * - * For frequency-hopping radios, the hop set (first byte) - * and pattern (second byte). - * - * IEEE80211_RADIOTAP_RATE u8 500kb/s - * - * Tx/Rx data rate - * - * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from - * one milliwatt (dBm) - * - * RF signal power at the antenna, decibel difference from - * one milliwatt. - * - * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from - * one milliwatt (dBm) - * - * RF noise power at the antenna, decibel difference from one - * milliwatt. - * - * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) - * - * RF signal power at the antenna, decibel difference from an - * arbitrary, fixed reference. - * - * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) - * - * RF noise power at the antenna, decibel difference from an - * arbitrary, fixed reference point. - * - * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless - * - * Quality of Barker code lock. Unitless. Monotonically - * nondecreasing with "better" lock strength. Called "Signal - * Quality" in datasheets. (Is there a standard way to measure - * this?) - * - * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless - * - * Transmit power expressed as unitless distance from max - * power set at factory calibration. 0 is max power. - * Monotonically nondecreasing with lower power levels. - * - * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB) - * - * Transmit power expressed as decibel distance from max power - * set at factory calibration. 0 is max power. Monotonically - * nondecreasing with lower power levels. - * - * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from - * one milliwatt (dBm) - * - * Transmit power expressed as dBm (decibels from a 1 milliwatt - * reference). This is the absolute power level measured at - * the antenna port. - * - * IEEE80211_RADIOTAP_FLAGS u8 bitmap - * - * Properties of transmitted and received frames. See flags - * defined below. - * - * IEEE80211_RADIOTAP_ANTENNA u8 antenna index - * - * Unitless indication of the Rx/Tx antenna for this packet. - * The first antenna is antenna 0. - * - * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap - * - * Properties of received frames. See flags defined below. - * - * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap - * - * Properties of transmitted frames. See flags defined below. - * - * IEEE80211_RADIOTAP_RTS_RETRIES u8 data - * - * Number of rts retries a transmitted frame used. - * - * IEEE80211_RADIOTAP_DATA_RETRIES u8 data - * - * Number of unicast retries a transmitted frame used. - * - */ -enum ieee80211_radiotap_type { - IEEE80211_RADIOTAP_TSFT = 0, - IEEE80211_RADIOTAP_FLAGS = 1, - IEEE80211_RADIOTAP_RATE = 2, - IEEE80211_RADIOTAP_CHANNEL = 3, - IEEE80211_RADIOTAP_FHSS = 4, - IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, - IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, - IEEE80211_RADIOTAP_LOCK_QUALITY = 7, - IEEE80211_RADIOTAP_TX_ATTENUATION = 8, - IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, - IEEE80211_RADIOTAP_DBM_TX_POWER = 10, - IEEE80211_RADIOTAP_ANTENNA = 11, - IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, - IEEE80211_RADIOTAP_DB_ANTNOISE = 13, - IEEE80211_RADIOTAP_RX_FLAGS = 14, - IEEE80211_RADIOTAP_TX_FLAGS = 15, - IEEE80211_RADIOTAP_RTS_RETRIES = 16, - IEEE80211_RADIOTAP_DATA_RETRIES = 17, - IEEE80211_RADIOTAP_EXT = 31 -}; - -/* Channel flags. */ -#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ -#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ -#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ -#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ -#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ -#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ -#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ -#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ - -/* For IEEE80211_RADIOTAP_FLAGS */ -#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received - * during CFP - */ -#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received - * with short - * preamble - */ -#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received - * with WEP encryption - */ -#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received - * with fragmentation - */ -#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ -#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between - * 802.11 header and payload - * (to 32-bit boundary) - */ -/* For IEEE80211_RADIOTAP_RX_FLAGS */ -#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ - -/* For IEEE80211_RADIOTAP_TX_FLAGS */ -#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive - * 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/contrib/hostapd/src/utils/radiotap_iter.h b/contrib/hostapd/src/utils/radiotap_iter.h deleted file mode 100644 index 2e0e87296e..0000000000 --- a/contrib/hostapd/src/utils/radiotap_iter.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Radiotap parser - * - * Copyright 2007 Andy Green - * - * 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 __RADIOTAP_ITER_H -#define __RADIOTAP_ITER_H - -#include "radiotap.h" - -/* Radiotap header iteration - * implemented in radiotap.c - */ -/** - * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args - * @rtheader: pointer to the radiotap header we are walking through - * @max_length: length of radiotap header in cpu byte ordering - * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg - * @this_arg: pointer to current radiotap arg - * @arg_index: internal next argument index - * @arg: internal next argument pointer - * @next_bitmap: internal pointer to next present u32 - * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present - */ - -struct ieee80211_radiotap_iterator { - struct ieee80211_radiotap_header *rtheader; - int max_length; - int this_arg_index; - unsigned char *this_arg; - - int arg_index; - unsigned char *arg; - uint32_t *next_bitmap; - uint32_t bitmap_shifter; -}; - -extern int ieee80211_radiotap_iterator_init( - struct ieee80211_radiotap_iterator *iterator, - struct ieee80211_radiotap_header *radiotap_header, - int max_length); - -extern int ieee80211_radiotap_iterator_next( - struct ieee80211_radiotap_iterator *iterator); - -#endif /* __RADIOTAP_ITER_H */ diff --git a/contrib/hostapd/src/utils/state_machine.h b/contrib/hostapd/src/utils/state_machine.h deleted file mode 100644 index a514315784..0000000000 --- a/contrib/hostapd/src/utils/state_machine.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * wpa_supplicant/hostapd - State machine definitions - * Copyright (c) 2002-2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * This file includes a set of pre-processor macros that can be used to - * implement a state machine. In addition to including this header file, each - * file implementing a state machine must define STATE_MACHINE_DATA to be the - * data structure including state variables (enum machine_state, - * Boolean changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used - * as a prefix for all debug messages. If SM_ENTRY_MA macro is used to define - * a group of state machines with shared data structure, STATE_MACHINE_ADDR - * needs to be defined to point to the MAC address used in debug output. - * SM_ENTRY_M macro can be used to define similar group of state machines - * without this additional debug info. - */ - -#ifndef STATE_MACHINE_H -#define STATE_MACHINE_H - -/** - * SM_STATE - Declaration of a state machine function - * @machine: State machine name - * @state: State machine state - * - * This macro is used to declare a state machine function. It is used in place - * of a C function definition to declare functions to be run when the state is - * entered by calling SM_ENTER or SM_ENTER_GLOBAL. - */ -#define SM_STATE(machine, state) \ -static void sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \ - int global) - -/** - * SM_ENTRY - State machine function entry point - * @machine: State machine name - * @state: State machine state - * - * This macro is used inside each state machine function declared with - * SM_STATE. SM_ENTRY should be in the beginning of the function body, but - * after declaration of possible local variables. This macro prints debug - * information about state transition and update the state machine state. - */ -#define SM_ENTRY(machine, state) \ -if (!global || sm->machine ## _state != machine ## _ ## state) { \ - sm->changed = TRUE; \ - wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \ - " entering state " #state); \ -} \ -sm->machine ## _state = machine ## _ ## state; - -/** - * SM_ENTRY_M - State machine function entry point for state machine group - * @machine: State machine name - * @_state: State machine state - * @data: State variable prefix (full variable: prefix_state) - * - * This macro is like SM_ENTRY, but for state machine groups that use a shared - * data structure for more than one state machine. Both machine and prefix - * parameters are set to "sub-state machine" name. prefix is used to allow more - * than one state variable to be stored in the same data structure. - */ -#define SM_ENTRY_M(machine, _state, data) \ -if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \ - sm->changed = TRUE; \ - wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " \ - #machine " entering state " #_state); \ -} \ -sm->data ## _ ## state = machine ## _ ## _state; - -/** - * SM_ENTRY_MA - State machine function entry point for state machine group - * @machine: State machine name - * @_state: State machine state - * @data: State variable prefix (full variable: prefix_state) - * - * This macro is like SM_ENTRY_M, but a MAC address is included in debug - * output. STATE_MACHINE_ADDR has to be defined to point to the MAC address to - * be included in debug. - */ -#define SM_ENTRY_MA(machine, _state, data) \ -if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \ - sm->changed = TRUE; \ - wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " MACSTR " " \ - #machine " entering state " #_state, \ - MAC2STR(STATE_MACHINE_ADDR)); \ -} \ -sm->data ## _ ## state = machine ## _ ## _state; - -/** - * SM_ENTER - Enter a new state machine state - * @machine: State machine name - * @state: State machine state - * - * This macro expands to a function call to a state machine function defined - * with SM_STATE macro. SM_ENTER is used in a state machine step function to - * move the state machine to a new state. - */ -#define SM_ENTER(machine, state) \ -sm_ ## machine ## _ ## state ## _Enter(sm, 0) - -/** - * SM_ENTER_GLOBAL - Enter a new state machine state based on global rule - * @machine: State machine name - * @state: State machine state - * - * This macro is like SM_ENTER, but this is used when entering a new state - * based on a global (not specific to any particular state) rule. A separate - * macro is used to avoid unwanted debug message floods when the same global - * rule is forcing a state machine to remain in on state. - */ -#define SM_ENTER_GLOBAL(machine, state) \ -sm_ ## machine ## _ ## state ## _Enter(sm, 1) - -/** - * SM_STEP - Declaration of a state machine step function - * @machine: State machine name - * - * This macro is used to declare a state machine step function. It is used in - * place of a C function definition to declare a function that is used to move - * state machine to a new state based on state variables. This function uses - * SM_ENTER and SM_ENTER_GLOBAL macros to enter new state. - */ -#define SM_STEP(machine) \ -static void sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm) - -/** - * SM_STEP_RUN - Call the state machine step function - * @machine: State machine name - * - * This macro expands to a function call to a state machine step function - * defined with SM_STEP macro. - */ -#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm) - -#endif /* STATE_MACHINE_H */ diff --git a/contrib/hostapd/src/utils/trace.c b/contrib/hostapd/src/utils/trace.c deleted file mode 100644 index 6795d417d5..0000000000 --- a/contrib/hostapd/src/utils/trace.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Backtrace debugging - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "trace.h" - -#ifdef WPA_TRACE - -static struct dl_list active_references = -{ &active_references, &active_references }; - -#ifdef WPA_TRACE_BFD -#include -#ifdef __linux__ -#include -#else /* __linux__ */ -#include -#endif /* __linux__ */ - -static char *prg_fname = NULL; -static bfd *cached_abfd = NULL; -static asymbol **syms = NULL; - -static void get_prg_fname(void) -{ - char exe[50], fname[512]; - int len; - os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid()); - len = readlink(exe, fname, sizeof(fname) - 1); - if (len < 0 || len >= (int) sizeof(fname)) { - perror("readlink"); - return; - } - fname[len] = '\0'; - prg_fname = strdup(fname); -} - - -static bfd * open_bfd(const char *fname) -{ - bfd *abfd; - char **matching; - - abfd = bfd_openr(prg_fname, NULL); - if (abfd == NULL) { - wpa_printf(MSG_INFO, "bfd_openr failed"); - return NULL; - } - - if (bfd_check_format(abfd, bfd_archive)) { - wpa_printf(MSG_INFO, "bfd_check_format failed"); - bfd_close(abfd); - return NULL; - } - - if (!bfd_check_format_matches(abfd, bfd_object, &matching)) { - wpa_printf(MSG_INFO, "bfd_check_format_matches failed"); - free(matching); - bfd_close(abfd); - return NULL; - } - - return abfd; -} - - -static void read_syms(bfd *abfd) -{ - long storage, symcount; - bfd_boolean dynamic = FALSE; - - if (syms) - return; - - if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) { - wpa_printf(MSG_INFO, "No symbols"); - return; - } - - storage = bfd_get_symtab_upper_bound(abfd); - if (storage == 0) { - storage = bfd_get_dynamic_symtab_upper_bound(abfd); - dynamic = TRUE; - } - if (storage < 0) { - wpa_printf(MSG_INFO, "Unknown symtab upper bound"); - return; - } - - syms = malloc(storage); - if (syms == NULL) { - wpa_printf(MSG_INFO, "Failed to allocate memory for symtab " - "(%ld bytes)", storage); - return; - } - if (dynamic) - symcount = bfd_canonicalize_dynamic_symtab(abfd, syms); - else - symcount = bfd_canonicalize_symtab(abfd, syms); - if (symcount < 0) { - wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab", - dynamic ? "dynamic " : ""); - free(syms); - syms = NULL; - return; - } -} - - -struct bfd_data { - bfd_vma pc; - bfd_boolean found; - const char *filename; - const char *function; - unsigned int line; -}; - - -static void find_addr_sect(bfd *abfd, asection *section, void *obj) -{ - struct bfd_data *data = obj; - bfd_vma vma; - bfd_size_type size; - - if (data->found) - return; - - if (!(bfd_get_section_vma(abfd, section))) - return; - - vma = bfd_get_section_vma(abfd, section); - if (data->pc < vma) - return; - - size = bfd_get_section_size(section); - if (data->pc >= vma + size) - return; - - data->found = bfd_find_nearest_line(abfd, section, syms, - data->pc - vma, - &data->filename, - &data->function, - &data->line); -} - - -static void wpa_trace_bfd_addr(void *pc) -{ - bfd *abfd = cached_abfd; - struct bfd_data data; - const char *name; - char *aname = NULL; - const char *filename; - - if (abfd == NULL) - return; - - data.pc = (bfd_vma) pc; - data.found = FALSE; - bfd_map_over_sections(abfd, find_addr_sect, &data); - - if (!data.found) - return; - - do { - if (data.function) - aname = bfd_demangle(abfd, data.function, - DMGL_ANSI | DMGL_PARAMS); - name = aname ? aname : data.function; - filename = data.filename; - if (filename) { - char *end = os_strrchr(filename, '/'); - int i = 0; - while (*filename && *filename == prg_fname[i] && - filename <= end) { - filename++; - i++; - } - } - wpa_printf(MSG_INFO, " %s() %s:%u", - name, filename, data.line); - free(aname); - - data.found = bfd_find_inliner_info(abfd, &data.filename, - &data.function, &data.line); - } while (data.found); -} - - -static const char * wpa_trace_bfd_addr2func(void *pc) -{ - bfd *abfd = cached_abfd; - struct bfd_data data; - - if (abfd == NULL) - return NULL; - - data.pc = (bfd_vma) pc; - data.found = FALSE; - bfd_map_over_sections(abfd, find_addr_sect, &data); - - if (!data.found) - return NULL; - - return data.function; -} - - -static void wpa_trace_bfd_init(void) -{ - if (!prg_fname) { - get_prg_fname(); - if (!prg_fname) - return; - } - - if (!cached_abfd) { - cached_abfd = open_bfd(prg_fname); - if (!cached_abfd) { - wpa_printf(MSG_INFO, "Failed to open bfd"); - return; - } - } - - read_syms(cached_abfd); - if (!syms) { - wpa_printf(MSG_INFO, "Failed to read symbols"); - return; - } -} - - -void wpa_trace_dump_funcname(const char *title, void *pc) -{ - wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc); - wpa_trace_bfd_init(); - wpa_trace_bfd_addr(pc); -} - -#else /* WPA_TRACE_BFD */ - -#define wpa_trace_bfd_init() do { } while (0) -#define wpa_trace_bfd_addr(pc) do { } while (0) -#define wpa_trace_bfd_addr2func(pc) NULL - -#endif /* WPA_TRACE_BFD */ - -void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num) -{ - char **sym; - int i; - enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state; - - wpa_trace_bfd_init(); - wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title); - sym = backtrace_symbols(btrace, btrace_num); - state = TRACE_HEAD; - for (i = 0; i < btrace_num; i++) { - const char *func = wpa_trace_bfd_addr2func(btrace[i]); - if (state == TRACE_HEAD && func && - (os_strcmp(func, "wpa_trace_add_ref_func") == 0 || - os_strcmp(func, "wpa_trace_check_ref") == 0 || - os_strcmp(func, "wpa_trace_show") == 0)) - continue; - if (state == TRACE_TAIL && sym && sym[i] && - os_strstr(sym[i], "__libc_start_main")) - break; - if (state == TRACE_HEAD) - state = TRACE_RELEVANT; - if (sym) - wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]); - else - wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]); - wpa_trace_bfd_addr(btrace[i]); - if (state == TRACE_RELEVANT && func && - os_strcmp(func, "main") == 0) - state = TRACE_TAIL; - } - free(sym); - wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title); -} - - -void wpa_trace_show(const char *title) -{ - struct info { - WPA_TRACE_INFO - } info; - wpa_trace_record(&info); - wpa_trace_dump(title, &info); -} - - -void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr) -{ - if (addr == NULL) - return; - ref->addr = addr; - wpa_trace_record(ref); - dl_list_add(&active_references, &ref->list); -} - - -void wpa_trace_check_ref(const void *addr) -{ - struct wpa_trace_ref *ref; - dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) { - if (addr != ref->addr) - continue; - wpa_trace_show("Freeing referenced memory"); - wpa_trace_dump("Reference registration", ref); - abort(); - } -} - -#endif /* WPA_TRACE */ diff --git a/contrib/hostapd/src/utils/trace.h b/contrib/hostapd/src/utils/trace.h deleted file mode 100644 index 38f43fbfab..0000000000 --- a/contrib/hostapd/src/utils/trace.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Backtrace debugging - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef TRACE_H -#define TRACE_H - -#define WPA_TRACE_LEN 16 - -#ifdef WPA_TRACE -#include - -#include "list.h" - -#define WPA_TRACE_INFO void *btrace[WPA_TRACE_LEN]; int btrace_num; - -struct wpa_trace_ref { - struct dl_list list; - const void *addr; - WPA_TRACE_INFO -}; -#define WPA_TRACE_REF(name) struct wpa_trace_ref wpa_trace_ref_##name - -#define wpa_trace_dump(title, ptr) \ - wpa_trace_dump_func((title), (ptr)->btrace, (ptr)->btrace_num) -void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num); -#define wpa_trace_record(ptr) \ - (ptr)->btrace_num = backtrace((ptr)->btrace, WPA_TRACE_LEN) -void wpa_trace_show(const char *title); -#define wpa_trace_add_ref(ptr, name, addr) \ - wpa_trace_add_ref_func(&(ptr)->wpa_trace_ref_##name, (addr)) -void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr); -#define wpa_trace_remove_ref(ptr, name, addr) \ - do { \ - if ((addr)) \ - dl_list_del(&(ptr)->wpa_trace_ref_##name.list); \ - } while (0) -void wpa_trace_check_ref(const void *addr); - -#else /* WPA_TRACE */ - -#define WPA_TRACE_INFO -#define WPA_TRACE_REF(n) -#define wpa_trace_dump(title, ptr) do { } while (0) -#define wpa_trace_record(ptr) do { } while (0) -#define wpa_trace_show(title) do { } while (0) -#define wpa_trace_add_ref(ptr, name, addr) do { } while (0) -#define wpa_trace_remove_ref(ptr, name, addr) do { } while (0) -#define wpa_trace_check_ref(addr) do { } while (0) - -#endif /* WPA_TRACE */ - - -#ifdef WPA_TRACE_BFD - -void wpa_trace_dump_funcname(const char *title, void *pc); - -#else /* WPA_TRACE_BFD */ - -#define wpa_trace_dump_funcname(title, pc) do { } while (0) - -#endif /* WPA_TRACE_BFD */ - -#endif /* TRACE_H */ diff --git a/contrib/hostapd/src/utils/uuid.c b/contrib/hostapd/src/utils/uuid.c deleted file mode 100644 index 2aa4bcb5fa..0000000000 --- a/contrib/hostapd/src/utils/uuid.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Universally Unique IDentifier (UUID) - * Copyright (c) 2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "uuid.h" - -int uuid_str2bin(const char *str, u8 *bin) -{ - const char *pos; - u8 *opos; - - pos = str; - opos = bin; - - if (hexstr2bin(pos, opos, 4)) - return -1; - pos += 8; - opos += 4; - - if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) - return -1; - pos += 4; - opos += 2; - - if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) - return -1; - pos += 4; - opos += 2; - - if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) - return -1; - pos += 4; - opos += 2; - - if (*pos++ != '-' || hexstr2bin(pos, opos, 6)) - return -1; - - return 0; -} - - -int uuid_bin2str(const u8 *bin, char *str, size_t max_len) -{ - int len; - len = os_snprintf(str, max_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-" - "%02x%02x-%02x%02x%02x%02x%02x%02x", - bin[0], bin[1], bin[2], bin[3], - bin[4], bin[5], bin[6], bin[7], - bin[8], bin[9], bin[10], bin[11], - bin[12], bin[13], bin[14], bin[15]); - if (len < 0 || (size_t) len >= max_len) - return -1; - return 0; -} - - -int is_nil_uuid(const u8 *uuid) -{ - int i; - for (i = 0; i < UUID_LEN; i++) - if (uuid[i]) - return 0; - return 1; -} diff --git a/contrib/hostapd/src/utils/uuid.h b/contrib/hostapd/src/utils/uuid.h deleted file mode 100644 index 5e860cbc59..0000000000 --- a/contrib/hostapd/src/utils/uuid.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Universally Unique IDentifier (UUID) - * Copyright (c) 2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef UUID_H -#define UUID_H - -#define UUID_LEN 16 - -int uuid_str2bin(const char *str, u8 *bin); -int uuid_bin2str(const u8 *bin, char *str, size_t max_len); -int is_nil_uuid(const u8 *uuid); - -#endif /* UUID_H */ diff --git a/contrib/hostapd/src/utils/wpa_debug.c b/contrib/hostapd/src/utils/wpa_debug.c deleted file mode 100644 index 7846c1e5f2..0000000000 --- a/contrib/hostapd/src/utils/wpa_debug.c +++ /dev/null @@ -1,736 +0,0 @@ -/* - * wpa_supplicant/hostapd / Debug prints - * Copyright (c) 2002-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" - -#ifdef CONFIG_DEBUG_SYSLOG -#include - -static int wpa_debug_syslog = 0; -#endif /* CONFIG_DEBUG_SYSLOG */ - -#ifdef CONFIG_DEBUG_LINUX_TRACING -#include -#include -#include -#include -#include - -static FILE *wpa_debug_tracing_file = NULL; - -#define WPAS_TRACE_PFX "wpas <%d>: " -#endif /* CONFIG_DEBUG_LINUX_TRACING */ - - -int wpa_debug_level = MSG_INFO; -int wpa_debug_show_keys = 0; -int wpa_debug_timestamp = 0; - - -#ifdef CONFIG_ANDROID_LOG - -#include - -#ifndef ANDROID_LOG_NAME -#define ANDROID_LOG_NAME "wpa_supplicant" -#endif /* ANDROID_LOG_NAME */ - -static int wpa_to_android_level(int level) -{ - if (level == MSG_ERROR) - return ANDROID_LOG_ERROR; - if (level == MSG_WARNING) - return ANDROID_LOG_WARN; - if (level == MSG_INFO) - return ANDROID_LOG_INFO; - return ANDROID_LOG_DEBUG; -} - -#endif /* CONFIG_ANDROID_LOG */ - -#ifndef CONFIG_NO_STDOUT_DEBUG - -#ifdef CONFIG_DEBUG_FILE -static FILE *out_file = NULL; -#endif /* CONFIG_DEBUG_FILE */ - - -void wpa_debug_print_timestamp(void) -{ -#ifndef CONFIG_ANDROID_LOG - struct os_time tv; - - if (!wpa_debug_timestamp) - return; - - os_get_time(&tv); -#ifdef CONFIG_DEBUG_FILE - if (out_file) { - fprintf(out_file, "%ld.%06u: ", (long) tv.sec, - (unsigned int) tv.usec); - } else -#endif /* CONFIG_DEBUG_FILE */ - printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec); -#endif /* CONFIG_ANDROID_LOG */ -} - - -#ifdef CONFIG_DEBUG_SYSLOG -#ifndef LOG_HOSTAPD -#define LOG_HOSTAPD LOG_DAEMON -#endif /* LOG_HOSTAPD */ - -void wpa_debug_open_syslog(void) -{ - openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_HOSTAPD); - wpa_debug_syslog++; -} - - -void wpa_debug_close_syslog(void) -{ - if (wpa_debug_syslog) - closelog(); -} - - -static int syslog_priority(int level) -{ - switch (level) { - case MSG_MSGDUMP: - case MSG_DEBUG: - return LOG_DEBUG; - case MSG_INFO: - return LOG_NOTICE; - case MSG_WARNING: - return LOG_WARNING; - case MSG_ERROR: - return LOG_ERR; - } - return LOG_INFO; -} -#endif /* CONFIG_DEBUG_SYSLOG */ - - -#ifdef CONFIG_DEBUG_LINUX_TRACING - -int wpa_debug_open_linux_tracing(void) -{ - int mounts, trace_fd; - char buf[4096] = {}; - ssize_t buflen; - char *line, *tmp1, *path = NULL; - - mounts = open("/proc/mounts", O_RDONLY); - if (mounts < 0) { - printf("no /proc/mounts\n"); - return -1; - } - - buflen = read(mounts, buf, sizeof(buf) - 1); - close(mounts); - if (buflen < 0) { - printf("failed to read /proc/mounts\n"); - return -1; - } - - line = strtok_r(buf, "\n", &tmp1); - while (line) { - char *tmp2, *tmp_path, *fstype; - /* " ..." */ - strtok_r(line, " ", &tmp2); - tmp_path = strtok_r(NULL, " ", &tmp2); - fstype = strtok_r(NULL, " ", &tmp2); - if (strcmp(fstype, "debugfs") == 0) { - path = tmp_path; - break; - } - - line = strtok_r(NULL, "\n", &tmp1); - } - - if (path == NULL) { - printf("debugfs mountpoint not found\n"); - return -1; - } - - snprintf(buf, sizeof(buf) - 1, "%s/tracing/trace_marker", path); - - trace_fd = open(buf, O_WRONLY); - if (trace_fd < 0) { - printf("failed to open trace_marker file\n"); - return -1; - } - wpa_debug_tracing_file = fdopen(trace_fd, "w"); - if (wpa_debug_tracing_file == NULL) { - close(trace_fd); - printf("failed to fdopen()\n"); - return -1; - } - - return 0; -} - - -void wpa_debug_close_linux_tracing(void) -{ - if (wpa_debug_tracing_file == NULL) - return; - fclose(wpa_debug_tracing_file); - wpa_debug_tracing_file = NULL; -} - -#endif /* CONFIG_DEBUG_LINUX_TRACING */ - - -/** - * wpa_printf - conditional printf - * @level: priority level (MSG_*) of the message - * @fmt: printf format string, followed by optional arguments - * - * This function is used to print conditional debugging and error messages. The - * output may be directed to stdout, stderr, and/or syslog based on - * configuration. - * - * Note: New line '\n' is added to the end of the text when printing to stdout. - */ -void wpa_printf(int level, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - if (level >= wpa_debug_level) { -#ifdef CONFIG_ANDROID_LOG - __android_log_vprint(wpa_to_android_level(level), - ANDROID_LOG_NAME, fmt, ap); -#else /* CONFIG_ANDROID_LOG */ -#ifdef CONFIG_DEBUG_SYSLOG - if (wpa_debug_syslog) { - vsyslog(syslog_priority(level), fmt, ap); - } else { -#endif /* CONFIG_DEBUG_SYSLOG */ - wpa_debug_print_timestamp(); -#ifdef CONFIG_DEBUG_FILE - if (out_file) { - vfprintf(out_file, fmt, ap); - fprintf(out_file, "\n"); - } else { -#endif /* CONFIG_DEBUG_FILE */ - vprintf(fmt, ap); - printf("\n"); -#ifdef CONFIG_DEBUG_FILE - } -#endif /* CONFIG_DEBUG_FILE */ -#ifdef CONFIG_DEBUG_SYSLOG - } -#endif /* CONFIG_DEBUG_SYSLOG */ -#endif /* CONFIG_ANDROID_LOG */ - } - va_end(ap); - -#ifdef CONFIG_DEBUG_LINUX_TRACING - if (wpa_debug_tracing_file != NULL) { - va_start(ap, fmt); - fprintf(wpa_debug_tracing_file, WPAS_TRACE_PFX, level); - vfprintf(wpa_debug_tracing_file, fmt, ap); - fprintf(wpa_debug_tracing_file, "\n"); - fflush(wpa_debug_tracing_file); - va_end(ap); - } -#endif /* CONFIG_DEBUG_LINUX_TRACING */ -} - - -static void _wpa_hexdump(int level, const char *title, const u8 *buf, - size_t len, int show) -{ - size_t i; - -#ifdef CONFIG_DEBUG_LINUX_TRACING - if (wpa_debug_tracing_file != NULL) { - fprintf(wpa_debug_tracing_file, - WPAS_TRACE_PFX "%s - hexdump(len=%lu):", - level, title, (unsigned long) len); - if (buf == NULL) { - fprintf(wpa_debug_tracing_file, " [NULL]\n"); - } else if (!show) { - fprintf(wpa_debug_tracing_file, " [REMOVED]\n"); - } else { - for (i = 0; i < len; i++) - fprintf(wpa_debug_tracing_file, - " %02x", buf[i]); - } - fflush(wpa_debug_tracing_file); - } -#endif /* CONFIG_DEBUG_LINUX_TRACING */ - - if (level < wpa_debug_level) - return; -#ifdef CONFIG_ANDROID_LOG - { - const char *display; - char *strbuf = NULL; - size_t slen = len; - if (buf == NULL) { - display = " [NULL]"; - } else if (len == 0) { - display = ""; - } else if (show && len) { - /* Limit debug message length for Android log */ - if (slen > 32) - slen = 32; - strbuf = os_malloc(1 + 3 * slen); - if (strbuf == NULL) { - wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to " - "allocate message buffer"); - return; - } - - for (i = 0; i < slen; i++) - os_snprintf(&strbuf[i * 3], 4, " %02x", - buf[i]); - - display = strbuf; - } else { - display = " [REMOVED]"; - } - - __android_log_print(wpa_to_android_level(level), - ANDROID_LOG_NAME, - "%s - hexdump(len=%lu):%s%s", - title, (long unsigned int) len, display, - len > slen ? " ..." : ""); - os_free(strbuf); - return; - } -#else /* CONFIG_ANDROID_LOG */ -#ifdef CONFIG_DEBUG_SYSLOG - if (wpa_debug_syslog) { - const char *display; - char *strbuf = NULL; - - if (buf == NULL) { - display = " [NULL]"; - } else if (len == 0) { - display = ""; - } else if (show && len) { - strbuf = os_malloc(1 + 3 * len); - if (strbuf == NULL) { - wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to " - "allocate message buffer"); - return; - } - - for (i = 0; i < len; i++) - os_snprintf(&strbuf[i * 3], 4, " %02x", - buf[i]); - - display = strbuf; - } else { - display = " [REMOVED]"; - } - - syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s", - title, (unsigned long) len, display); - os_free(strbuf); - return; - } -#endif /* CONFIG_DEBUG_SYSLOG */ - wpa_debug_print_timestamp(); -#ifdef CONFIG_DEBUG_FILE - if (out_file) { - fprintf(out_file, "%s - hexdump(len=%lu):", - title, (unsigned long) len); - if (buf == NULL) { - fprintf(out_file, " [NULL]"); - } else if (show) { - for (i = 0; i < len; i++) - fprintf(out_file, " %02x", buf[i]); - } else { - fprintf(out_file, " [REMOVED]"); - } - fprintf(out_file, "\n"); - } else { -#endif /* CONFIG_DEBUG_FILE */ - printf("%s - hexdump(len=%lu):", title, (unsigned long) len); - if (buf == NULL) { - printf(" [NULL]"); - } else if (show) { - for (i = 0; i < len; i++) - printf(" %02x", buf[i]); - } else { - printf(" [REMOVED]"); - } - printf("\n"); -#ifdef CONFIG_DEBUG_FILE - } -#endif /* CONFIG_DEBUG_FILE */ -#endif /* CONFIG_ANDROID_LOG */ -} - -void wpa_hexdump(int level, const char *title, const void *buf, size_t len) -{ - _wpa_hexdump(level, title, buf, len, 1); -} - - -void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len) -{ - _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); -} - - -static void _wpa_hexdump_ascii(int level, const char *title, const void *buf, - size_t len, int show) -{ - size_t i, llen; - const u8 *pos = buf; - const size_t line_len = 16; - -#ifdef CONFIG_DEBUG_LINUX_TRACING - if (wpa_debug_tracing_file != NULL) { - fprintf(wpa_debug_tracing_file, - WPAS_TRACE_PFX "%s - hexdump_ascii(len=%lu):", - level, title, (unsigned long) len); - if (buf == NULL) { - fprintf(wpa_debug_tracing_file, " [NULL]\n"); - } else if (!show) { - fprintf(wpa_debug_tracing_file, " [REMOVED]\n"); - } else { - /* can do ascii processing in userspace */ - for (i = 0; i < len; i++) - fprintf(wpa_debug_tracing_file, - " %02x", pos[i]); - } - fflush(wpa_debug_tracing_file); - } -#endif /* CONFIG_DEBUG_LINUX_TRACING */ - - if (level < wpa_debug_level) - return; -#ifdef CONFIG_ANDROID_LOG - _wpa_hexdump(level, title, buf, len, show); -#else /* CONFIG_ANDROID_LOG */ - wpa_debug_print_timestamp(); -#ifdef CONFIG_DEBUG_FILE - if (out_file) { - if (!show) { - fprintf(out_file, - "%s - hexdump_ascii(len=%lu): [REMOVED]\n", - title, (unsigned long) len); - return; - } - if (buf == NULL) { - fprintf(out_file, - "%s - hexdump_ascii(len=%lu): [NULL]\n", - title, (unsigned long) len); - return; - } - fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n", - title, (unsigned long) len); - while (len) { - llen = len > line_len ? line_len : len; - fprintf(out_file, " "); - for (i = 0; i < llen; i++) - fprintf(out_file, " %02x", pos[i]); - for (i = llen; i < line_len; i++) - fprintf(out_file, " "); - fprintf(out_file, " "); - for (i = 0; i < llen; i++) { - if (isprint(pos[i])) - fprintf(out_file, "%c", pos[i]); - else - fprintf(out_file, "_"); - } - for (i = llen; i < line_len; i++) - fprintf(out_file, " "); - fprintf(out_file, "\n"); - pos += llen; - len -= llen; - } - } else { -#endif /* CONFIG_DEBUG_FILE */ - if (!show) { - printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n", - title, (unsigned long) len); - return; - } - if (buf == NULL) { - printf("%s - hexdump_ascii(len=%lu): [NULL]\n", - title, (unsigned long) len); - return; - } - printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len); - while (len) { - llen = len > line_len ? line_len : len; - printf(" "); - for (i = 0; i < llen; i++) - printf(" %02x", pos[i]); - for (i = llen; i < line_len; i++) - printf(" "); - printf(" "); - for (i = 0; i < llen; i++) { - if (isprint(pos[i])) - printf("%c", pos[i]); - else - printf("_"); - } - for (i = llen; i < line_len; i++) - printf(" "); - printf("\n"); - pos += llen; - len -= llen; - } -#ifdef CONFIG_DEBUG_FILE - } -#endif /* CONFIG_DEBUG_FILE */ -#endif /* CONFIG_ANDROID_LOG */ -} - - -void wpa_hexdump_ascii(int level, const char *title, const void *buf, - size_t len) -{ - _wpa_hexdump_ascii(level, title, buf, len, 1); -} - - -void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, - size_t len) -{ - _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); -} - - -#ifdef CONFIG_DEBUG_FILE -static char *last_path = NULL; -#endif /* CONFIG_DEBUG_FILE */ - -int wpa_debug_reopen_file(void) -{ -#ifdef CONFIG_DEBUG_FILE - int rv; - if (last_path) { - char *tmp = os_strdup(last_path); - wpa_debug_close_file(); - rv = wpa_debug_open_file(tmp); - os_free(tmp); - } else { - wpa_printf(MSG_ERROR, "Last-path was not set, cannot " - "re-open log file."); - rv = -1; - } - return rv; -#else /* CONFIG_DEBUG_FILE */ - return 0; -#endif /* CONFIG_DEBUG_FILE */ -} - - -int wpa_debug_open_file(const char *path) -{ -#ifdef CONFIG_DEBUG_FILE - if (!path) - return 0; - - if (last_path == NULL || os_strcmp(last_path, path) != 0) { - /* Save our path to enable re-open */ - os_free(last_path); - last_path = os_strdup(path); - } - - out_file = fopen(path, "a"); - if (out_file == NULL) { - wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open " - "output file, using standard output"); - return -1; - } -#ifndef _WIN32 - setvbuf(out_file, NULL, _IOLBF, 0); -#endif /* _WIN32 */ -#endif /* CONFIG_DEBUG_FILE */ - return 0; -} - - -void wpa_debug_close_file(void) -{ -#ifdef CONFIG_DEBUG_FILE - if (!out_file) - return; - fclose(out_file); - out_file = NULL; - os_free(last_path); - last_path = NULL; -#endif /* CONFIG_DEBUG_FILE */ -} - -#endif /* CONFIG_NO_STDOUT_DEBUG */ - - -#ifndef CONFIG_NO_WPA_MSG -static wpa_msg_cb_func wpa_msg_cb = NULL; - -void wpa_msg_register_cb(wpa_msg_cb_func func) -{ - wpa_msg_cb = func; -} - - -static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL; - -void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func) -{ - wpa_msg_ifname_cb = func; -} - - -void wpa_msg(void *ctx, int level, const char *fmt, ...) -{ - va_list ap; - char *buf; - const int buflen = 2048; - int len; - char prefix[130]; - - buf = os_malloc(buflen); - if (buf == NULL) { - wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message " - "buffer"); - return; - } - va_start(ap, fmt); - prefix[0] = '\0'; - if (wpa_msg_ifname_cb) { - const char *ifname = wpa_msg_ifname_cb(ctx); - if (ifname) { - int res = os_snprintf(prefix, sizeof(prefix), "%s: ", - ifname); - if (res < 0 || res >= (int) sizeof(prefix)) - prefix[0] = '\0'; - } - } - len = vsnprintf(buf, buflen, fmt, ap); - va_end(ap); - wpa_printf(level, "%s%s", prefix, buf); - if (wpa_msg_cb) - wpa_msg_cb(ctx, level, 0, buf, len); - os_free(buf); -} - - -void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) -{ - va_list ap; - char *buf; - const int buflen = 2048; - int len; - - if (!wpa_msg_cb) - return; - - buf = os_malloc(buflen); - if (buf == NULL) { - wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate " - "message buffer"); - return; - } - va_start(ap, fmt); - len = vsnprintf(buf, buflen, fmt, ap); - va_end(ap); - wpa_msg_cb(ctx, level, 0, buf, len); - os_free(buf); -} - - -void wpa_msg_global(void *ctx, int level, const char *fmt, ...) -{ - va_list ap; - char *buf; - const int buflen = 2048; - int len; - - buf = os_malloc(buflen); - if (buf == NULL) { - wpa_printf(MSG_ERROR, "wpa_msg_global: Failed to allocate " - "message buffer"); - return; - } - va_start(ap, fmt); - len = vsnprintf(buf, buflen, fmt, ap); - va_end(ap); - wpa_printf(level, "%s", buf); - if (wpa_msg_cb) - wpa_msg_cb(ctx, level, 1, buf, len); - os_free(buf); -} - - -void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...) -{ - va_list ap; - char *buf; - const int buflen = 2048; - int len; - - buf = os_malloc(buflen); - if (buf == NULL) { - wpa_printf(MSG_ERROR, "wpa_msg_no_global: Failed to allocate " - "message buffer"); - return; - } - va_start(ap, fmt); - len = vsnprintf(buf, buflen, fmt, ap); - va_end(ap); - wpa_printf(level, "%s", buf); - if (wpa_msg_cb) - wpa_msg_cb(ctx, level, 2, buf, len); - os_free(buf); -} - -#endif /* CONFIG_NO_WPA_MSG */ - - -#ifndef CONFIG_NO_HOSTAPD_LOGGER -static hostapd_logger_cb_func hostapd_logger_cb = NULL; - -void hostapd_logger_register_cb(hostapd_logger_cb_func func) -{ - hostapd_logger_cb = func; -} - - -void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, - const char *fmt, ...) -{ - va_list ap; - char *buf; - const int buflen = 2048; - int len; - - buf = os_malloc(buflen); - if (buf == NULL) { - wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate " - "message buffer"); - return; - } - va_start(ap, fmt); - len = vsnprintf(buf, buflen, fmt, ap); - va_end(ap); - if (hostapd_logger_cb) - hostapd_logger_cb(ctx, addr, module, level, buf, len); - else if (addr) - wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s", - MAC2STR(addr), buf); - else - wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf); - os_free(buf); -} -#endif /* CONFIG_NO_HOSTAPD_LOGGER */ diff --git a/contrib/hostapd/src/utils/wpa_debug.h b/contrib/hostapd/src/utils/wpa_debug.h deleted file mode 100644 index 50e8ae9d55..0000000000 --- a/contrib/hostapd/src/utils/wpa_debug.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - * wpa_supplicant/hostapd / Debug prints - * Copyright (c) 2002-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_DEBUG_H -#define WPA_DEBUG_H - -#include "wpabuf.h" - -extern int wpa_debug_level; -extern int wpa_debug_show_keys; -extern int wpa_debug_timestamp; - -/* Debugging function - conditional printf and hex dump. Driver wrappers can - * use these for debugging purposes. */ - -enum { - MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR -}; - -#ifdef CONFIG_NO_STDOUT_DEBUG - -#define wpa_debug_print_timestamp() do { } while (0) -#define wpa_printf(args...) do { } while (0) -#define wpa_hexdump(l,t,b,le) do { } while (0) -#define wpa_hexdump_buf(l,t,b) do { } while (0) -#define wpa_hexdump_key(l,t,b,le) do { } while (0) -#define wpa_hexdump_buf_key(l,t,b) do { } while (0) -#define wpa_hexdump_ascii(l,t,b,le) do { } while (0) -#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0) -#define wpa_debug_open_file(p) do { } while (0) -#define wpa_debug_close_file() do { } while (0) -#define wpa_dbg(args...) do { } while (0) - -static inline int wpa_debug_reopen_file(void) -{ - return 0; -} - -#else /* CONFIG_NO_STDOUT_DEBUG */ - -int wpa_debug_open_file(const char *path); -int wpa_debug_reopen_file(void); -void wpa_debug_close_file(void); - -/** - * wpa_debug_printf_timestamp - Print timestamp for debug output - * - * This function prints a timestamp in seconds_from_1970.microsoconds - * format if debug output has been configured to include timestamps in debug - * messages. - */ -void wpa_debug_print_timestamp(void); - -/** - * wpa_printf - conditional printf - * @level: priority level (MSG_*) of the message - * @fmt: printf format string, followed by optional arguments - * - * This function is used to print conditional debugging and error messages. The - * output may be directed to stdout, stderr, and/or syslog based on - * configuration. - * - * Note: New line '\n' is added to the end of the text when printing to stdout. - */ -void wpa_printf(int level, const char *fmt, ...) -PRINTF_FORMAT(2, 3); - -/** - * wpa_hexdump - conditional hex dump - * @level: priority level (MSG_*) of the message - * @title: title of for the message - * @buf: data buffer to be dumped - * @len: length of the buf - * - * This function is used to print conditional debugging and error messages. The - * output may be directed to stdout, stderr, and/or syslog based on - * configuration. The contents of buf is printed out has hex dump. - */ -void wpa_hexdump(int level, const char *title, const void *buf, size_t len); - -static inline void wpa_hexdump_buf(int level, const char *title, - const struct wpabuf *buf) -{ - wpa_hexdump(level, title, buf ? wpabuf_head(buf) : NULL, - buf ? wpabuf_len(buf) : 0); -} - -/** - * wpa_hexdump_key - conditional hex dump, hide keys - * @level: priority level (MSG_*) of the message - * @title: title of for the message - * @buf: data buffer to be dumped - * @len: length of the buf - * - * This function is used to print conditional debugging and error messages. The - * output may be directed to stdout, stderr, and/or syslog based on - * configuration. The contents of buf is printed out has hex dump. This works - * like wpa_hexdump(), but by default, does not include secret keys (passwords, - * etc.) in debug output. - */ -void wpa_hexdump_key(int level, const char *title, const void *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) : NULL, - buf ? wpabuf_len(buf) : 0); -} - -/** - * wpa_hexdump_ascii - conditional hex dump - * @level: priority level (MSG_*) of the message - * @title: title of for the message - * @buf: data buffer to be dumped - * @len: length of the buf - * - * This function is used to print conditional debugging and error messages. The - * output may be directed to stdout, stderr, and/or syslog based on - * configuration. The contents of buf is printed out has hex dump with both - * the hex numbers and ASCII characters (for printable range) are shown. 16 - * bytes per line will be shown. - */ -void wpa_hexdump_ascii(int level, const char *title, const void *buf, - size_t len); - -/** - * wpa_hexdump_ascii_key - conditional hex dump, hide keys - * @level: priority level (MSG_*) of the message - * @title: title of for the message - * @buf: data buffer to be dumped - * @len: length of the buf - * - * This function is used to print conditional debugging and error messages. The - * output may be directed to stdout, stderr, and/or syslog based on - * configuration. The contents of buf is printed out has hex dump with both - * the hex numbers and ASCII characters (for printable range) are shown. 16 - * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by - * default, does not include secret keys (passwords, etc.) in debug output. - */ -void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, - size_t len); - -/* - * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce - * binary size. As such, it should be used with debugging messages that are not - * needed in the control interface while wpa_msg() has to be used for anything - * that needs to shown to control interface monitors. - */ -#define wpa_dbg(args...) wpa_msg(args) - -#endif /* CONFIG_NO_STDOUT_DEBUG */ - - -#ifdef CONFIG_NO_WPA_MSG -#define wpa_msg(args...) do { } while (0) -#define wpa_msg_ctrl(args...) do { } while (0) -#define wpa_msg_global(args...) do { } while (0) -#define wpa_msg_no_global(args...) do { } while (0) -#define wpa_msg_register_cb(f) do { } while (0) -#define wpa_msg_register_ifname_cb(f) do { } while (0) -#else /* CONFIG_NO_WPA_MSG */ -/** - * wpa_msg - Conditional printf for default target and ctrl_iface monitors - * @ctx: Pointer to context data; this is the ctx variable registered - * with struct wpa_driver_ops::init() - * @level: priority level (MSG_*) of the message - * @fmt: printf format string, followed by optional arguments - * - * This function is used to print conditional debugging and error messages. The - * output may be directed to stdout, stderr, and/or syslog based on - * configuration. This function is like wpa_printf(), but it also sends the - * same message to all attached ctrl_iface monitors. - * - * Note: New line '\n' is added to the end of the text when printing to stdout. - */ -void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); - -/** - * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors - * @ctx: Pointer to context data; this is the ctx variable registered - * with struct wpa_driver_ops::init() - * @level: priority level (MSG_*) of the message - * @fmt: printf format string, followed by optional arguments - * - * This function is used to print conditional debugging and error messages. - * This function is like wpa_msg(), but it sends the output only to the - * attached ctrl_iface monitors. In other words, it can be used for frequent - * events that do not need to be sent to syslog. - */ -void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) -PRINTF_FORMAT(3, 4); - -/** - * wpa_msg_global - Global printf for ctrl_iface monitors - * @ctx: Pointer to context data; this is the ctx variable registered - * with struct wpa_driver_ops::init() - * @level: priority level (MSG_*) of the message - * @fmt: printf format string, followed by optional arguments - * - * This function is used to print conditional debugging and error messages. - * This function is like wpa_msg(), but it sends the output as a global event, - * i.e., without being specific to an interface. For backwards compatibility, - * an old style event is also delivered on one of the interfaces (the one - * specified by the context data). - */ -void wpa_msg_global(void *ctx, int level, const char *fmt, ...) -PRINTF_FORMAT(3, 4); - -/** - * wpa_msg_no_global - Conditional printf for ctrl_iface monitors - * @ctx: Pointer to context data; this is the ctx variable registered - * with struct wpa_driver_ops::init() - * @level: priority level (MSG_*) of the message - * @fmt: printf format string, followed by optional arguments - * - * This function is used to print conditional debugging and error messages. - * This function is like wpa_msg(), but it does not send the output as a global - * event. - */ -void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...) -PRINTF_FORMAT(3, 4); - -typedef void (*wpa_msg_cb_func)(void *ctx, int level, int global, - const char *txt, size_t len); - -/** - * wpa_msg_register_cb - Register callback function for wpa_msg() messages - * @func: Callback function (%NULL to unregister) - */ -void wpa_msg_register_cb(wpa_msg_cb_func func); - -typedef const char * (*wpa_msg_get_ifname_func)(void *ctx); -void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func); - -#endif /* CONFIG_NO_WPA_MSG */ - -#ifdef CONFIG_NO_HOSTAPD_LOGGER -#define hostapd_logger(args...) do { } while (0) -#define hostapd_logger_register_cb(f) do { } while (0) -#else /* CONFIG_NO_HOSTAPD_LOGGER */ -void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, - const char *fmt, ...) PRINTF_FORMAT(5, 6); - -typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr, - unsigned int module, int level, - const char *txt, size_t len); - -/** - * hostapd_logger_register_cb - Register callback function for hostapd_logger() - * @func: Callback function (%NULL to unregister) - */ -void hostapd_logger_register_cb(hostapd_logger_cb_func func); -#endif /* CONFIG_NO_HOSTAPD_LOGGER */ - -#define HOSTAPD_MODULE_IEEE80211 0x00000001 -#define HOSTAPD_MODULE_IEEE8021X 0x00000002 -#define HOSTAPD_MODULE_RADIUS 0x00000004 -#define HOSTAPD_MODULE_WPA 0x00000008 -#define HOSTAPD_MODULE_DRIVER 0x00000010 -#define HOSTAPD_MODULE_IAPP 0x00000020 -#define HOSTAPD_MODULE_MLME 0x00000040 - -enum hostapd_logger_level { - HOSTAPD_LEVEL_DEBUG_VERBOSE = 0, - HOSTAPD_LEVEL_DEBUG = 1, - HOSTAPD_LEVEL_INFO = 2, - HOSTAPD_LEVEL_NOTICE = 3, - HOSTAPD_LEVEL_WARNING = 4 -}; - - -#ifdef CONFIG_DEBUG_SYSLOG - -void wpa_debug_open_syslog(void); -void wpa_debug_close_syslog(void); - -#else /* CONFIG_DEBUG_SYSLOG */ - -static inline void wpa_debug_open_syslog(void) -{ -} - -static inline void wpa_debug_close_syslog(void) -{ -} - -#endif /* CONFIG_DEBUG_SYSLOG */ - -#ifdef CONFIG_DEBUG_LINUX_TRACING - -int wpa_debug_open_linux_tracing(void); -void wpa_debug_close_linux_tracing(void); - -#else /* CONFIG_DEBUG_LINUX_TRACING */ - -static inline int wpa_debug_open_linux_tracing(void) -{ - return 0; -} - -static inline void wpa_debug_close_linux_tracing(void) -{ -} - -#endif /* CONFIG_DEBUG_LINUX_TRACING */ - - -#ifdef EAPOL_TEST -#define WPA_ASSERT(a) \ - do { \ - if (!(a)) { \ - printf("WPA_ASSERT FAILED '" #a "' " \ - "%s %s:%d\n", \ - __FUNCTION__, __FILE__, __LINE__); \ - exit(1); \ - } \ - } while (0) -#else -#define WPA_ASSERT(a) do { } while (0) -#endif - -#endif /* WPA_DEBUG_H */ diff --git a/contrib/hostapd/src/utils/wpabuf.c b/contrib/hostapd/src/utils/wpabuf.c deleted file mode 100644 index b257b365c7..0000000000 --- a/contrib/hostapd/src/utils/wpabuf.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Dynamic data buffer - * Copyright (c) 2007-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "trace.h" -#include "wpabuf.h" - -#ifdef WPA_TRACE -#define WPABUF_MAGIC 0x51a974e3 - -struct wpabuf_trace { - unsigned int magic; -}; - -static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf) -{ - return (struct wpabuf_trace *) - ((const u8 *) buf - sizeof(struct wpabuf_trace)); -} -#endif /* WPA_TRACE */ - - -static void wpabuf_overflow(const struct wpabuf *buf, size_t len) -{ -#ifdef WPA_TRACE - struct wpabuf_trace *trace = wpabuf_get_trace(buf); - if (trace->magic != WPABUF_MAGIC) { - wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", - trace->magic); - } -#endif /* WPA_TRACE */ - wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu", - buf, (unsigned long) buf->size, (unsigned long) buf->used, - (unsigned long) len); - wpa_trace_show("wpabuf overflow"); - abort(); -} - - -int wpabuf_resize(struct wpabuf **_buf, size_t add_len) -{ - struct wpabuf *buf = *_buf; -#ifdef WPA_TRACE - struct wpabuf_trace *trace; -#endif /* WPA_TRACE */ - - if (buf == NULL) { - *_buf = wpabuf_alloc(add_len); - return *_buf == NULL ? -1 : 0; - } - -#ifdef WPA_TRACE - trace = wpabuf_get_trace(buf); - if (trace->magic != WPABUF_MAGIC) { - wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", - trace->magic); - wpa_trace_show("wpabuf_resize invalid magic"); - abort(); - } -#endif /* WPA_TRACE */ - - if (buf->used + add_len > buf->size) { - unsigned char *nbuf; - if (buf->flags & WPABUF_FLAG_EXT_DATA) { - nbuf = os_realloc(buf->buf, buf->used + add_len); - if (nbuf == NULL) - return -1; - os_memset(nbuf + buf->used, 0, add_len); - buf->buf = nbuf; - } else { -#ifdef WPA_TRACE - nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) + - sizeof(struct wpabuf) + - buf->used + add_len); - if (nbuf == NULL) - return -1; - trace = (struct wpabuf_trace *) nbuf; - buf = (struct wpabuf *) (trace + 1); - os_memset(nbuf + sizeof(struct wpabuf_trace) + - sizeof(struct wpabuf) + buf->used, 0, - add_len); -#else /* WPA_TRACE */ - nbuf = os_realloc(buf, sizeof(struct wpabuf) + - buf->used + add_len); - if (nbuf == NULL) - return -1; - buf = (struct wpabuf *) nbuf; - os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0, - add_len); -#endif /* WPA_TRACE */ - buf->buf = (u8 *) (buf + 1); - *_buf = buf; - } - buf->size = buf->used + add_len; - } - - return 0; -} - - -/** - * wpabuf_alloc - Allocate a wpabuf of the given size - * @len: Length for the allocated buffer - * Returns: Buffer to the allocated wpabuf or %NULL on failure - */ -struct wpabuf * wpabuf_alloc(size_t len) -{ -#ifdef WPA_TRACE - struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + - sizeof(struct wpabuf) + len); - struct wpabuf *buf; - if (trace == NULL) - return NULL; - trace->magic = WPABUF_MAGIC; - buf = (struct wpabuf *) (trace + 1); -#else /* WPA_TRACE */ - struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len); - if (buf == NULL) - return NULL; -#endif /* WPA_TRACE */ - - buf->size = len; - buf->buf = (u8 *) (buf + 1); - return buf; -} - - -struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len) -{ -#ifdef WPA_TRACE - struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + - sizeof(struct wpabuf)); - struct wpabuf *buf; - if (trace == NULL) - return NULL; - trace->magic = WPABUF_MAGIC; - buf = (struct wpabuf *) (trace + 1); -#else /* WPA_TRACE */ - struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf)); - if (buf == NULL) - return NULL; -#endif /* WPA_TRACE */ - - buf->size = len; - buf->used = len; - buf->buf = data; - buf->flags |= WPABUF_FLAG_EXT_DATA; - - return buf; -} - - -struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len) -{ - struct wpabuf *buf = wpabuf_alloc(len); - if (buf) - wpabuf_put_data(buf, data, len); - return buf; -} - - -struct wpabuf * wpabuf_dup(const struct wpabuf *src) -{ - struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src)); - if (buf) - wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src)); - return buf; -} - - -/** - * wpabuf_free - Free a wpabuf - * @buf: wpabuf buffer - */ -void wpabuf_free(struct wpabuf *buf) -{ -#ifdef WPA_TRACE - struct wpabuf_trace *trace; - if (buf == NULL) - return; - trace = wpabuf_get_trace(buf); - if (trace->magic != WPABUF_MAGIC) { - wpa_printf(MSG_ERROR, "wpabuf_free: invalid magic %x", - trace->magic); - wpa_trace_show("wpabuf_free magic mismatch"); - abort(); - } - if (buf->flags & WPABUF_FLAG_EXT_DATA) - os_free(buf->buf); - os_free(trace); -#else /* WPA_TRACE */ - if (buf == NULL) - return; - if (buf->flags & WPABUF_FLAG_EXT_DATA) - os_free(buf->buf); - os_free(buf); -#endif /* WPA_TRACE */ -} - - -void * wpabuf_put(struct wpabuf *buf, size_t len) -{ - void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); - buf->used += len; - if (buf->used > buf->size) { - wpabuf_overflow(buf, len); - } - return tmp; -} - - -/** - * wpabuf_concat - Concatenate two buffers into a newly allocated one - * @a: First buffer - * @b: Second buffer - * Returns: wpabuf with concatenated a + b data or %NULL on failure - * - * Both buffers a and b will be freed regardless of the return value. Input - * buffers can be %NULL which is interpreted as an empty buffer. - */ -struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b) -{ - struct wpabuf *n = NULL; - size_t len = 0; - - if (b == NULL) - return a; - - if (a) - len += wpabuf_len(a); - if (b) - len += wpabuf_len(b); - - n = wpabuf_alloc(len); - if (n) { - if (a) - wpabuf_put_buf(n, a); - if (b) - wpabuf_put_buf(n, b); - } - - wpabuf_free(a); - wpabuf_free(b); - - return n; -} - - -/** - * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length - * @buf: Buffer to be padded - * @len: Length for the padded buffer - * Returns: wpabuf padded to len octets or %NULL on failure - * - * If buf is longer than len octets or of same size, it will be returned as-is. - * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed - * by the source data. The source buffer will be freed on error, i.e., caller - * will only be responsible on freeing the returned buffer. If buf is %NULL, - * %NULL will be returned. - */ -struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len) -{ - struct wpabuf *ret; - size_t blen; - - if (buf == NULL) - return NULL; - - blen = wpabuf_len(buf); - if (blen >= len) - return buf; - - ret = wpabuf_alloc(len); - if (ret) { - os_memset(wpabuf_put(ret, len - blen), 0, len - blen); - wpabuf_put_buf(ret, buf); - } - wpabuf_free(buf); - - return ret; -} - - -void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) -{ - va_list ap; - void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); - int res; - - va_start(ap, fmt); - res = vsnprintf(tmp, buf->size - buf->used, fmt, ap); - va_end(ap); - if (res < 0 || (size_t) res >= buf->size - buf->used) - wpabuf_overflow(buf, res); - buf->used += res; -} diff --git a/contrib/hostapd/src/utils/wpabuf.h b/contrib/hostapd/src/utils/wpabuf.h deleted file mode 100644 index dbce925ca1..0000000000 --- a/contrib/hostapd/src/utils/wpabuf.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Dynamic data buffer - * Copyright (c) 2007-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPABUF_H -#define WPABUF_H - -/* wpabuf::buf is a pointer to external data */ -#define WPABUF_FLAG_EXT_DATA BIT(0) - -/* - * Internal data structure for wpabuf. Please do not touch this directly from - * elsewhere. This is only defined in header file to allow inline functions - * from this file to access data. - */ -struct wpabuf { - size_t size; /* total size of the allocated buffer */ - size_t used; /* length of data in the buffer */ - u8 *buf; /* pointer to the head of the buffer */ - unsigned int flags; - /* optionally followed by the allocated buffer */ -}; - - -int wpabuf_resize(struct wpabuf **buf, size_t add_len); -struct wpabuf * wpabuf_alloc(size_t len); -struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len); -struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len); -struct wpabuf * wpabuf_dup(const struct wpabuf *src); -void wpabuf_free(struct wpabuf *buf); -void * wpabuf_put(struct wpabuf *buf, size_t len); -struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b); -struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len); -void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3); - - -/** - * wpabuf_size - Get the currently allocated size of a wpabuf buffer - * @buf: wpabuf buffer - * Returns: Currently allocated size of the buffer - */ -static inline size_t wpabuf_size(const struct wpabuf *buf) -{ - return buf->size; -} - -/** - * wpabuf_len - Get the current length of a wpabuf buffer data - * @buf: wpabuf buffer - * Returns: Currently used length of the buffer - */ -static inline size_t wpabuf_len(const struct wpabuf *buf) -{ - return buf->used; -} - -/** - * wpabuf_tailroom - Get size of available tail room in the end of the buffer - * @buf: wpabuf buffer - * Returns: Tail room (in bytes) of available space in the end of the buffer - */ -static inline size_t wpabuf_tailroom(const struct wpabuf *buf) -{ - return buf->size - buf->used; -} - -/** - * wpabuf_head - Get pointer to the head of the buffer data - * @buf: wpabuf buffer - * Returns: Pointer to the head of the buffer data - */ -static inline const void * wpabuf_head(const struct wpabuf *buf) -{ - return buf->buf; -} - -static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf) -{ - return wpabuf_head(buf); -} - -/** - * wpabuf_mhead - Get modifiable pointer to the head of the buffer data - * @buf: wpabuf buffer - * Returns: Pointer to the head of the buffer data - */ -static inline void * wpabuf_mhead(struct wpabuf *buf) -{ - return buf->buf; -} - -static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf) -{ - return wpabuf_mhead(buf); -} - -static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data) -{ - u8 *pos = wpabuf_put(buf, 1); - *pos = data; -} - -static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data) -{ - u8 *pos = wpabuf_put(buf, 2); - WPA_PUT_LE16(pos, data); -} - -static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data) -{ - u8 *pos = wpabuf_put(buf, 4); - WPA_PUT_LE32(pos, data); -} - -static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data) -{ - u8 *pos = wpabuf_put(buf, 2); - WPA_PUT_BE16(pos, data); -} - -static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data) -{ - u8 *pos = wpabuf_put(buf, 3); - WPA_PUT_BE24(pos, data); -} - -static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data) -{ - u8 *pos = wpabuf_put(buf, 4); - WPA_PUT_BE32(pos, data); -} - -static inline void wpabuf_put_data(struct wpabuf *buf, const void *data, - size_t len) -{ - if (data) - os_memcpy(wpabuf_put(buf, len), data, len); -} - -static inline void wpabuf_put_buf(struct wpabuf *dst, - const struct wpabuf *src) -{ - wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src)); -} - -static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len) -{ - buf->buf = (u8 *) data; - buf->flags = WPABUF_FLAG_EXT_DATA; - buf->size = buf->used = len; -} - -static inline void wpabuf_put_str(struct wpabuf *dst, const char *str) -{ - wpabuf_put_data(dst, str, os_strlen(str)); -} - -#endif /* WPABUF_H */ diff --git a/contrib/hostapd/src/wps/http.h b/contrib/hostapd/src/wps/http.h deleted file mode 100644 index 2fee3a8f87..0000000000 --- a/contrib/hostapd/src/wps/http.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * HTTP for WPS - * Copyright (c) 2000-2003 Intel Corporation - * Copyright (c) 2006-2007 Sony Corporation - * Copyright (c) 2008-2009 Atheros Communications - * Copyright (c) 2009, Jouni Malinen - * - * See wps_upnp.c for more details on licensing and code history. - */ - -#ifndef HTTP_H -#define HTTP_H - -enum http_reply_code { - HTTP_OK = 200, - HTTP_BAD_REQUEST = 400, - UPNP_INVALID_ACTION = 401, - UPNP_INVALID_ARGS = 402, - HTTP_NOT_FOUND = 404, - HTTP_PRECONDITION_FAILED = 412, - HTTP_INTERNAL_SERVER_ERROR = 500, - HTTP_UNIMPLEMENTED = 501, - UPNP_ACTION_FAILED = 501, - UPNP_ARG_VALUE_INVALID = 600, - UPNP_ARG_VALUE_OUT_OF_RANGE = 601, - UPNP_OUT_OF_MEMORY = 603 -}; - -#endif /* HTTP_H */ diff --git a/contrib/hostapd/src/wps/http_client.c b/contrib/hostapd/src/wps/http_client.c deleted file mode 100644 index 029001306c..0000000000 --- a/contrib/hostapd/src/wps/http_client.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * http_client - HTTP client - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "eloop.h" -#include "httpread.h" -#include "http_client.h" - - -#define HTTP_CLIENT_TIMEOUT_SEC 30 - - -struct http_client { - struct sockaddr_in dst; - int sd; - struct wpabuf *req; - size_t req_pos; - size_t max_response; - - void (*cb)(void *ctx, struct http_client *c, - enum http_client_event event); - void *cb_ctx; - struct httpread *hread; - struct wpabuf body; -}; - - -static void http_client_timeout(void *eloop_data, void *user_ctx) -{ - struct http_client *c = eloop_data; - wpa_printf(MSG_DEBUG, "HTTP: Timeout (c=%p)", c); - c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT); -} - - -static void http_client_got_response(struct httpread *handle, void *cookie, - enum httpread_event e) -{ - struct http_client *c = cookie; - - wpa_printf(MSG_DEBUG, "HTTP: httpread callback: handle=%p cookie=%p " - "e=%d", handle, cookie, e); - - eloop_cancel_timeout(http_client_timeout, c, NULL); - switch (e) { - case HTTPREAD_EVENT_FILE_READY: - if (httpread_hdr_type_get(c->hread) == HTTPREAD_HDR_TYPE_REPLY) - { - int reply_code = httpread_reply_code_get(c->hread); - if (reply_code == 200 /* OK */) { - wpa_printf(MSG_DEBUG, "HTTP: Response OK from " - "%s:%d", - inet_ntoa(c->dst.sin_addr), - ntohs(c->dst.sin_port)); - c->cb(c->cb_ctx, c, HTTP_CLIENT_OK); - } else { - wpa_printf(MSG_DEBUG, "HTTP: Error %d from " - "%s:%d", reply_code, - inet_ntoa(c->dst.sin_addr), - ntohs(c->dst.sin_port)); - c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY); - } - } else - c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY); - break; - case HTTPREAD_EVENT_TIMEOUT: - c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT); - break; - case HTTPREAD_EVENT_ERROR: - c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED); - break; - } -} - - -static void http_client_tx_ready(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct http_client *c = eloop_ctx; - int res; - - wpa_printf(MSG_DEBUG, "HTTP: Send client request to %s:%d (%lu of %lu " - "bytes remaining)", - inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port), - (unsigned long) wpabuf_len(c->req), - (unsigned long) wpabuf_len(c->req) - c->req_pos); - - res = send(c->sd, wpabuf_head_u8(c->req) + c->req_pos, - wpabuf_len(c->req) - c->req_pos, 0); - if (res < 0) { - wpa_printf(MSG_DEBUG, "HTTP: Failed to send buffer: %s", - strerror(errno)); - eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE); - c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED); - return; - } - - if ((size_t) res < wpabuf_len(c->req) - c->req_pos) { - wpa_printf(MSG_DEBUG, "HTTP: Sent %d of %lu bytes; %lu bytes " - "remaining", - res, (unsigned long) wpabuf_len(c->req), - (unsigned long) wpabuf_len(c->req) - c->req_pos - - res); - c->req_pos += res; - return; - } - - wpa_printf(MSG_DEBUG, "HTTP: Full client request sent to %s:%d", - inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port)); - eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE); - wpabuf_free(c->req); - c->req = NULL; - - c->hread = httpread_create(c->sd, http_client_got_response, c, - c->max_response, HTTP_CLIENT_TIMEOUT_SEC); - if (c->hread == NULL) { - c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED); - return; - } -} - - -struct http_client * http_client_addr(struct sockaddr_in *dst, - struct wpabuf *req, size_t max_response, - void (*cb)(void *ctx, - struct http_client *c, - enum http_client_event event), - void *cb_ctx) -{ - struct http_client *c; - - c = os_zalloc(sizeof(*c)); - if (c == NULL) - return NULL; - c->sd = -1; - c->dst = *dst; - c->max_response = max_response; - c->cb = cb; - c->cb_ctx = cb_ctx; - - c->sd = socket(AF_INET, SOCK_STREAM, 0); - if (c->sd < 0) { - http_client_free(c); - return NULL; - } - - if (fcntl(c->sd, F_SETFL, O_NONBLOCK) != 0) { - wpa_printf(MSG_DEBUG, "HTTP: fnctl(O_NONBLOCK) failed: %s", - strerror(errno)); - http_client_free(c); - return NULL; - } - - if (connect(c->sd, (struct sockaddr *) dst, sizeof(*dst))) { - if (errno != EINPROGRESS) { - wpa_printf(MSG_DEBUG, "HTTP: Failed to connect: %s", - strerror(errno)); - http_client_free(c); - return NULL; - } - - /* - * Continue connecting in the background; eloop will call us - * once the connection is ready (or failed). - */ - } - - if (eloop_register_sock(c->sd, EVENT_TYPE_WRITE, http_client_tx_ready, - c, NULL)) { - http_client_free(c); - return NULL; - } - - if (eloop_register_timeout(HTTP_CLIENT_TIMEOUT_SEC, 0, - http_client_timeout, c, NULL)) { - http_client_free(c); - return NULL; - } - - c->req = req; - - return c; -} - - -char * http_client_url_parse(const char *url, struct sockaddr_in *dst, - char **ret_path) -{ - char *u, *addr, *port, *path; - - u = os_strdup(url); - if (u == NULL) - return NULL; - - os_memset(dst, 0, sizeof(*dst)); - dst->sin_family = AF_INET; - addr = u + 7; - path = os_strchr(addr, '/'); - port = os_strchr(addr, ':'); - if (path == NULL) { - path = "/"; - } else { - *path = '\0'; /* temporary nul termination for address */ - if (port > path) - port = NULL; - } - if (port) - *port++ = '\0'; - - if (inet_aton(addr, &dst->sin_addr) == 0) { - /* TODO: name lookup */ - wpa_printf(MSG_DEBUG, "HTTP: Unsupported address in URL '%s' " - "(addr='%s' port='%s')", - url, addr, port); - os_free(u); - return NULL; - } - - if (port) - dst->sin_port = htons(atoi(port)); - else - dst->sin_port = htons(80); - - if (*path == '\0') { - /* remove temporary nul termination for address */ - *path = '/'; - } - - *ret_path = path; - - return u; -} - - -struct http_client * http_client_url(const char *url, - struct wpabuf *req, size_t max_response, - void (*cb)(void *ctx, - struct http_client *c, - enum http_client_event event), - void *cb_ctx) -{ - struct sockaddr_in dst; - struct http_client *c; - char *u, *path; - struct wpabuf *req_buf = NULL; - - if (os_strncmp(url, "http://", 7) != 0) - return NULL; - u = http_client_url_parse(url, &dst, &path); - if (u == NULL) - return NULL; - - if (req == NULL) { - req_buf = wpabuf_alloc(os_strlen(url) + 1000); - if (req_buf == NULL) { - os_free(u); - return NULL; - } - req = req_buf; - wpabuf_printf(req, - "GET %s HTTP/1.1\r\n" - "Cache-Control: no-cache\r\n" - "Pragma: no-cache\r\n" - "Accept: text/xml, application/xml\r\n" - "User-Agent: wpa_supplicant\r\n" - "Host: %s:%d\r\n" - "\r\n", - path, inet_ntoa(dst.sin_addr), - ntohs(dst.sin_port)); - } - os_free(u); - - c = http_client_addr(&dst, req, max_response, cb, cb_ctx); - if (c == NULL) { - wpabuf_free(req_buf); - return NULL; - } - - return c; -} - - -void http_client_free(struct http_client *c) -{ - if (c == NULL) - return; - httpread_destroy(c->hread); - wpabuf_free(c->req); - if (c->sd >= 0) { - eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE); - close(c->sd); - } - eloop_cancel_timeout(http_client_timeout, c, NULL); - os_free(c); -} - - -struct wpabuf * http_client_get_body(struct http_client *c) -{ - if (c->hread == NULL) - return NULL; - wpabuf_set(&c->body, httpread_data_get(c->hread), - httpread_length_get(c->hread)); - return &c->body; -} - - -char * http_client_get_hdr_line(struct http_client *c, const char *tag) -{ - if (c->hread == NULL) - return NULL; - return httpread_hdr_line_get(c->hread, tag); -} - - -char * http_link_update(char *url, const char *base) -{ - char *n; - size_t len; - const char *pos; - - /* RFC 2396, Chapter 5.2 */ - /* TODO: consider adding all cases described in RFC 2396 */ - - if (url == NULL) - return NULL; - - if (os_strncmp(url, "http://", 7) == 0) - return url; /* absolute link */ - - if (os_strncmp(base, "http://", 7) != 0) - return url; /* unable to handle base URL */ - - len = os_strlen(url) + 1 + os_strlen(base) + 1; - n = os_malloc(len); - if (n == NULL) - return url; /* failed */ - - if (url[0] == '/') { - pos = os_strchr(base + 7, '/'); - if (pos == NULL) { - os_snprintf(n, len, "%s%s", base, url); - } else { - os_memcpy(n, base, pos - base); - os_memcpy(n + (pos - base), url, os_strlen(url) + 1); - } - } else { - pos = os_strrchr(base + 7, '/'); - if (pos == NULL) { - os_snprintf(n, len, "%s/%s", base, url); - } else { - os_memcpy(n, base, pos - base + 1); - os_memcpy(n + (pos - base) + 1, url, os_strlen(url) + - 1); - } - } - - os_free(url); - - return n; -} diff --git a/contrib/hostapd/src/wps/http_client.h b/contrib/hostapd/src/wps/http_client.h deleted file mode 100644 index ddee2adb69..0000000000 --- a/contrib/hostapd/src/wps/http_client.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * http_client - HTTP client - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef HTTP_CLIENT_H -#define HTTP_CLIENT_H - -struct http_client; - -enum http_client_event { - HTTP_CLIENT_FAILED, - HTTP_CLIENT_TIMEOUT, - HTTP_CLIENT_OK, - HTTP_CLIENT_INVALID_REPLY, -}; - -char * http_client_url_parse(const char *url, struct sockaddr_in *dst, - char **path); -struct http_client * http_client_addr(struct sockaddr_in *dst, - struct wpabuf *req, size_t max_response, - void (*cb)(void *ctx, - struct http_client *c, - enum http_client_event event), - void *cb_ctx); -struct http_client * http_client_url(const char *url, - struct wpabuf *req, size_t max_response, - void (*cb)(void *ctx, - struct http_client *c, - enum http_client_event event), - void *cb_ctx); -void http_client_free(struct http_client *c); -struct wpabuf * http_client_get_body(struct http_client *c); -char * http_client_get_hdr_line(struct http_client *c, const char *tag); -char * http_link_update(char *url, const char *base); - -#endif /* HTTP_CLIENT_H */ diff --git a/contrib/hostapd/src/wps/http_server.c b/contrib/hostapd/src/wps/http_server.c deleted file mode 100644 index 06c8bee24c..0000000000 --- a/contrib/hostapd/src/wps/http_server.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * http_server - HTTP server - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "eloop.h" -#include "httpread.h" -#include "http_server.h" - -#define HTTP_SERVER_TIMEOUT 30 -#define HTTP_SERVER_MAX_REQ_LEN 8000 -#define HTTP_SERVER_MAX_CONNECTIONS 10 - -struct http_request { - struct http_request *next; - struct http_server *srv; - int fd; - struct sockaddr_in cli; - struct httpread *hread; -}; - -struct http_server { - void (*cb)(void *ctx, struct http_request *req); - void *cb_ctx; - - int fd; - int port; - - struct http_request *requests; - unsigned int request_count; -}; - - -static void http_request_cb(struct httpread *handle, void *cookie, - enum httpread_event en) -{ - struct http_request *req = cookie; - struct http_server *srv = req->srv; - - if (en == HTTPREAD_EVENT_FILE_READY) { - wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d received", - inet_ntoa(req->cli.sin_addr), - ntohs(req->cli.sin_port)); - srv->cb(srv->cb_ctx, req); - return; - } - wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d could not be received " - "completely", inet_ntoa(req->cli.sin_addr), - ntohs(req->cli.sin_port)); - http_request_deinit(req); -} - - -static struct http_request * http_request_init(struct http_server *srv, int fd, - struct sockaddr_in *cli) -{ - struct http_request *req; - - if (srv->request_count >= HTTP_SERVER_MAX_CONNECTIONS) { - wpa_printf(MSG_DEBUG, "HTTP: Too many concurrent requests"); - return NULL; - } - - req = os_zalloc(sizeof(*req)); - if (req == NULL) - return NULL; - - req->srv = srv; - req->fd = fd; - req->cli = *cli; - - req->hread = httpread_create(req->fd, http_request_cb, req, - HTTP_SERVER_MAX_REQ_LEN, - HTTP_SERVER_TIMEOUT); - if (req->hread == NULL) { - http_request_deinit(req); - return NULL; - } - - return req; -} - - -void http_request_deinit(struct http_request *req) -{ - struct http_request *r, *p; - struct http_server *srv; - - if (req == NULL) - return; - - srv = req->srv; - p = NULL; - r = srv->requests; - while (r) { - if (r == req) { - if (p) - p->next = r->next; - else - srv->requests = r->next; - srv->request_count--; - break; - } - p = r; - r = r->next; - } - - httpread_destroy(req->hread); - close(req->fd); - os_free(req); -} - - -static void http_request_free_all(struct http_request *req) -{ - struct http_request *prev; - while (req) { - prev = req; - req = req->next; - http_request_deinit(prev); - } -} - - -void http_request_send(struct http_request *req, struct wpabuf *resp) -{ - int res; - - wpa_printf(MSG_DEBUG, "HTTP: Send %lu byte response to %s:%d", - (unsigned long) wpabuf_len(resp), - inet_ntoa(req->cli.sin_addr), - ntohs(req->cli.sin_port)); - - res = send(req->fd, wpabuf_head(resp), wpabuf_len(resp), 0); - if (res < 0) { - wpa_printf(MSG_DEBUG, "HTTP: Send failed: %s", - strerror(errno)); - } else if ((size_t) res < wpabuf_len(resp)) { - wpa_printf(MSG_DEBUG, "HTTP: Sent only %d of %lu bytes", - res, (unsigned long) wpabuf_len(resp)); - /* TODO: add eloop handler for sending rest of the data */ - } - - wpabuf_free(resp); -} - - -void http_request_send_and_deinit(struct http_request *req, - struct wpabuf *resp) -{ - http_request_send(req, resp); - http_request_deinit(req); -} - - -enum httpread_hdr_type http_request_get_type(struct http_request *req) -{ - return httpread_hdr_type_get(req->hread); -} - - -char * http_request_get_uri(struct http_request *req) -{ - return httpread_uri_get(req->hread); -} - - -char * http_request_get_hdr(struct http_request *req) -{ - return httpread_hdr_get(req->hread); -} - - -char * http_request_get_data(struct http_request *req) -{ - return httpread_data_get(req->hread); -} - - -char * http_request_get_hdr_line(struct http_request *req, const char *tag) -{ - return httpread_hdr_line_get(req->hread, tag); -} - - -struct sockaddr_in * http_request_get_cli_addr(struct http_request *req) -{ - return &req->cli; -} - - -static void http_server_cb(int sd, void *eloop_ctx, void *sock_ctx) -{ - struct sockaddr_in addr; - socklen_t addr_len = sizeof(addr); - struct http_server *srv = eloop_ctx; - int conn; - struct http_request *req; - - conn = accept(srv->fd, (struct sockaddr *) &addr, &addr_len); - if (conn < 0) { - wpa_printf(MSG_DEBUG, "HTTP: Failed to accept new connection: " - "%s", strerror(errno)); - return; - } - wpa_printf(MSG_DEBUG, "HTTP: Connection from %s:%d", - inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); - - req = http_request_init(srv, conn, &addr); - if (req == NULL) { - close(conn); - return; - } - - req->next = srv->requests; - srv->requests = req; - srv->request_count++; -} - - -struct http_server * http_server_init(struct in_addr *addr, int port, - void (*cb)(void *ctx, - struct http_request *req), - void *cb_ctx) -{ - struct sockaddr_in sin; - struct http_server *srv; - int on = 1; - - srv = os_zalloc(sizeof(*srv)); - if (srv == NULL) - return NULL; - srv->cb = cb; - srv->cb_ctx = cb_ctx; - - srv->fd = socket(AF_INET, SOCK_STREAM, 0); - if (srv->fd < 0) - goto fail; - - setsockopt(srv->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - - if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0) - goto fail; - if (port < 0) - srv->port = 49152; - else - srv->port = port; - - os_memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = addr->s_addr; - - for (;;) { - sin.sin_port = htons(srv->port); - if (bind(srv->fd, (struct sockaddr *) &sin, sizeof(sin)) == 0) - break; - if (errno == EADDRINUSE) { - /* search for unused port */ - if (++srv->port == 65535 || port >= 0) - goto fail; - continue; - } - wpa_printf(MSG_DEBUG, "HTTP: Failed to bind server port %d: " - "%s", srv->port, strerror(errno)); - goto fail; - } - if (listen(srv->fd, 10 /* max backlog */) < 0) - goto fail; - if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0) - goto fail; - if (eloop_register_sock(srv->fd, EVENT_TYPE_READ, http_server_cb, - srv, NULL)) - goto fail; - - wpa_printf(MSG_DEBUG, "HTTP: Started server on %s:%d", - inet_ntoa(*addr), srv->port); - - return srv; - -fail: - http_server_deinit(srv); - return NULL; -} - - -void http_server_deinit(struct http_server *srv) -{ - if (srv == NULL) - return; - if (srv->fd >= 0) { - eloop_unregister_sock(srv->fd, EVENT_TYPE_READ); - close(srv->fd); - } - http_request_free_all(srv->requests); - - os_free(srv); -} - - -int http_server_get_port(struct http_server *srv) -{ - return srv->port; -} diff --git a/contrib/hostapd/src/wps/http_server.h b/contrib/hostapd/src/wps/http_server.h deleted file mode 100644 index 4b2b749f16..0000000000 --- a/contrib/hostapd/src/wps/http_server.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * http_server - HTTP server - * Copyright (c) 2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef HTTP_SERVER_H -#define HTTP_SERVER_H - -struct http_server; -struct http_request; - -void http_request_deinit(struct http_request *req); -void http_request_send(struct http_request *req, struct wpabuf *resp); -void http_request_send_and_deinit(struct http_request *req, - struct wpabuf *resp); -enum httpread_hdr_type http_request_get_type(struct http_request *req); -char * http_request_get_uri(struct http_request *req); -char * http_request_get_hdr(struct http_request *req); -char * http_request_get_data(struct http_request *req); -char * http_request_get_hdr_line(struct http_request *req, const char *tag); -struct sockaddr_in * http_request_get_cli_addr(struct http_request *req); - -struct http_server * http_server_init(struct in_addr *addr, int port, - void (*cb)(void *ctx, - struct http_request *req), - void *cb_ctx); -void http_server_deinit(struct http_server *srv); -int http_server_get_port(struct http_server *srv); - -#endif /* HTTP_SERVER_H */ diff --git a/contrib/hostapd/src/wps/httpread.c b/contrib/hostapd/src/wps/httpread.c deleted file mode 100644 index b51d975712..0000000000 --- a/contrib/hostapd/src/wps/httpread.c +++ /dev/null @@ -1,826 +0,0 @@ -/* - * httpread - Manage reading file(s) from HTTP/TCP socket - * Author: Ted Merrill - * Copyright 2008 Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - * - * The files are buffered via internal callbacks from eloop, then presented to - * an application callback routine when completely read into memory. May also - * be used if no file is expected but just to get the header, including HTTP - * replies (e.g. HTTP/1.1 200 OK etc.). - * - * This does not attempt to be an optimally efficient implementation, but does - * attempt to be of reasonably small size and memory consumption; assuming that - * only small files are to be read. A maximum file size is provided by - * application and enforced. - * - * It is assumed that the application does not expect any of the following: - * -- transfer encoding other than chunked - * -- trailer fields - * It is assumed that, even if the other side requested that the connection be - * kept open, that we will close it (thus HTTP messages sent by application - * should have the connection closed field); this is allowed by HTTP/1.1 and - * simplifies things for us. - * - * Other limitations: - * -- HTTP header may not exceed a hard-coded size. - * - * Notes: - * This code would be massively simpler without some of the new features of - * HTTP/1.1, especially chunked data. - */ - -#include "includes.h" - -#include "common.h" -#include "eloop.h" -#include "httpread.h" - - -/* Tunable parameters */ -#define HTTPREAD_READBUF_SIZE 1024 /* read in chunks of this size */ -#define HTTPREAD_HEADER_MAX_SIZE 4096 /* max allowed for headers */ -#define HTTPREAD_BODYBUF_DELTA 4096 /* increase allocation by this */ - -#if 0 -/* httpread_debug -- set this global variable > 0 e.g. from debugger - * to enable debugs (larger numbers for more debugs) - * Make this a #define of 0 to eliminate the debugging code. - */ -int httpread_debug = 99; -#else -#define httpread_debug 0 /* eliminates even the debugging code */ -#endif - - -/* control instance -- actual definition (opaque to application) - */ -struct httpread { - /* information from creation */ - int sd; /* descriptor of TCP socket to read from */ - void (*cb)(struct httpread *handle, void *cookie, - enum httpread_event e); /* call on event */ - void *cookie; /* pass to callback */ - int max_bytes; /* maximum file size else abort it */ - int timeout_seconds; /* 0 or total duration timeout period */ - - /* dynamically used information follows */ - - int got_hdr; /* nonzero when header is finalized */ - char hdr[HTTPREAD_HEADER_MAX_SIZE+1]; /* headers stored here */ - int hdr_nbytes; - - enum httpread_hdr_type hdr_type; - int version; /* 1 if we've seen 1.1 */ - int reply_code; /* for type REPLY, e.g. 200 for HTTP/1.1 200 OK */ - int got_content_length; /* true if we know content length for sure */ - int content_length; /* body length, iff got_content_length */ - int chunked; /* nonzero for chunked data */ - char *uri; - - int got_body; /* nonzero when body is finalized */ - char *body; - int body_nbytes; - int body_alloc_nbytes; /* amount allocated */ - - int got_file; /* here when we are done */ - - /* The following apply if data is chunked: */ - int in_chunk_data; /* 0=in/at header, 1=in the data or tail*/ - int chunk_start; /* offset in body of chunk hdr or data */ - int chunk_size; /* data of chunk (not hdr or ending CRLF)*/ - int in_trailer; /* in header fields after data (chunked only)*/ - enum trailer_state { - trailer_line_begin = 0, - trailer_empty_cr, /* empty line + CR */ - trailer_nonempty, - trailer_nonempty_cr, - } trailer_state; -}; - - -/* Check words for equality, where words consist of graphical characters - * delimited by whitespace - * Returns nonzero if "equal" doing case insensitive comparison. - */ -static int word_eq(char *s1, char *s2) -{ - int c1; - int c2; - int end1 = 0; - int end2 = 0; - for (;;) { - c1 = *s1++; - c2 = *s2++; - if (isalpha(c1) && isupper(c1)) - c1 = tolower(c1); - if (isalpha(c2) && isupper(c2)) - c2 = tolower(c2); - end1 = !isgraph(c1); - end2 = !isgraph(c2); - if (end1 || end2 || c1 != c2) - break; - } - return end1 && end2; /* reached end of both words? */ -} - - -static void httpread_timeout_handler(void *eloop_data, void *user_ctx); - -/* httpread_destroy -- if h is non-NULL, clean up - * This must eventually be called by the application following - * call of the application's callback and may be called - * earlier if desired. - */ -void httpread_destroy(struct httpread *h) -{ - if (httpread_debug >= 10) - wpa_printf(MSG_DEBUG, "ENTER httpread_destroy(%p)", h); - if (!h) - return; - - eloop_cancel_timeout(httpread_timeout_handler, NULL, h); - eloop_unregister_sock(h->sd, EVENT_TYPE_READ); - os_free(h->body); - os_free(h->uri); - os_memset(h, 0, sizeof(*h)); /* aid debugging */ - h->sd = -1; /* aid debugging */ - os_free(h); -} - - -/* httpread_timeout_handler -- called on excessive total duration - */ -static void httpread_timeout_handler(void *eloop_data, void *user_ctx) -{ - struct httpread *h = user_ctx; - wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h); - (*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT); -} - - -/* Analyze options only so far as is needed to correctly obtain the file. - * The application can look at the raw header to find other options. - */ -static int httpread_hdr_option_analyze( - struct httpread *h, - char *hbp /* pointer to current line in header buffer */ - ) -{ - if (word_eq(hbp, "CONTENT-LENGTH:")) { - while (isgraph(*hbp)) - hbp++; - while (*hbp == ' ' || *hbp == '\t') - hbp++; - if (!isdigit(*hbp)) - return -1; - h->content_length = atol(hbp); - h->got_content_length = 1; - return 0; - } - if (word_eq(hbp, "TRANSFER_ENCODING:") || - word_eq(hbp, "TRANSFER-ENCODING:")) { - while (isgraph(*hbp)) - hbp++; - while (*hbp == ' ' || *hbp == '\t') - hbp++; - /* There should (?) be no encodings of interest - * other than chunked... - */ - if (word_eq(hbp, "CHUNKED")) { - h->chunked = 1; - h->in_chunk_data = 0; - /* ignore possible ; */ - } - return 0; - } - /* skip anything we don't know, which is a lot */ - return 0; -} - - -static int httpread_hdr_analyze(struct httpread *h) -{ - char *hbp = h->hdr; /* pointer into h->hdr */ - int standard_first_line = 1; - - /* First line is special */ - h->hdr_type = HTTPREAD_HDR_TYPE_UNKNOWN; - if (!isgraph(*hbp)) - goto bad; - if (os_strncmp(hbp, "HTTP/", 5) == 0) { - h->hdr_type = HTTPREAD_HDR_TYPE_REPLY; - standard_first_line = 0; - hbp += 5; - if (hbp[0] == '1' && hbp[1] == '.' && - isdigit(hbp[2]) && hbp[2] != '0') - h->version = 1; - while (isgraph(*hbp)) - hbp++; - while (*hbp == ' ' || *hbp == '\t') - hbp++; - if (!isdigit(*hbp)) - goto bad; - h->reply_code = atol(hbp); - } else if (word_eq(hbp, "GET")) - h->hdr_type = HTTPREAD_HDR_TYPE_GET; - else if (word_eq(hbp, "HEAD")) - h->hdr_type = HTTPREAD_HDR_TYPE_HEAD; - else if (word_eq(hbp, "POST")) - h->hdr_type = HTTPREAD_HDR_TYPE_POST; - else if (word_eq(hbp, "PUT")) - h->hdr_type = HTTPREAD_HDR_TYPE_PUT; - else if (word_eq(hbp, "DELETE")) - h->hdr_type = HTTPREAD_HDR_TYPE_DELETE; - else if (word_eq(hbp, "TRACE")) - h->hdr_type = HTTPREAD_HDR_TYPE_TRACE; - else if (word_eq(hbp, "CONNECT")) - h->hdr_type = HTTPREAD_HDR_TYPE_CONNECT; - else if (word_eq(hbp, "NOTIFY")) - h->hdr_type = HTTPREAD_HDR_TYPE_NOTIFY; - else if (word_eq(hbp, "M-SEARCH")) - h->hdr_type = HTTPREAD_HDR_TYPE_M_SEARCH; - else if (word_eq(hbp, "M-POST")) - h->hdr_type = HTTPREAD_HDR_TYPE_M_POST; - else if (word_eq(hbp, "SUBSCRIBE")) - h->hdr_type = HTTPREAD_HDR_TYPE_SUBSCRIBE; - else if (word_eq(hbp, "UNSUBSCRIBE")) - h->hdr_type = HTTPREAD_HDR_TYPE_UNSUBSCRIBE; - else { - } - - if (standard_first_line) { - char *rawuri; - char *uri; - /* skip type */ - while (isgraph(*hbp)) - hbp++; - while (*hbp == ' ' || *hbp == '\t') - hbp++; - /* parse uri. - * Find length, allocate memory for translated - * copy, then translate by changing % - * into represented value. - */ - rawuri = hbp; - while (isgraph(*hbp)) - hbp++; - h->uri = os_malloc((hbp - rawuri) + 1); - if (h->uri == NULL) - goto bad; - uri = h->uri; - while (rawuri < hbp) { - int c = *rawuri; - if (c == '%' && - isxdigit(rawuri[1]) && isxdigit(rawuri[2])) { - *uri++ = hex2byte(rawuri + 1); - rawuri += 3; - } else { - *uri++ = c; - rawuri++; - } - } - *uri = 0; /* null terminate */ - while (isgraph(*hbp)) - hbp++; - while (*hbp == ' ' || *hbp == '\t') - hbp++; - /* get version */ - if (0 == strncmp(hbp, "HTTP/", 5)) { - hbp += 5; - if (hbp[0] == '1' && hbp[1] == '.' && - isdigit(hbp[2]) && hbp[2] != '0') - h->version = 1; - } - } - /* skip rest of line */ - while (*hbp) - if (*hbp++ == '\n') - break; - - /* Remainder of lines are options, in any order; - * or empty line to terminate - */ - for (;;) { - /* Empty line to terminate */ - if (hbp[0] == '\n' || - (hbp[0] == '\r' && hbp[1] == '\n')) - break; - if (!isgraph(*hbp)) - goto bad; - if (httpread_hdr_option_analyze(h, hbp)) - goto bad; - /* skip line */ - while (*hbp) - if (*hbp++ == '\n') - break; - } - - /* chunked overrides content-length always */ - if (h->chunked) - h->got_content_length = 0; - - /* For some types, we should not try to read a body - * This is in addition to the application determining - * that we should not read a body. - */ - switch (h->hdr_type) { - case HTTPREAD_HDR_TYPE_REPLY: - /* Some codes can have a body and some not. - * For now, just assume that any other than 200 - * do not... - */ - if (h->reply_code != 200) - h->max_bytes = 0; - break; - case HTTPREAD_HDR_TYPE_GET: - case HTTPREAD_HDR_TYPE_HEAD: - /* in practice it appears that it is assumed - * that GETs have a body length of 0... ? - */ - if (h->chunked == 0 && h->got_content_length == 0) - h->max_bytes = 0; - break; - case HTTPREAD_HDR_TYPE_POST: - case HTTPREAD_HDR_TYPE_PUT: - case HTTPREAD_HDR_TYPE_DELETE: - case HTTPREAD_HDR_TYPE_TRACE: - case HTTPREAD_HDR_TYPE_CONNECT: - case HTTPREAD_HDR_TYPE_NOTIFY: - case HTTPREAD_HDR_TYPE_M_SEARCH: - case HTTPREAD_HDR_TYPE_M_POST: - case HTTPREAD_HDR_TYPE_SUBSCRIBE: - case HTTPREAD_HDR_TYPE_UNSUBSCRIBE: - default: - break; - } - - return 0; - -bad: - /* Error */ - return -1; -} - - -/* httpread_read_handler -- called when socket ready to read - * - * Note: any extra data we read past end of transmitted file is ignored; - * if we were to support keeping connections open for multiple files then - * this would have to be addressed. - */ -static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx) -{ - struct httpread *h = sock_ctx; - int nread; - char *rbp; /* pointer into read buffer */ - char *hbp; /* pointer into header buffer */ - char *bbp; /* pointer into body buffer */ - char readbuf[HTTPREAD_READBUF_SIZE]; /* temp use to read into */ - - if (httpread_debug >= 20) - wpa_printf(MSG_DEBUG, "ENTER httpread_read_handler(%p)", h); - - /* read some at a time, then search for the interal - * boundaries between header and data and etc. - */ - nread = read(h->sd, readbuf, sizeof(readbuf)); - if (nread < 0) - goto bad; - if (nread == 0) { - /* end of transmission... this may be normal - * or may be an error... in some cases we can't - * tell which so we must assume it is normal then. - */ - if (!h->got_hdr) { - /* Must at least have completed header */ - wpa_printf(MSG_DEBUG, "httpread premature eof(%p)", h); - goto bad; - } - if (h->chunked || h->got_content_length) { - /* Premature EOF; e.g. dropped connection */ - wpa_printf(MSG_DEBUG, - "httpread premature eof(%p) %d/%d", - h, h->body_nbytes, - h->content_length); - goto bad; - } - /* No explicit length, hopefully we have all the data - * although dropped connections can cause false - * end - */ - if (httpread_debug >= 10) - wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h); - h->got_body = 1; - goto got_file; - } - rbp = readbuf; - - /* Header consists of text lines (terminated by both CR and LF) - * and an empty line (CR LF only). - */ - if (!h->got_hdr) { - hbp = h->hdr + h->hdr_nbytes; - /* add to headers until: - * -- we run out of data in read buffer - * -- or, we run out of header buffer room - * -- or, we get double CRLF in headers - */ - for (;;) { - if (nread == 0) - goto get_more; - if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) { - goto bad; - } - *hbp++ = *rbp++; - nread--; - h->hdr_nbytes++; - if (h->hdr_nbytes >= 4 && - hbp[-1] == '\n' && - hbp[-2] == '\r' && - hbp[-3] == '\n' && - hbp[-4] == '\r' ) { - h->got_hdr = 1; - *hbp = 0; /* null terminate */ - break; - } - } - /* here we've just finished reading the header */ - if (httpread_hdr_analyze(h)) { - wpa_printf(MSG_DEBUG, "httpread bad hdr(%p)", h); - goto bad; - } - if (h->max_bytes == 0) { - if (httpread_debug >= 10) - wpa_printf(MSG_DEBUG, - "httpread no body hdr end(%p)", h); - goto got_file; - } - if (h->got_content_length && h->content_length == 0) { - if (httpread_debug >= 10) - wpa_printf(MSG_DEBUG, - "httpread zero content length(%p)", - h); - goto got_file; - } - } - - /* Certain types of requests never have data and so - * must be specially recognized. - */ - if (!os_strncasecmp(h->hdr, "SUBSCRIBE", 9) || - !os_strncasecmp(h->hdr, "UNSUBSCRIBE", 11) || - !os_strncasecmp(h->hdr, "HEAD", 4) || - !os_strncasecmp(h->hdr, "GET", 3)) { - if (!h->got_body) { - if (httpread_debug >= 10) - wpa_printf(MSG_DEBUG, - "httpread NO BODY for sp. type"); - } - h->got_body = 1; - goto got_file; - } - - /* Data can be just plain binary data, or if "chunked" - * consists of chunks each with a header, ending with - * an ending header. - */ - if (nread == 0) - goto get_more; - if (!h->got_body) { - /* Here to get (more of) body */ - /* ensure we have enough room for worst case for body - * plus a null termination character - */ - if (h->body_alloc_nbytes < (h->body_nbytes + nread + 1)) { - char *new_body; - int new_alloc_nbytes; - - if (h->body_nbytes >= h->max_bytes) - goto bad; - new_alloc_nbytes = h->body_alloc_nbytes + - HTTPREAD_BODYBUF_DELTA; - /* For content-length case, the first time - * through we allocate the whole amount - * we need. - */ - if (h->got_content_length && - new_alloc_nbytes < (h->content_length + 1)) - new_alloc_nbytes = h->content_length + 1; - if ((new_body = os_realloc(h->body, new_alloc_nbytes)) - == NULL) - goto bad; - - h->body = new_body; - h->body_alloc_nbytes = new_alloc_nbytes; - } - /* add bytes */ - bbp = h->body + h->body_nbytes; - for (;;) { - int ncopy; - /* See if we need to stop */ - if (h->chunked && h->in_chunk_data == 0) { - /* in chunk header */ - char *cbp = h->body + h->chunk_start; - if (bbp-cbp >= 2 && bbp[-2] == '\r' && - bbp[-1] == '\n') { - /* end of chunk hdr line */ - /* hdr line consists solely - * of a hex numeral and CFLF - */ - if (!isxdigit(*cbp)) - goto bad; - h->chunk_size = strtoul(cbp, NULL, 16); - /* throw away chunk header - * so we have only real data - */ - h->body_nbytes = h->chunk_start; - bbp = cbp; - if (h->chunk_size == 0) { - /* end of chunking */ - /* trailer follows */ - h->in_trailer = 1; - if (httpread_debug >= 20) - wpa_printf( - MSG_DEBUG, - "httpread end chunks(%p)", h); - break; - } - h->in_chunk_data = 1; - /* leave chunk_start alone */ - } - } else if (h->chunked) { - /* in chunk data */ - if ((h->body_nbytes - h->chunk_start) == - (h->chunk_size + 2)) { - /* end of chunk reached, - * new chunk starts - */ - /* check chunk ended w/ CRLF - * which we'll throw away - */ - if (bbp[-1] == '\n' && - bbp[-2] == '\r') { - } else - goto bad; - h->body_nbytes -= 2; - bbp -= 2; - h->chunk_start = h->body_nbytes; - h->in_chunk_data = 0; - h->chunk_size = 0; /* just in case */ - } - } else if (h->got_content_length && - h->body_nbytes >= h->content_length) { - h->got_body = 1; - if (httpread_debug >= 10) - wpa_printf( - MSG_DEBUG, - "httpread got content(%p)", h); - goto got_file; - } - if (nread <= 0) - break; - /* Now transfer. Optimize using memcpy where we can. */ - if (h->chunked && h->in_chunk_data) { - /* copy up to remainder of chunk data - * plus the required CR+LF at end - */ - ncopy = (h->chunk_start + h->chunk_size + 2) - - h->body_nbytes; - } else if (h->chunked) { - /*in chunk header -- don't optimize */ - *bbp++ = *rbp++; - nread--; - h->body_nbytes++; - continue; - } else if (h->got_content_length) { - ncopy = h->content_length - h->body_nbytes; - } else { - ncopy = nread; - } - /* Note: should never be 0 */ - if (ncopy > nread) - ncopy = nread; - os_memcpy(bbp, rbp, ncopy); - bbp += ncopy; - h->body_nbytes += ncopy; - rbp += ncopy; - nread -= ncopy; - } /* body copy loop */ - } /* !got_body */ - if (h->chunked && h->in_trailer) { - /* If "chunked" then there is always a trailer, - * consisting of zero or more non-empty lines - * ending with CR LF and then an empty line w/ CR LF. - * We do NOT support trailers except to skip them -- - * this is supported (generally) by the http spec. - */ - bbp = h->body + h->body_nbytes; - for (;;) { - int c; - if (nread <= 0) - break; - c = *rbp++; - nread--; - switch (h->trailer_state) { - case trailer_line_begin: - if (c == '\r') - h->trailer_state = trailer_empty_cr; - else - h->trailer_state = trailer_nonempty; - break; - case trailer_empty_cr: - /* end empty line */ - if (c == '\n') { - h->trailer_state = trailer_line_begin; - h->in_trailer = 0; - if (httpread_debug >= 10) - wpa_printf( - MSG_DEBUG, - "httpread got content(%p)", h); - h->got_body = 1; - goto got_file; - } - h->trailer_state = trailer_nonempty; - break; - case trailer_nonempty: - if (c == '\r') - h->trailer_state = trailer_nonempty_cr; - break; - case trailer_nonempty_cr: - if (c == '\n') - h->trailer_state = trailer_line_begin; - else - h->trailer_state = trailer_nonempty; - break; - } - } - } - goto get_more; - -bad: - /* Error */ - wpa_printf(MSG_DEBUG, "httpread read/parse failure (%p)", h); - (*h->cb)(h, h->cookie, HTTPREAD_EVENT_ERROR); - return; - -get_more: - return; - -got_file: - if (httpread_debug >= 10) - wpa_printf(MSG_DEBUG, - "httpread got file %d bytes type %d", - h->body_nbytes, h->hdr_type); - /* Null terminate for convenience of some applications */ - if (h->body) - h->body[h->body_nbytes] = 0; /* null terminate */ - h->got_file = 1; - /* Assume that we do NOT support keeping connection alive, - * and just in case somehow we don't get destroyed right away, - * unregister now. - */ - eloop_unregister_sock(h->sd, EVENT_TYPE_READ); - /* The application can destroy us whenever they feel like... - * cancel timeout. - */ - eloop_cancel_timeout(httpread_timeout_handler, NULL, h); - (*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY); -} - - -/* httpread_create -- start a new reading session making use of eloop. - * The new instance will use the socket descriptor for reading (until - * it gets a file and not after) but will not close the socket, even - * when the instance is destroyed (the application must do that). - * Return NULL on error. - * - * Provided that httpread_create successfully returns a handle, - * the callback fnc is called to handle httpread_event events. - * The caller should do destroy on any errors or unknown events. - * - * Pass max_bytes == 0 to not read body at all (required for e.g. - * reply to HEAD request). - */ -struct httpread * httpread_create( - int sd, /* descriptor of TCP socket to read from */ - void (*cb)(struct httpread *handle, void *cookie, - enum httpread_event e), /* call on event */ - void *cookie, /* pass to callback */ - int max_bytes, /* maximum body size else abort it */ - int timeout_seconds /* 0; or total duration timeout period */ - ) -{ - struct httpread *h = NULL; - - h = os_zalloc(sizeof(*h)); - if (h == NULL) - goto fail; - h->sd = sd; - h->cb = cb; - h->cookie = cookie; - h->max_bytes = max_bytes; - h->timeout_seconds = timeout_seconds; - - if (timeout_seconds > 0 && - eloop_register_timeout(timeout_seconds, 0, - httpread_timeout_handler, NULL, h)) { - /* No way to recover (from malloc failure) */ - goto fail; - } - if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler, - NULL, h)) { - /* No way to recover (from malloc failure) */ - goto fail; - } - return h; - -fail: - - /* Error */ - httpread_destroy(h); - return NULL; -} - - -/* httpread_hdr_type_get -- When file is ready, returns header type. */ -enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h) -{ - return h->hdr_type; -} - - -/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI - * or possibly NULL (which would be an error). - */ -char * httpread_uri_get(struct httpread *h) -{ - return h->uri; -} - - -/* httpread_reply_code_get -- When reply is ready, returns reply code */ -int httpread_reply_code_get(struct httpread *h) -{ - return h->reply_code; -} - - -/* httpread_length_get -- When file is ready, returns file length. */ -int httpread_length_get(struct httpread *h) -{ - return h->body_nbytes; -} - - -/* httpread_data_get -- When file is ready, returns file content - * with null byte appened. - * Might return NULL in some error condition. - */ -void * httpread_data_get(struct httpread *h) -{ - return h->body ? h->body : ""; -} - - -/* httpread_hdr_get -- When file is ready, returns header content - * with null byte appended. - * Might return NULL in some error condition. - */ -char * httpread_hdr_get(struct httpread *h) -{ - return h->hdr; -} - - -/* httpread_hdr_line_get -- When file is ready, returns pointer - * to line within header content matching the given tag - * (after the tag itself and any spaces/tabs). - * - * The tag should end with a colon for reliable matching. - * - * If not found, returns NULL; - */ -char * httpread_hdr_line_get(struct httpread *h, const char *tag) -{ - int tag_len = os_strlen(tag); - char *hdr = h->hdr; - hdr = os_strchr(hdr, '\n'); - if (hdr == NULL) - return NULL; - hdr++; - for (;;) { - if (!os_strncasecmp(hdr, tag, tag_len)) { - hdr += tag_len; - while (*hdr == ' ' || *hdr == '\t') - hdr++; - return hdr; - } - hdr = os_strchr(hdr, '\n'); - if (hdr == NULL) - return NULL; - hdr++; - } -} diff --git a/contrib/hostapd/src/wps/httpread.h b/contrib/hostapd/src/wps/httpread.h deleted file mode 100644 index 454b618bf4..0000000000 --- a/contrib/hostapd/src/wps/httpread.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * httpread - Manage reading file(s) from HTTP/TCP socket - * Author: Ted Merrill - * Copyright 2008 Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef HTTPREAD_H -#define HTTPREAD_H - -/* event types (passed to callback) */ -enum httpread_event { - HTTPREAD_EVENT_FILE_READY = 1, /* including reply ready */ - HTTPREAD_EVENT_TIMEOUT = 2, - HTTPREAD_EVENT_ERROR = 3 /* misc. error, esp malloc error */ -}; - - -/* header type detected - * available to callback via call to httpread_reply_code_get() - */ -enum httpread_hdr_type { - HTTPREAD_HDR_TYPE_UNKNOWN = 0, /* none of the following */ - HTTPREAD_HDR_TYPE_REPLY = 1, /* hdr begins w/ HTTP/ */ - HTTPREAD_HDR_TYPE_GET = 2, /* hdr begins with GET */ - HTTPREAD_HDR_TYPE_HEAD = 3, /* hdr begins with HEAD */ - HTTPREAD_HDR_TYPE_POST = 4, /* hdr begins with POST */ - HTTPREAD_HDR_TYPE_PUT = 5, /* hdr begins with ... */ - HTTPREAD_HDR_TYPE_DELETE = 6, /* hdr begins with ... */ - HTTPREAD_HDR_TYPE_TRACE = 7, /* hdr begins with ... */ - HTTPREAD_HDR_TYPE_CONNECT = 8, /* hdr begins with ... */ - HTTPREAD_HDR_TYPE_NOTIFY = 9, /* hdr begins with ... */ - HTTPREAD_HDR_TYPE_M_SEARCH = 10, /* hdr begins with ... */ - HTTPREAD_HDR_TYPE_M_POST = 11, /* hdr begins with ... */ - HTTPREAD_HDR_TYPE_SUBSCRIBE = 12, /* hdr begins with ... */ - HTTPREAD_HDR_TYPE_UNSUBSCRIBE = 13, /* hdr begins with ... */ - - HTTPREAD_N_HDR_TYPES /* keep last */ -}; - - -/* control instance -- opaque struct declaration - */ -struct httpread; - - -/* httpread_destroy -- if h is non-NULL, clean up - * This must eventually be called by the application following - * call of the application's callback and may be called - * earlier if desired. - */ -void httpread_destroy(struct httpread *h); - -/* httpread_create -- start a new reading session making use of eloop. - * The new instance will use the socket descriptor for reading (until - * it gets a file and not after) but will not close the socket, even - * when the instance is destroyed (the application must do that). - * Return NULL on error. - * - * Provided that httpread_create successfully returns a handle, - * the callback fnc is called to handle httpread_event events. - * The caller should do destroy on any errors or unknown events. - * - * Pass max_bytes == 0 to not read body at all (required for e.g. - * reply to HEAD request). - */ -struct httpread * httpread_create( - int sd, /* descriptor of TCP socket to read from */ - void (*cb)(struct httpread *handle, void *cookie, - enum httpread_event e), /* call on event */ - void *cookie, /* pass to callback */ - int max_bytes, /* maximum file size else abort it */ - int timeout_seconds /* 0; or total duration timeout period */ - ); - -/* httpread_hdr_type_get -- When file is ready, returns header type. - */ -enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h); - - -/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI - * or possibly NULL (which would be an error). - */ -char *httpread_uri_get(struct httpread *h); - -/* httpread_reply_code_get -- When reply is ready, returns reply code */ -int httpread_reply_code_get(struct httpread *h); - - -/* httpread_length_get -- When file is ready, returns file length. */ -int httpread_length_get(struct httpread *h); - -/* httpread_data_get -- When file is ready, returns file content - * with null byte appened. - * Might return NULL in some error condition. - */ -void * httpread_data_get(struct httpread *h); - -/* httpread_hdr_get -- When file is ready, returns header content - * with null byte appended. - * Might return NULL in some error condition. - */ -char * httpread_hdr_get(struct httpread *h); - -/* httpread_hdr_line_get -- When file is ready, returns pointer - * to line within header content matching the given tag - * (after the tag itself and any spaces/tabs). - * - * The tag should end with a colon for reliable matching. - * - * If not found, returns NULL; - */ -char * httpread_hdr_line_get(struct httpread *h, const char *tag); - -#endif /* HTTPREAD_H */ diff --git a/contrib/hostapd/src/wps/ndef.c b/contrib/hostapd/src/wps/ndef.c deleted file mode 100644 index 2b3506476e..0000000000 --- a/contrib/hostapd/src/wps/ndef.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * NDEF(NFC Data Exchange Format) routines for Wi-Fi Protected Setup - * Reference is "NFCForum-TS-NDEF_1.0 2006-07-24". - * Copyright (c) 2009-2012, Masashi Honma - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" -#include "common.h" -#include "wps/wps.h" - -#define FLAG_MESSAGE_BEGIN (1 << 7) -#define FLAG_MESSAGE_END (1 << 6) -#define FLAG_CHUNK (1 << 5) -#define FLAG_SHORT_RECORD (1 << 4) -#define FLAG_ID_LENGTH_PRESENT (1 << 3) -#define FLAG_TNF_NFC_FORUM (0x01) -#define FLAG_TNF_RFC2046 (0x02) - -struct ndef_record { - const u8 *type; - const u8 *id; - const u8 *payload; - u8 type_length; - u8 id_length; - u32 payload_length; - u32 total_length; -}; - -static char wifi_handover_type[] = "application/vnd.wfa.wsc"; -static char p2p_handover_type[] = "application/vnd.wfa.p2p"; - -static int ndef_parse_record(const u8 *data, u32 size, - struct ndef_record *record) -{ - const u8 *pos = data + 1; - - if (size < 2) - return -1; - record->type_length = *pos++; - if (data[0] & FLAG_SHORT_RECORD) { - if (size < 3) - return -1; - record->payload_length = *pos++; - } else { - if (size < 6) - return -1; - record->payload_length = ntohl(*(u32 *)pos); - pos += sizeof(u32); - } - - if (data[0] & FLAG_ID_LENGTH_PRESENT) { - if ((int) size < pos - data + 1) - return -1; - record->id_length = *pos++; - } else - record->id_length = 0; - - record->type = record->type_length == 0 ? NULL : pos; - pos += record->type_length; - - record->id = record->id_length == 0 ? NULL : pos; - pos += record->id_length; - - record->payload = record->payload_length == 0 ? NULL : pos; - pos += record->payload_length; - - record->total_length = pos - data; - if (record->total_length > size) - return -1; - return 0; -} - - -static struct wpabuf * ndef_parse_records(const struct wpabuf *buf, - int (*filter)(struct ndef_record *)) -{ - struct ndef_record record; - int len = wpabuf_len(buf); - const u8 *data = wpabuf_head(buf); - - while (len > 0) { - if (ndef_parse_record(data, len, &record) < 0) { - wpa_printf(MSG_ERROR, "NDEF : Failed to parse"); - return NULL; - } - if (filter == NULL || filter(&record)) - return wpabuf_alloc_copy(record.payload, - record.payload_length); - data += record.total_length; - len -= record.total_length; - } - wpa_printf(MSG_ERROR, "NDEF : Record not found"); - return NULL; -} - - -static struct wpabuf * ndef_build_record(u8 flags, void *type, - u8 type_length, void *id, - u8 id_length, - const struct wpabuf *payload) -{ - struct wpabuf *record; - size_t total_len; - int short_record; - u8 local_flag; - size_t payload_length = wpabuf_len(payload); - - short_record = payload_length < 256 ? 1 : 0; - - total_len = 2; /* flag + type length */ - /* payload length */ - total_len += short_record ? sizeof(u8) : sizeof(u32); - if (id_length > 0) - total_len += 1; - total_len += type_length + id_length + payload_length; - record = wpabuf_alloc(total_len); - if (record == NULL) { - wpa_printf(MSG_ERROR, "NDEF : Failed to allocate " - "record for build"); - return NULL; - } - - local_flag = flags; - if (id_length > 0) - local_flag |= FLAG_ID_LENGTH_PRESENT; - if (short_record) - local_flag |= FLAG_SHORT_RECORD; - wpabuf_put_u8(record, local_flag); - - wpabuf_put_u8(record, type_length); - - if (short_record) - wpabuf_put_u8(record, payload_length); - else - wpabuf_put_be32(record, payload_length); - - if (id_length > 0) - wpabuf_put_u8(record, id_length); - wpabuf_put_data(record, type, type_length); - wpabuf_put_data(record, id, id_length); - wpabuf_put_buf(record, payload); - return record; -} - - -static int wifi_filter(struct ndef_record *record) -{ - if (record->type_length != os_strlen(wifi_handover_type)) - return 0; - if (os_memcmp(record->type, wifi_handover_type, - os_strlen(wifi_handover_type)) != 0) - return 0; - return 1; -} - - -struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf) -{ - return ndef_parse_records(buf, wifi_filter); -} - - -struct wpabuf * ndef_build_wifi(const struct wpabuf *buf) -{ - return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END | - FLAG_TNF_RFC2046, wifi_handover_type, - os_strlen(wifi_handover_type), NULL, 0, buf); -} - - -static int p2p_filter(struct ndef_record *record) -{ - if (record->type_length != os_strlen(p2p_handover_type)) - return 0; - if (os_memcmp(record->type, p2p_handover_type, - os_strlen(p2p_handover_type)) != 0) - return 0; - return 1; -} - - -struct wpabuf * ndef_parse_p2p(const struct wpabuf *buf) -{ - return ndef_parse_records(buf, p2p_filter); -} - - -struct wpabuf * ndef_build_p2p(const struct wpabuf *buf) -{ - return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END | - FLAG_TNF_RFC2046, p2p_handover_type, - os_strlen(p2p_handover_type), NULL, 0, buf); -} diff --git a/contrib/hostapd/src/wps/upnp_xml.c b/contrib/hostapd/src/wps/upnp_xml.c deleted file mode 100644 index a9958eeda8..0000000000 --- a/contrib/hostapd/src/wps/upnp_xml.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * UPnP XML helper routines - * Copyright (c) 2000-2003 Intel Corporation - * Copyright (c) 2006-2007 Sony Corporation - * Copyright (c) 2008-2009 Atheros Communications - * Copyright (c) 2009, Jouni Malinen - * - * See wps_upnp.c for more details on licensing and code history. - */ - -#include "includes.h" - -#include "common.h" -#include "base64.h" -#include "http.h" -#include "upnp_xml.h" - - -/* - * XML parsing and formatting - * - * XML is a markup language based on unicode; usually (and in our case, - * always!) based on utf-8. utf-8 uses a variable number of bytes per - * character. utf-8 has the advantage that all non-ASCII unicode characters are - * represented by sequences of non-ascii (high bit set) bytes, whereas ASCII - * characters are single ascii bytes, thus we can use typical text processing. - * - * (One other interesting thing about utf-8 is that it is possible to look at - * any random byte and determine if it is the first byte of a character as - * versus a continuation byte). - * - * The base syntax of XML uses a few ASCII punctionation characters; any - * characters that would appear in the payload data are rewritten using - * sequences, e.g., & for ampersand(&) and < for left angle bracket (<). - * Five such escapes total (more can be defined but that does not apply to our - * case). Thus we can safely parse for angle brackets etc. - * - * XML describes tree structures of tagged data, with each element beginning - * with an opening tag with - * matching label. (There is also a self-closing tag