aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2017-10-18 03:44:27 +0000
committerCy Schubert <cy@FreeBSD.org>2017-10-18 03:44:27 +0000
commit256810032c472505440606bd9c1c4f7dbf06b0a2 (patch)
treed019f4f1ae29b86cbd3e9e74f832689976a267cf
parentb834757ea3bcd1bba3381ff7cab216458d8f7efb (diff)
downloadsrc-256810032c472505440606bd9c1c4f7dbf06b0a2.tar.gz
src-256810032c472505440606bd9c1c4f7dbf06b0a2.zip
Import wpa_supplicant/hostapd 2.6.vendor/wpa/2.6
Notes
Notes: svn path=/vendor/wpa/dist/; revision=324714 svn path=/vendor/wpa/2.6/; revision=324715; tag=vendor/wpa/2.6
-rw-r--r--CONTRIBUTIONS30
-rw-r--r--COPYING2
-rw-r--r--README2
-rw-r--r--hostapd/Android.mk1001
-rw-r--r--hostapd/ChangeLog73
-rw-r--r--hostapd/Makefile106
-rw-r--r--hostapd/README2
-rw-r--r--hostapd/android.config201
-rw-r--r--hostapd/config_file.c216
-rw-r--r--hostapd/ctrl_iface.c860
-rw-r--r--hostapd/defconfig17
-rw-r--r--hostapd/hapd_module_tests.c1
-rw-r--r--hostapd/hlr_auc_gw.c136
-rw-r--r--hostapd/hostapd.android.rc20
-rw-r--r--hostapd/hostapd.conf143
-rw-r--r--hostapd/hostapd_cli.c650
-rw-r--r--hostapd/main.c131
-rw-r--r--hs20/client/Android.mk2
-rw-r--r--hs20/client/Makefile1
-rw-r--r--hs20/client/est.c60
-rw-r--r--hs20/client/osu_client.c35
-rw-r--r--patches/openssl-0.9.8za-tls-extensions.patch397
-rw-r--r--patches/openssl-0.9.8zf-tls-extensions.patch398
-rw-r--r--src/ap/accounting.c256
-rw-r--r--src/ap/accounting.h7
-rw-r--r--src/ap/acs.c6
-rw-r--r--src/ap/ap_config.c70
-rw-r--r--src/ap/ap_config.h55
-rw-r--r--src/ap/ap_drv_ops.c228
-rw-r--r--src/ap/ap_drv_ops.h18
-rw-r--r--src/ap/ap_mlme.c3
-rw-r--r--src/ap/authsrv.c3
-rw-r--r--src/ap/beacon.c242
-rw-r--r--src/ap/beacon.h3
-rw-r--r--src/ap/ctrl_iface_ap.c121
-rw-r--r--src/ap/ctrl_iface_ap.h8
-rw-r--r--src/ap/dfs.c26
-rw-r--r--src/ap/dhcp_snoop.c3
-rw-r--r--src/ap/drv_callbacks.c111
-rw-r--r--src/ap/gas_serv.c297
-rw-r--r--src/ap/gas_serv.h19
-rw-r--r--src/ap/hostapd.c424
-rw-r--r--src/ap/hostapd.h56
-rw-r--r--src/ap/hw_features.c6
-rw-r--r--src/ap/iapp.c17
-rw-r--r--src/ap/ieee802_11.c631
-rw-r--r--src/ap/ieee802_11.h33
-rw-r--r--src/ap/ieee802_11_auth.c154
-rw-r--r--src/ap/ieee802_11_auth.h5
-rw-r--r--src/ap/ieee802_11_ht.c23
-rw-r--r--src/ap/ieee802_11_shared.c78
-rw-r--r--src/ap/ieee802_11_vht.c202
-rw-r--r--src/ap/ieee802_1x.c239
-rw-r--r--src/ap/ieee802_1x.h2
-rw-r--r--src/ap/mbo_ap.c244
-rw-r--r--src/ap/mbo_ap.h51
-rw-r--r--src/ap/ndisc_snoop.c1
-rw-r--r--src/ap/neighbor_db.c133
-rw-r--r--src/ap/neighbor_db.h24
-rw-r--r--src/ap/pmksa_cache_auth.c111
-rw-r--r--src/ap/pmksa_cache_auth.h14
-rw-r--r--src/ap/rrm.c544
-rw-r--r--src/ap/rrm.h28
-rw-r--r--src/ap/sta_info.c322
-rw-r--r--src/ap/sta_info.h74
-rw-r--r--src/ap/taxonomy.c291
-rw-r--r--src/ap/taxonomy.h24
-rw-r--r--src/ap/vlan.c34
-rw-r--r--src/ap/vlan.h30
-rw-r--r--src/ap/vlan_full.c752
-rw-r--r--src/ap/vlan_ifconfig.c69
-rw-r--r--src/ap/vlan_init.c973
-rw-r--r--src/ap/vlan_init.h17
-rw-r--r--src/ap/vlan_ioctl.c155
-rw-r--r--src/ap/vlan_util.c44
-rw-r--r--src/ap/vlan_util.h18
-rw-r--r--src/ap/wnm_ap.c39
-rw-r--r--src/ap/wnm_ap.h3
-rw-r--r--src/ap/wpa_auth.c223
-rw-r--r--src/ap/wpa_auth.h40
-rw-r--r--src/ap/wpa_auth_ft.c10
-rw-r--r--src/ap/wpa_auth_glue.c20
-rw-r--r--src/ap/wpa_auth_i.h4
-rw-r--r--src/ap/wpa_auth_ie.c19
-rw-r--r--src/ap/wps_hostapd.c34
-rw-r--r--src/common/cli.c267
-rw-r--r--src/common/cli.h47
-rw-r--r--src/common/common_module_tests.c1
-rw-r--r--src/common/ctrl_iface_common.c173
-rw-r--r--src/common/ctrl_iface_common.h38
-rw-r--r--src/common/defs.h15
-rw-r--r--src/common/eapol_common.h2
-rw-r--r--src/common/ieee802_11_common.c212
-rw-r--r--src/common/ieee802_11_common.h28
-rw-r--r--src/common/ieee802_11_defs.h245
-rw-r--r--src/common/ieee802_1x_defs.h2
-rw-r--r--src/common/linux_bridge.h24
-rw-r--r--src/common/linux_vlan.h52
-rw-r--r--src/common/qca-vendor.h1235
-rw-r--r--src/common/sae.c32
-rw-r--r--src/common/sae.h1
-rw-r--r--src/common/version.h6
-rw-r--r--src/common/wpa_common.c141
-rw-r--r--src/common/wpa_common.h4
-rw-r--r--src/common/wpa_ctrl.c2
-rw-r--r--src/common/wpa_ctrl.h32
-rw-r--r--src/common/wpa_helpers.c3
-rw-r--r--src/crypto/Makefile4
-rw-r--r--src/crypto/aes-cbc.c6
-rw-r--r--src/crypto/aes-omac1.c3
-rw-r--r--src/crypto/crypto.h25
-rw-r--r--src/crypto/crypto_internal.c50
-rw-r--r--src/crypto/crypto_module_tests.c61
-rw-r--r--src/crypto/crypto_openssl.c403
-rw-r--r--src/crypto/dh_group5.c1
-rw-r--r--src/crypto/dh_groups.c7
-rw-r--r--src/crypto/fips_prf_openssl.c25
-rw-r--r--src/crypto/md4-internal.c3
-rw-r--r--src/crypto/md5-internal.c3
-rw-r--r--src/crypto/ms_funcs.c2
-rw-r--r--src/crypto/sha1-internal.c4
-rw-r--r--src/crypto/sha256-internal.c3
-rw-r--r--src/crypto/sha256-prf.c26
-rw-r--r--src/crypto/sha256.h12
-rw-r--r--src/crypto/sha384-internal.c92
-rw-r--r--src/crypto/sha384_i.h23
-rw-r--r--src/crypto/sha512-internal.c264
-rw-r--r--src/crypto/sha512_i.h25
-rw-r--r--src/crypto/tls.h47
-rw-r--r--src/crypto/tls_gnutls.c81
-rw-r--r--src/crypto/tls_internal.c64
-rw-r--r--src/crypto/tls_none.c12
-rw-r--r--src/crypto/tls_openssl.c586
-rw-r--r--src/crypto/tls_openssl.h19
-rw-r--r--src/crypto/tls_openssl_ocsp.c846
-rw-r--r--src/drivers/driver.h344
-rw-r--r--src/drivers/driver_atheros.c176
-rw-r--r--src/drivers/driver_bsd.c346
-rw-r--r--src/drivers/driver_common.c57
-rw-r--r--src/drivers/driver_hostap.c19
-rw-r--r--src/drivers/driver_macsec_qca.c14
-rw-r--r--src/drivers/driver_ndis.c16
-rw-r--r--src/drivers/driver_nl80211.c1163
-rw-r--r--src/drivers/driver_nl80211.h36
-rw-r--r--src/drivers/driver_nl80211_capa.c246
-rw-r--r--src/drivers/driver_nl80211_event.c309
-rw-r--r--src/drivers/driver_nl80211_monitor.c2
-rw-r--r--src/drivers/driver_nl80211_scan.c408
-rw-r--r--src/drivers/driver_privsep.c4
-rw-r--r--src/drivers/driver_roboswitch.c6
-rw-r--r--src/drivers/driver_wext.c30
-rw-r--r--src/drivers/driver_wired.c11
-rw-r--r--src/drivers/drivers.c36
-rw-r--r--src/drivers/drivers.mak13
-rw-r--r--src/drivers/drivers.mk13
-rw-r--r--src/drivers/nl80211_copy.h311
-rw-r--r--src/drivers/rfkill.c46
-rw-r--r--src/eap_common/eap_eke_common.c42
-rw-r--r--src/eap_common/eap_fast_common.c25
-rw-r--r--src/eap_common/eap_fast_common.h6
-rw-r--r--src/eap_common/eap_gpsk_common.c9
-rw-r--r--src/eap_common/eap_pax_common.c6
-rw-r--r--src/eap_common/eap_pwd_common.c20
-rw-r--r--src/eap_common/eap_sake_common.c2
-rw-r--r--src/eap_common/ikev2_common.c15
-rw-r--r--src/eap_peer/eap.c80
-rw-r--r--src/eap_peer/eap_aka.c13
-rw-r--r--src/eap_peer/eap_config.h20
-rw-r--r--src/eap_peer/eap_eke.c7
-rw-r--r--src/eap_peer/eap_fast.c83
-rw-r--r--src/eap_peer/eap_fast_pac.c9
-rw-r--r--src/eap_peer/eap_gpsk.c6
-rw-r--r--src/eap_peer/eap_gtc.c6
-rw-r--r--src/eap_peer/eap_i.h2
-rw-r--r--src/eap_peer/eap_ikev2.c6
-rw-r--r--src/eap_peer/eap_leap.c6
-rw-r--r--src/eap_peer/eap_md5.c6
-rw-r--r--src/eap_peer/eap_methods.c17
-rw-r--r--src/eap_peer/eap_methods.h1
-rw-r--r--src/eap_peer/eap_mschapv2.c6
-rw-r--r--src/eap_peer/eap_otp.c6
-rw-r--r--src/eap_peer/eap_pax.c49
-rw-r--r--src/eap_peer/eap_peap.c76
-rw-r--r--src/eap_peer/eap_psk.c6
-rw-r--r--src/eap_peer/eap_pwd.c18
-rw-r--r--src/eap_peer/eap_sake.c25
-rw-r--r--src/eap_peer/eap_sim.c10
-rw-r--r--src/eap_peer/eap_tls.c60
-rw-r--r--src/eap_peer/eap_tls_common.c23
-rw-r--r--src/eap_peer/eap_tnc.c18
-rw-r--r--src/eap_peer/eap_ttls.c128
-rw-r--r--src/eap_peer/eap_vendor_test.c6
-rw-r--r--src/eap_peer/eap_wsc.c12
-rw-r--r--src/eap_peer/ikev2.c4
-rw-r--r--src/eap_peer/tncc.c19
-rw-r--r--src/eap_server/eap_methods.h1
-rw-r--r--src/eap_server/eap_server_aka.c13
-rw-r--r--src/eap_server/eap_server_eke.c6
-rw-r--r--src/eap_server/eap_server_fast.c56
-rw-r--r--src/eap_server/eap_server_gpsk.c6
-rw-r--r--src/eap_server/eap_server_gtc.c6
-rw-r--r--src/eap_server/eap_server_identity.c6
-rw-r--r--src/eap_server/eap_server_ikev2.c6
-rw-r--r--src/eap_server/eap_server_md5.c6
-rw-r--r--src/eap_server/eap_server_methods.c15
-rw-r--r--src/eap_server/eap_server_mschapv2.c6
-rw-r--r--src/eap_server/eap_server_pax.c6
-rw-r--r--src/eap_server/eap_server_peap.c24
-rw-r--r--src/eap_server/eap_server_psk.c6
-rw-r--r--src/eap_server/eap_server_pwd.c21
-rw-r--r--src/eap_server/eap_server_sake.c6
-rw-r--r--src/eap_server/eap_server_sim.c6
-rw-r--r--src/eap_server/eap_server_tls.c18
-rw-r--r--src/eap_server/eap_server_tls_common.c4
-rw-r--r--src/eap_server/eap_server_tnc.c6
-rw-r--r--src/eap_server/eap_server_ttls.c6
-rw-r--r--src/eap_server/eap_server_vendor_test.c6
-rw-r--r--src/eap_server/eap_server_wsc.c6
-rw-r--r--src/eap_server/eap_sim_db.c88
-rw-r--r--src/eap_server/eap_sim_db.h2
-rw-r--r--src/eap_server/ikev2.c6
-rw-r--r--src/eap_server/tncs.c14
-rw-r--r--src/eapol_auth/eapol_auth_sm.c21
-rw-r--r--src/eapol_auth/eapol_auth_sm_i.h12
-rw-r--r--src/eapol_supp/eapol_supp_sm.c10
-rw-r--r--src/fst/fst.c8
-rw-r--r--src/fst/fst_ctrl_aux.c31
-rw-r--r--src/fst/fst_ctrl_iface.c8
-rw-r--r--src/fst/fst_defs.h10
-rw-r--r--src/fst/fst_group.c270
-rw-r--r--src/fst/fst_group.h12
-rw-r--r--src/fst/fst_iface.c7
-rw-r--r--src/fst/fst_iface.h3
-rw-r--r--src/fst/fst_session.c95
-rw-r--r--src/l2_packet/l2_packet_linux.c40
-rw-r--r--src/l2_packet/l2_packet_pcap.c12
-rw-r--r--src/p2p/p2p.c267
-rw-r--r--src/p2p/p2p.h71
-rw-r--r--src/p2p/p2p_build.c6
-rw-r--r--src/p2p/p2p_go_neg.c27
-rw-r--r--src/p2p/p2p_group.c23
-rw-r--r--src/p2p/p2p_i.h14
-rw-r--r--src/p2p/p2p_invitation.c4
-rw-r--r--src/p2p/p2p_parse.c98
-rw-r--r--src/p2p/p2p_pd.c888
-rw-r--r--src/p2p/p2p_sd.c74
-rw-r--r--src/pae/ieee802_1x_cp.c56
-rw-r--r--src/pae/ieee802_1x_cp.h14
-rw-r--r--src/pae/ieee802_1x_kay.c1128
-rw-r--r--src/pae/ieee802_1x_kay.h13
-rw-r--r--src/pae/ieee802_1x_kay_i.h164
-rw-r--r--src/pae/ieee802_1x_secy_ops.c5
-rw-r--r--src/pae/ieee802_1x_secy_ops.h3
-rw-r--r--src/radius/radius.c124
-rw-r--r--src/radius/radius.h19
-rw-r--r--src/radius/radius_client.c150
-rw-r--r--src/radius/radius_client.h3
-rw-r--r--src/radius/radius_das.c11
-rw-r--r--src/radius/radius_das.h1
-rw-r--r--src/rsn_supp/pmksa_cache.c13
-rw-r--r--src/rsn_supp/pmksa_cache.h8
-rw-r--r--src/rsn_supp/preauth.c6
-rw-r--r--src/rsn_supp/preauth.h6
-rw-r--r--src/rsn_supp/tdls.c25
-rw-r--r--src/rsn_supp/wpa.c167
-rw-r--r--src/rsn_supp/wpa.h14
-rw-r--r--src/rsn_supp/wpa_i.h16
-rw-r--r--src/rsn_supp/wpa_ie.c6
-rw-r--r--src/tls/Makefile1
-rw-r--r--src/tls/asn1.h4
-rw-r--r--src/tls/pkcs5.c446
-rw-r--r--src/tls/tlsv1_client.c55
-rw-r--r--src/tls/tlsv1_client.h10
-rw-r--r--src/tls/tlsv1_client_i.h18
-rw-r--r--src/tls/tlsv1_client_ocsp.c803
-rw-r--r--src/tls/tlsv1_client_read.c487
-rw-r--r--src/tls/tlsv1_client_write.c158
-rw-r--r--src/tls/tlsv1_common.c39
-rw-r--r--src/tls/tlsv1_common.h5
-rw-r--r--src/tls/tlsv1_cred.c777
-rw-r--r--src/tls/tlsv1_cred.h8
-rw-r--r--src/tls/tlsv1_server_i.h3
-rw-r--r--src/tls/tlsv1_server_read.c86
-rw-r--r--src/tls/tlsv1_server_write.c168
-rw-r--r--src/tls/x509v3.c300
-rw-r--r--src/tls/x509v3.h36
-rw-r--r--src/utils/browser-android.c6
-rw-r--r--src/utils/common.c83
-rw-r--r--src/utils/common.h16
-rw-r--r--src/utils/edit_simple.c6
-rw-r--r--src/utils/eloop.c292
-rw-r--r--src/utils/eloop.h8
-rw-r--r--src/utils/eloop_win.c6
-rw-r--r--src/utils/ext_password.c4
-rw-r--r--src/utils/ext_password_i.h6
-rw-r--r--src/utils/http_curl.c74
-rw-r--r--src/utils/module_tests.h20
-rw-r--r--src/utils/os.h4
-rw-r--r--src/utils/os_unix.c15
-rw-r--r--src/utils/pcsc_funcs.c29
-rw-r--r--src/utils/platform.h4
-rw-r--r--src/utils/radiotap.c2
-rw-r--r--src/utils/radiotap.h4
-rw-r--r--src/utils/radiotap_iter.h2
-rw-r--r--src/utils/trace.c9
-rw-r--r--src/utils/trace.h2
-rw-r--r--src/utils/utils_module_tests.c1
-rw-r--r--src/utils/wpa_debug.c24
-rw-r--r--src/utils/wpabuf.c30
-rw-r--r--src/utils/wpabuf.h17
-rw-r--r--src/utils/xml_libxml2.c2
-rw-r--r--src/wps/wps.c6
-rw-r--r--src/wps/wps.h14
-rw-r--r--src/wps/wps_attr_build.c31
-rw-r--r--src/wps/wps_attr_parse.c4
-rw-r--r--src/wps/wps_attr_process.c10
-rw-r--r--src/wps/wps_common.c47
-rw-r--r--src/wps/wps_defs.h4
-rw-r--r--src/wps/wps_enrollee.c33
-rw-r--r--src/wps/wps_i.h4
-rw-r--r--src/wps/wps_module_tests.c3
-rw-r--r--src/wps/wps_registrar.c77
-rw-r--r--src/wps/wps_upnp.c11
-rw-r--r--src/wps/wps_upnp.h3
-rw-r--r--src/wps/wps_upnp_i.h3
-rw-r--r--src/wps/wps_upnp_ssdp.c6
-rw-r--r--src/wps/wps_upnp_web.c88
-rw-r--r--wpa_supplicant/Android.mk1680
-rw-r--r--wpa_supplicant/ChangeLog144
-rw-r--r--wpa_supplicant/Makefile162
-rw-r--r--wpa_supplicant/README48
-rw-r--r--wpa_supplicant/README-HS2067
-rw-r--r--wpa_supplicant/README-P2P22
-rw-r--r--wpa_supplicant/README-Windows.txt299
-rw-r--r--wpa_supplicant/android.config492
-rw-r--r--wpa_supplicant/ap.c200
-rw-r--r--wpa_supplicant/ap.h10
-rw-r--r--wpa_supplicant/autoscan.c34
-rw-r--r--wpa_supplicant/autoscan.h10
-rw-r--r--wpa_supplicant/bgscan.c6
-rw-r--r--wpa_supplicant/bgscan.h9
-rw-r--r--wpa_supplicant/binder/.clang-format9
-rw-r--r--wpa_supplicant/binder/binder.cpp104
-rw-r--r--wpa_supplicant/binder/binder.h46
-rw-r--r--wpa_supplicant/binder/binder_constants.cpp18
-rw-r--r--wpa_supplicant/binder/binder_constants.h21
-rw-r--r--wpa_supplicant/binder/binder_i.h28
-rw-r--r--wpa_supplicant/binder/binder_manager.cpp100
-rw-r--r--wpa_supplicant/binder/binder_manager.h58
-rw-r--r--wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl16
-rw-r--r--wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl59
-rw-r--r--wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl20
-rw-r--r--wpa_supplicant/binder/iface.cpp16
-rw-r--r--wpa_supplicant/binder/iface.h42
-rw-r--r--wpa_supplicant/binder/supplicant.cpp127
-rw-r--r--wpa_supplicant/binder/supplicant.h55
-rw-r--r--wpa_supplicant/bss.c97
-rw-r--r--wpa_supplicant/bss.h20
-rw-r--r--wpa_supplicant/config.c190
-rw-r--r--wpa_supplicant/config.h88
-rw-r--r--wpa_supplicant/config_file.c45
-rw-r--r--wpa_supplicant/config_ssid.h45
-rw-r--r--wpa_supplicant/config_winreg.c1
-rw-r--r--wpa_supplicant/ctrl_iface.c1052
-rw-r--r--wpa_supplicant/ctrl_iface_udp.c170
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c358
-rw-r--r--wpa_supplicant/dbus/dbus-wpa_supplicant.conf2
-rw-r--r--wpa_supplicant/dbus/dbus_common_i.h10
-rw-r--r--wpa_supplicant/dbus/dbus_dict_helpers.c74
-rw-r--r--wpa_supplicant/dbus/dbus_dict_helpers.h15
-rw-r--r--wpa_supplicant/dbus/dbus_new.c359
-rw-r--r--wpa_supplicant/dbus/dbus_new.h7
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c655
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.h267
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.c201
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.h164
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_wps.c26
-rw-r--r--wpa_supplicant/dbus/dbus_new_helpers.c9
-rw-r--r--wpa_supplicant/dbus/dbus_new_helpers.h12
-rw-r--r--wpa_supplicant/dbus/dbus_new_introspect.c4
-rw-r--r--wpa_supplicant/dbus/dbus_old_handlers.c23
-rw-r--r--wpa_supplicant/defconfig44
-rw-r--r--wpa_supplicant/doc/docbook/eapol_test.84
-rw-r--r--wpa_supplicant/doc/docbook/eapol_test.sgml2
-rw-r--r--wpa_supplicant/doc/docbook/wpa_background.84
-rw-r--r--wpa_supplicant/doc/docbook/wpa_background.sgml2
-rw-r--r--wpa_supplicant/doc/docbook/wpa_cli.84
-rw-r--r--wpa_supplicant/doc/docbook/wpa_cli.sgml2
-rw-r--r--wpa_supplicant/doc/docbook/wpa_gui.84
-rw-r--r--wpa_supplicant/doc/docbook/wpa_gui.sgml2
-rw-r--r--wpa_supplicant/doc/docbook/wpa_passphrase.84
-rw-r--r--wpa_supplicant/doc/docbook/wpa_passphrase.sgml2
-rw-r--r--wpa_supplicant/doc/docbook/wpa_priv.84
-rw-r--r--wpa_supplicant/doc/docbook/wpa_priv.sgml2
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.87
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.conf.52
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.sgml9
-rw-r--r--wpa_supplicant/driver_i.h82
-rw-r--r--wpa_supplicant/eapol_test.c18
-rw-r--r--wpa_supplicant/events.c530
-rw-r--r--wpa_supplicant/gas_query.c154
-rw-r--r--wpa_supplicant/gas_query.h2
-rw-r--r--wpa_supplicant/hs20_supplicant.c313
-rw-r--r--wpa_supplicant/hs20_supplicant.h15
-rw-r--r--wpa_supplicant/ibss_rsn.c12
-rw-r--r--wpa_supplicant/ibss_rsn.h3
-rw-r--r--wpa_supplicant/interworking.c231
-rw-r--r--wpa_supplicant/interworking.h3
-rw-r--r--wpa_supplicant/libwpa_test.c32
-rw-r--r--wpa_supplicant/main.c96
-rw-r--r--wpa_supplicant/mbo.c836
-rw-r--r--wpa_supplicant/mesh.c130
-rw-r--r--wpa_supplicant/mesh.h3
-rw-r--r--wpa_supplicant/mesh_mpm.c376
-rw-r--r--wpa_supplicant/mesh_mpm.h5
-rw-r--r--wpa_supplicant/mesh_rsn.c374
-rw-r--r--wpa_supplicant/mesh_rsn.h11
-rw-r--r--wpa_supplicant/notify.c25
-rw-r--r--wpa_supplicant/notify.h3
-rw-r--r--wpa_supplicant/offchannel.c52
-rw-r--r--wpa_supplicant/p2p_supplicant.c1289
-rw-r--r--wpa_supplicant/p2p_supplicant.h26
-rw-r--r--wpa_supplicant/p2p_supplicant_sd.c18
-rw-r--r--wpa_supplicant/scan.c471
-rw-r--r--wpa_supplicant/scan.h13
-rw-r--r--wpa_supplicant/sme.c125
-rw-r--r--wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in15
-rw-r--r--wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in15
-rw-r--r--wpa_supplicant/systemd/wpa_supplicant.service.arg.in15
-rw-r--r--wpa_supplicant/systemd/wpa_supplicant.service.in13
-rw-r--r--wpa_supplicant/tests/link_test.c83
-rw-r--r--wpa_supplicant/tests/test_eap_sim_common.c47
-rw-r--r--wpa_supplicant/tests/test_wpa.c369
-rwxr-xr-xwpa_supplicant/vs2005/eapol_test/eapol_test.vcproj473
-rwxr-xr-xwpa_supplicant/vs2005/win_if_list/win_if_list.vcproj203
-rwxr-xr-xwpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj215
-rwxr-xr-xwpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj236
-rwxr-xr-xwpa_supplicant/vs2005/wpa_supplicant.sln52
-rwxr-xr-xwpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj461
-rwxr-xr-xwpa_supplicant/vs2005/wpasvc/wpasvc.vcproj461
-rw-r--r--wpa_supplicant/wmm_ac.h2
-rw-r--r--wpa_supplicant/wnm_sta.c503
-rw-r--r--wpa_supplicant/wnm_sta.h2
-rw-r--r--wpa_supplicant/wpa_cli.c529
-rw-r--r--wpa_supplicant/wpa_gui-qt4/.gitignore4
-rw-r--r--wpa_supplicant/wpa_gui-qt4/addinterface.cpp239
-rw-r--r--wpa_supplicant/wpa_gui-qt4/addinterface.h39
-rw-r--r--wpa_supplicant/wpa_gui-qt4/eventhistory.cpp124
-rw-r--r--wpa_supplicant/wpa_gui-qt4/eventhistory.h57
-rw-r--r--wpa_supplicant/wpa_gui-qt4/eventhistory.ui61
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons.qrc9
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons/Makefile23
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons/README74
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons/ap.svg832
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons/group.svg616
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons/invitation.svg374
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons/laptop.svg1568
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg256
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons_png.qrc9
-rw-r--r--wpa_supplicant/wpa_gui-qt4/lang/.gitignore1
-rw-r--r--wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts1262
-rw-r--r--wpa_supplicant/wpa_gui-qt4/main.cpp67
-rw-r--r--wpa_supplicant/wpa_gui-qt4/networkconfig.cpp853
-rw-r--r--wpa_supplicant/wpa_gui-qt4/networkconfig.h55
-rw-r--r--wpa_supplicant/wpa_gui-qt4/networkconfig.ui435
-rw-r--r--wpa_supplicant/wpa_gui-qt4/peers.cpp1883
-rw-r--r--wpa_supplicant/wpa_gui-qt4/peers.h90
-rw-r--r--wpa_supplicant/wpa_gui-qt4/peers.ui40
-rw-r--r--wpa_supplicant/wpa_gui-qt4/scanresults.cpp141
-rw-r--r--wpa_supplicant/wpa_gui-qt4/scanresults.h40
-rw-r--r--wpa_supplicant/wpa_gui-qt4/scanresults.ui94
-rw-r--r--wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp18
-rw-r--r--wpa_supplicant/wpa_gui-qt4/scanresultsitem.h21
-rw-r--r--wpa_supplicant/wpa_gui-qt4/signalbar.cpp58
-rw-r--r--wpa_supplicant/wpa_gui-qt4/signalbar.h28
-rw-r--r--wpa_supplicant/wpa_gui-qt4/stringquery.cpp31
-rw-r--r--wpa_supplicant/wpa_gui-qt4/stringquery.h28
-rw-r--r--wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp94
-rw-r--r--wpa_supplicant/wpa_gui-qt4/userdatarequest.h40
-rw-r--r--wpa_supplicant/wpa_gui-qt4/userdatarequest.ui109
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpa_gui.pro73
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpagui.cpp1898
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpagui.h180
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpagui.ui524
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpamsg.h35
-rw-r--r--wpa_supplicant/wpa_priv.c61
-rw-r--r--wpa_supplicant/wpa_supplicant.c1197
-rw-r--r--wpa_supplicant/wpa_supplicant.conf184
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h149
-rw-r--r--wpa_supplicant/wpas_glue.c11
-rw-r--r--wpa_supplicant/wpas_kay.c11
-rw-r--r--wpa_supplicant/wpas_module_tests.c33
-rw-r--r--wpa_supplicant/wps_supplicant.c46
-rw-r--r--wpa_supplicant/wps_supplicant.h7
495 files changed, 51409 insertions, 10141 deletions
diff --git a/CONTRIBUTIONS b/CONTRIBUTIONS
index ca09bae6e15d..76600bc87280 100644
--- a/CONTRIBUTIONS
+++ b/CONTRIBUTIONS
@@ -29,6 +29,34 @@ using your real name. Pseudonyms or anonymous contributions cannot
unfortunately be accepted.
+The preferred method of submitting the contribution to the project is by
+email to the hostap mailing list:
+hostap@lists.infradead.org
+Note that the list may require subscription before accepting message
+without moderation. You can subscribe to the list at this address:
+http://lists.infradead.org/mailman/listinfo/hostap
+
+The message should contain an inlined patch against the current
+development branch (i.e., the master branch of
+git://w1.fi/hostap.git). Please make sure the software you use for
+sending the patch does not corrupt whitespace. If that cannot be fixed
+for some reason, it is better to include an attached version of the
+patch file than just send a whitespace damaged version in the message
+body.
+
+The patches should be separate logical changes rather than doing
+everything in a single patch. In other words, please keep cleanup, new
+features, and bug fixes all in their own patches. Each patch needs a
+commit log that describes the changes (what the changes fix, what
+functionality is added, why the changes are useful, etc.).
+
+Please try to follow the coding style used in the project.
+
+In general, the best way of generating a suitable formatted patch file
+is by committing the changes to a cloned git repository and using git
+format-patch. The patch can then be sent, e.g., with git send-email.
+
+
History of license and contributions terms
------------------------------------------
@@ -112,7 +140,7 @@ The license terms used for hostap.git files
Modified BSD license (no advertisement clause):
-Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/COPYING b/COPYING
index 5962e2fca0bc..7efce0dee1a7 100644
--- a/COPYING
+++ b/COPYING
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
diff --git a/README b/README
index 07d1d25db777..9685f586beb7 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
These programs are licensed under the BSD license (the one with
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
new file mode 100644
index 000000000000..ea3a39a9719f
--- /dev/null
+++ b/hostapd/Android.mk
@@ -0,0 +1,1001 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+WPA_BUILD_HOSTAPD := false
+ifneq ($(BOARD_HOSTAPD_DRIVER),)
+ WPA_BUILD_HOSTAPD := true
+ CONFIG_DRIVER_$(BOARD_HOSTAPD_DRIVER) := y
+endif
+
+ifeq ($(WPA_BUILD_HOSTAPD),true)
+
+include $(LOCAL_PATH)/android.config
+
+# To ignore possible wrong network configurations
+L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS
+
+L_CFLAGS += -DVERSION_STR_POSTFIX=\"-$(PLATFORM_VERSION)\"
+
+# Set Android log name
+L_CFLAGS += -DANDROID_LOG_NAME=\"hostapd\"
+
+# Disable unused parameter warnings
+L_CFLAGS += -Wno-unused-parameter
+
+# Set Android extended P2P functionality
+L_CFLAGS += -DANDROID_P2P
+
+ifeq ($(BOARD_HOSTAPD_PRIVATE_LIB),)
+L_CFLAGS += -DANDROID_LIB_STUB
+endif
+
+# Use Android specific directory for control interface sockets
+L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
+L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/hostapd\"
+
+# To force sizeof(enum) = 4
+ifeq ($(TARGET_ARCH),arm)
+L_CFLAGS += -mabi=aapcs-linux
+endif
+
+INCLUDES = $(LOCAL_PATH)
+INCLUDES += $(LOCAL_PATH)/src
+INCLUDES += $(LOCAL_PATH)/src/utils
+INCLUDES += system/security/keystore/include
+ifdef CONFIG_DRIVER_NL80211
+ifneq ($(wildcard external/libnl),)
+INCLUDES += external/libnl/include
+else
+INCLUDES += external/libnl-headers
+endif
+endif
+
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+L_CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+L_CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32
+endif
+
+OBJS = main.c
+OBJS += config_file.c
+
+OBJS += src/ap/hostapd.c
+OBJS += src/ap/wpa_auth_glue.c
+OBJS += src/ap/drv_callbacks.c
+OBJS += src/ap/ap_drv_ops.c
+OBJS += src/ap/utils.c
+OBJS += src/ap/authsrv.c
+OBJS += src/ap/ieee802_1x.c
+OBJS += src/ap/ap_config.c
+OBJS += src/ap/eap_user_db.c
+OBJS += src/ap/ieee802_11_auth.c
+OBJS += src/ap/sta_info.c
+OBJS += src/ap/wpa_auth.c
+OBJS += src/ap/tkip_countermeasures.c
+OBJS += src/ap/ap_mlme.c
+OBJS += src/ap/wpa_auth_ie.c
+OBJS += src/ap/preauth_auth.c
+OBJS += src/ap/pmksa_cache_auth.c
+OBJS += src/ap/ieee802_11_shared.c
+OBJS += src/ap/beacon.c
+OBJS += src/ap/bss_load.c
+OBJS += src/ap/neighbor_db.c
+OBJS += src/ap/rrm.c
+OBJS_d =
+OBJS_p =
+LIBS =
+LIBS_c =
+HOBJS =
+LIBS_h =
+
+NEED_RC4=y
+NEED_AES=y
+NEED_MD5=y
+NEED_SHA1=y
+
+OBJS += src/drivers/drivers.c
+L_CFLAGS += -DHOSTAPD
+
+ifdef CONFIG_WPA_TRACE
+L_CFLAGS += -DWPA_TRACE
+OBJS += src/utils/trace.c
+HOBJS += src/utils/trace.c
+LDFLAGS += -rdynamic
+L_CFLAGS += -funwind-tables
+ifdef CONFIG_WPA_TRACE_BFD
+L_CFLAGS += -DWPA_TRACE_BFD
+LIBS += -lbfd
+LIBS_c += -lbfd
+LIBS_h += -lbfd
+endif
+endif
+
+OBJS += src/utils/eloop.c
+
+ifdef CONFIG_ELOOP_POLL
+L_CFLAGS += -DCONFIG_ELOOP_POLL
+endif
+
+ifdef CONFIG_ELOOP_EPOLL
+L_CFLAGS += -DCONFIG_ELOOP_EPOLL
+endif
+
+OBJS += src/utils/common.c
+OBJS += src/utils/wpa_debug.c
+OBJS += src/utils/wpabuf.c
+OBJS += src/utils/os_$(CONFIG_OS).c
+OBJS += src/utils/ip_addr.c
+
+OBJS += src/common/ieee802_11_common.c
+OBJS += src/common/wpa_common.c
+OBJS += src/common/hw_features_common.c
+
+OBJS += src/eapol_auth/eapol_auth_sm.c
+
+
+ifndef CONFIG_NO_DUMP_STATE
+# define HOSTAPD_DUMP_STATE to include support for dumping internal state
+# through control interface commands (undefine it, if you want to save in
+# binary size)
+L_CFLAGS += -DHOSTAPD_DUMP_STATE
+OBJS += src/eapol_auth/eapol_auth_dump.c
+endif
+
+ifdef CONFIG_NO_RADIUS
+L_CFLAGS += -DCONFIG_NO_RADIUS
+CONFIG_NO_ACCOUNTING=y
+else
+OBJS += src/radius/radius.c
+OBJS += src/radius/radius_client.c
+OBJS += src/radius/radius_das.c
+endif
+
+ifdef CONFIG_NO_ACCOUNTING
+L_CFLAGS += -DCONFIG_NO_ACCOUNTING
+else
+OBJS += src/ap/accounting.c
+endif
+
+ifdef CONFIG_NO_VLAN
+L_CFLAGS += -DCONFIG_NO_VLAN
+else
+OBJS += src/ap/vlan_init.c
+OBJS += src/ap/vlan_ifconfig.c
+OBJS += src/ap/vlan.c
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+# Define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
+# and VLAN interfaces for the VLAN feature.
+L_CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
+OBJS += src/ap/vlan_full.c
+ifdef CONFIG_VLAN_NETLINK
+OBJS += src/ap/vlan_util.c
+else
+OBJS += src/ap/vlan_ioctl.c
+endif
+endif
+endif
+
+ifdef CONFIG_NO_CTRL_IFACE
+L_CFLAGS += -DCONFIG_NO_CTRL_IFACE
+else
+OBJS += src/common/ctrl_iface_common.c
+OBJS += ctrl_iface.c
+OBJS += src/ap/ctrl_iface_ap.c
+endif
+
+L_CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
+
+ifdef CONFIG_IAPP
+L_CFLAGS += -DCONFIG_IAPP
+OBJS += src/ap/iapp.c
+endif
+
+ifdef CONFIG_RSN_PREAUTH
+L_CFLAGS += -DCONFIG_RSN_PREAUTH
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_PEERKEY
+L_CFLAGS += -DCONFIG_PEERKEY
+OBJS += src/ap/peerkey_auth.c
+endif
+
+ifdef CONFIG_HS20
+NEED_AES_OMAC1=y
+CONFIG_PROXYARP=y
+endif
+
+ifdef CONFIG_PROXYARP
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_SUITEB
+L_CFLAGS += -DCONFIG_SUITEB
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_SUITEB192
+L_CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
+endif
+
+ifdef CONFIG_IEEE80211W
+L_CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_IEEE80211R
+L_CFLAGS += -DCONFIG_IEEE80211R
+OBJS += src/ap/wpa_auth_ft.c
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+OBJS += src/common/sae.c
+NEED_ECC=y
+NEED_DH_GROUPS=y
+endif
+
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM
+OBJS += src/ap/wnm_ap.c
+endif
+
+ifdef CONFIG_IEEE80211N
+L_CFLAGS += -DCONFIG_IEEE80211N
+endif
+
+ifdef CONFIG_IEEE80211AC
+L_CFLAGS += -DCONFIG_IEEE80211AC
+endif
+
+ifdef CONFIG_MBO
+L_CFLAGS += -DCONFIG_MBO
+OBJS += src/ap/mbo_ap.c
+endif
+
+ifdef CONFIG_FST
+L_CFLAGS += -DCONFIG_FST
+OBJS += src/fst/fst.c
+OBJS += src/fst/fst_group.c
+OBJS += src/fst/fst_iface.c
+OBJS += src/fst/fst_session.c
+OBJS += src/fst/fst_ctrl_aux.c
+ifdef CONFIG_FST_TEST
+L_CFLAGS += -DCONFIG_FST_TEST
+endif
+ifndef CONFIG_NO_CTRL_IFACE
+OBJS += src/fst/fst_ctrl_iface.c
+endif
+endif
+
+
+include $(LOCAL_PATH)/src/drivers/drivers.mk
+
+OBJS += $(DRV_AP_OBJS)
+L_CFLAGS += $(DRV_AP_CFLAGS)
+LDFLAGS += $(DRV_AP_LDFLAGS)
+LIBS += $(DRV_AP_LIBS)
+
+ifdef CONFIG_L2_PACKET
+ifdef CONFIG_DNET_PCAP
+ifdef CONFIG_L2_FREEBSD
+LIBS += -lpcap
+OBJS += src/l2_packet/l2_packet_freebsd.c
+else
+LIBS += -ldnet -lpcap
+OBJS += src/l2_packet/l2_packet_pcap.c
+endif
+else
+OBJS += src/l2_packet/l2_packet_linux.c
+endif
+else
+OBJS += src/l2_packet/l2_packet_none.c
+endif
+
+
+ifdef CONFIG_EAP_MD5
+L_CFLAGS += -DEAP_SERVER_MD5
+OBJS += src/eap_server/eap_server_md5.c
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_TLS
+L_CFLAGS += -DEAP_SERVER_TLS
+OBJS += src/eap_server/eap_server_tls.c
+TLS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_UNAUTH_TLS
+L_CFLAGS += -DEAP_SERVER_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += src/eap_server/eap_server_tls.c
+TLS_FUNCS=y
+endif
+endif
+
+ifdef CONFIG_EAP_PEAP
+L_CFLAGS += -DEAP_SERVER_PEAP
+OBJS += src/eap_server/eap_server_peap.c
+OBJS += src/eap_common/eap_peap_common.c
+TLS_FUNCS=y
+CONFIG_EAP_MSCHAPV2=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+L_CFLAGS += -DEAP_SERVER_TTLS
+OBJS += src/eap_server/eap_server_ttls.c
+TLS_FUNCS=y
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+L_CFLAGS += -DEAP_SERVER_MSCHAPV2
+OBJS += src/eap_server/eap_server_mschapv2.c
+MS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_GTC
+L_CFLAGS += -DEAP_SERVER_GTC
+OBJS += src/eap_server/eap_server_gtc.c
+endif
+
+ifdef CONFIG_EAP_SIM
+L_CFLAGS += -DEAP_SERVER_SIM
+OBJS += src/eap_server/eap_server_sim.c
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA
+L_CFLAGS += -DEAP_SERVER_AKA
+OBJS += src/eap_server/eap_server_aka.c
+CONFIG_EAP_SIM_COMMON=y
+NEED_SHA256=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+L_CFLAGS += -DEAP_SERVER_AKA_PRIME
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += src/eap_common/eap_sim_common.c
+# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
+# replaced with another file implementating the interface specified in
+# eap_sim_db.h.
+OBJS += src/eap_server/eap_sim_db.c
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+L_CFLAGS += -DEAP_SERVER_PAX
+OBJS += src/eap_server/eap_server_pax.c src/eap_common/eap_pax_common.c
+endif
+
+ifdef CONFIG_EAP_PSK
+L_CFLAGS += -DEAP_SERVER_PSK
+OBJS += src/eap_server/eap_server_psk.c src/eap_common/eap_psk_common.c
+NEED_AES_OMAC1=y
+NEED_AES_ENCBLOCK=y
+NEED_AES_EAX=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+L_CFLAGS += -DEAP_SERVER_SAKE
+OBJS += src/eap_server/eap_server_sake.c src/eap_common/eap_sake_common.c
+endif
+
+ifdef CONFIG_EAP_GPSK
+L_CFLAGS += -DEAP_SERVER_GPSK
+OBJS += src/eap_server/eap_server_gpsk.c src/eap_common/eap_gpsk_common.c
+ifdef CONFIG_EAP_GPSK_SHA256
+L_CFLAGS += -DEAP_GPSK_SHA256
+endif
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_EAP_PWD
+L_CFLAGS += -DEAP_SERVER_PWD
+OBJS += src/eap_server/eap_server_pwd.c src/eap_common/eap_pwd_common.c
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_EKE
+L_CFLAGS += -DEAP_SERVER_EKE
+OBJS += src/eap_server/eap_server_eke.c src/eap_common/eap_eke_common.c
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+L_CFLAGS += -DEAP_SERVER_VENDOR_TEST
+OBJS += src/eap_server/eap_server_vendor_test.c
+endif
+
+ifdef CONFIG_EAP_FAST
+L_CFLAGS += -DEAP_SERVER_FAST
+OBJS += src/eap_server/eap_server_fast.c
+OBJS += src/eap_common/eap_fast_common.c
+TLS_FUNCS=y
+NEED_T_PRF=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_WPS
+L_CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC
+OBJS += src/utils/uuid.c
+OBJS += src/ap/wps_hostapd.c
+OBJS += src/eap_server/eap_server_wsc.c src/eap_common/eap_wsc_common.c
+OBJS += src/wps/wps.c
+OBJS += src/wps/wps_common.c
+OBJS += src/wps/wps_attr_parse.c
+OBJS += src/wps/wps_attr_build.c
+OBJS += src/wps/wps_attr_process.c
+OBJS += src/wps/wps_dev_attr.c
+OBJS += src/wps/wps_enrollee.c
+OBJS += src/wps/wps_registrar.c
+NEED_DH_GROUPS=y
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_AES_CBC=y
+NEED_MODEXP=y
+CONFIG_EAP=y
+
+ifdef CONFIG_WPS_NFC
+L_CFLAGS += -DCONFIG_WPS_NFC
+OBJS += src/wps/ndef.c
+NEED_WPS_OOB=y
+endif
+
+ifdef NEED_WPS_OOB
+L_CFLAGS += -DCONFIG_WPS_OOB
+endif
+
+ifdef CONFIG_WPS_UPNP
+L_CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += src/wps/wps_upnp.c
+OBJS += src/wps/wps_upnp_ssdp.c
+OBJS += src/wps/wps_upnp_web.c
+OBJS += src/wps/wps_upnp_event.c
+OBJS += src/wps/wps_upnp_ap.c
+OBJS += src/wps/upnp_xml.c
+OBJS += src/wps/httpread.c
+OBJS += src/wps/http_client.c
+OBJS += src/wps/http_server.c
+endif
+
+ifdef CONFIG_WPS_STRICT
+L_CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += src/wps/wps_validate.c
+endif
+
+ifdef CONFIG_WPS_TESTING
+L_CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+endif
+
+ifdef CONFIG_EAP_IKEV2
+L_CFLAGS += -DEAP_SERVER_IKEV2
+OBJS += src/eap_server/eap_server_ikev2.c src/eap_server/ikev2.c
+OBJS += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+endif
+
+ifdef CONFIG_EAP_TNC
+L_CFLAGS += -DEAP_SERVER_TNC
+OBJS += src/eap_server/eap_server_tnc.c
+OBJS += src/eap_server/tncs.c
+NEED_BASE64=y
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+
+# Basic EAP functionality is needed for EAPOL
+OBJS += eap_register.c
+OBJS += src/eap_server/eap_server.c
+OBJS += src/eap_common/eap_common.c
+OBJS += src/eap_server/eap_server_methods.c
+OBJS += src/eap_server/eap_server_identity.c
+L_CFLAGS += -DEAP_SERVER_IDENTITY
+
+ifdef CONFIG_EAP
+L_CFLAGS += -DEAP_SERVER
+endif
+
+ifdef CONFIG_PKCS12
+L_CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef MS_FUNCS
+OBJS += src/crypto/ms_funcs.c
+NEED_DES=y
+NEED_MD4=y
+endif
+
+ifdef CHAP
+OBJS += src/eap_common/chap.c
+endif
+
+ifdef TLS_FUNCS
+NEED_DES=y
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
+L_CFLAGS += -DEAP_TLS_FUNCS
+OBJS += src/eap_server/eap_server_tls_common.c
+NEED_TLS_PRF=y
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifdef CONFIG_TLSV11
+L_CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+L_CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_openssl.c
+OBJS += src/crypto/tls_openssl_ocsp.c
+LIBS += -lssl
+endif
+OBJS += src/crypto/crypto_openssl.c
+HOBJS += src/crypto/crypto_openssl.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_openssl.c
+endif
+NEED_SHA256=y
+NEED_TLS_PRF_SHA256=y
+LIBS += -lcrypto
+LIBS_h += -lcrypto
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_gnutls.c
+LIBS += -lgnutls -lgpg-error
+endif
+OBJS += src/crypto/crypto_gnutls.c
+HOBJS += src/crypto/crypto_gnutls.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_internal.c
+OBJS += src/crypto/sha1-internal.c
+endif
+LIBS += -lgcrypt
+LIBS_h += -lgcrypt
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+ifdef TLS_FUNCS
+OBJS += src/crypto/crypto_internal-rsa.c
+OBJS += src/crypto/tls_internal.c
+OBJS += src/tls/tlsv1_common.c
+OBJS += src/tls/tlsv1_record.c
+OBJS += src/tls/tlsv1_cred.c
+OBJS += src/tls/tlsv1_server.c
+OBJS += src/tls/tlsv1_server_write.c
+OBJS += src/tls/tlsv1_server_read.c
+OBJS += src/tls/asn1.c
+OBJS += src/tls/rsa.c
+OBJS += src/tls/x509v3.c
+OBJS += src/tls/pkcs1.c
+OBJS += src/tls/pkcs5.c
+OBJS += src/tls/pkcs8.c
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
+NEED_MODEXP=y
+NEED_CIPHER=y
+L_CFLAGS += -DCONFIG_TLS_INTERNAL
+L_CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+endif
+ifdef NEED_CIPHER
+NEED_DES=y
+OBJS += src/crypto/crypto_internal-cipher.c
+endif
+ifdef NEED_MODEXP
+OBJS += src/crypto/crypto_internal-modexp.c
+OBJS += src/tls/bignum.c
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += src/crypto/crypto_libtomcrypt.c
+LIBS += -ltomcrypt -ltfm
+LIBS_h += -ltomcrypt -ltfm
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += src/crypto/crypto_internal.c
+NEED_AES_DEC=y
+L_CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+L_CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+L_CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_h += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_SHA384=y
+CONFIG_INTERNAL_SHA512=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += src/crypto/crypto_cryptoapi.c
+OBJS_p += src/crypto/crypto_cryptoapi.c
+L_CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), none)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_none.c
+L_CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+OBJS += src/crypto/crypto_none.c
+OBJS_p += src/crypto/crypto_none.c
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+
+ifndef TLS_FUNCS
+OBJS += src/crypto/tls_none.c
+ifeq ($(CONFIG_TLS), internal)
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+AESOBJS = # none so far
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-enc.c
+endif
+
+ifneq ($(CONFIG_TLS), openssl)
+AESOBJS += src/crypto/aes-wrap.c
+endif
+ifdef NEED_AES_EAX
+AESOBJS += src/crypto/aes-eax.c
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_CTR
+AESOBJS += src/crypto/aes-ctr.c
+endif
+ifdef NEED_AES_ENCBLOCK
+AESOBJS += src/crypto/aes-encblock.c
+endif
+ifdef NEED_AES_OMAC1
+AESOBJS += src/crypto/aes-omac1.c
+endif
+ifdef NEED_AES_UNWRAP
+ifneq ($(CONFIG_TLS), openssl)
+NEED_AES_DEC=y
+AESOBJS += src/crypto/aes-unwrap.c
+endif
+endif
+ifdef NEED_AES_CBC
+NEED_AES_DEC=y
+ifneq ($(CONFIG_TLS), openssl)
+AESOBJS += src/crypto/aes-cbc.c
+endif
+endif
+ifdef NEED_AES_DEC
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += src/crypto/aes-internal-dec.c
+endif
+endif
+ifdef NEED_AES
+OBJS += $(AESOBJS)
+endif
+
+SHA1OBJS =
+ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
+SHA1OBJS += src/crypto/sha1.c
+endif
+SHA1OBJS += src/crypto/sha1-prf.c
+ifdef CONFIG_INTERNAL_SHA1
+SHA1OBJS += src/crypto/sha1-internal.c
+ifdef NEED_FIPS186_2_PRF
+SHA1OBJS += src/crypto/fips_prf_internal.c
+endif
+endif
+ifneq ($(CONFIG_TLS), openssl)
+SHA1OBJS += src/crypto/sha1-pbkdf2.c
+endif
+ifdef NEED_T_PRF
+SHA1OBJS += src/crypto/sha1-tprf.c
+endif
+ifdef NEED_TLS_PRF
+SHA1OBJS += src/crypto/sha1-tlsprf.c
+endif
+endif
+
+ifdef NEED_SHA1
+OBJS += $(SHA1OBJS)
+endif
+
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += src/crypto/md5.c
+endif
+
+ifdef NEED_MD5
+ifdef CONFIG_INTERNAL_MD5
+OBJS += src/crypto/md5-internal.c
+HOBJS += src/crypto/md5-internal.c
+endif
+endif
+
+ifdef NEED_MD4
+ifdef CONFIG_INTERNAL_MD4
+OBJS += src/crypto/md4-internal.c
+endif
+endif
+
+ifdef NEED_DES
+ifdef CONFIG_INTERNAL_DES
+OBJS += src/crypto/des-internal.c
+endif
+endif
+
+ifdef CONFIG_NO_RC4
+L_CFLAGS += -DCONFIG_NO_RC4
+endif
+
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+ifndef CONFIG_NO_RC4
+OBJS += src/crypto/rc4.c
+endif
+endif
+endif
+
+ifdef NEED_SHA256
+L_CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += src/crypto/sha256.c
+endif
+OBJS += src/crypto/sha256-prf.c
+ifdef CONFIG_INTERNAL_SHA256
+OBJS += src/crypto/sha256-internal.c
+endif
+ifdef NEED_TLS_PRF_SHA256
+OBJS += src/crypto/sha256-tlsprf.c
+endif
+endif
+ifdef NEED_SHA384
+L_CFLAGS += -DCONFIG_SHA384
+OBJS += src/crypto/sha384-prf.c
+endif
+
+ifdef CONFIG_INTERNAL_SHA384
+L_CFLAGS += -DCONFIG_INTERNAL_SHA384
+OBJS += src/crypto/sha384-internal.c
+endif
+
+ifdef CONFIG_INTERNAL_SHA512
+L_CFLAGS += -DCONFIG_INTERNAL_SHA512
+OBJS += src/crypto/sha512-internal.c
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += src/crypto/dh_groups.c
+endif
+ifdef NEED_DH_GROUPS_ALL
+L_CFLAGS += -DALL_DH_GROUPS
+endif
+ifdef CONFIG_INTERNAL_DH_GROUP5
+ifdef NEED_DH_GROUPS
+OBJS += src/crypto/dh_group5.c
+endif
+endif
+
+ifdef NEED_ECC
+L_CFLAGS += -DCONFIG_ECC
+endif
+
+ifdef CONFIG_NO_RANDOM_POOL
+L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+OBJS += src/crypto/random.c
+HOBJS += src/crypto/random.c
+HOBJS += src/utils/eloop.c
+HOBJS += $(SHA1OBJS)
+ifneq ($(CONFIG_TLS), openssl)
+HOBJS += src/crypto/md5.c
+endif
+endif
+
+ifdef CONFIG_RADIUS_SERVER
+L_CFLAGS += -DRADIUS_SERVER
+OBJS += src/radius/radius_server.c
+endif
+
+ifdef CONFIG_IPV6
+L_CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef CONFIG_DRIVER_RADIUS_ACL
+L_CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
+endif
+
+ifdef NEED_BASE64
+OBJS += src/utils/base64.c
+endif
+
+ifdef NEED_AP_MLME
+OBJS += src/ap/wmm.c
+OBJS += src/ap/ap_list.c
+OBJS += src/ap/ieee802_11.c
+OBJS += src/ap/hw_features.c
+OBJS += src/ap/dfs.c
+L_CFLAGS += -DNEED_AP_MLME
+endif
+ifdef CONFIG_IEEE80211N
+OBJS += src/ap/ieee802_11_ht.c
+endif
+
+ifdef CONFIG_IEEE80211AC
+OBJS += src/ap/ieee802_11_vht.c
+endif
+
+ifdef CONFIG_P2P_MANAGER
+L_CFLAGS += -DCONFIG_P2P_MANAGER
+OBJS += src/ap/p2p_hostapd.c
+endif
+
+ifdef CONFIG_HS20
+L_CFLAGS += -DCONFIG_HS20
+OBJS += src/ap/hs20.c
+CONFIG_INTERWORKING=y
+endif
+
+ifdef CONFIG_INTERWORKING
+L_CFLAGS += -DCONFIG_INTERWORKING
+OBJS += src/common/gas.c
+OBJS += src/ap/gas_serv.c
+endif
+
+ifdef CONFIG_PROXYARP
+L_CFLAGS += -DCONFIG_PROXYARP
+OBJS += src/ap/x_snoop.c
+OBJS += src/ap/dhcp_snoop.c
+ifdef CONFIG_IPV6
+OBJS += src/ap/ndisc_snoop.c
+endif
+endif
+
+OBJS += src/drivers/driver_common.c
+
+ifdef CONFIG_ACS
+L_CFLAGS += -DCONFIG_ACS
+OBJS += src/ap/acs.c
+LIBS += -lm
+endif
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+endif
+
+ifdef CONFIG_DEBUG_LINUX_TRACING
+L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
+ifdef CONFIG_DEBUG_FILE
+L_CFLAGS += -DCONFIG_DEBUG_FILE
+endif
+
+ifdef CONFIG_ANDROID_LOG
+L_CFLAGS += -DCONFIG_ANDROID_LOG
+endif
+
+OBJS_c = hostapd_cli.c
+OBJS_c += src/common/wpa_ctrl.c
+OBJS_c += src/utils/os_$(CONFIG_OS).c
+OBJS_c += src/common/cli.c
+OBJS_c += src/utils/eloop.c
+OBJS_c += src/utils/common.c
+ifdef CONFIG_WPA_TRACE
+OBJS_c += src/utils/trace.c
+endif
+OBJS_c += src/utils/wpa_debug.c
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += src/utils/edit.c
+else
+OBJS_c += src/utils/edit_simple.c
+endif
+
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := hostapd_cli
+LOCAL_MODULE_TAGS := debug
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(OBJS_c)
+LOCAL_C_INCLUDES := $(INCLUDES)
+include $(BUILD_EXECUTABLE)
+
+########################
+include $(CLEAR_VARS)
+LOCAL_MODULE := hostapd
+LOCAL_MODULE_TAGS := optional
+ifdef CONFIG_DRIVER_CUSTOM
+LOCAL_STATIC_LIBRARIES := libCustomWifi
+endif
+ifneq ($(BOARD_HOSTAPD_PRIVATE_LIB),)
+LOCAL_STATIC_LIBRARIES += $(BOARD_HOSTAPD_PRIVATE_LIB)
+endif
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog libcrypto libssl
+ifdef CONFIG_DRIVER_NL80211
+ifneq ($(wildcard external/libnl),)
+LOCAL_SHARED_LIBRARIES += libnl
+else
+LOCAL_STATIC_LIBRARIES += libnl_2
+endif
+endif
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(OBJS)
+LOCAL_C_INCLUDES := $(INCLUDES)
+LOCAL_INIT_RC := hostapd.android.rc
+include $(BUILD_EXECUTABLE)
+
+endif # ifeq ($(WPA_BUILD_HOSTAPD),true)
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index af54e1e5b4e4..d2b669b58654 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,5 +1,78 @@
ChangeLog for hostapd
+2016-10-02 - v2.6
+ * fixed EAP-pwd last fragment validation
+ [http://w1.fi/security/2015-7/] (CVE-2015-5314)
+ * fixed WPS configuration update vulnerability with malformed passphrase
+ [http://w1.fi/security/2016-1/] (CVE-2016-4476)
+ * extended channel switch support for VHT bandwidth changes
+ * added support for configuring new ANQP-elements with
+ anqp_elem=<InfoID>:<hexdump of payload>
+ * fixed Suite B 192-bit AKM to use proper PMK length
+ (note: this makes old releases incompatible with the fixed behavior)
+ * added no_probe_resp_if_max_sta=1 parameter to disable Probe Response
+ frame sending for not-associated STAs if max_num_sta limit has been
+ reached
+ * added option (-S as command line argument) to request all interfaces
+ to be started at the same time
+ * modified rts_threshold and fragm_threshold configuration parameters
+ to allow -1 to be used to disable RTS/fragmentation
+ * EAP-pwd: added support for Brainpool Elliptic Curves
+ (with OpenSSL 1.0.2 and newer)
+ * fixed EAPOL reauthentication after FT protocol run
+ * fixed FTIE generation for 4-way handshake after FT protocol run
+ * fixed and improved various FST operations
+ * TLS server
+ - support SHA384 and SHA512 hashes
+ - support TLS v1.2 signature algorithm with SHA384 and SHA512
+ - support PKCS #5 v2.0 PBES2
+ - support PKCS #5 with PKCS #12 style key decryption
+ - minimal support for PKCS #12
+ - support OCSP stapling (including ocsp_multi)
+ * added support for OpenSSL 1.1 API changes
+ - drop support for OpenSSL 0.9.8
+ - drop support for OpenSSL 1.0.0
+ * EAP-PEAP: support fast-connect crypto binding
+ * RADIUS
+ - fix Called-Station-Id to not escape SSID
+ - add Event-Timestamp to all Accounting-Request packets
+ - add Acct-Session-Id to Accounting-On/Off
+ - add Acct-Multi-Session-Id ton Access-Request packets
+ - add Service-Type (= Frames)
+ - allow server to provide PSK instead of passphrase for WPA-PSK
+ Tunnel_password case
+ - update full message for interim accounting updates
+ - add Acct-Delay-Time into Accounting messages
+ - add require_message_authenticator configuration option to require
+ CoA/Disconnect-Request packets to be authenticated
+ * started to postpone WNM-Notification frame sending by 100 ms so that
+ the STA has some more time to configure the key before this frame is
+ received after the 4-way handshake
+ * VHT: added interoperability workaround for 80+80 and 160 MHz channels
+ * extended VLAN support (per-STA vif, etc.)
+ * fixed PMKID derivation with SAE
+ * nl80211
+ - added support for full station state operations
+ - fix IEEE 802.1X/WEP EAP reauthentication and rekeying to use
+ unencrypted EAPOL frames
+ * added initial MBO support; number of extensions to WNM BSS Transition
+ Management
+ * added initial functionality for location related operations
+ * added assocresp_elements parameter to allow vendor specific elements
+ to be added into (Re)Association Response frames
+ * improved Public Action frame addressing
+ - use Address 3 = wildcard BSSID in GAS response if a query from an
+ unassociated STA used that address
+ - fix TX status processing for Address 3 = wildcard BSSID
+ - add gas_address3 configuration parameter to control Address 3
+ behavior
+ * added command line parameter -i to override interface parameter in
+ hostapd.conf
+ * added command completion support to hostapd_cli
+ * added passive client taxonomy determination (CONFIG_TAXONOMY=y
+ compile option and "SIGNATURE <addr>" control interface command)
+ * number of small fixes
+
2015-09-27 - v2.5
* fixed WPS UPnP vulnerability with HTTP chunked transfer encoding
[http://w1.fi/security/2015-2/] (CVE-2015-4141)
diff --git a/hostapd/Makefile b/hostapd/Makefile
index a812b9d661c3..46dffe5a3aca 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -6,18 +6,39 @@ ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
+ifdef LIBS
+# If LIBS is set with some global build system defaults, clone those for
+# LIBS_c, LIBS_h, and LIBS_n to cover hostapd_cli, hlr_auc_gw, and
+# nt_password_hash as well.
+ifndef LIBS_c
+LIBS_c := $(LIBS)
+endif
+ifndef LIBS_h
+LIBS_h := $(LIBS)
+endif
+ifndef LIBS_n
+LIBS_n := $(LIBS)
+endif
+endif
+
CFLAGS += $(EXTRA_CFLAGS)
CFLAGS += -I$(abspath ../src)
CFLAGS += -I$(abspath ../src/utils)
export BINDIR ?= /usr/local/bin/
-# Uncomment following line and set the path to your kernel tree include
-# directory if your C library does not include all header files.
-# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include
-
-include .config
+ifndef CONFIG_NO_GITVER
+# Add VERSION_STR postfix for builds from a git repository
+ifeq ($(wildcard ../.git),../.git)
+GITVER := $(shell git describe --dirty=+)
+ifneq ($(GITVER),)
+CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\"
+endif
+endif
+endif
+
ifdef CONFIG_TESTING_OPTIONS
CFLAGS += -DCONFIG_TESTING_OPTIONS
CONFIG_WPS_TESTING=y
@@ -63,8 +84,13 @@ OBJS += ../src/ap/pmksa_cache_auth.o
OBJS += ../src/ap/ieee802_11_shared.o
OBJS += ../src/ap/beacon.o
OBJS += ../src/ap/bss_load.o
+OBJS += ../src/ap/neighbor_db.o
+OBJS += ../src/ap/rrm.o
-OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
+OBJS_c = hostapd_cli.o
+OBJS_c += ../src/common/wpa_ctrl.o
+OBJS_c += ../src/utils/os_$(CONFIG_OS).o
+OBJS_c += ../src/common/cli.o
NEED_RC4=y
NEED_AES=y
@@ -74,6 +100,11 @@ NEED_SHA1=y
OBJS += ../src/drivers/drivers.o
CFLAGS += -DHOSTAPD
+ifdef CONFIG_TAXONOMY
+CFLAGS += -DCONFIG_TAXONOMY
+OBJS += ../src/ap/taxonomy.o
+endif
+
ifdef CONFIG_MODULE_TESTS
CFLAGS += -DCONFIG_MODULE_TESTS
OBJS += hapd_module_tests.o
@@ -115,6 +146,10 @@ ifdef CONFIG_ELOOP_EPOLL
CFLAGS += -DCONFIG_ELOOP_EPOLL
endif
+ifdef CONFIG_ELOOP_KQUEUE
+CFLAGS += -DCONFIG_ELOOP_KQUEUE
+endif
+
OBJS += ../src/utils/common.o
OBJS_c += ../src/utils/common.o
OBJS += ../src/utils/wpa_debug.o
@@ -165,22 +200,53 @@ ifdef CONFIG_NO_VLAN
CFLAGS += -DCONFIG_NO_VLAN
else
OBJS += ../src/ap/vlan_init.o
-ifdef CONFIG_VLAN_NETLINK
+OBJS += ../src/ap/vlan_ifconfig.o
+OBJS += ../src/ap/vlan.o
ifdef CONFIG_FULL_DYNAMIC_VLAN
+# Define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
+# and VLAN interfaces for the VLAN feature.
+CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
+OBJS += ../src/ap/vlan_full.o
+ifdef CONFIG_VLAN_NETLINK
OBJS += ../src/ap/vlan_util.o
+else
+OBJS += ../src/ap/vlan_ioctl.o
endif
-CFLAGS += -DCONFIG_VLAN_NETLINK
endif
endif
ifdef CONFIG_NO_CTRL_IFACE
CFLAGS += -DCONFIG_NO_CTRL_IFACE
else
+ifeq ($(CONFIG_CTRL_IFACE), udp)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+else
+ifeq ($(CONFIG_CTRL_IFACE), udp6)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6
+else
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+else
+ifeq ($(CONFIG_CTRL_IFACE), udp6-remote)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6
+else
+CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+endif
+endif
+endif
+endif
+OBJS += ../src/common/ctrl_iface_common.o
OBJS += ctrl_iface.o
OBJS += ../src/ap/ctrl_iface_ap.o
endif
-CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
+ifndef CONFIG_NO_CTRL_IFACE
+CFLAGS += -DCONFIG_CTRL_IFACE
+endif
ifdef CONFIG_IAPP
CFLAGS += -DCONFIG_IAPP
@@ -252,6 +318,11 @@ ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_MBO
+CFLAGS += -DCONFIG_MBO
+OBJS += ../src/ap/mbo_ap.o
+endif
+
include ../src/drivers/drivers.mak
OBJS += $(DRV_AP_OBJS)
CFLAGS += $(DRV_AP_CFLAGS)
@@ -534,6 +605,7 @@ endif
ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
OBJS += ../src/crypto/tls_openssl.o
+OBJS += ../src/crypto/tls_openssl_ocsp.o
LIBS += -lssl
endif
OBJS += ../src/crypto/crypto_openssl.o
@@ -634,6 +706,8 @@ CONFIG_INTERNAL_SHA1=y
CONFIG_INTERNAL_MD4=y
CONFIG_INTERNAL_MD5=y
CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_SHA384=y
+CONFIG_INTERNAL_SHA512=y
CONFIG_INTERNAL_RC4=y
CONFIG_INTERNAL_DH_GROUP5=y
endif
@@ -794,6 +868,16 @@ CFLAGS += -DCONFIG_SHA384
OBJS += ../src/crypto/sha384-prf.o
endif
+ifdef CONFIG_INTERNAL_SHA384
+CFLAGS += -DCONFIG_INTERNAL_SHA384
+OBJS += ../src/crypto/sha384-internal.o
+endif
+
+ifdef CONFIG_INTERNAL_SHA512
+CFLAGS += -DCONFIG_INTERNAL_SHA512
+OBJS += ../src/crypto/sha512-internal.o
+endif
+
ifdef NEED_DH_GROUPS
OBJS += ../src/crypto/dh_groups.o
endif
@@ -835,12 +919,6 @@ ifdef CONFIG_DRIVER_RADIUS_ACL
CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
endif
-ifdef CONFIG_FULL_DYNAMIC_VLAN
-# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
-# and vlan interfaces for the vlan feature.
-CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
-endif
-
ifdef NEED_BASE64
OBJS += ../src/utils/base64.o
endif
diff --git a/hostapd/README b/hostapd/README
index 366b1998f484..5d5fd365bb62 100644
--- a/hostapd/README
+++ b/hostapd/README
@@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
Authenticator and RADIUS authentication server
================================================================
-Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
diff --git a/hostapd/android.config b/hostapd/android.config
new file mode 100644
index 000000000000..e382c4081ebb
--- /dev/null
+++ b/hostapd/android.config
@@ -0,0 +1,201 @@
+# Example hostapd build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cass, these lines should use += in order not
+# to override previous values of the variables.
+
+# Driver interface for Host AP driver
+#CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for wired authenticator
+#CONFIG_DRIVER_WIRED=y
+
+# Driver interface for drivers using the nl80211 kernel interface
+#CONFIG_DRIVER_NL80211=y
+# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be
+# shipped with your distribution yet. If that is the case, you need to build
+# newer libnl version and point the hostapd build to use it.
+#LIBNL=/usr/src/libnl
+#CFLAGS += -I$(LIBNL)/include
+#LIBS += -L$(LIBNL)/lib
+CONFIG_LIBNL20=y
+
+# QCA vendor extensions to nl80211
+CONFIG_DRIVER_NL80211_QCA=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for no driver (e.g., RADIUS server only)
+#CONFIG_DRIVER_NONE=y
+
+# IEEE 802.11F/IAPP
+#CONFIG_IAPP=y
+
+# WPA2/IEEE 802.11i RSN pre-authentication
+#CONFIG_RSN_PREAUTH=y
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+#CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+CONFIG_IEEE80211W=y
+
+# Integrated EAP server
+#CONFIG_EAP=y
+
+# EAP-MD5 for the integrated EAP server
+#CONFIG_EAP_MD5=y
+
+# EAP-TLS for the integrated EAP server
+#CONFIG_EAP_TLS=y
+
+# EAP-MSCHAPv2 for the integrated EAP server
+#CONFIG_EAP_MSCHAPV2=y
+
+# EAP-PEAP for the integrated EAP server
+#CONFIG_EAP_PEAP=y
+
+# EAP-GTC for the integrated EAP server
+#CONFIG_EAP_GTC=y
+
+# EAP-TTLS for the integrated EAP server
+#CONFIG_EAP_TTLS=y
+
+# EAP-SIM for the integrated EAP server
+#CONFIG_EAP_SIM=y
+
+# EAP-AKA for the integrated EAP server
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' for the integrated EAP server
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# EAP-PAX for the integrated EAP server
+#CONFIG_EAP_PAX=y
+
+# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-SAKE for the integrated EAP server
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK for the integrated EAP server
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-FAST for the integrated EAP server
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# Wi-Fi Protected Setup (WPS)
+CONFIG_WPS=y
+# Enable UPnP support for external WPS Registrars
+#CONFIG_WPS_UPNP=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# Trusted Network Connect (EAP-TNC)
+#CONFIG_EAP_TNC=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# RADIUS authentication server. This provides access to the integrated EAP
+# server from external hosts using RADIUS.
+#CONFIG_RADIUS_SERVER=y
+
+# Build IPv6 support for RADIUS operations
+CONFIG_IPV6=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Use the hostapd's IEEE 802.11 authentication (ACL), but without
+# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
+#CONFIG_DRIVER_RADIUS_ACL=y
+
+# IEEE 802.11n (High Throughput) support
+CONFIG_IEEE80211N=y
+
+# Remove debugging code that is printing out debug messages to stdout.
+# This can be used to reduce the size of the hostapd considerably if debugging
+# code is not needed.
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Add support for writing debug log to Android logcat instead of standard output
+CONFIG_ANDROID_LOG=y
+
+# Remove support for RADIUS accounting
+#CONFIG_NO_ACCOUNTING=y
+
+# Remove support for RADIUS
+CONFIG_NO_RADIUS=y
+
+# Remove support for VLANs
+#CONFIG_NO_VLAN=y
+
+# Remove support for dumping internal state through control interface commands
+# This can be used to reduce binary size at the cost of disabling a debugging
+# option.
+#CONFIG_NO_DUMP_STATE=y
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+CONFIG_OS=unix
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# Should we use poll instead of select? Select is used by default.
+#CONFIG_ELOOP_POLL=y
+
+# Should we use epoll instead of select? Select is used by default.
+#CONFIG_ELOOP_EPOLL=y
+
+# Enable AP
+CONFIG_AP=y
+
+# Enable Fast Session Transfer (FST)
+#CONFIG_FST=y
+
+# Multiband Operation support
+# These extentions facilitate efficient use of multiple frequency bands
+# available to the AP and the devices that may associate with it.
+#CONFIG_MBO=y
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 82ac61d7729a..5079f69e3bc5 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -97,6 +97,8 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
}
vlan->vlan_id = vlan_id;
+ vlan->vlan_desc.untagged = vlan_id;
+ vlan->vlan_desc.notempty = !!vlan_id;
os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
vlan->next = bss->vlan;
bss->vlan = vlan;
@@ -197,7 +199,10 @@ static int hostapd_config_read_maclist(const char *fname,
*acl = newacl;
os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
- (*acl)[*num].vlan_id = vlan_id;
+ os_memset(&(*acl)[*num].vlan_id, 0,
+ sizeof((*acl)[*num].vlan_id));
+ (*acl)[*num].vlan_id.untagged = vlan_id;
+ (*acl)[*num].vlan_id.notempty = !!vlan_id;
(*num)++;
}
@@ -631,8 +636,7 @@ hostapd_parse_radius_attr(const char *value)
}
-static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
- const char *val)
+static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val)
{
char *secret;
@@ -640,7 +644,7 @@ static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
if (secret == NULL)
return -1;
- secret++;
+ *secret++ = '\0';
if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
return -1;
@@ -1519,6 +1523,54 @@ fail:
}
+static int parse_anqp_elem(struct hostapd_bss_config *bss, char *buf, int line)
+{
+ char *delim;
+ u16 infoid;
+ size_t len;
+ struct wpabuf *payload;
+ struct anqp_element *elem;
+
+ delim = os_strchr(buf, ':');
+ if (!delim)
+ return -1;
+ delim++;
+ infoid = atoi(buf);
+ len = os_strlen(delim);
+ if (len & 1)
+ return -1;
+ len /= 2;
+ payload = wpabuf_alloc(len);
+ if (!payload)
+ return -1;
+ if (hexstr2bin(delim, wpabuf_put(payload, len), len) < 0) {
+ wpabuf_free(payload);
+ return -1;
+ }
+
+ dl_list_for_each(elem, &bss->anqp_elem, struct anqp_element, list) {
+ if (elem->infoid == infoid) {
+ /* Update existing entry */
+ wpabuf_free(elem->payload);
+ elem->payload = payload;
+ return 0;
+ }
+ }
+
+ /* Add a new entry */
+ elem = os_zalloc(sizeof(*elem));
+ if (!elem) {
+ wpabuf_free(payload);
+ return -1;
+ }
+ elem->infoid = infoid;
+ elem->payload = payload;
+ dl_list_add(&bss->anqp_elem, &elem->list);
+
+ return 0;
+}
+
+
static int parse_qos_map_set(struct hostapd_bss_config *bss,
char *buf, int line)
{
@@ -1867,31 +1919,6 @@ static int hs20_parse_osu_service_desc(struct hostapd_bss_config *bss,
#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 */
-
-
#ifdef CONFIG_ACS
static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf,
char *pos)
@@ -1934,6 +1961,31 @@ fail:
#endif /* CONFIG_ACS */
+static int parse_wpabuf_hex(int line, const char *name, struct wpabuf **buf,
+ const char *val)
+{
+ struct wpabuf *elems;
+
+ if (val[0] == '\0') {
+ wpabuf_free(*buf);
+ *buf = NULL;
+ return 0;
+ }
+
+ elems = wpabuf_parse_bin(val);
+ if (!elems) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid %s '%s'",
+ line, name, val);
+ return -1;
+ }
+
+ wpabuf_free(*buf);
+ *buf = elems;
+
+ return 0;
+}
+
+
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
const char *buf, char *pos, int line)
@@ -2084,6 +2136,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} 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, "ocsp_stapling_response_multi") == 0) {
+ os_free(bss->ocsp_stapling_response_multi);
+ bss->ocsp_stapling_response_multi = os_strdup(pos);
} else if (os_strcmp(buf, "dh_file") == 0) {
os_free(bss->dh_file);
bss->dh_file = os_strdup(pos);
@@ -2139,6 +2194,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} 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_db_timeout") == 0) {
+ bss->eap_sim_db_timeout = atoi(pos);
} else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
bss->eap_sim_aka_result_ind = atoi(pos);
#endif /* EAP_SERVER_SIM */
@@ -2353,6 +2410,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
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);
+ } else if (os_strcmp(buf, "radius_das_require_message_authenticator") ==
+ 0) {
+ bss->radius_das_require_message_authenticator = atoi(pos);
#endif /* CONFIG_NO_RADIUS */
} else if (os_strcmp(buf, "auth_algs") == 0) {
bss->auth_algs = atoi(pos);
@@ -2644,7 +2704,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "rts_threshold") == 0) {
conf->rts_threshold = atoi(pos);
- if (conf->rts_threshold < 0 || conf->rts_threshold > 2347) {
+ if (conf->rts_threshold < -1 || conf->rts_threshold > 65535) {
wpa_printf(MSG_ERROR,
"Line %d: invalid rts_threshold %d",
line, conf->rts_threshold);
@@ -2652,8 +2712,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "fragm_threshold") == 0) {
conf->fragm_threshold = atoi(pos);
- if (conf->fragm_threshold < 256 ||
- conf->fragm_threshold > 2346) {
+ if (conf->fragm_threshold == -1) {
+ /* allow a value of -1 */
+ } else if (conf->fragm_threshold < 256 ||
+ conf->fragm_threshold > 2346) {
wpa_printf(MSG_ERROR,
"Line %d: invalid fragm_threshold %d",
line, conf->fragm_threshold);
@@ -2686,6 +2748,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->preamble = LONG_PREAMBLE;
} else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
bss->ignore_broadcast_ssid = atoi(pos);
+ } else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) {
+ bss->no_probe_resp_if_max_sta = atoi(pos);
} else if (os_strcmp(buf, "wep_default_key") == 0) {
bss->ssid.wep.idx = atoi(pos);
if (bss->ssid.wep.idx > 3) {
@@ -2707,6 +2771,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
#ifndef CONFIG_NO_VLAN
} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
bss->ssid.dynamic_vlan = atoi(pos);
+ } else if (os_strcmp(buf, "per_sta_vif") == 0) {
+ bss->ssid.per_sta_vif = 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'",
@@ -2762,6 +2828,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line);
return 1;
}
+ } else if (os_strcmp(buf, "use_driver_iface_addr") == 0) {
+ conf->use_driver_iface_addr = atoi(pos);
#ifdef CONFIG_IEEE80211W
} else if (os_strcmp(buf, "ieee80211w") == 0) {
bss->ieee80211w = atoi(pos);
@@ -2827,6 +2895,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
} else if (os_strcmp(buf, "vendor_vht") == 0) {
bss->vendor_vht = atoi(pos);
+ } else if (os_strcmp(buf, "use_sta_nsts") == 0) {
+ bss->use_sta_nsts = atoi(pos);
#endif /* CONFIG_IEEE80211AC */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@@ -2965,15 +3035,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
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_dh_pubkey = wpabuf_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_dh_privkey = wpabuf_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_dev_pw = wpabuf_parse_bin(pos);
bss->wps_nfc_pw_from_config = 1;
#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
@@ -3136,6 +3206,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "nai_realm") == 0) {
if (parse_nai_realm(bss, pos, line) < 0)
return 1;
+ } else if (os_strcmp(buf, "anqp_elem") == 0) {
+ if (parse_anqp_elem(bss, pos, line) < 0)
+ return 1;
} else if (os_strcmp(buf, "gas_frag_limit") == 0) {
bss->gas_frag_limit = atoi(pos);
} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
@@ -3149,13 +3222,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
os_free(bss->dump_msk_file);
bss->dump_msk_file = os_strdup(pos);
#endif /* CONFIG_RADIUS_TEST */
+#ifdef CONFIG_PROXYARP
+ } else if (os_strcmp(buf, "proxy_arp") == 0) {
+ bss->proxy_arp = atoi(pos);
+#endif /* CONFIG_PROXYARP */
#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, "proxy_arp") == 0) {
- bss->proxy_arp = atoi(pos);
} else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) {
bss->na_mcast_to_ucast = atoi(pos);
} else if (os_strcmp(buf, "osen") == 0) {
@@ -3231,6 +3306,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "subscr_remediation_method") == 0) {
bss->subscr_remediation_method = atoi(pos);
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ } else if (os_strcmp(buf, "mbo") == 0) {
+ bss->mbo_enabled = atoi(pos);
+#endif /* CONFIG_MBO */
#ifdef CONFIG_TESTING_OPTIONS
#define PARSE_TEST_PROBABILITY(_val) \
} else if (os_strcmp(buf, #_val) == 0) { \
@@ -3249,6 +3328,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
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, "ecsa_ie_only") == 0) {
+ conf->ecsa_ie_only = atoi(pos);
} else if (os_strcmp(buf, "bss_load_test") == 0) {
WPA_PUT_LE16(bss->bss_load_test, atoi(pos));
pos = os_strchr(pos, ':');
@@ -3269,7 +3350,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos));
bss->bss_load_test_set = 1;
} else if (os_strcmp(buf, "radio_measurements") == 0) {
- bss->radio_measurements = atoi(pos);
+ /*
+ * DEPRECATED: This parameter will be removed in the future.
+ * Use rrm_neighbor_report instead.
+ */
+ int val = atoi(pos);
+
+ if (val & BIT(0))
+ bss->radio_measurements[0] |=
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT;
} else if (os_strcmp(buf, "own_ie_override") == 0) {
struct wpabuf *tmp;
size_t len = os_strlen(pos) / 2;
@@ -3290,35 +3379,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->own_ie_override = tmp;
#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)
+ if (parse_wpabuf_hex(line, buf, &bss->vendor_elements, pos))
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);
+ } else if (os_strcmp(buf, "assocresp_elements") == 0) {
+ if (parse_wpabuf_hex(line, buf, &bss->assocresp_elements, 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) {
@@ -3391,7 +3456,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
return -1;
}
val = strtol(pos, &endp, 0);
- if (*endp || val < 1 || val > FST_MAX_LLT_MS) {
+ if (*endp || val < 1 ||
+ (unsigned long int) val > FST_MAX_LLT_MS) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid fst_llt %ld (%s) (expected 1..%u)",
line, val, pos, FST_MAX_LLT_MS);
@@ -3409,6 +3475,22 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "no_auth_if_seen_on") == 0) {
os_free(bss->no_auth_if_seen_on);
bss->no_auth_if_seen_on = os_strdup(pos);
+ } else if (os_strcmp(buf, "lci") == 0) {
+ wpabuf_free(conf->lci);
+ conf->lci = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "civic") == 0) {
+ wpabuf_free(conf->civic);
+ conf->civic = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "rrm_neighbor_report") == 0) {
+ if (atoi(pos))
+ bss->radio_measurements[0] |=
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT;
+ } else if (os_strcmp(buf, "gas_address3") == 0) {
+ bss->gas_address3 = atoi(pos);
+ } else if (os_strcmp(buf, "ftm_responder") == 0) {
+ bss->ftm_responder = atoi(pos);
+ } else if (os_strcmp(buf, "ftm_initiator") == 0) {
+ bss->ftm_initiator = atoi(pos);
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
@@ -3429,7 +3511,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
{
struct hostapd_config *conf;
FILE *f;
- char buf[512], *pos;
+ char buf[4096], *pos;
int line = 0;
int errors = 0;
size_t i;
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index cb6fb1757708..d7db4a7c3c48 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -19,10 +19,16 @@
#include <sys/stat.h>
#include <stddef.h>
+#ifdef CONFIG_CTRL_IFACE_UDP
+#include <netdb.h>
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/module_tests.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
+#include "common/ctrl_iface_common.h"
#include "crypto/tls.h"
#include "drivers/driver.h"
#include "eapol_auth/eapol_auth_sm.h"
@@ -42,6 +48,8 @@
#include "ap/wnm_ap.h"
#include "ap/wpa_auth.h"
#include "ap/beacon.h"
+#include "ap/neighbor_db.h"
+#include "ap/rrm.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
#include "fst/fst_ctrl_iface.h"
@@ -51,14 +59,15 @@
#define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
-struct wpa_ctrl_dst {
- struct wpa_ctrl_dst *next;
- struct sockaddr_un addr;
- socklen_t addrlen;
- int debug_level;
- int errors;
-};
-
+#ifdef CONFIG_CTRL_IFACE_UDP
+#define COOKIE_LEN 8
+static unsigned char cookie[COOKIE_LEN];
+static unsigned char gcookie[COOKIE_LEN];
+#define HOSTAPD_CTRL_IFACE_PORT 8877
+#define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50
+#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878
+#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT 50
+#endif /* CONFIG_CTRL_IFACE_UDP */
static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
enum wpa_msg_type type,
@@ -66,81 +75,27 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
- struct sockaddr_un *from,
+ struct sockaddr_storage *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;
+ return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen);
}
static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
- struct sockaddr_un *from,
+ struct sockaddr_storage *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;
+ return ctrl_iface_detach(&hapd->ctrl_dst, from, fromlen);
}
static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
- struct sockaddr_un *from,
+ struct sockaddr_storage *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;
+ return ctrl_iface_level(&hapd->ctrl_dst, from, fromlen, level);
}
@@ -884,6 +839,8 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
int ret;
u8 nei_rep[1000];
u8 *nei_pos = nei_rep;
+ u8 mbo[10];
+ size_t mbo_len = 0;
if (hwaddr_aton(cmd, addr)) {
wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
@@ -1049,10 +1006,66 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
if (os_strstr(cmd, " disassoc_imminent=1"))
req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+#ifdef CONFIG_MBO
+ pos = os_strstr(cmd, "mbo=");
+ if (pos) {
+ unsigned int mbo_reason, cell_pref, reassoc_delay;
+ u8 *mbo_pos = mbo;
+
+ ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
+ &reassoc_delay, &cell_pref);
+ if (ret != 3) {
+ wpa_printf(MSG_DEBUG,
+ "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
+ return -1;
+ }
+
+ if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid MBO transition reason code %u",
+ mbo_reason);
+ return -1;
+ }
+
+ /* Valid values for Cellular preference are: 0, 1, 255 */
+ if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid MBO cellular capability %u",
+ cell_pref);
+ return -1;
+ }
+
+ if (reassoc_delay > 65535 ||
+ (reassoc_delay &&
+ !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Assoc retry delay is only valid in disassoc imminent mode");
+ return -1;
+ }
+
+ *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = mbo_reason;
+ *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = cell_pref;
+
+ if (reassoc_delay) {
+ *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
+ *mbo_pos++ = 2;
+ WPA_PUT_LE16(mbo_pos, reassoc_delay);
+ mbo_pos += 2;
+ }
+
+ mbo_len = mbo_pos - mbo;
+ }
+#endif /* CONFIG_MBO */
+
ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
valid_int, bss_term_dur, url,
nei_pos > nei_rep ? nei_rep : NULL,
- nei_pos - nei_rep);
+ nei_pos - nei_rep, mbo_len ? mbo : NULL,
+ mbo_len);
os_free(url);
return ret;
}
@@ -1320,9 +1333,28 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
} else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
hapd->ext_eapol_frame_io = atoi(value);
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_MBO
+ } else if (os_strcasecmp(cmd, "mbo_assoc_disallow") == 0) {
+ int val;
+
+ if (!hapd->conf->mbo_enabled)
+ return -1;
+
+ val = atoi(value);
+ if (val < 0 || val > 1)
+ return -1;
+
+ hapd->mbo_assoc_disallow = val;
+ ieee802_11_update_beacons(hapd->iface);
+
+ /*
+ * TODO: Need to configure drivers that do AP MLME offload with
+ * disallowing station logic.
+ */
+#endif /* CONFIG_MBO */
} else {
struct sta_info *sta;
- int vlan_id;
+ struct vlan_description vlan_id;
ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
if (ret)
@@ -1334,7 +1366,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
hapd->conf->deny_mac,
hapd->conf->num_deny_mac, sta->addr,
&vlan_id) &&
- (!vlan_id || vlan_id == sta->vlan_id))
+ (!vlan_id.notempty ||
+ !vlan_compare(&vlan_id, sta->vlan_desc)))
ap_sta_disconnect(
hapd, sta, sta->addr,
WLAN_REASON_UNSPECIFIED);
@@ -1346,7 +1379,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
hapd->conf->accept_mac,
hapd->conf->num_accept_mac,
sta->addr, &vlan_id) ||
- (vlan_id && vlan_id != sta->vlan_id))
+ (vlan_id.notempty &&
+ vlan_compare(&vlan_id, sta->vlan_desc)))
ap_sta_disconnect(
hapd, sta, sta->addr,
WLAN_REASON_UNSPECIFIED);
@@ -1557,8 +1591,8 @@ static u16 ipv4_hdr_checksum(const void *buf, size_t len)
#define HWSIM_PACKETLEN 1500
#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
-void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
+static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
{
struct hostapd_data *hapd = ctx;
const struct ether_header *eth;
@@ -1745,8 +1779,6 @@ done:
static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_fail_func[256];
- extern unsigned int wpa_trace_fail_after;
char *pos;
wpa_trace_fail_after = atoi(cmd);
@@ -1770,9 +1802,6 @@ static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
char *buf, size_t buflen)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_fail_func[256];
- extern unsigned int wpa_trace_fail_after;
-
return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
wpa_trace_fail_func);
#else /* WPA_TRACE_BFD */
@@ -1784,8 +1813,6 @@ static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
static int hostapd_ctrl_test_fail(struct hostapd_data *hapd, char *cmd)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_test_fail_func[256];
- extern unsigned int wpa_trace_test_fail_after;
char *pos;
wpa_trace_test_fail_after = atoi(cmd);
@@ -1809,9 +1836,6 @@ static int hostapd_ctrl_get_fail(struct hostapd_data *hapd,
char *buf, size_t buflen)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_test_fail_func[256];
- extern unsigned int wpa_trace_test_fail_after;
-
return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
wpa_trace_test_fail_func);
#else /* WPA_TRACE_BFD */
@@ -1875,13 +1899,13 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
/* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
vendor_id = strtoul(cmd, &pos, 16);
- if (!isblank(*pos))
+ if (!isblank((unsigned char) *pos))
return -EINVAL;
subcmd = strtoul(pos, &pos, 10);
if (*pos != '\0') {
- if (!isblank(*pos++))
+ if (!isblank((unsigned char) *pos++))
return -EINVAL;
data_len = os_strlen(pos);
}
@@ -2016,6 +2040,9 @@ static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
struct hostapd_sta_info *info;
struct os_reltime now;
+ if (!iface->num_sta_seen)
+ return 0;
+
sta_track_expire(iface, 0);
pos = buf;
@@ -2040,10 +2067,228 @@ static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
+static int hostapd_ctrl_iface_req_lci(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+
+ if (hwaddr_aton(cmd, addr)) {
+ wpa_printf(MSG_INFO, "CTRL: REQ_LCI: Invalid MAC address");
+ return -1;
+ }
+
+ return hostapd_send_lci_req(hapd, addr);
+}
+
+
+static int hostapd_ctrl_iface_req_range(struct hostapd_data *hapd, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ char *token, *context = NULL;
+ int random_interval, min_ap;
+ u8 responders[ETH_ALEN * RRM_RANGE_REQ_MAX_RESPONDERS];
+ unsigned int n_responders;
+
+ token = str_token(cmd, " ", &context);
+ if (!token || hwaddr_aton(token, addr)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE - Bad destination address");
+ return -1;
+ }
+
+ token = str_token(cmd, " ", &context);
+ if (!token)
+ return -1;
+
+ random_interval = atoi(token);
+ if (random_interval < 0 || random_interval > 0xffff)
+ return -1;
+
+ token = str_token(cmd, " ", &context);
+ if (!token)
+ return -1;
+
+ min_ap = atoi(token);
+ if (min_ap <= 0 || min_ap > WLAN_RRM_RANGE_REQ_MAX_MIN_AP)
+ return -1;
+
+ n_responders = 0;
+ while ((token = str_token(cmd, " ", &context))) {
+ if (n_responders == RRM_RANGE_REQ_MAX_RESPONDERS) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE: Too many responders");
+ return -1;
+ }
+
+ if (hwaddr_aton(token, responders + n_responders * ETH_ALEN)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE: Bad responder address");
+ return -1;
+ }
+
+ n_responders++;
+ }
+
+ if (!n_responders) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE - No FTM responder address");
+ return -1;
+ }
+
+ return hostapd_send_range_req(hapd, addr, random_interval, min_ap,
+ responders, n_responders);
+}
+
+
+static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
+{
+ struct wpa_ssid_value ssid;
+ u8 bssid[ETH_ALEN];
+ struct wpabuf *nr, *lci = NULL, *civic = NULL;
+ char *tmp;
+ int ret;
+
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Neighbor report is not enabled");
+ return -1;
+ }
+
+ if (hwaddr_aton(buf, bssid)) {
+ wpa_printf(MSG_ERROR, "CTRL: SET_NEIGHBOR: Bad BSSID");
+ return -1;
+ }
+
+ tmp = os_strstr(buf, "ssid=");
+ if (!tmp || ssid_parse(tmp + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad or missing SSID");
+ return -1;
+ }
+ buf = os_strchr(tmp + 6, tmp[5] == '"' ? '"' : ' ');
+ if (!buf)
+ return -1;
+
+ tmp = os_strstr(buf, "nr=");
+ if (!tmp) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Missing Neighbor Report element");
+ return -1;
+ }
+
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+
+ nr = wpabuf_parse_bin(tmp + 3);
+ if (!nr) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad Neighbor Report element");
+ return -1;
+ }
+
+ if (!buf)
+ goto set;
+
+ tmp = os_strstr(buf, "lci=");
+ if (tmp) {
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+ lci = wpabuf_parse_bin(tmp + 4);
+ if (!lci) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad LCI subelement");
+ wpabuf_free(nr);
+ return -1;
+ }
+ }
+
+ if (!buf)
+ goto set;
+
+ tmp = os_strstr(buf, "civic=");
+ if (tmp) {
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+ civic = wpabuf_parse_bin(tmp + 6);
+ if (!civic) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad civic subelement");
+ wpabuf_free(nr);
+ wpabuf_free(lci);
+ return -1;
+ }
+ }
+
+set:
+ ret = hostapd_neighbor_set(hapd, bssid, &ssid, nr, lci, civic);
+
+ wpabuf_free(nr);
+ wpabuf_free(lci);
+ wpabuf_free(civic);
+
+ return ret;
+}
+
+
+static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
+ char *buf)
+{
+ struct wpa_ssid_value ssid;
+ u8 bssid[ETH_ALEN];
+ char *tmp;
+
+ if (hwaddr_aton(buf, bssid)) {
+ wpa_printf(MSG_ERROR, "CTRL: REMOVE_NEIGHBOR: Bad BSSID");
+ return -1;
+ }
+
+ tmp = os_strstr(buf, "ssid=");
+ if (!tmp || ssid_parse(tmp + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: REMOVE_NEIGHBORr: Bad or missing SSID");
+ return -1;
+ }
+
+ return hostapd_neighbor_remove(hapd, bssid, &ssid);
+}
+
+
+static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf,
+ size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) iface->drv_flags);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (iface->drv_flags & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
char *buf, char *reply,
int reply_size,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen)
{
int reply_len, res;
@@ -2122,6 +2367,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
reply_len = -1;
+#ifdef CONFIG_TAXONOMY
+ } else if (os_strncmp(buf, "SIGNATURE ", 10) == 0) {
+ reply_len = hostapd_ctrl_iface_signature(hapd, buf + 10,
+ reply, reply_size);
+#endif /* CONFIG_TAXONOMY */
+ } else if (os_strncmp(buf, "POLL_STA ", 9) == 0) {
+ if (hostapd_ctrl_iface_poll_sta(hapd, buf + 9))
+ reply_len = -1;
} else if (os_strcmp(buf, "STOP_AP") == 0) {
if (hostapd_ctrl_iface_stop_ap(hapd))
reply_len = -1;
@@ -2276,6 +2529,26 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
reply_len = hostapd_ctrl_iface_track_sta_list(
hapd, reply, reply_size);
#endif /* NEED_AP_MLME */
+ } else if (os_strcmp(buf, "PMKSA") == 0) {
+ reply_len = hostapd_ctrl_iface_pmksa_list(hapd, reply,
+ reply_size);
+ } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
+ hostapd_ctrl_iface_pmksa_flush(hapd);
+ } else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) {
+ if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) {
+ if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REQ_LCI ", 8) == 0) {
+ if (hostapd_ctrl_iface_req_lci(hapd, buf + 8))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REQ_RANGE ", 10) == 0) {
+ if (hostapd_ctrl_iface_req_range(hapd, buf + 10))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
+ reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
+ reply_size);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -2296,12 +2569,15 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
struct hostapd_data *hapd = eloop_ctx;
char buf[4096];
int res;
- struct sockaddr_un from;
+ struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
- char *reply;
+ char *reply, *pos = buf;
const int reply_size = 4096;
int reply_len;
int level = MSG_DEBUG;
+#ifdef CONFIG_CTRL_IFACE_UDP
+ unsigned char lcookie[COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
@@ -2311,9 +2587,6 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
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) {
@@ -2325,10 +2598,46 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
return;
}
- reply_len = hostapd_ctrl_iface_receive_process(hapd, buf,
+#ifdef CONFIG_CTRL_IFACE_UDP
+ if (os_strcmp(buf, "GET_COOKIE") == 0) {
+ os_memcpy(reply, "COOKIE=", 7);
+ wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
+ cookie, COOKIE_LEN);
+ reply_len = 7 + 2 * COOKIE_LEN;
+ goto done;
+ }
+
+ if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
+ hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: No cookie in the request - drop request");
+ os_free(reply);
+ return;
+ }
+
+ if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid cookie in the request - drop request");
+ os_free(reply);
+ return;
+ }
+
+ pos = buf + 7 + 2 * COOKIE_LEN;
+ while (*pos == ' ')
+ pos++;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+ if (os_strcmp(pos, "PING") == 0)
+ level = MSG_EXCESSIVE;
+ wpa_hexdump_ascii(level, "RX ctrl_iface", pos, res);
+
+ reply_len = hostapd_ctrl_iface_receive_process(hapd, pos,
reply, reply_size,
&from, fromlen);
+#ifdef CONFIG_CTRL_IFACE_UDP
+done:
+#endif /* CONFIG_CTRL_IFACE_UDP */
if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
fromlen) < 0) {
wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
@@ -2338,6 +2647,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
}
+#ifndef CONFIG_CTRL_IFACE_UDP
static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
{
char *buf;
@@ -2357,6 +2667,7 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
buf[len - 1] = '\0';
return buf;
}
+#endif /* CONFIG_CTRL_IFACE_UDP */
static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
@@ -2372,6 +2683,99 @@ static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
{
+#ifdef CONFIG_CTRL_IFACE_UDP
+ int port = HOSTAPD_CTRL_IFACE_PORT;
+ char p[32] = { 0 };
+ char port_str[40], *tmp;
+ char *pos;
+ struct addrinfo hints = { 0 }, *res, *saveres;
+ int n;
+
+ if (hapd->ctrl_sock > -1) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+ return 0;
+ }
+
+ if (hapd->conf->ctrl_interface == NULL)
+ return 0;
+
+ pos = os_strstr(hapd->conf->ctrl_interface, "udp:");
+ if (pos) {
+ pos += 4;
+ port = atoi(pos);
+ if (port <= 0) {
+ wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port");
+ goto fail;
+ }
+ }
+
+ dl_list_init(&hapd->ctrl_dst);
+ hapd->ctrl_sock = -1;
+ os_get_random(cookie, COOKIE_LEN);
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ hints.ai_flags = AI_PASSIVE;
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ hints.ai_family = AF_INET6;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+ hints.ai_family = AF_INET;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+ hints.ai_socktype = SOCK_DGRAM;
+
+try_again:
+ os_snprintf(p, sizeof(p), "%d", port);
+ n = getaddrinfo(NULL, p, &hints, &res);
+ if (n) {
+ wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
+ goto fail;
+ }
+
+ saveres = res;
+ hapd->ctrl_sock = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+ if (hapd->ctrl_sock < 0) {
+ wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
+ goto fail;
+ }
+
+ if (bind(hapd->ctrl_sock, res->ai_addr, res->ai_addrlen) < 0) {
+ port--;
+ if ((HOSTAPD_CTRL_IFACE_PORT - port) <
+ HOSTAPD_CTRL_IFACE_PORT_LIMIT && !pos)
+ goto try_again;
+ wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
+ goto fail;
+ }
+
+ freeaddrinfo(saveres);
+
+ os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
+ tmp = os_strdup(port_str);
+ if (tmp) {
+ os_free(hapd->conf->ctrl_interface);
+ hapd->conf->ctrl_interface = tmp;
+ }
+ wpa_printf(MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
+
+ if (eloop_register_read_sock(hapd->ctrl_sock,
+ hostapd_ctrl_iface_receive, hapd, NULL) <
+ 0) {
+ hostapd_ctrl_iface_deinit(hapd);
+ return -1;
+ }
+
+ hapd->msg_ctx = hapd;
+ wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
+ return 0;
+
+fail:
+ if (hapd->ctrl_sock >= 0)
+ close(hapd->ctrl_sock);
+ return -1;
+#else /* CONFIG_CTRL_IFACE_UDP */
struct sockaddr_un addr;
int s = -1;
char *fname = NULL;
@@ -2381,6 +2785,8 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
return 0;
}
+ dl_list_init(&hapd->ctrl_dst);
+
if (hapd->conf->ctrl_interface == NULL)
return 0;
@@ -2520,6 +2926,7 @@ fail:
os_free(fname);
}
return -1;
+#endif /* CONFIG_CTRL_IFACE_UDP */
}
@@ -2528,10 +2935,14 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
struct wpa_ctrl_dst *dst, *prev;
if (hapd->ctrl_sock > -1) {
+#ifndef CONFIG_CTRL_IFACE_UDP
char *fname;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
+
eloop_unregister_read_sock(hapd->ctrl_sock);
close(hapd->ctrl_sock);
hapd->ctrl_sock = -1;
+#ifndef CONFIG_CTRL_IFACE_UDP
fname = hostapd_ctrl_iface_path(hapd);
if (fname)
unlink(fname);
@@ -2550,15 +2961,12 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
strerror(errno));
}
}
+#endif /* !CONFIG_CTRL_IFACE_UDP */
}
- dst = hapd->ctrl_dst;
- hapd->ctrl_dst = NULL;
- while (dst) {
- prev = dst;
- dst = dst->next;
- os_free(prev);
- }
+ dl_list_for_each_safe(dst, prev, &hapd->ctrl_dst, struct wpa_ctrl_dst,
+ list)
+ os_free(dst);
#ifdef CONFIG_TESTING_OPTIONS
l2_packet_deinit(hapd->l2_test);
@@ -2590,54 +2998,18 @@ static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
- struct sockaddr_un *from,
+ struct sockaddr_storage *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 = interfaces->global_ctrl_dst;
- interfaces->global_ctrl_dst = dst;
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached (global)",
- from->sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path));
- return 0;
+ return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen);
}
static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen)
{
- struct wpa_ctrl_dst *dst, *prev = NULL;
-
- dst = interfaces->global_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 (global)",
- from->sun_path,
- fromlen -
- offsetof(struct sockaddr_un, sun_path));
- if (prev == NULL)
- interfaces->global_ctrl_dst = dst->next;
- else
- prev->next = dst->next;
- os_free(dst);
- return 0;
- }
- prev = dst;
- dst = dst->next;
- }
- return -1;
+ return ctrl_iface_detach(&interfaces->global_ctrl_dst, from, fromlen);
}
@@ -2791,6 +3163,51 @@ error_return:
static int
+hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces *interfaces,
+ const char *input,
+ char *reply, int reply_size)
+{
+ size_t i, j;
+ int res;
+ char *pos, *end;
+ struct hostapd_iface *iface;
+ int show_ctrl = 0;
+
+ if (input)
+ show_ctrl = !!os_strstr(input, "ctrl");
+
+ pos = reply;
+ end = reply + reply_size;
+
+ for (i = 0; i < interfaces->count; i++) {
+ iface = interfaces->iface[i];
+
+ for (j = 0; j < iface->num_bss; j++) {
+ struct hostapd_bss_config *conf;
+
+ conf = iface->conf->bss[j];
+ if (show_ctrl)
+ res = os_snprintf(pos, end - pos,
+ "%s ctrl_iface=%s\n",
+ conf->iface,
+ conf->ctrl_interface ?
+ conf->ctrl_interface : "N/A");
+ else
+ res = os_snprintf(pos, end - pos, "%s\n",
+ conf->iface);
+ if (os_snprintf_error(end - pos, res)) {
+ *pos = '\0';
+ return pos - reply;
+ }
+ pos += res;
+ }
+ }
+
+ return pos - reply;
+}
+
+
+static int
hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces *interfaces,
char *cmd)
{
@@ -2839,7 +3256,7 @@ static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
const char *ifname,
char *buf, char *reply,
int reply_size,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen)
{
struct hostapd_data *hapd;
@@ -2863,15 +3280,18 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
void *interfaces = eloop_ctx;
- char buf[256];
+ char buffer[256], *buf = buffer;
int res;
- struct sockaddr_un from;
+ struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
char *reply;
int reply_len;
const int reply_size = 4096;
+#ifdef CONFIG_CTRL_IFACE_UDP
+ unsigned char lcookie[COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
@@ -2894,6 +3314,35 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
os_memcpy(reply, "OK\n", 3);
reply_len = 3;
+#ifdef CONFIG_CTRL_IFACE_UDP
+ if (os_strcmp(buf, "GET_COOKIE") == 0) {
+ os_memcpy(reply, "COOKIE=", 7);
+ wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
+ gcookie, COOKIE_LEN);
+ reply_len = 7 + 2 * COOKIE_LEN;
+ goto send_reply;
+ }
+
+ if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
+ hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: No cookie in the request - drop request");
+ os_free(reply);
+ return;
+ }
+
+ if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid cookie in the request - drop request");
+ os_free(reply);
+ return;
+ }
+
+ buf += 7 + 2 * COOKIE_LEN;
+ while (*buf == ' ')
+ buf++;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
if (os_strncmp(buf, "IFNAME=", 7) == 0) {
char *pos = os_strchr(buf + 7, ' ');
@@ -2930,7 +3379,6 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
reply_len = -1;
#ifdef CONFIG_MODULE_TESTS
} else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
- int hapd_module_tests(void);
if (hapd_module_tests() < 0)
reply_len = -1;
#endif /* CONFIG_MODULE_TESTS */
@@ -2954,6 +3402,11 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
reply_len = os_snprintf(reply, reply_size, "OK\n");
else
reply_len = -1;
+ } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
+ reply_len = hostapd_global_ctrl_iface_interfaces(
+ interfaces, buf + 10, reply, sizeof(buffer));
+ } else if (os_strcmp(buf, "TERMINATE") == 0) {
+ eloop_terminate();
} else {
wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
"ignored");
@@ -2975,6 +3428,7 @@ send_reply:
}
+#ifndef CONFIG_CTRL_IFACE_UDP
static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
{
char *buf;
@@ -2994,10 +3448,95 @@ static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
buf[len - 1] = '\0';
return buf;
}
+#endif /* CONFIG_CTRL_IFACE_UDP */
int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
{
+#ifdef CONFIG_CTRL_IFACE_UDP
+ int port = HOSTAPD_GLOBAL_CTRL_IFACE_PORT;
+ char p[32] = { 0 };
+ char *pos;
+ struct addrinfo hints = { 0 }, *res, *saveres;
+ int n;
+
+ if (interface->global_ctrl_sock > -1) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+ return 0;
+ }
+
+ if (interface->global_iface_path == NULL)
+ return 0;
+
+ pos = os_strstr(interface->global_iface_path, "udp:");
+ if (pos) {
+ pos += 4;
+ port = atoi(pos);
+ if (port <= 0) {
+ wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port");
+ goto fail;
+ }
+ }
+
+ dl_list_init(&interface->global_ctrl_dst);
+ interface->global_ctrl_sock = -1;
+ os_get_random(gcookie, COOKIE_LEN);
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ hints.ai_flags = AI_PASSIVE;
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ hints.ai_family = AF_INET6;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+ hints.ai_family = AF_INET;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+ hints.ai_socktype = SOCK_DGRAM;
+
+try_again:
+ os_snprintf(p, sizeof(p), "%d", port);
+ n = getaddrinfo(NULL, p, &hints, &res);
+ if (n) {
+ wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
+ goto fail;
+ }
+
+ saveres = res;
+ interface->global_ctrl_sock = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+ if (interface->global_ctrl_sock < 0) {
+ wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
+ goto fail;
+ }
+
+ if (bind(interface->global_ctrl_sock, res->ai_addr, res->ai_addrlen) <
+ 0) {
+ port++;
+ if ((port - HOSTAPD_GLOBAL_CTRL_IFACE_PORT) <
+ HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
+ goto try_again;
+ wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
+ goto fail;
+ }
+
+ freeaddrinfo(saveres);
+
+ wpa_printf(MSG_DEBUG, "global ctrl_iface_init UDP port: %d", port);
+
+ if (eloop_register_read_sock(interface->global_ctrl_sock,
+ hostapd_global_ctrl_iface_receive,
+ interface, NULL) < 0) {
+ hostapd_global_ctrl_iface_deinit(interface);
+ return -1;
+ }
+
+ return 0;
+
+fail:
+ if (interface->global_ctrl_sock >= 0)
+ close(interface->global_ctrl_sock);
+ return -1;
+#else /* CONFIG_CTRL_IFACE_UDP */
struct sockaddr_un addr;
int s = -1;
char *fname = NULL;
@@ -3103,18 +3642,22 @@ fail:
os_free(fname);
}
return -1;
+#endif /* CONFIG_CTRL_IFACE_UDP */
}
void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
{
+#ifndef CONFIG_CTRL_IFACE_UDP
char *fname = NULL;
+#endif /* CONFIG_CTRL_IFACE_UDP */
struct wpa_ctrl_dst *dst, *prev;
if (interfaces->global_ctrl_sock > -1) {
eloop_unregister_read_sock(interfaces->global_ctrl_sock);
close(interfaces->global_ctrl_sock);
interfaces->global_ctrl_sock = -1;
+#ifndef CONFIG_CTRL_IFACE_UDP
fname = hostapd_global_ctrl_iface_path(interfaces);
if (fname) {
unlink(fname);
@@ -3134,18 +3677,15 @@ void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
strerror(errno));
}
}
+#endif /* CONFIG_CTRL_IFACE_UDP */
}
os_free(interfaces->global_iface_path);
interfaces->global_iface_path = NULL;
- dst = interfaces->global_ctrl_dst;
- interfaces->global_ctrl_dst = NULL;
- while (dst) {
- prev = dst;
- dst = dst->next;
- os_free(prev);
- }
+ dl_list_for_each_safe(dst, prev, &interfaces->global_ctrl_dst,
+ struct wpa_ctrl_dst, list)
+ os_free(dst);
}
@@ -3154,6 +3694,7 @@ 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 dl_list *ctrl_dst;
struct msghdr msg;
int idx;
struct iovec io[2];
@@ -3162,13 +3703,13 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
if (type != WPA_MSG_ONLY_GLOBAL) {
s = hapd->ctrl_sock;
- dst = hapd->ctrl_dst;
+ ctrl_dst = &hapd->ctrl_dst;
} else {
s = hapd->iface->interfaces->global_ctrl_sock;
- dst = hapd->iface->interfaces->global_ctrl_dst;
+ ctrl_dst = &hapd->iface->interfaces->global_ctrl_dst;
}
- if (s < 0 || dst == NULL)
+ if (s < 0 || dl_list_empty(ctrl_dst))
return;
os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
@@ -3181,12 +3722,10 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
msg.msg_iovlen = 2;
idx = 0;
- while (dst) {
- next = dst->next;
+ dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
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));
+ sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor send",
+ &dst->addr, dst->addrlen);
msg.msg_name = &dst->addr;
msg.msg_namelen = dst->addrlen;
if (sendmsg(s, &msg, 0) < 0) {
@@ -3210,7 +3749,6 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
dst->errors = 0;
}
idx++;
- dst = next;
}
}
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 430f7584b167..4659dd1e6bcb 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -18,6 +18,9 @@ CONFIG_DRIVER_HOSTAP=y
# Driver interface for drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
+# QCA vendor extensions to nl80211
+#CONFIG_DRIVER_NL80211_QCA=y
+
# driver_nl80211.c requires libnl. If you are compiling it yourself
# you may need to point hostapd to your version of libnl.
#
@@ -246,6 +249,9 @@ CONFIG_IPV6=y
# Should we use epoll instead of select? Select is used by default.
#CONFIG_ELOOP_EPOLL=y
+# Should we use kqueue instead of select? Select is used by default.
+#CONFIG_ELOOP_KQUEUE=y
+
# Select TLS implementation
# openssl = OpenSSL (default)
# gnutls = GnuTLS
@@ -326,3 +332,14 @@ CONFIG_IPV6=y
# http://wireless.kernel.org/en/users/Documentation/acs
#
#CONFIG_ACS=y
+
+# Multiband Operation support
+# These extentions facilitate efficient use of multiple frequency bands
+# available to the AP and the devices that may associate with it.
+#CONFIG_MBO=y
+
+# Client Taxonomy
+# Has the AP retain the Probe Request and (Re)Association Request frames from
+# a client, from which a signature can be produced which can identify the model
+# of client device like "Nexus 6P" or "iPhone 5s".
+#CONFIG_TAXONOMY=y
diff --git a/hostapd/hapd_module_tests.c b/hostapd/hapd_module_tests.c
index f7887ebfb7d3..a5016f22bf09 100644
--- a/hostapd/hapd_module_tests.c
+++ b/hostapd/hapd_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/module_tests.h"
int hapd_module_tests(void)
{
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index 84d0308262e6..2117d3423a1b 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -1,6 +1,6 @@
/*
* HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
- * Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2007, 2012-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -284,7 +284,7 @@ static int read_gsm_triplets(const char *fname)
f = fopen(fname, "r");
if (f == NULL) {
- printf("Could not open GSM tripler data file '%s'\n", fname);
+ printf("Could not open GSM triplet data file '%s'\n", fname);
return -1;
}
@@ -312,66 +312,40 @@ static int read_gsm_triplets(const char *fname)
}
/* IMSI */
- pos2 = strchr(pos, ':');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid IMSI (%s)\n",
- fname, line, pos);
- ret = -1;
- break;
- }
- *pos2 = '\0';
- if (strlen(pos) >= sizeof(g->imsi)) {
- printf("%s:%d - Too long IMSI (%s)\n",
- fname, line, pos);
+ pos2 = NULL;
+ pos = str_token(buf, ":", &pos2);
+ if (!pos || os_strlen(pos) >= sizeof(g->imsi)) {
+ printf("%s:%d - Invalid IMSI\n", fname, line);
ret = -1;
break;
}
os_strlcpy(g->imsi, pos, sizeof(g->imsi));
- pos = pos2 + 1;
/* Kc */
- pos2 = strchr(pos, ':');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
- ret = -1;
- break;
- }
- *pos2 = '\0';
- if (strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
- printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
+ pos = str_token(buf, ":", &pos2);
+ if (!pos || os_strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
+ printf("%s:%d - Invalid Kc\n", fname, line);
ret = -1;
break;
}
- pos = pos2 + 1;
/* SRES */
- pos2 = strchr(pos, ':');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid SRES (%s)\n", fname, line,
- pos);
+ pos = str_token(buf, ":", &pos2);
+ if (!pos || os_strlen(pos) != 8 ||
+ hexstr2bin(pos, g->sres, 4)) {
+ printf("%s:%d - Invalid SRES\n", fname, line);
ret = -1;
break;
}
- *pos2 = '\0';
- if (strlen(pos) != 8 || hexstr2bin(pos, g->sres, 4)) {
- printf("%s:%d - Invalid SRES (%s)\n", fname, line,
- pos);
- ret = -1;
- break;
- }
- pos = pos2 + 1;
/* RAND */
- pos2 = strchr(pos, ':');
- if (pos2)
- *pos2 = '\0';
- if (strlen(pos) != 32 || hexstr2bin(pos, g->_rand, 16)) {
- printf("%s:%d - Invalid RAND (%s)\n", fname, line,
- pos);
+ pos = str_token(buf, ":", &pos2);
+ if (!pos || os_strlen(pos) != 32 ||
+ hexstr2bin(pos, g->_rand, 16)) {
+ printf("%s:%d - Invalid RAND\n", fname, line);
ret = -1;
break;
}
- pos = pos2 + 1;
g->next = gsm_db;
gsm_db = g;
@@ -450,86 +424,58 @@ static int read_milenage(const char *fname)
}
/* IMSI */
- pos2 = strchr(pos, ' ');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid IMSI (%s)\n",
- fname, line, pos);
- ret = -1;
- break;
- }
- *pos2 = '\0';
- if (strlen(pos) >= sizeof(m->imsi)) {
- printf("%s:%d - Too long IMSI (%s)\n",
- fname, line, pos);
+ pos2 = NULL;
+ pos = str_token(buf, " ", &pos2);
+ if (!pos || os_strlen(pos) >= sizeof(m->imsi)) {
+ printf("%s:%d - Invalid IMSI\n", fname, line);
ret = -1;
break;
}
os_strlcpy(m->imsi, pos, sizeof(m->imsi));
- pos = pos2 + 1;
/* Ki */
- pos2 = strchr(pos, ' ');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
+ pos = str_token(buf, " ", &pos2);
+ if (!pos || os_strlen(pos) != 32 ||
+ hexstr2bin(pos, m->ki, 16)) {
+ printf("%s:%d - Invalid Ki\n", fname, line);
ret = -1;
break;
}
- *pos2 = '\0';
- if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) {
- printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
- ret = -1;
- break;
- }
- pos = pos2 + 1;
/* OPc */
- pos2 = strchr(pos, ' ');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
- ret = -1;
- break;
- }
- *pos2 = '\0';
- if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) {
- printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
+ pos = str_token(buf, " ", &pos2);
+ if (!pos || os_strlen(pos) != 32 ||
+ hexstr2bin(pos, m->opc, 16)) {
+ printf("%s:%d - Invalid OPc\n", fname, line);
ret = -1;
break;
}
- pos = pos2 + 1;
/* AMF */
- pos2 = strchr(pos, ' ');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
- ret = -1;
- break;
- }
- *pos2 = '\0';
- if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
- printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
+ pos = str_token(buf, " ", &pos2);
+ if (!pos || os_strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
+ printf("%s:%d - Invalid AMF\n", fname, line);
ret = -1;
break;
}
- pos = pos2 + 1;
/* SQN */
- pos2 = strchr(pos, ' ');
- if (pos2)
- *pos2 = '\0';
- if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) {
- printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos);
+ pos = str_token(buf, " ", &pos2);
+ if (!pos || os_strlen(pos) != 12 ||
+ hexstr2bin(pos, m->sqn, 6)) {
+ printf("%s:%d - Invalid SEQ\n", fname, line);
ret = -1;
break;
}
- if (pos2) {
- pos = pos2 + 1;
+ pos = str_token(buf, " ", &pos2);
+ if (pos) {
m->res_len = atoi(pos);
if (m->res_len &&
(m->res_len < EAP_AKA_RES_MIN_LEN ||
m->res_len > EAP_AKA_RES_MAX_LEN)) {
- printf("%s:%d - Invalid RES_len (%s)\n",
- fname, line, pos);
+ printf("%s:%d - Invalid RES_len\n",
+ fname, line);
ret = -1;
break;
}
@@ -1027,7 +973,7 @@ static void usage(void)
{
printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
"database/authenticator\n"
- "Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>\n"
+ "Copyright (c) 2005-2016, Jouni Malinen <j@w1.fi>\n"
"\n"
"usage:\n"
"hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
diff --git a/hostapd/hostapd.android.rc b/hostapd/hostapd.android.rc
new file mode 100644
index 000000000000..83e8d8791e3c
--- /dev/null
+++ b/hostapd/hostapd.android.rc
@@ -0,0 +1,20 @@
+#
+# init.rc fragment for hostapd on Android
+# Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+#
+
+on post-fs-data
+ mkdir /data/misc/wifi/hostapd 0770 wifi wifi
+
+service hostapd /system/bin/hostapd \
+ -e /data/misc/wifi/entropy.bin \
+ /data/misc/wifi/hostapd.conf
+ class main
+ user wifi
+ writepid /data/misc/wifi/hostapd.pid
+ group wifi
+ disabled
+ oneshot
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index a0071f7d82c4..fa9a855a6e5f 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -3,6 +3,8 @@
# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
# management frames with the Host AP driver); wlan0 with many nl80211 drivers
+# Note: This attribute can be overridden by the values supplied with the '-i'
+# command line parameter.
interface=wlan0
# In case of atheros and nl80211 driver interfaces, an additional
@@ -125,11 +127,13 @@ ssid=test
# ieee80211d=1 and local_pwr_constraint configured.
#spectrum_mgmt_required=1
-# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
-# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
-# specify band). When using ACS (see channel parameter), a special value "any"
-# can be used to indicate that any support band can be used. This special case
-# is currently supported only with drivers with which offloaded ACS is used.
+# Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz),
+# g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used
+# with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this
+# needs to be set to hw_mode=a. When using ACS (see channel parameter), a
+# special value "any" can be used to indicate that any support band can be used.
+# This special case is currently supported only with drivers with which
+# offloaded ACS is used.
# Default: IEEE 802.11b
hw_mode=g
@@ -173,7 +177,7 @@ channel=1
# Channel list restriction. This option allows hostapd to select one of the
# provided channels when a channel should be automatically selected.
# Channel list can be provided as range using hyphen ('-') or individual
-# channels can be specified by space (' ') seperated values
+# channels can be specified by space (' ') separated values
# Default: all channels allowed in selected hw_mode
#chanlist=100 104 108 112 116
#chanlist=1 6 11-13
@@ -192,16 +196,16 @@ dtim_period=2
# (default: 2007)
max_num_sta=255
-# RTS/CTS threshold; 2347 = disabled (default); range 0..2347
+# RTS/CTS threshold; -1 = disabled (default); range -1..65535
# If this field is not included in hostapd.conf, hostapd will not control
# RTS threshold and 'iwconfig wlan# rts <val>' can be used to set it.
-rts_threshold=2347
+rts_threshold=-1
-# Fragmentation threshold; 2346 = disabled (default); range 256..2346
+# Fragmentation threshold; -1 = disabled (default); range -1, 256..2346
# If this field is not included in hostapd.conf, hostapd will not control
# fragmentation threshold and 'iwconfig wlan# frag <val>' can be used to set
# it.
-fragm_threshold=2346
+fragm_threshold=-1
# Rate configuration
# Default is to enable all rates supported by the hardware. This configuration
@@ -267,13 +271,27 @@ auth_algs=3
# requests for broadcast SSID
ignore_broadcast_ssid=0
-# Additional vendor specfic elements for Beacon and Probe Response frames
+# Do not reply to broadcast Probe Request frames from unassociated STA if there
+# is no room for additional stations (max_num_sta). This can be used to
+# discourage a STA from trying to associate with this AP if the association
+# would be rejected due to maximum STA limit.
+# Default: 0 (disabled)
+#no_probe_resp_if_max_sta=0
+
+# Additional vendor specific elements for Beacon and Probe Response frames
# This parameter can be used to add additional vendor specific element(s) into
# the end of the Beacon and Probe Response frames. The format for these
# element(s) is a hexdump of the raw information elements (id+len+payload for
# one or more elements)
#vendor_elements=dd0411223301
+# Additional vendor specific elements for (Re)Association Response frames
+# This parameter can be used to add additional vendor specific element(s) into
+# the end of the (Re)Association Response frames. The format for these
+# element(s) is a hexdump of the raw information elements (id+len+payload for
+# one or more elements)
+#assocresp_elements=dd0411223301
+
# TX queue parameters (EDCF / bursting)
# tx_queue_<queue name>_<param>
# queues: data0, data1, data2, data3, after_beacon, beacon
@@ -470,6 +488,7 @@ wmm_ac_vo_acm=0
# 0 = disabled (default)
# 1 = enabled
# Note: You will also need to enable WMM for full HT functionality.
+# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band.
#ieee80211n=1
# ht_capab: HT capabilities (list of flags)
@@ -523,6 +542,7 @@ wmm_ac_vo_acm=0
# 0 = disabled (default)
# 1 = enabled
# Note: You will also need to enable WMM for full VHT functionality.
+# Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
#ieee80211ac=1
# vht_capab: VHT capabilities (list of flags)
@@ -605,9 +625,9 @@ wmm_ac_vo_acm=0
# VHT TXOP PS: [VHT-TXOP-PS]
# Indicates whether or not the AP supports VHT TXOP Power Save Mode
# or whether or not the STA is in VHT TXOP Power Save mode
-# 0 = VHT AP doesnt support VHT TXOP PS mode (OR) VHT Sta not in VHT TXOP PS
+# 0 = VHT AP doesn't support VHT TXOP PS mode (OR) VHT STA not in VHT TXOP PS
# mode
-# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT Sta is in VHT TXOP power save
+# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT STA is in VHT TXOP power save
# mode
#
# +HTC-VHT Capable: [HTC-VHT]
@@ -665,6 +685,13 @@ wmm_ac_vo_acm=0
#
#vht_oper_centr_freq_seg1_idx=159
+# Workaround to use station's nsts capability in (Re)Association Response frame
+# This may be needed with some deployed devices as an interoperability
+# workaround for beamforming if the AP's capability is greater than the
+# station's capability. This is disabled by default and can be enabled by
+# setting use_sta_nsts=1.
+#use_sta_nsts=0
+
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
@@ -788,6 +815,11 @@ eap_server=0
# -respout /tmp/ocsp-cache.der
#ocsp_stapling_response=/tmp/ocsp-cache.der
+# Cached OCSP stapling response list (DER encoded OCSPResponseList)
+# This is similar to ocsp_stapling_response, but the extended version defined in
+# RFC 6961 to allow multiple OCSP responses to be provided.
+#ocsp_stapling_response_multi=/tmp/ocsp-multi-cache.der
+
# dh_file: File path to DH/DSA parameters file (in PEM format)
# This is an optional configuration file for setting parameters for an
# ephemeral DH key exchange. In most cases, the default RSA authentication does
@@ -825,6 +857,11 @@ eap_server=0
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db
+# EAP-SIM DB request timeout
+# This parameter sets the maximum time to wait for a database request response.
+# The parameter value is in seconds.
+#eap_sim_db_timeout=1
+
# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
# random value. It is configured as a 16-octet value in hex format. It can be
# generated, e.g., with the following command:
@@ -888,11 +925,23 @@ eap_server=0
# The own IP address of the access point (used as NAS-IP-Address)
own_ip_addr=127.0.0.1
-# Optional NAS-Identifier string for RADIUS messages. When used, this should be
-# a unique to the NAS within the scope of the RADIUS server. For example, a
-# fully qualified domain name can be used here.
+# NAS-Identifier string for RADIUS messages. When used, this should be unique
+# to the NAS within the scope of the RADIUS server. Please note that hostapd
+# uses a separate RADIUS client for each BSS and as such, a unique
+# nas_identifier value should be configured separately for each BSS. This is
+# particularly important for cases where RADIUS accounting is used
+# (Accounting-On/Off messages are interpreted as clearing all ongoing sessions
+# and that may get interpreted as applying to all BSSes if the same
+# NAS-Identifier value is used.) For example, a fully qualified domain name
+# prefixed with a unique identifier of the BSS (e.g., BSSID) can be used here.
+#
# When using IEEE 802.11r, nas_identifier must be set and must be between 1 and
# 48 octets long.
+#
+# It is mandatory to configure either own_ip_addr or nas_identifier to be
+# compliant with the RADIUS protocol. When using RADIUS accounting, it is
+# strongly recommended that nas_identifier is set to a unique value for each
+# BSS.
#nas_identifier=ap.example.com
# RADIUS client forced local IP address for the access point
@@ -957,6 +1006,17 @@ own_ip_addr=127.0.0.1
# 2 = required; reject authentication if RADIUS server does not include VLAN ID
#dynamic_vlan=0
+# Per-Station AP_VLAN interface mode
+# If enabled, each station is assigned its own AP_VLAN interface.
+# This implies per-station group keying and ebtables filtering of inter-STA
+# traffic (when passed through the AP).
+# If the sta is not assigned to any VLAN, then its AP_VLAN interface will be
+# added to the bridge given by the "bridge" configuration option (see above).
+# Otherwise, it will be added to the per-VLAN bridge.
+# 0 = disabled (default)
+# 1 = enabled
+#per_sta_vif=0
+
# VLAN interface list for dynamic VLAN mode is read from a separate text file.
# This list is used to map VLAN ID from the RADIUS server to a network
# interface. Each station is bound to one interface in the same way as with
@@ -1035,6 +1095,9 @@ own_ip_addr=127.0.0.1
#
# DAS require Event-Timestamp
#radius_das_require_event_timestamp=1
+#
+# DAS require Message-Authenticator
+#radius_das_require_message_authenticator=1
##### RADIUS authentication server configuration ##############################
@@ -1228,6 +1291,7 @@ own_ip_addr=127.0.0.1
# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
# 6-octet identifier as a hex string.
+# Defaults to BSSID.
#r1_key_holder=000102030405
# Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535)
@@ -1684,6 +1748,24 @@ own_ip_addr=127.0.0.1
# username/password
#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
+# Arbitrary ANQP-element configuration
+# Additional ANQP-elements with arbitrary values can be defined by specifying
+# their contents in raw format as a hexdump of the payload. Note that these
+# values will override ANQP-element contents that may have been specified in the
+# more higher layer configuration parameters listed above.
+# format: anqp_elem=<InfoID>:<hexdump of payload>
+# For example, AP Geospatial Location ANQP-element with unknown location:
+#anqp_elem=265:0000
+# For example, AP Civic Location ANQP-element with unknown location:
+#anqp_elem=266:000000
+
+# GAS Address 3 behavior
+# 0 = P2P specification (Address3 = AP BSSID) workaround enabled by default
+# based on GAS request Address3
+# 1 = IEEE 802.11 standard compliant regardless of GAS request Address3
+# 2 = Force non-compliant behavior (Address3 = AP BSSID for all cases)
+#gas_address3=0
+
# QoS Map Set configuration
#
# Comma delimited QoS Map Set in decimal values
@@ -1823,6 +1905,27 @@ own_ip_addr=127.0.0.1
# Transitioning between states).
#fst_llt=100
+##### Radio measurements / location ###########################################
+
+# The content of a LCI measurement subelement
+#lci=<Hexdump of binary data of the LCI report>
+
+# The content of a location civic measurement subelement
+#civic=<Hexdump of binary data of the location civic report>
+
+# Enable neighbor report via radio measurements
+#rrm_neighbor_report=1
+
+# Publish fine timing measurement (FTM) responder functionality
+# This parameter only controls publishing via Extended Capabilities element.
+# Actual functionality is managed outside hostapd.
+#ftm_responder=0
+
+# Publish fine timing measurement (FTM) initiator functionality
+# This parameter only controls publishing via Extended Capabilities element.
+# Actual functionality is managed outside hostapd.
+#ftm_initiator=0
+
##### TESTING OPTIONS #########################################################
#
# The options in this section are only available when the build configuration
@@ -1844,6 +1947,10 @@ own_ip_addr=127.0.0.1
#
# Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability
#corrupt_gtk_rekey_mic_probability=0.0
+#
+# Include only ECSA IE without CSA IE where possible
+# (channel switch operating class is needed)
+#ecsa_ie_only=0
##### Multiple BSSID support ##################################################
#
@@ -1866,6 +1973,10 @@ own_ip_addr=127.0.0.1
# - is not the same as the MAC address of the radio
# - is not the same as any other explicitly specified BSSID
#
+# Alternatively, the 'use_driver_iface_addr' parameter can be used to request
+# hostapd to use the driver auto-generated interface address (e.g., to use the
+# exact MAC addresses allocated to the device).
+#
# Not all drivers support multiple BSSes. The exact mechanism for determining
# the driver capabilities is driver specific. With the current (i.e., a recent
# kernel) drivers using nl80211, this information can be checked with "iw list"
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 46c2f37e4601..5e6254244b31 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1,6 +1,6 @@
/*
* hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,79 +15,13 @@
#include "utils/eloop.h"
#include "utils/edit.h"
#include "common/version.h"
+#include "common/cli.h"
+#ifndef CONFIG_NO_CTRL_IFACE
static const char *const hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
-
-
-static const char *const 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 *const 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 *const commands_help =
-"Commands:\n"
-" mib get MIB variables (dot1x, dot11, radius)\n"
-" sta <addr> get MIB variables for one station\n"
-" all_sta get MIB variables for all stations\n"
-" new_sta <addr> add a new station\n"
-" deauthenticate <addr> deauthenticate a station\n"
-" disassociate <addr> disassociate a station\n"
-#ifdef CONFIG_IEEE80211W
-" sa_query <addr> send SA Query to a station\n"
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_WPS
-" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
-" wps_check_pin <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 <hexdump> report read NFC tag with WPS data\n"
-" wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
-" wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n"
-#endif /* CONFIG_WPS_NFC */
-" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
-" wps_config <SSID> <auth> <encr> <key> 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 <debug level> change debug level\n"
-" license show full hostapd_cli license\n"
-" quit exit hostapd_cli\n";
+"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
static struct wpa_ctrl *ctrl_conn;
static int hostapd_cli_quit = 0;
@@ -104,6 +38,13 @@ static const char *pid_file = NULL;
static const char *action_file = NULL;
static int ping_interval = 5;
static int interactive = 0;
+static int event_handler_registered = 0;
+
+static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
+
+static void print_help(FILE *stream, const char *cmd);
+static char ** list_cmd_list(void);
+static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx);
static void usage(void)
@@ -128,20 +69,49 @@ static void usage(void)
" -B run a daemon in the background\n"
" -i<ifname> Interface to listen on (default: first "
"interface found in the\n"
- " socket path)\n\n"
- "%s",
- commands_help);
+ " socket path)\n\n");
+ print_help(stderr, NULL);
+}
+
+
+static void register_event_handler(struct wpa_ctrl *ctrl)
+{
+ if (!ctrl_conn)
+ return;
+ if (interactive) {
+ event_handler_registered =
+ !eloop_register_read_sock(wpa_ctrl_get_fd(ctrl),
+ hostapd_cli_receive,
+ NULL, NULL);
+ }
+}
+
+
+static void unregister_event_handler(struct wpa_ctrl *ctrl)
+{
+ if (!ctrl_conn)
+ return;
+ if (interactive && event_handler_registered) {
+ eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl));
+ event_handler_registered = 0;
+ }
}
static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
{
+#ifndef CONFIG_CTRL_IFACE_UDP
char *cfile;
int flen;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
if (ifname == NULL)
return NULL;
+#ifdef CONFIG_CTRL_IFACE_UDP
+ ctrl_conn = wpa_ctrl_open(ifname);
+ return ctrl_conn;
+#else /* CONFIG_CTRL_IFACE_UDP */
flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
cfile = malloc(flen);
if (cfile == NULL)
@@ -158,6 +128,7 @@ static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
free(cfile);
return ctrl_conn;
+#endif /* CONFIG_CTRL_IFACE_UDP */
}
@@ -166,6 +137,7 @@ static void hostapd_cli_close_connection(void)
if (ctrl_conn == NULL)
return;
+ unregister_event_handler(ctrl_conn);
if (hostapd_cli_attached) {
wpa_ctrl_detach(ctrl_conn);
hostapd_cli_attached = 0;
@@ -215,6 +187,22 @@ static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
}
+static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
+ int min_args, int argc, char *argv[])
+{
+ char buf[4096];
+
+ if (argc < min_args) {
+ printf("Invalid %s command - at least %d argument%s required.\n",
+ cmd, min_args, min_args > 1 ? "s are" : " is");
+ return -1;
+ }
+ if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_ctrl_command(ctrl, "PING");
@@ -330,6 +318,21 @@ static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
}
+static char ** hostapd_complete_deauthenticate(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = cli_txt_list_array(&stations);
+ break;
+ }
+
+ return res;
+}
+
+
static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -348,6 +351,37 @@ static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
}
+static char ** hostapd_complete_disassociate(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = cli_txt_list_array(&stations);
+ break;
+ }
+
+ return res;
+}
+
+
+#ifdef CONFIG_TAXONOMY
+static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[64];
+
+ if (argc != 1) {
+ printf("Invalid 'signature' command - exactly one argument, STA address, is required.\n");
+ return -1;
+ }
+ os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]);
+ return wpa_ctrl_command(ctrl, buf);
+}
+#endif /* CONFIG_TAXONOMY */
+
+
#ifdef CONFIG_IEEE80211W
static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
char *argv[])
@@ -720,15 +754,30 @@ static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- printf("%s", commands_help);
+ print_help(stdout, argc > 0 ? argv[0] : NULL);
return 0;
}
+static char ** hostapd_cli_complete_help(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = list_cmd_list();
+ break;
+ }
+
+ return res;
+}
+
+
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);
+ printf("%s\n\n%s\n", hostapd_cli_version, cli_full_license);
return 0;
}
@@ -839,6 +888,28 @@ static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl,
+ struct dl_list *interfaces)
+{
+ struct dirent *dent;
+ DIR *dir;
+
+ if (!ctrl || !interfaces)
+ return;
+ dir = opendir(ctrl_iface_dir);
+ if (dir == NULL)
+ return;
+
+ while ((dent = readdir(dir))) {
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+ cli_txt_list_add(interfaces, dent->d_name);
+ }
+ closedir(dir);
+}
+
+
static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
{
struct dirent *dent;
@@ -880,6 +951,7 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
printf("Connected to interface '%s.\n", ctrl_ifname);
if (wpa_ctrl_attach(ctrl_conn) == 0) {
hostapd_cli_attached = 1;
+ register_event_handler(ctrl_conn);
} else {
printf("Warning: Failed to attach to "
"hostapd.\n");
@@ -892,6 +964,24 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
}
+static char ** hostapd_complete_interface(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+ DEFINE_DL_LIST(interfaces);
+
+ switch (arg) {
+ case 1:
+ hostapd_cli_get_interfaces(ctrl_conn, &interfaces);
+ res = cli_txt_list_array(&interfaces);
+ cli_txt_list_flush(&interfaces);
+ break;
+ }
+
+ return res;
+}
+
+
static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@@ -1068,68 +1158,245 @@ static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
}
+static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ if (argc == 0)
+ return -1;
+ return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
+}
+
+
+static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "PMKSA");
+}
+
+
+static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
+}
+
+
+static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[2048];
+ int res;
+
+ if (argc < 3 || argc > 5) {
+ printf("Invalid set_neighbor command: needs 3-5 arguments\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s",
+ argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
+ argc == 5 ? argv[4] : "");
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long SET_NEIGHBOR command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[400];
+ int res;
+
+ if (argc != 2) {
+ printf("Invalid remove_neighbor command: needs 2 arguments\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
+ argv[0], argv[1]);
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long REMOVE_NEIGHBOR command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid req_lci command - requires destination address\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long REQ_LCI command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ if (argc < 4) {
+ printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n");
+ return -1;
+ }
+
+ return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
+}
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+ char ** (*completion)(const char *str, int pos);
+ const char *usage;
};
static const 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 },
+ { "ping", hostapd_cli_cmd_ping, NULL,
+ "= pings hostapd" },
+ { "mib", hostapd_cli_cmd_mib, NULL,
+ "= get MIB variables (dot1x, dot11, radius)" },
+ { "relog", hostapd_cli_cmd_relog, NULL, NULL },
+ { "status", hostapd_cli_cmd_status, NULL, NULL },
+ { "sta", hostapd_cli_cmd_sta, NULL,
+ "<addr> = get MIB variables for one station" },
+ { "all_sta", hostapd_cli_cmd_all_sta, NULL,
+ "= get MIB variables for all stations" },
+ { "new_sta", hostapd_cli_cmd_new_sta, NULL,
+ "<addr> = add a new station" },
+ { "deauthenticate", hostapd_cli_cmd_deauthenticate,
+ hostapd_complete_deauthenticate,
+ "<addr> = deauthenticate a station" },
+ { "disassociate", hostapd_cli_cmd_disassociate,
+ hostapd_complete_disassociate,
+ "<addr> = disassociate a station" },
+#ifdef CONFIG_TAXONOMY
+ { "signature", hostapd_cli_cmd_signature, NULL,
+ "<addr> = get taxonomy signature for a station" },
+#endif /* CONFIG_TAXONOMY */
#ifdef CONFIG_IEEE80211W
- { "sa_query", hostapd_cli_cmd_sa_query },
+ { "sa_query", hostapd_cli_cmd_sa_query, NULL,
+ "<addr> = send SA Query to a station" },
#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 },
+ { "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
+ "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
+ { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
+ "<PIN> = verify PIN checksum" },
+ { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL,
+ "= indicate button pushed to initiate PBC" },
+ { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL,
+ "= cancel the pending WPS operation" },
#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 },
+ { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL,
+ "<hexdump> = report read NFC tag with WPS data" },
+ { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL,
+ "<WPS/NDEF> = build NFC configuration token" },
+ { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL,
+ "<WPS/NDEF/enable/disable> = manager NFC password token" },
+ { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL,
+ NULL },
#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 },
+ { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL,
+ "<cmd> [params..] = enable/disable AP PIN" },
+ { "wps_config", hostapd_cli_cmd_wps_config, NULL,
+ "<SSID> <auth> <encr> <key> = configure AP" },
+ { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
+ "= show current WPS status" },
#endif /* CONFIG_WPS */
- { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
- { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
- { "bss_tm_req", hostapd_cli_cmd_bss_tm_req },
- { "get_config", hostapd_cli_cmd_get_config },
- { "help", hostapd_cli_cmd_help },
- { "interface", hostapd_cli_cmd_interface },
+ { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL },
+ { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL },
+ { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL },
+ { "get_config", hostapd_cli_cmd_get_config, NULL,
+ "= show current configuration" },
+ { "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
+ "= show this usage help" },
+ { "interface", hostapd_cli_cmd_interface, hostapd_complete_interface,
+ "[ifname] = show interfaces/select interface" },
#ifdef CONFIG_FST
- { "fst", hostapd_cli_cmd_fst },
+ { "fst", hostapd_cli_cmd_fst, NULL, NULL },
#endif /* CONFIG_FST */
- { "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 },
- { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
- { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
- { "vendor", hostapd_cli_cmd_vendor },
- { "enable", hostapd_cli_cmd_enable },
- { "reload", hostapd_cli_cmd_reload },
- { "disable", hostapd_cli_cmd_disable },
- { "erp_flush", hostapd_cli_cmd_erp_flush },
- { "log_level", hostapd_cli_cmd_log_level },
- { NULL, NULL }
+ { "raw", hostapd_cli_cmd_raw, NULL, NULL },
+ { "level", hostapd_cli_cmd_level, NULL,
+ "<debug level> = change debug level" },
+ { "license", hostapd_cli_cmd_license, NULL,
+ "= show full hostapd_cli license" },
+ { "quit", hostapd_cli_cmd_quit, NULL,
+ "= exit hostapd_cli" },
+ { "set", hostapd_cli_cmd_set, NULL, NULL },
+ { "get", hostapd_cli_cmd_get, NULL, NULL },
+ { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, NULL },
+ { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, NULL, NULL },
+ { "chan_switch", hostapd_cli_cmd_chan_switch, NULL, NULL },
+ { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, NULL },
+ { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, NULL },
+ { "vendor", hostapd_cli_cmd_vendor, NULL, NULL },
+ { "enable", hostapd_cli_cmd_enable, NULL, NULL },
+ { "reload", hostapd_cli_cmd_reload, NULL, NULL },
+ { "disable", hostapd_cli_cmd_disable, NULL, NULL },
+ { "erp_flush", hostapd_cli_cmd_erp_flush, NULL, NULL },
+ { "log_level", hostapd_cli_cmd_log_level, NULL, NULL },
+ { "pmksa", hostapd_cli_cmd_pmksa, NULL, NULL },
+ { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, NULL },
+ { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, NULL },
+ { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, NULL },
+ { "req_lci", hostapd_cli_cmd_req_lci, NULL, NULL },
+ { "req_range", hostapd_cli_cmd_req_range, NULL, NULL },
+ { "driver_flags", hostapd_cli_cmd_driver_flags, NULL, NULL },
+ { NULL, NULL, NULL, NULL }
};
+/*
+ * Prints command usage, lines are padded with the specified string.
+ */
+static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd,
+ const char *pad)
+{
+ char c;
+ size_t n;
+
+ if (cmd->usage == NULL)
+ return;
+ fprintf(stream, "%s%s ", pad, cmd->cmd);
+ for (n = 0; (c = cmd->usage[n]); n++) {
+ fprintf(stream, "%c", c);
+ if (c == '\n')
+ fprintf(stream, "%s", pad);
+ }
+ fprintf(stream, "\n");
+}
+
+
+static void print_help(FILE *stream, const char *cmd)
+{
+ int n;
+
+ fprintf(stream, "commands:\n");
+ for (n = 0; hostapd_cli_commands[n].cmd; n++) {
+ if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd))
+ print_cmd_help(stream, &hostapd_cli_commands[n], " ");
+ }
+}
+
+
static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
const struct hostapd_cli_cmd *cmd, *match = NULL;
@@ -1169,6 +1436,34 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static void cli_event(const char *str)
+{
+ const char *start, *s;
+
+ start = os_strchr(str, '>');
+ if (start == NULL)
+ return;
+
+ start++;
+
+ if (str_starts(start, AP_STA_CONNECTED)) {
+ s = os_strchr(start, ' ');
+ if (s == NULL)
+ return;
+ cli_txt_list_add(&stations, s + 1);
+ return;
+ }
+
+ if (str_starts(start, AP_STA_DISCONNECTED)) {
+ s = os_strchr(start, ' ');
+ if (s == NULL)
+ return;
+ cli_txt_list_del_addr(&stations, s + 1);
+ return;
+ }
+}
+
+
static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
int action_monitor)
{
@@ -1183,6 +1478,7 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
if (action_monitor)
hostapd_cli_action_process(buf, len);
else {
+ cli_event(buf);
if (in_read && first)
printf("\n");
first = 0;
@@ -1196,35 +1492,9 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
}
-#define max_args 10
-
-static int tokenize_cmd(char *cmd, char *argv[])
+static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
- 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;
+ hostapd_cli_recv_pending(ctrl_conn, 0, 0);
}
@@ -1240,6 +1510,7 @@ static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
printf("Connection to hostapd re-established\n");
if (wpa_ctrl_attach(ctrl_conn) == 0) {
hostapd_cli_attached = 1;
+ register_event_handler(ctrl_conn);
} else {
printf("Warning: Failed to attach to "
"hostapd.\n");
@@ -1274,17 +1545,82 @@ static void hostapd_cli_edit_eof_cb(void *ctx)
}
+static char ** list_cmd_list(void)
+{
+ char **res;
+ int i, count;
+
+ count = ARRAY_SIZE(hostapd_cli_commands);
+ res = os_calloc(count + 1, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+
+ for (i = 0; hostapd_cli_commands[i].cmd; i++) {
+ res[i] = os_strdup(hostapd_cli_commands[i].cmd);
+ if (res[i] == NULL)
+ break;
+ }
+
+ return res;
+}
+
+
+static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str,
+ int pos)
+{
+ int i;
+
+ for (i = 0; hostapd_cli_commands[i].cmd; i++) {
+ if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0)
+ continue;
+ if (hostapd_cli_commands[i].completion)
+ return hostapd_cli_commands[i].completion(str, pos);
+ if (!hostapd_cli_commands[i].usage)
+ return NULL;
+ edit_clear_line();
+ printf("\r%s\n", hostapd_cli_commands[i].usage);
+ edit_redraw();
+ break;
+ }
+
+ return NULL;
+}
+
+
+static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
+ int pos)
+{
+ char **res;
+ const char *end;
+ char *cmd;
+
+ end = os_strchr(str, ' ');
+ if (end == NULL || str + pos < end)
+ return list_cmd_list();
+
+ cmd = os_malloc(pos + 1);
+ if (cmd == NULL)
+ return NULL;
+ os_memcpy(cmd, str, pos);
+ cmd[end - str] = '\0';
+ res = hostapd_cli_cmd_completion(cmd, str, pos);
+ os_free(cmd);
+ return res;
+}
+
+
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);
+ hostapd_cli_edit_completion_cb, NULL, NULL, NULL);
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
eloop_run();
+ cli_txt_list_flush(&stations);
edit_deinit(NULL, NULL);
eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
}
@@ -1388,8 +1724,7 @@ int main(int argc, char *argv[])
interactive = (argc == optind) && (action_file == NULL);
if (interactive) {
- printf("%s\n\n%s\n\n", hostapd_cli_version,
- hostapd_cli_license);
+ printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license);
}
if (eloop_init())
@@ -1437,6 +1772,7 @@ int main(int argc, char *argv[])
if (interactive || action_file) {
if (wpa_ctrl_attach(ctrl_conn) == 0) {
hostapd_cli_attached = 1;
+ register_event_handler(ctrl_conn);
} else {
printf("Warning: Failed to attach to hostapd.\n");
if (action_file)
@@ -1444,7 +1780,7 @@ int main(int argc, char *argv[])
}
}
- if (daemonize && os_daemonize(pid_file))
+ if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
return -1;
if (interactive)
@@ -1454,8 +1790,18 @@ int main(int argc, char *argv[])
else
wpa_request(ctrl_conn, argc - optind, &argv[optind]);
+ unregister_event_handler(ctrl_conn);
os_free(ctrl_ifname);
eloop_destroy();
hostapd_cli_cleanup();
return 0;
}
+
+#else /* CONFIG_NO_CTRL_IFACE */
+
+int main(int argc, char *argv[])
+{
+ return -1;
+}
+
+#endif /* CONFIG_NO_CTRL_IFACE */
diff --git a/hostapd/main.c b/hostapd/main.c
index 6c7406af447e..2c8dbd30a274 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -1,6 +1,6 @@
/*
* hostapd / main()
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -171,7 +171,8 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
if (global.drv_priv[i] == NULL &&
wpa_drivers[i]->global_init) {
- global.drv_priv[i] = wpa_drivers[i]->global_init();
+ global.drv_priv[i] =
+ wpa_drivers[i]->global_init(iface->interfaces);
if (global.drv_priv[i] == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize "
"driver '%s'",
@@ -216,11 +217,20 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
iface->drv_flags = capa.flags;
iface->smps_modes = capa.smps_modes;
iface->probe_resp_offloads = capa.probe_resp_offloads;
+ /*
+ * Use default extended capa values from per-radio information
+ */
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;
+ /*
+ * Override extended capa with per-interface type (AP), if
+ * available from the driver.
+ */
+ hostapd_get_ext_capa(iface);
+
triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
if (triggs && hapd->driver->set_wowlan) {
if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
@@ -241,7 +251,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
* interfaces. No actiual driver operations are started.
*/
static struct hostapd_iface *
-hostapd_interface_init(struct hapd_interfaces *interfaces,
+hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
const char *config_fname, int debug)
{
struct hostapd_iface *iface;
@@ -251,6 +261,12 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
iface = hostapd_init(interfaces, config_fname);
if (!iface)
return NULL;
+
+ if (if_name) {
+ os_strlcpy(iface->conf->bss[0]->iface, if_name,
+ sizeof(iface->conf->bss[0]->iface));
+ }
+
iface->interfaces = interfaces;
for (k = 0; k < debug; k++) {
@@ -260,7 +276,8 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
if (iface->conf->bss[0]->iface[0] == '\0' &&
!hostapd_drv_none(iface->bss[0])) {
- wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+ wpa_printf(MSG_ERROR,
+ "Interface name not specified in %s, nor by '-i' parameter",
config_fname);
hostapd_interface_deinit_free(iface);
return NULL;
@@ -329,6 +346,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces,
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
return -1;
}
+ interfaces->eloop_initialized = 1;
random_init(entropy_file);
@@ -356,7 +374,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces,
}
-static void hostapd_global_deinit(const char *pid_file)
+static void hostapd_global_deinit(const char *pid_file, int eloop_initialized)
{
int i;
@@ -374,7 +392,8 @@ static void hostapd_global_deinit(const char *pid_file)
random_deinit();
- eloop_destroy();
+ if (eloop_initialized)
+ eloop_destroy();
#ifndef CONFIG_NATIVE_WINDOWS
closelog();
@@ -408,9 +427,16 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
}
#endif /* EAP_SERVER_TNC */
- if (daemonize && os_daemonize(pid_file)) {
- wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
- return -1;
+ if (daemonize) {
+ if (os_daemonize(pid_file)) {
+ wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
+ return -1;
+ }
+ if (eloop_sock_requeue()) {
+ wpa_printf(MSG_ERROR, "eloop_sock_requeue: %s",
+ strerror(errno));
+ return -1;
+ }
}
eloop_run();
@@ -425,7 +451,7 @@ static void show_version(void)
"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-2015, Jouni Malinen <j@w1.fi> "
+ "Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> "
"and contributors\n");
}
@@ -437,7 +463,8 @@ static void usage(void)
"\n"
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
"\\\n"
- " [-g <global ctrl_iface>] [-G <group>] \\\n"
+ " [-g <global ctrl_iface>] [-G <group>]\\\n"
+ " [-i <comma-separated list of interface names>]\\\n"
" <configuration file(s)>\n"
"\n"
"options:\n"
@@ -456,6 +483,8 @@ static void usage(void)
" -T = record to Linux tracing in addition to logging\n"
" (records all messages regardless of debug verbosity)\n"
#endif /* CONFIG_DEBUG_LINUX_TRACING */
+ " -i list of interface names to use\n"
+ " -S start all the interfaces synchronously\n"
" -t include timestamps in some debug messages\n"
" -v show hostapd version\n");
@@ -466,9 +495,8 @@ static void usage(void)
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;
+ if (hapd && hapd->conf)
+ return hapd->conf->iface;
return NULL;
}
@@ -476,11 +504,16 @@ static const char * hostapd_msg_ifname_cb(void *ctx)
static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
const char *path)
{
+#ifndef CONFIG_CTRL_IFACE_UDP
char *pos;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
+
os_free(interfaces->global_iface_path);
interfaces->global_iface_path = os_strdup(path);
if (interfaces->global_iface_path == NULL)
return -1;
+
+#ifndef CONFIG_CTRL_IFACE_UDP
pos = os_strrchr(interfaces->global_iface_path, '/');
if (pos == NULL) {
wpa_printf(MSG_ERROR, "No '/' in the global control interface "
@@ -492,6 +525,7 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
*pos = '\0';
interfaces->global_iface_name = pos + 1;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
return 0;
}
@@ -513,6 +547,43 @@ static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
}
+static int hostapd_get_interface_names(char ***if_names,
+ size_t *if_names_size,
+ char *optarg)
+{
+ char *if_name, *tmp, **nnames;
+ size_t i;
+
+ if (!optarg)
+ return -1;
+ if_name = strtok_r(optarg, ",", &tmp);
+
+ while (if_name) {
+ nnames = os_realloc_array(*if_names, 1 + *if_names_size,
+ sizeof(char *));
+ if (!nnames)
+ goto fail;
+ *if_names = nnames;
+
+ (*if_names)[*if_names_size] = os_strdup(if_name);
+ if (!(*if_names)[*if_names_size])
+ goto fail;
+ (*if_names_size)++;
+ if_name = strtok_r(NULL, ",", &tmp);
+ }
+
+ return 0;
+
+fail:
+ for (i = 0; i < *if_names_size; i++)
+ os_free((*if_names)[i]);
+ os_free(*if_names);
+ *if_names = NULL;
+ *if_names_size = 0;
+ return -1;
+}
+
+
#ifdef CONFIG_WPS
static int gen_uuid(const char *txt_addr)
{
@@ -570,6 +641,9 @@ int main(int argc, char *argv[])
#ifdef CONFIG_DEBUG_LINUX_TRACING
int enable_trace_dbg = 0;
#endif /* CONFIG_DEBUG_LINUX_TRACING */
+ int start_ifaces_in_sync = 0;
+ char **if_names = NULL;
+ size_t if_names_size = 0;
if (os_program_init())
return -1;
@@ -584,10 +658,10 @@ int main(int argc, char *argv[])
interfaces.global_iface_path = NULL;
interfaces.global_iface_name = NULL;
interfaces.global_ctrl_sock = -1;
- interfaces.global_ctrl_dst = NULL;
+ dl_list_init(&interfaces.global_ctrl_dst);
for (;;) {
- c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
+ c = getopt(argc, argv, "b:Bde:f:hi:KP:STtu:vg:G:");
if (c < 0)
break;
switch (c) {
@@ -644,10 +718,18 @@ int main(int argc, char *argv[])
bss_config = tmp_bss;
bss_config[num_bss_configs++] = optarg;
break;
+ case 'S':
+ start_ifaces_in_sync = 1;
+ break;
#ifdef CONFIG_WPS
case 'u':
return gen_uuid(optarg);
#endif /* CONFIG_WPS */
+ case 'i':
+ if (hostapd_get_interface_names(&if_names,
+ &if_names_size, optarg))
+ goto out;
+ break;
default:
usage();
break;
@@ -705,13 +787,21 @@ int main(int argc, char *argv[])
/* Allocate and parse configuration for full interface files */
for (i = 0; i < interfaces.count; i++) {
+ char *if_name = NULL;
+
+ if (i < if_names_size)
+ if_name = if_names[i];
+
interfaces.iface[i] = hostapd_interface_init(&interfaces,
+ if_name,
argv[optind + i],
debug);
if (!interfaces.iface[i]) {
wpa_printf(MSG_ERROR, "Failed to initialize interface");
goto out;
}
+ if (start_ifaces_in_sync)
+ interfaces.iface[i]->need_to_start_in_sync = 1;
}
/* Allocate and parse configuration for per-BSS files */
@@ -787,8 +877,9 @@ int main(int argc, char *argv[])
}
os_free(interfaces.iface);
- eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
- hostapd_global_deinit(pid_file);
+ if (interfaces.eloop_initialized)
+ eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
+ hostapd_global_deinit(pid_file, interfaces.eloop_initialized);
os_free(pid_file);
if (log_file)
@@ -797,6 +888,10 @@ int main(int argc, char *argv[])
os_free(bss_config);
+ for (i = 0; i < if_names_size; i++)
+ os_free(if_names[i]);
+ os_free(if_names);
+
fst_global_deinit();
os_program_deinit();
diff --git a/hs20/client/Android.mk b/hs20/client/Android.mk
index b23ac17b4b62..e4db32208d50 100644
--- a/hs20/client/Android.mk
+++ b/hs20/client/Android.mk
@@ -4,7 +4,6 @@ INCLUDES = $(LOCAL_PATH)
INCLUDES += $(LOCAL_PATH)/../../src/utils
INCLUDES += $(LOCAL_PATH)/../../src/common
INCLUDES += $(LOCAL_PATH)/../../src
-INCLUDES += external/openssl/include
INCLUDES += external/libxml2/include
INCLUDES += external/curl/include
INCLUDES += external/webkit/Source/WebKit/gtk
@@ -55,6 +54,7 @@ OBJS += ../../src/crypto/crypto_internal.c
OBJS += ../../src/crypto/md5-internal.c
OBJS += ../../src/crypto/sha1-internal.c
OBJS += ../../src/crypto/sha256-internal.c
+OBJS += ../../src/crypto/tls_openssl_ocsp.c
L_CFLAGS += -DEAP_TLS_OPENSSL
diff --git a/hs20/client/Makefile b/hs20/client/Makefile
index 94cd5f14df14..fc9b61940c4f 100644
--- a/hs20/client/Makefile
+++ b/hs20/client/Makefile
@@ -76,6 +76,7 @@ LIBS += -lcurl
endif
CFLAGS += -DEAP_TLS_OPENSSL
+OBJS += ../../src/crypto/tls_openssl_ocsp.o
LIBS += -lssl -lcrypto
hs20-osu-client: $(OBJS)
diff --git a/hs20/client/est.c b/hs20/client/est.c
index ec05bc4e0f62..9f1519bf4e4e 100644
--- a/hs20/client/est.c
+++ b/hs20/client/est.c
@@ -16,6 +16,9 @@
#include <openssl/asn1t.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#ifdef OPENSSL_IS_BORINGSSL
+#include <openssl/buf.h>
+#endif /* OPENSSL_IS_BORINGSSL */
#include "common.h"
#include "utils/base64.h"
@@ -27,12 +30,28 @@
static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
size_t len, char *pem_file, char *der_file)
{
+#ifdef OPENSSL_IS_BORINGSSL
+ CBS pkcs7_cbs;
+#else /* OPENSSL_IS_BORINGSSL */
PKCS7 *p7 = NULL;
const unsigned char *p = pkcs7;
+#endif /* OPENSSL_IS_BORINGSSL */
STACK_OF(X509) *certs;
int i, num, ret = -1;
BIO *out = NULL;
+#ifdef OPENSSL_IS_BORINGSSL
+ certs = sk_X509_new_null();
+ if (!certs)
+ goto fail;
+ CBS_init(&pkcs7_cbs, pkcs7, len);
+ if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) {
+ wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ write_result(ctx, "Could not parse PKCS#7 object from EST");
+ goto fail;
+ }
+#else /* OPENSSL_IS_BORINGSSL */
p7 = d2i_PKCS7(NULL, &p, len);
if (p7 == NULL) {
wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
@@ -52,6 +71,7 @@ static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
certs = NULL;
break;
}
+#endif /* OPENSSL_IS_BORINGSSL */
if (!certs || ((num = sk_X509_num(certs)) == 0)) {
wpa_printf(MSG_INFO, "No certificates found in PKCS#7 object");
@@ -84,7 +104,12 @@ static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
ret = 0;
fail:
+#ifdef OPENSSL_IS_BORINGSSL
+ if (certs)
+ sk_X509_pop_free(certs, X509_free);
+#else /* OPENSSL_IS_BORINGSSL */
PKCS7_free(p7);
+#endif /* OPENSSL_IS_BORINGSSL */
if (out)
BIO_free_all(out);
@@ -310,6 +335,23 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
if (!csrattrs || ! csrattrs->attrs)
return;
+#ifdef OPENSSL_IS_BORINGSSL
+ num = sk_num(CHECKED_CAST(_STACK *, STACK_OF(AttrOrOID) *,
+ csrattrs->attrs));
+ for (i = 0; i < num; i++) {
+ AttrOrOID *ao = sk_value(
+ CHECKED_CAST(_STACK *, const STACK_OF(AttrOrOID) *,
+ csrattrs->attrs), i);
+ switch (ao->type) {
+ case 0:
+ add_csrattrs_oid(ctx, ao->d.oid, exts);
+ break;
+ case 1:
+ add_csrattrs_attr(ctx, ao->d.attribute, exts);
+ break;
+ }
+ }
+#else /* OPENSSL_IS_BORINGSSL */
num = SKM_sk_num(AttrOrOID, csrattrs->attrs);
for (i = 0; i < num; i++) {
AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i);
@@ -322,6 +364,7 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
break;
}
}
+#endif /* OPENSSL_IS_BORINGSSL */
}
@@ -340,6 +383,7 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
STACK_OF(X509_EXTENSION) *exts = NULL;
X509_EXTENSION *ex;
BIO *out;
+ CONF *ctmp = NULL;
wpa_printf(MSG_INFO, "Generate RSA private key");
write_summary(ctx, "Generate RSA private key");
@@ -421,20 +465,20 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
if (!exts)
goto fail;
- ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints,
- "CA:FALSE");
+ ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_basic_constraints,
+ "CA:FALSE");
if (ex == NULL ||
!sk_X509_EXTENSION_push(exts, ex))
goto fail;
- ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage,
- "nonRepudiation,digitalSignature,keyEncipherment");
+ ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_key_usage,
+ "nonRepudiation,digitalSignature,keyEncipherment");
if (ex == NULL ||
!sk_X509_EXTENSION_push(exts, ex))
goto fail;
- ex = X509V3_EXT_conf_nid(NULL, NULL, NID_ext_key_usage,
- "1.3.6.1.4.1.40808.1.1.2");
+ ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_ext_key_usage,
+ "1.3.6.1.4.1.40808.1.1.2");
if (ex == NULL ||
!sk_X509_EXTENSION_push(exts, ex))
goto fail;
@@ -454,7 +498,9 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
char *txt;
size_t rlen;
+#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
X509_REQ_print(out, req);
+#endif
rlen = BIO_ctrl_pending(out);
txt = os_malloc(rlen + 1);
if (txt) {
@@ -473,7 +519,9 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
FILE *f = fopen(csr_pem, "w");
if (f == NULL)
goto fail;
+#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
X509_REQ_print_fp(f, req);
+#endif
if (!PEM_write_X509_REQ(f, req)) {
fclose(f);
goto fail;
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index 0315f7b75ad4..c05c57d44f89 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -2229,7 +2229,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
fprintf(f, "</table></a><br><small>BSSID: %s<br>\n"
"SSID: %s<br>\n",
last->bssid, last->osu_ssid);
- if (last->osu_nai)
+ if (last->osu_nai[0])
fprintf(f, "NAI: %s<br>\n", last->osu_nai);
fprintf(f, "URL: %s<br>\n"
"methods:%s%s<br>\n"
@@ -2339,12 +2339,23 @@ static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc,
return -1;
snprintf(fname, sizeof(fname), "%s/osu-info", dir);
- if (mkdir(fname, S_IRWXU | S_IRWXG) < 0 && errno != EEXIST) {
+ if (mkdir(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0 &&
+ errno != EEXIST) {
wpa_printf(MSG_INFO, "mkdir(%s) failed: %s",
fname, strerror(errno));
return -1;
}
+#ifdef ANDROID
+ /* Allow processes running with Group ID as AID_WIFI
+ * to read/write files from osu-info directory
+ */
+ if (chown(fname, -1, AID_WIFI)) {
+ wpa_printf(MSG_INFO, "Could not chown osu-info directory: %s",
+ strerror(errno));
+ }
+#endif /* ANDROID */
+
snprintf(buf, sizeof(buf), "SET osu_dir %s", fname);
if (wpa_command(ifname, buf) < 0) {
wpa_printf(MSG_INFO, "Failed to configure osu_dir to wpa_supplicant");
@@ -2559,7 +2570,7 @@ static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
if (!pps_fname) {
char buf[256];
wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information");
- if (os_strncmp(address, "fqdn=", 5) == 0) {
+ if (address && os_strncmp(address, "fqdn=", 5) == 0) {
wpa_printf(MSG_INFO, "Use requested FQDN from command line");
os_snprintf(buf, sizeof(buf), "%s", address + 5);
address = NULL;
@@ -3122,20 +3133,12 @@ int main(int argc, char *argv[])
usage();
exit(0);
}
- if (argc - optind < 2)
- wpa_printf(MSG_ERROR, "Server URL missing from command line");
- else
- ret = cmd_sub_rem(&ctx, argv[optind + 1],
- argc > optind + 2 ?
- argv[optind + 2] : NULL,
- argc > optind + 3 ?
- argv[optind + 3] : NULL);
+ ret = cmd_sub_rem(&ctx, argv[optind + 1],
+ argc > optind + 2 ? argv[optind + 2] : NULL,
+ argc > optind + 3 ? argv[optind + 3] : NULL);
} else if (strcmp(argv[optind], "pol_upd") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- ret = cmd_pol_upd(&ctx, argc > 2 ? argv[optind + 1] : NULL,
+ ret = cmd_pol_upd(&ctx,
+ argc > optind + 1 ? argv[optind + 1] : NULL,
argc > optind + 2 ? argv[optind + 2] : NULL,
argc > optind + 3 ? argv[optind + 3] : NULL);
} else if (strcmp(argv[optind], "prov") == 0) {
diff --git a/patches/openssl-0.9.8za-tls-extensions.patch b/patches/openssl-0.9.8za-tls-extensions.patch
deleted file mode 100644
index 82bfe2302ea3..000000000000
--- a/patches/openssl-0.9.8za-tls-extensions.patch
+++ /dev/null
@@ -1,397 +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 <akobozev@cisco.com>
-(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
-
-OpenSSL 0.9.8za 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.8za.orig/ssl/s3_clnt.c openssl-0.9.8za/ssl/s3_clnt.c
---- openssl-0.9.8za.orig/ssl/s3_clnt.c 2014-06-05 11:09:26.000000000 +0300
-+++ openssl-0.9.8za/ssl/s3_clnt.c 2014-06-05 20:37:09.221387312 +0300
-@@ -767,6 +767,22 @@ 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);
-+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
-+ }
-+ }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- if (j != 0 && j == s->session->session_id_length
- && memcmp(p,s->session->session_id,j) == 0)
- {
-@@ -2745,11 +2760,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.8za.orig/ssl/s3_srvr.c openssl-0.9.8za/ssl/s3_srvr.c
---- openssl-0.9.8za.orig/ssl/s3_srvr.c 2014-06-05 11:09:26.000000000 +0300
-+++ openssl-0.9.8za/ssl/s3_srvr.c 2014-06-05 20:37:09.225387312 +0300
-@@ -1011,6 +1011,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
-@@ -1161,16 +1214,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.8za.orig/ssl/ssl_err.c openssl-0.9.8za/ssl/ssl_err.c
---- openssl-0.9.8za.orig/ssl/ssl_err.c 2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/ssl_err.c 2014-06-05 20:37:09.225387312 +0300
-@@ -265,6 +265,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.8za.orig/ssl/ssl.h openssl-0.9.8za/ssl/ssl.h
---- openssl-0.9.8za.orig/ssl/ssl.h 2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/ssl.h 2014-06-05 20:37:09.229387312 +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
- {
-@@ -1053,6 +1057,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
-@@ -1668,6 +1684,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.
-@@ -1872,6 +1897,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.8za.orig/ssl/ssl_sess.c openssl-0.9.8za/ssl/ssl_sess.c
---- openssl-0.9.8za.orig/ssl/ssl_sess.c 2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/ssl_sess.c 2014-06-05 20:37:09.229387312 +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.8za.orig/ssl/t1_lib.c openssl-0.9.8za/ssl/t1_lib.c
---- openssl-0.9.8za.orig/ssl/t1_lib.c 2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/t1_lib.c 2014-06-05 20:37:09.229387312 +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)
-@@ -574,6 +596,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)
- {
-@@ -751,6 +782,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))
- {
-@@ -1043,6 +1080,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.8za.orig/ssl/tls1.h openssl-0.9.8za/ssl/tls1.h
---- openssl-0.9.8za.orig/ssl/tls1.h 2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/tls1.h 2014-06-05 20:37:09.229387312 +0300
-@@ -415,6 +415,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.8za.orig/util/ssleay.num openssl-0.9.8za/util/ssleay.num
---- openssl-0.9.8za.orig/util/ssleay.num 2014-06-05 12:38:45.000000000 +0300
-+++ openssl-0.9.8za/util/ssleay.num 2014-06-05 20:37:09.229387312 +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/patches/openssl-0.9.8zf-tls-extensions.patch b/patches/openssl-0.9.8zf-tls-extensions.patch
deleted file mode 100644
index 3a8f90e40ce2..000000000000
--- a/patches/openssl-0.9.8zf-tls-extensions.patch
+++ /dev/null
@@ -1,398 +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 <akobozev@cisco.com>
-(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
-
-OpenSSL 0.9.8zf 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.8zf.orig/ssl/s3_clnt.c openssl-0.9.8zf/ssl/s3_clnt.c
---- openssl-0.9.8zf.orig/ssl/s3_clnt.c 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/s3_clnt.c 2015-03-24 16:19:14.043911769 +0200
-@@ -760,6 +760,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);
-+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
-+ }
-+ }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- if (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
-@@ -2684,12 +2701,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,
-diff -upr openssl-0.9.8zf.orig/ssl/s3_srvr.c openssl-0.9.8zf/ssl/s3_srvr.c
---- openssl-0.9.8zf.orig/ssl/s3_srvr.c 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/s3_srvr.c 2015-03-24 16:23:34.567909681 +0200
-@@ -999,6 +999,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
-@@ -1143,15 +1196,21 @@ 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.8zf.orig/ssl/ssl_err.c openssl-0.9.8zf/ssl/ssl_err.c
---- openssl-0.9.8zf.orig/ssl/ssl_err.c 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/ssl_err.c 2015-03-24 16:35:58.627903717 +0200
-@@ -316,6 +316,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.8zf.orig/ssl/ssl.h openssl-0.9.8zf/ssl/ssl.h
---- openssl-0.9.8zf.orig/ssl/ssl.h 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/ssl.h 2015-03-24 16:25:44.339908641 +0200
-@@ -349,6 +349,7 @@ extern "C" {
- * 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 {
-@@ -366,6 +367,12 @@ 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 {
- int version;
-@@ -1116,6 +1123,18 @@ struct ssl_st {
- int tlsext_ocsp_resplen;
- /* 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
-@@ -1772,6 +1791,17 @@ 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
-@@ -1977,6 +2007,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.8zf.orig/ssl/ssl_sess.c openssl-0.9.8zf/ssl/ssl_sess.c
---- openssl-0.9.8zf.orig/ssl/ssl_sess.c 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/ssl_sess.c 2015-03-24 16:28:04.819907515 +0200
-@@ -716,6 +716,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;
- long time;
-diff -upr openssl-0.9.8zf.orig/ssl/t1_lib.c openssl-0.9.8zf/ssl/t1_lib.c
---- openssl-0.9.8zf.orig/ssl/t1_lib.c 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/t1_lib.c 2015-03-24 16:32:46.923905254 +0200
-@@ -108,6 +108,11 @@ 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 +211,20 @@ unsigned char *ssl_add_clienthello_tlsex
- int ticklen;
- if (!s->new_session && s->session && s->session->tlsext_tick)
- ticklen = s->session->tlsext_ticklen;
-- else
-+ 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 +238,7 @@ unsigned char *ssl_add_clienthello_tlsex
- ret += ticklen;
- }
- }
-+skip_ext:
-
- if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
- s->version != DTLS1_VERSION) {
-@@ -560,6 +578,14 @@ int ssl_parse_clienthello_tlsext(SSL *s,
- if (!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
- 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) {
-
-@@ -710,6 +736,13 @@ int ssl_parse_serverhello_tlsext(SSL *s,
- }
- tlsext_servername = 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;
-+ }
- if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
- || (size > 0)) {
- *al = TLS1_AD_UNSUPPORTED_EXTENSION;
-@@ -993,6 +1026,14 @@ 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);
- }
- p += size;
-diff -upr openssl-0.9.8zf.orig/ssl/tls1.h openssl-0.9.8zf/ssl/tls1.h
---- openssl-0.9.8zf.orig/ssl/tls1.h 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/tls1.h 2015-03-24 16:33:31.855904894 +0200
-@@ -460,6 +460,12 @@ 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"
- # endif
-
-+/* TLS extension struct */
-+struct tls_session_ticket_ext_st {
-+ unsigned short length;
-+ void *data;
-+};
-+
- #ifdef __cplusplus
- }
- #endif
-diff -upr openssl-0.9.8zf.orig/util/ssleay.num openssl-0.9.8zf/util/ssleay.num
---- openssl-0.9.8zf.orig/util/ssleay.num 2015-03-19 15:47:15.000000000 +0200
-+++ openssl-0.9.8zf/util/ssleay.num 2015-03-24 16:33:51.127904739 +0200
-@@ -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/src/ap/accounting.c b/src/ap/accounting.c
index a096de4d3e51..0aacc3c95b08 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -1,6 +1,6 @@
/*
* hostapd / RADIUS Accounting
- * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -41,6 +41,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
size_t len;
int i;
struct wpabuf *b;
+ struct os_time now;
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
radius_client_get_id(hapd->radius));
@@ -49,44 +50,24 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
return NULL;
}
- if (sta) {
- radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
-
- if ((hapd->conf->wpa & 2) &&
- !hapd->conf->disable_pmksa_caching &&
- sta->eapol_sm && sta->eapol_sm->acct_multi_session_id_hi) {
- os_snprintf(buf, sizeof(buf), "%08X+%08X",
- sta->eapol_sm->acct_multi_session_id_hi,
- sta->eapol_sm->acct_multi_session_id_lo);
- if (!radius_msg_add_attr(
- msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
- (u8 *) buf, os_strlen(buf))) {
- wpa_printf(MSG_INFO,
- "Could not add Acct-Multi-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) {
+ 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;
+ }
+
/* Use 802.1X identity if available */
val = ieee802_1x_get_identity(sta->eapol_sm, &len);
@@ -147,6 +128,32 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
wpa_printf(MSG_ERROR, "Could not add CUI from ACL");
goto fail;
}
+
+ if (sta->ipaddr &&
+ !radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_FRAMED_IP_ADDRESS,
+ be_to_host32(sta->ipaddr))) {
+ wpa_printf(MSG_ERROR,
+ "Could not add Framed-IP-Address");
+ goto fail;
+ }
+ }
+
+ os_get_time(&now);
+ if (now.sec > 1000000000 &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+ now.sec)) {
+ wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
+ goto fail;
+ }
+
+ /*
+ * Add Acct-Delay-Time with zero value for the first transmission. This
+ * will be updated within radius_client.c when retransmitting the frame.
+ */
+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_DELAY_TIME, 0)) {
+ wpa_printf(MSG_INFO, "Could not add Acct-Delay-Time");
+ goto fail;
}
return msg;
@@ -164,19 +171,25 @@ static int accounting_sta_update_stats(struct hostapd_data *hapd,
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;
+ if (!data->bytes_64bit) {
+ /* Extend 32-bit counters from the driver to 64-bit counters */
+ if (sta->last_rx_bytes_lo > data->rx_bytes)
+ sta->last_rx_bytes_hi++;
+ sta->last_rx_bytes_lo = data->rx_bytes;
+
+ if (sta->last_tx_bytes_lo > data->tx_bytes)
+ sta->last_tx_bytes_hi++;
+ sta->last_tx_bytes_lo = 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);
+ HOSTAPD_LEVEL_DEBUG,
+ "updated TX/RX stats: rx_bytes=%llu [%u:%u] tx_bytes=%llu [%u:%u] bytes_64bit=%d",
+ data->rx_bytes, sta->last_rx_bytes_hi,
+ sta->last_rx_bytes_lo,
+ data->tx_bytes, sta->last_tx_bytes_hi,
+ sta->last_tx_bytes_lo,
+ data->bytes_64bit);
return 0;
}
@@ -217,12 +230,14 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
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);
+ "starting accounting session %016llX",
+ (unsigned long long) sta->acct_session_id);
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;
+ sta->last_rx_bytes_hi = 0;
+ sta->last_rx_bytes_lo = 0;
+ sta->last_tx_bytes_hi = 0;
+ sta->last_tx_bytes_lo = 0;
hostapd_drv_sta_clear_stats(hapd, sta->addr);
if (!hapd->conf->radius->acct_server)
@@ -251,8 +266,7 @@ static void accounting_sta_report(struct hostapd_data *hapd,
int cause = sta->acct_terminate_cause;
struct hostap_sta_driver_data data;
struct os_reltime now_r, diff;
- struct os_time now;
- u32 gigawords;
+ u64 bytes;
if (!hapd->conf->radius->acct_server)
return;
@@ -266,7 +280,6 @@ static void accounting_sta_report(struct hostapd_data *hapd,
}
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)) {
@@ -287,48 +300,42 @@ static void accounting_sta_report(struct hostapd_data *hapd,
wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
goto fail;
}
+ if (data.bytes_64bit)
+ bytes = data.rx_bytes;
+ else
+ bytes = ((u64) sta->last_rx_bytes_hi << 32) |
+ sta->last_rx_bytes_lo;
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_INPUT_OCTETS,
- data.rx_bytes)) {
+ (u32) 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)) {
+ if (!radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
+ (u32) (bytes >> 32))) {
wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
goto fail;
}
+ if (data.bytes_64bit)
+ bytes = data.tx_bytes;
+ else
+ bytes = ((u64) sta->last_tx_bytes_hi << 32) |
+ sta->last_tx_bytes_lo;
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
- data.tx_bytes)) {
+ (u32) 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)) {
+ if (!radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
+ (u32) (bytes >> 32))) {
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;
@@ -375,22 +382,17 @@ void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
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);
+ "stopped accounting session %016llX",
+ (unsigned long long) sta->acct_session_id);
sta->acct_session_started = 0;
}
}
-void accounting_sta_get_id(struct hostapd_data *hapd,
- struct sta_info *sta)
+int 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;
+ return radius_gen_session_id((u8 *) &sta->acct_session_id,
+ sizeof(sta->acct_session_id));
}
@@ -437,12 +439,14 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
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 (hapd->acct_session_id) {
+ char buf[20];
+
+ os_snprintf(buf, sizeof(buf), "%016llX",
+ (unsigned long long) hapd->acct_session_id);
+ 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");
}
if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0)
@@ -450,6 +454,63 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
}
+static void accounting_interim_error_cb(const u8 *addr, void *ctx)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+ unsigned int i, wait_time;
+ int res;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return;
+ sta->acct_interim_errors++;
+ if (sta->acct_interim_errors > 10 /* RADIUS_CLIENT_MAX_RETRIES */) {
+ wpa_printf(MSG_DEBUG,
+ "Interim RADIUS accounting update failed for " MACSTR
+ " - too many errors, abandon this interim accounting update",
+ MAC2STR(addr));
+ sta->acct_interim_errors = 0;
+ /* Next update will be tried after normal update interval */
+ return;
+ }
+
+ /*
+ * Use a shorter update interval as an improved retransmission mechanism
+ * for failed interim accounting updates. This allows the statistics to
+ * be updated for each retransmission.
+ *
+ * RADIUS client code has already waited RADIUS_CLIENT_FIRST_WAIT.
+ * Schedule the first retry attempt immediately and every following one
+ * with exponential backoff.
+ */
+ if (sta->acct_interim_errors == 1) {
+ wait_time = 0;
+ } else {
+ wait_time = 3; /* RADIUS_CLIENT_FIRST_WAIT */
+ for (i = 1; i < sta->acct_interim_errors; i++)
+ wait_time *= 2;
+ }
+ res = eloop_deplete_timeout(wait_time, 0, accounting_interim_update,
+ hapd, sta);
+ if (res == 1)
+ wpa_printf(MSG_DEBUG,
+ "Interim RADIUS accounting update failed for " MACSTR
+ " (error count: %u) - schedule next update in %u seconds",
+ MAC2STR(addr), sta->acct_interim_errors, wait_time);
+ else if (res == 0)
+ wpa_printf(MSG_DEBUG,
+ "Interim RADIUS accounting update failed for " MACSTR
+ " (error count: %u)", MAC2STR(addr),
+ sta->acct_interim_errors);
+ else
+ wpa_printf(MSG_DEBUG,
+ "Interim RADIUS accounting update failed for " MACSTR
+ " (error count: %u) - no timer found", MAC2STR(addr),
+ sta->acct_interim_errors);
+}
+
+
/**
* accounting_init: Initialize accounting
* @hapd: hostapd BSS data
@@ -457,20 +518,15 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
*/
int accounting_init(struct hostapd_data *hapd)
{
- struct os_time now;
-
- /* Acct-Session-Id should be unique over reboots. Using a random number
- * is preferred. If that is not available, take the current time. Mix
- * in microseconds to make this more likely to be unique. */
- os_get_time(&now);
- if (os_get_random((u8 *) &hapd->acct_session_id_hi,
- sizeof(hapd->acct_session_id_hi)) < 0)
- hapd->acct_session_id_hi = now.sec;
- hapd->acct_session_id_hi ^= now.usec;
+ if (radius_gen_session_id((u8 *) &hapd->acct_session_id,
+ sizeof(hapd->acct_session_id)) < 0)
+ return -1;
if (radius_client_register(hapd->radius, RADIUS_ACCT,
accounting_receive, hapd))
return -1;
+ radius_client_set_interim_error_cb(hapd->radius,
+ accounting_interim_error_cb, hapd);
accounting_report_state(hapd, 1);
diff --git a/src/ap/accounting.h b/src/ap/accounting.h
index dcc54ee94b54..de5a33f3c7ce 100644
--- a/src/ap/accounting.h
+++ b/src/ap/accounting.h
@@ -10,9 +10,10 @@
#define ACCOUNTING_H
#ifdef CONFIG_NO_ACCOUNTING
-static inline void accounting_sta_get_id(struct hostapd_data *hapd,
- struct sta_info *sta)
+static inline int accounting_sta_get_id(struct hostapd_data *hapd,
+ struct sta_info *sta)
{
+ return 0;
}
static inline void accounting_sta_start(struct hostapd_data *hapd,
@@ -34,7 +35,7 @@ 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);
+int 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);
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 03d797fe8836..5e8380535854 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -599,8 +599,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
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);
+ 80);
for (i = 0; i < iface->current_mode->num_channels; i++) {
double total_weight;
@@ -933,6 +932,9 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
return HOSTAPD_CHAN_ACS;
}
+ if (!iface->current_mode)
+ return HOSTAPD_CHAN_INVALID;
+
acs_cleanup(iface);
err = acs_request_scan(iface);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 9a96e50b7385..228de2baf946 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -38,6 +38,8 @@ static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
{
+ dl_list_init(&bss->anqp_elem);
+
bss->logger_syslog_level = HOSTAPD_LEVEL_INFO;
bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
bss->logger_syslog = (unsigned int) -1;
@@ -63,6 +65,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->dtim_period = 2;
bss->radius_server_auth_port = 1812;
+ bss->eap_sim_db_timeout = 1;
bss->ap_max_inactivity = AP_MAX_INACTIVITY;
bss->eapol_version = EAPOL_VERSION;
@@ -180,6 +183,7 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->ignore_assoc_probability = 0.0;
conf->ignore_reassoc_probability = 0.0;
conf->corrupt_gtk_rekey_mic_probability = 0.0;
+ conf->ecsa_ie_only = 0;
#endif /* CONFIG_TESTING_OPTIONS */
conf->acs = 0;
@@ -198,13 +202,6 @@ int hostapd_mac_comp(const void *a, const void *b)
}
-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)
{
@@ -410,6 +407,19 @@ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
}
+static void hostapd_config_free_anqp_elem(struct hostapd_bss_config *conf)
+{
+ struct anqp_element *elem;
+
+ while ((elem = dl_list_first(&conf->anqp_elem, struct anqp_element,
+ list))) {
+ dl_list_del(&elem->list);
+ wpabuf_free(elem->payload);
+ os_free(elem);
+ }
+}
+
+
void hostapd_config_free_bss(struct hostapd_bss_config *conf)
{
struct hostapd_eap_user *user, *prev_user;
@@ -454,6 +464,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->private_key);
os_free(conf->private_key_passwd);
os_free(conf->ocsp_stapling_response);
+ os_free(conf->ocsp_stapling_response_multi);
os_free(conf->dh_file);
os_free(conf->openssl_ciphers);
os_free(conf->pac_opaque_encr_key);
@@ -523,6 +534,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->network_auth_type);
os_free(conf->anqp_3gpp_cell_net);
os_free(conf->domain_name);
+ hostapd_config_free_anqp_elem(conf);
#ifdef CONFIG_RADIUS_TEST
os_free(conf->dump_msk_file);
@@ -555,6 +567,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
#endif /* CONFIG_HS20 */
wpabuf_free(conf->vendor_elements);
+ wpabuf_free(conf->assocresp_elements);
os_free(conf->sae_groups);
@@ -594,6 +607,8 @@ void hostapd_config_free(struct hostapd_config *conf)
#ifdef CONFIG_ACS
os_free(conf->acs_chan_bias);
#endif /* CONFIG_ACS */
+ wpabuf_free(conf->lci);
+ wpabuf_free(conf->civic);
os_free(conf);
}
@@ -610,7 +625,7 @@ void hostapd_config_free(struct hostapd_config *conf)
* 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)
+ const u8 *addr, struct vlan_description *vlan_id)
{
int start, end, middle, res;
@@ -650,11 +665,26 @@ int hostapd_rate_found(int *list, int rate)
}
-int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id)
+int hostapd_vlan_valid(struct hostapd_vlan *vlan,
+ struct vlan_description *vlan_desc)
{
struct hostapd_vlan *v = vlan;
+ int i;
+
+ if (!vlan_desc->notempty || vlan_desc->untagged < 0 ||
+ vlan_desc->untagged > MAX_VLAN_ID)
+ return 0;
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN; i++) {
+ if (vlan_desc->tagged[i] < 0 ||
+ vlan_desc->tagged[i] > MAX_VLAN_ID)
+ return 0;
+ }
+ if (!vlan_desc->untagged && !vlan_desc->tagged[0])
+ return 0;
+
while (v) {
- if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
+ if (!vlan_compare(&v->vlan_desc, vlan_desc) ||
+ v->vlan_id == VLAN_ID_WILDCARD)
return 1;
v = v->next;
}
@@ -756,7 +786,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
return -1;
}
- if (full_config && hostapd_mac_comp_empty(bss->bssid) != 0) {
+ if (full_config && !is_zero_ether_addr(bss->bssid)) {
size_t i;
for (i = 0; i < conf->num_bss; i++) {
@@ -811,6 +841,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ if (full_config && conf->ieee80211ac &&
+ bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+ bss->disable_11ac = 1;
+ wpa_printf(MSG_ERROR,
+ "VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
+ }
+#endif /* CONFIG_IEEE80211AC */
+
#ifdef CONFIG_WPS
if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
@@ -847,6 +886,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ if (full_config && bss->mbo_enabled && (bss->wpa & 2) &&
+ bss->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+ wpa_printf(MSG_ERROR,
+ "MBO: PMF needs to be enabled whenever using WPA2 with MBO");
+ return -1;
+ }
+#endif /* CONFIG_MBO */
+
return 0;
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index de470a969b50..8c8f7e286bda 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -10,12 +10,14 @@
#define HOSTAPD_CONFIG_H
#include "common/defs.h"
+#include "utils/list.h"
#include "ip_addr.h"
#include "common/wpa_common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "wps/wps.h"
#include "fst/fst.h"
+#include "vlan.h"
/**
* mesh_conf - local MBSS state and settings
@@ -39,6 +41,10 @@ struct mesh_conf {
#define MESH_CONF_SEC_AUTH BIT(1)
#define MESH_CONF_SEC_AMPE BIT(2)
unsigned int security;
+ enum mfp_options ieee80211w;
+ unsigned int pairwise_cipher;
+ unsigned int group_cipher;
+ unsigned int mgmt_group_cipher;
int dot11MeshMaxRetries;
int dot11MeshRetryTimeout; /* msec */
int dot11MeshConfirmTimeout; /* msec */
@@ -52,7 +58,7 @@ typedef u8 macaddr[ETH_ALEN];
struct mac_acl_entry {
macaddr addr;
- int vlan_id;
+ struct vlan_description vlan_id;
};
struct hostapd_radius_servers;
@@ -102,6 +108,7 @@ struct hostapd_ssid {
#define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1
#define DYNAMIC_VLAN_NAMING_END 2
int vlan_naming;
+ int per_sta_vif;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
char *vlan_tagged_interface;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
@@ -113,6 +120,7 @@ struct hostapd_ssid {
struct hostapd_vlan {
struct hostapd_vlan *next;
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
+ struct vlan_description vlan_desc;
char ifname[IFNAMSIZ + 1];
int configured;
int dynamic_vlan;
@@ -124,9 +132,14 @@ struct hostapd_vlan {
};
#define PMK_LEN 32
+#define MIN_PASSPHRASE_LEN 8
+#define MAX_PASSPHRASE_LEN 63
struct hostapd_sta_wpa_psk_short {
struct hostapd_sta_wpa_psk_short *next;
+ unsigned int is_passphrase:1;
u8 psk[PMK_LEN];
+ char passphrase[MAX_PASSPHRASE_LEN + 1];
+ int ref; /* (number of references held) - 1 */
};
struct hostapd_wpa_psk {
@@ -205,6 +218,13 @@ struct hostapd_nai_realm_data {
} eap_method[MAX_NAI_EAP_METHODS];
};
+struct anqp_element {
+ struct dl_list list;
+ u16 infoid;
+ struct wpabuf *payload;
+};
+
+
/**
* struct hostapd_bss_config - Per-BSS configuration
*/
@@ -231,6 +251,7 @@ struct hostapd_bss_config {
struct hostapd_eap_user *eap_user;
char *eap_user_sqlite;
char *eap_sim_db;
+ unsigned int eap_sim_db_timeout;
int eap_server_erp; /* Whether ERP is enabled on internal EAP server */
struct hostapd_ip_addr own_ip_addr;
char *nas_identifier;
@@ -242,6 +263,7 @@ struct hostapd_bss_config {
int radius_das_port;
unsigned int radius_das_time_window;
int radius_das_require_event_timestamp;
+ int radius_das_require_message_authenticator;
struct hostapd_ip_addr radius_das_client_addr;
u8 *radius_das_shared_secret;
size_t radius_das_shared_secret_len;
@@ -332,6 +354,7 @@ struct hostapd_bss_config {
int check_crl;
unsigned int tls_session_lifetime;
char *ocsp_stapling_response;
+ char *ocsp_stapling_response_multi;
char *dh_file;
char *openssl_ciphers;
u8 *pac_opaque_encr_key;
@@ -358,6 +381,7 @@ struct hostapd_bss_config {
int ap_max_inactivity;
int ignore_broadcast_ssid;
+ int no_probe_resp_if_max_sta;
int wmm_enabled;
int wmm_uapsd;
@@ -481,8 +505,11 @@ struct hostapd_bss_config {
unsigned int nai_realm_count;
struct hostapd_nai_realm_data *nai_realm_data;
+ struct dl_list anqp_elem; /* list of struct anqp_element */
+
u16 gas_comeback_delay;
int gas_frag_limit;
+ int gas_address3;
u8 qos_map_set[16 + 2 * 21];
unsigned int qos_map_set_len;
@@ -536,6 +563,7 @@ struct hostapd_bss_config {
#endif /* CONFIG_RADIUS_TEST */
struct wpabuf *vendor_elements;
+ struct wpabuf *assocresp_elements;
unsigned int sae_anti_clogging_threshold;
int *sae_groups;
@@ -551,12 +579,22 @@ struct hostapd_bss_config {
#define MESH_ENABLED BIT(0)
int mesh;
- int radio_measurements;
+ u8 radio_measurements[RRM_CAPABILITIES_IE_LEN];
int vendor_vht;
+ int use_sta_nsts;
char *no_probe_resp_if_seen_on;
char *no_auth_if_seen_on;
+
+ int pbss;
+
+#ifdef CONFIG_MBO
+ int mbo_enabled;
+#endif /* CONFIG_MBO */
+
+ int ftm_responder;
+ int ftm_initiator;
};
@@ -638,6 +676,9 @@ struct hostapd_config {
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
+ /* Use driver-generated interface addresses when adding multiple BSSs */
+ u8 use_driver_iface_addr;
+
#ifdef CONFIG_FST
struct fst_iface_cfg fst_cfg;
#endif /* CONFIG_FST */
@@ -652,6 +693,7 @@ struct hostapd_config {
double ignore_assoc_probability;
double ignore_reassoc_probability;
double corrupt_gtk_rekey_mic_probability;
+ int ecsa_ie_only;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_ACS
@@ -662,11 +704,13 @@ struct hostapd_config {
} *acs_chan_bias;
unsigned int num_acs_chan_bias;
#endif /* CONFIG_ACS */
+
+ struct wpabuf *lci;
+ struct wpabuf *civic;
};
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_eap_user(struct hostapd_eap_user *user);
@@ -674,13 +718,14 @@ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
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);
+ const u8 *addr, struct vlan_description *vlan_id);
int hostapd_rate_found(int *list, int rate);
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);
+int hostapd_vlan_valid(struct hostapd_vlan *vlan,
+ struct vlan_description *vlan_desc);
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
int vlan_id);
struct hostapd_radius_attr *
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 6cafcb749351..f1394654d3a8 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -33,10 +33,36 @@ u32 hostapd_sta_flags_to_drv(u32 flags)
res |= WPA_STA_SHORT_PREAMBLE;
if (flags & WLAN_STA_MFP)
res |= WPA_STA_MFP;
+ if (flags & WLAN_STA_AUTH)
+ res |= WPA_STA_AUTHENTICATED;
+ if (flags & WLAN_STA_ASSOC)
+ res |= WPA_STA_ASSOCIATED;
return res;
}
+static int add_buf(struct wpabuf **dst, const struct wpabuf *src)
+{
+ if (!src)
+ return 0;
+ if (wpabuf_resize(dst, wpabuf_len(src)) != 0)
+ return -1;
+ wpabuf_put_buf(*dst, src);
+ return 0;
+}
+
+
+static int add_buf_data(struct wpabuf **dst, const u8 *data, size_t len)
+{
+ if (!data || !len)
+ return 0;
+ if (wpabuf_resize(dst, len) != 0)
+ return -1;
+ wpabuf_put_data(*dst, data, len);
+ return 0;
+}
+
+
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
struct wpabuf **beacon_ret,
struct wpabuf **proberesp_ret,
@@ -49,82 +75,38 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
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);
- }
+ if (add_buf_data(&beacon, buf, pos - buf) < 0)
+ goto fail;
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);
- }
+ if (add_buf_data(&proberesp, buf, pos - buf) < 0)
+ goto fail;
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);
- }
+ if (add_buf_data(&assocresp, buf, pos - buf) < 0)
+ goto fail;
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 (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+ add_buf_data(&proberesp, buf, pos - buf) < 0)
+ goto fail;
#ifdef CONFIG_FST
- if (hapd->iface->fst_ies) {
- size_t add = wpabuf_len(hapd->iface->fst_ies);
-
- if (wpabuf_resize(&beacon, add) < 0)
- goto fail;
- wpabuf_put_buf(beacon, hapd->iface->fst_ies);
- if (wpabuf_resize(&proberesp, add) < 0)
- goto fail;
- wpabuf_put_buf(proberesp, hapd->iface->fst_ies);
- if (wpabuf_resize(&assocresp, add) < 0)
- goto fail;
- wpabuf_put_buf(assocresp, hapd->iface->fst_ies);
- }
+ if (add_buf(&beacon, hapd->iface->fst_ies) < 0 ||
+ add_buf(&proberesp, hapd->iface->fst_ies) < 0 ||
+ add_buf(&assocresp, hapd->iface->fst_ies) < 0)
+ goto fail;
#endif /* CONFIG_FST */
- 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);
- }
+ if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
+ add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
+ goto fail;
#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);
- }
+ if (add_buf(&beacon, hapd->p2p_beacon_ie) < 0 ||
+ add_buf(&proberesp, hapd->p2p_probe_resp_ie) < 0)
+ goto fail;
#endif /* CONFIG_P2P */
#ifdef CONFIG_P2P_MANAGER
@@ -148,8 +130,7 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
#ifdef CONFIG_WPS
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);
+ add_buf(&assocresp, a);
wpabuf_free(a);
}
#endif /* CONFIG_WPS */
@@ -169,44 +150,36 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
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);
+ add_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);
- }
+ pos = hostapd_eid_hs20_indication(hapd, buf);
+ if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+ add_buf_data(&proberesp, buf, pos - buf) < 0)
+ goto fail;
pos = hostapd_eid_osen(hapd, buf);
- if (pos != buf) {
- if (wpabuf_resize(&beacon, pos - buf) != 0)
- goto fail;
- wpabuf_put_data(beacon, buf, pos - buf);
+ if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+ add_buf_data(&proberesp, buf, pos - buf) < 0)
+ goto fail;
+#endif /* CONFIG_HS20 */
- if (wpabuf_resize(&proberesp, pos - buf) != 0)
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled) {
+ pos = hostapd_eid_mbo(hapd, buf, sizeof(buf));
+ if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+ add_buf_data(&proberesp, buf, pos - buf) < 0 ||
+ add_buf_data(&assocresp, buf, pos - buf) < 0)
goto fail;
- wpabuf_put_data(proberesp, buf, pos - buf);
}
-#endif /* CONFIG_HS20 */
+#endif /* CONFIG_MBO */
- 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);
- }
+ add_buf(&beacon, hapd->conf->vendor_elements);
+ add_buf(&proberesp, hapd->conf->vendor_elements);
+ add_buf(&assocresp, hapd->conf->assocresp_elements);
*beacon_ret = beacon;
*proberesp_ret = proberesp;
@@ -390,7 +363,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
- u32 flags, u8 qosinfo, u8 vht_opmode)
+ u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
+ int set)
{
struct hostapd_sta_add_params params;
@@ -412,6 +386,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags);
params.qosinfo = qosinfo;
+ params.support_p2p_ps = supp_p2p_ps;
+ params.set = set;
return hapd->driver->sta_add(hapd->drv_priv, &params);
}
@@ -468,7 +444,7 @@ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
return -1;
return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
bss_ctx, drv_priv, force_ifname, if_addr,
- bridge, use_existing);
+ bridge, use_existing, 1);
}
@@ -647,16 +623,28 @@ int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
const void *msg, size_t len, int noack)
{
+ if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
+ return 0;
+ return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
+ NULL, 0);
+}
+
+
+int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
+ const void *msg, size_t len, int noack,
+ const u16 *csa_offs, size_t csa_offs_len)
+{
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
return 0;
- return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0);
+ return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
+ csa_offs, csa_offs_len);
}
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason)
{
- if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
+ if (!hapd->driver || !hapd->driver->sta_deauth || !hapd->drv_priv)
return 0;
return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
reason);
@@ -666,7 +654,7 @@ int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
const u8 *addr, int reason)
{
- if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
+ if (!hapd->driver || !hapd->driver->sta_disassoc || !hapd->drv_priv)
return 0;
return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
reason);
@@ -687,6 +675,36 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
unsigned int wait, const u8 *dst, const u8 *data,
size_t len)
{
+ const u8 *bssid;
+ const u8 wildcard_bssid[ETH_ALEN] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ if (!hapd->driver || !hapd->driver->send_action || !hapd->drv_priv)
+ return 0;
+ bssid = hapd->own_addr;
+ if (!is_multicast_ether_addr(dst) &&
+ len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
+ struct sta_info *sta;
+
+ /*
+ * Public Action frames to a STA that is not a member of the BSS
+ * shall use wildcard BSSID value.
+ */
+ sta = ap_get_sta(hapd, dst);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC))
+ bssid = wildcard_bssid;
+ }
+ return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
+ hapd->own_addr, bssid, data, len, 0);
+}
+
+
+int hostapd_drv_send_action_addr3_ap(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,
@@ -736,7 +754,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
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)
+ if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv)
return 0;
return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
qos_map_set_len);
@@ -762,6 +780,20 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
}
+void hostapd_get_ext_capa(struct hostapd_iface *iface)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+
+ if (!hapd->driver || !hapd->driver->get_ext_capab)
+ return;
+
+ hapd->driver->get_ext_capab(hapd->drv_priv, WPA_IF_AP_BSS,
+ &iface->extended_capa,
+ &iface->extended_capa_mask,
+ &iface->extended_capa_len);
+}
+
+
int hostapd_drv_do_acs(struct hostapd_data *hapd)
{
struct drv_acs_params params;
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 82eaf3f08bb5..0bb7954ec061 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -41,7 +41,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
- u32 flags, u8 qosinfo, u8 vht_opmode);
+ u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
+ int set);
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);
@@ -88,6 +89,9 @@ int hostapd_drv_set_key(const char *ifname,
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_send_mlme_csa(struct hostapd_data *hapd,
+ const void *msg, size_t len, int noack,
+ const u16 *csa_offs, size_t csa_offs_len);
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason);
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
@@ -95,6 +99,10 @@ int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
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_drv_send_action_addr3_ap(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,
@@ -120,6 +128,8 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd,
int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
u8 qos_map_set_len);
+void hostapd_get_ext_capa(struct hostapd_iface *iface);
+
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
int enabled)
{
@@ -150,7 +160,7 @@ static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd,
static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
const u8 *addr)
{
- if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
+ if (!hapd->driver || !hapd->driver->sta_remove || !hapd->drv_priv)
return 0;
return hapd->driver->sta_remove(hapd->drv_priv, addr);
}
@@ -273,7 +283,7 @@ static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
size_t buflen)
{
- if (hapd->driver == NULL || hapd->driver->status == NULL)
+ if (!hapd->driver || !hapd->driver->status || !hapd->drv_priv)
return -1;
return hapd->driver->status(hapd->drv_priv, buf, buflen);
}
@@ -332,7 +342,7 @@ static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
{
- if (hapd->driver == NULL || hapd->driver->stop_ap == NULL)
+ if (!hapd->driver || !hapd->driver->stop_ap || !hapd->drv_priv)
return 0;
return hapd->driver->stop_ap(hapd->drv_priv);
}
diff --git a/src/ap/ap_mlme.c b/src/ap/ap_mlme.c
index 13604edc4940..e7308a01d743 100644
--- a/src/ap/ap_mlme.c
+++ b/src/ap/ap_mlme.c
@@ -59,6 +59,7 @@ void mlme_authenticate_indication(struct hostapd_data *hapd,
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);
+ ap_sta_clear_disconnect_timeouts(hapd, sta);
}
@@ -106,6 +107,7 @@ void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
MAC2STR(sta->addr));
if (sta->auth_alg != WLAN_AUTH_FT)
mlme_deletekeys_request(hapd, sta);
+ ap_sta_clear_disconnect_timeouts(hapd, sta);
}
@@ -130,6 +132,7 @@ void mlme_reassociate_indication(struct hostapd_data *hapd,
MAC2STR(sta->addr));
if (sta->auth_alg != WLAN_AUTH_FT)
mlme_deletekeys_request(hapd, sta);
+ ap_sta_clear_disconnect_timeouts(hapd, sta);
}
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 934dcfc8d631..cdb49cdd9d32 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -173,6 +173,8 @@ int authsrv_init(struct hostapd_data *hapd)
params.openssl_ciphers = hapd->conf->openssl_ciphers;
params.ocsp_stapling_response =
hapd->conf->ocsp_stapling_response;
+ params.ocsp_stapling_response_multi =
+ hapd->conf->ocsp_stapling_response_multi;
if (tls_global_set_params(hapd->ssl_ctx, &params)) {
wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
@@ -193,6 +195,7 @@ int authsrv_init(struct hostapd_data *hapd)
if (hapd->conf->eap_sim_db) {
hapd->eap_sim_db_priv =
eap_sim_db_init(hapd->conf->eap_sim_db,
+ hapd->conf->eap_sim_db_timeout,
hostapd_sim_db_cb, hapd);
if (hapd->eap_sim_db_priv == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize EAP-SIM "
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 5fe8fd5660b4..233320d2e978 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -29,6 +29,7 @@
#include "beacon.h"
#include "hs20.h"
#include "dfs.h"
+#include "taxonomy.h"
#ifdef NEED_AP_MLME
@@ -36,18 +37,21 @@
static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
size_t len)
{
- if (!hapd->conf->radio_measurements || len < 2 + 4)
+ size_t i;
+
+ for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
+ if (hapd->conf->radio_measurements[i])
+ break;
+ }
+
+ if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
return eid;
*eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
- *eid++ = 5;
- *eid++ = (hapd->conf->radio_measurements & BIT(0)) ?
- WLAN_RRM_CAPS_NEIGHBOR_REPORT : 0x00;
- *eid++ = 0x00;
- *eid++ = 0x00;
- *eid++ = 0x00;
- *eid++ = 0x00;
- return eid;
+ *eid++ = RRM_CAPABILITIES_IE_LEN;
+ os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
+
+ return eid + RRM_CAPABILITIES_IE_LEN;
}
@@ -297,65 +301,65 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
{
- u8 chan;
-
- if (!hapd->cs_freq_params.freq)
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->iface->cs_oper_class && hapd->iconf->ecsa_ie_only)
return eid;
+#endif /* CONFIG_TESTING_OPTIONS */
- if (ieee80211_freq_to_chan(hapd->cs_freq_params.freq, &chan) ==
- NUM_HOSTAPD_MODES)
+ if (!hapd->cs_freq_params.channel)
return eid;
*eid++ = WLAN_EID_CHANNEL_SWITCH;
*eid++ = 3;
*eid++ = hapd->cs_block_tx;
- *eid++ = chan;
+ *eid++ = hapd->cs_freq_params.channel;
*eid++ = hapd->cs_count;
return eid;
}
-static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
+static u8 * hostapd_eid_ecsa(struct hostapd_data *hapd, u8 *eid)
{
- u8 sec_ch;
-
- if (!hapd->cs_freq_params.sec_channel_offset)
+ if (!hapd->cs_freq_params.channel || !hapd->iface->cs_oper_class)
return eid;
- if (hapd->cs_freq_params.sec_channel_offset == -1)
- sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
- else if (hapd->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;
+ *eid++ = WLAN_EID_EXT_CHANSWITCH_ANN;
+ *eid++ = 4;
+ *eid++ = hapd->cs_block_tx;
+ *eid++ = hapd->iface->cs_oper_class;
+ *eid++ = hapd->cs_freq_params.channel;
+ *eid++ = hapd->cs_count;
return eid;
}
-static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos,
- u8 *start, unsigned int *csa_counter_off)
+static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
{
- u8 *old_pos = pos;
+ u8 op_class, channel;
- if (!csa_counter_off)
- return pos;
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) ||
+ !hapd->iface->freq)
+ return eid;
- *csa_counter_off = 0;
- pos = hostapd_eid_csa(hapd, pos);
+ if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
+ hapd->iconf->secondary_channel,
+ hapd->iconf->vht_oper_chwidth,
+ &op_class, &channel) ==
+ NUM_HOSTAPD_MODES)
+ return eid;
- 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);
- }
+ *eid++ = WLAN_EID_SUPPORTED_OPERATING_CLASSES;
+ *eid++ = 2;
- return pos;
+ /* Current Operating Class */
+ *eid++ = op_class;
+
+ /* TODO: Advertise all the supported operating classes */
+ *eid++ = 0;
+
+ return eid;
}
@@ -364,7 +368,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
int is_p2p, size_t *resp_len)
{
struct ieee80211_mgmt *resp;
- u8 *pos, *epos;
+ u8 *pos, *epos, *csa_pos;
size_t buflen;
#define MAX_PROBERESP_LEN 768
@@ -387,6 +391,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
2 + sizeof(struct ieee80211_vht_operation);
}
+
+ buflen += hostapd_mbo_ie_len(hapd);
+
resp = os_zalloc(buflen);
if (resp == NULL)
return NULL;
@@ -424,6 +431,12 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
/* Power Constraint element */
pos = hostapd_eid_pwr_constraint(hapd, pos);
+ /* CSA IE */
+ csa_pos = hostapd_eid_csa(hapd, pos);
+ if (csa_pos != pos)
+ hapd->cs_c_off_proberesp = csa_pos - (u8 *) resp - 1;
+ pos = csa_pos;
+
/* ERP Information element */
pos = hostapd_eid_erp_info(hapd, pos);
@@ -437,7 +450,19 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
+ /* eCSA IE */
+ csa_pos = hostapd_eid_ecsa(hapd, pos);
+ if (csa_pos != pos)
+ hapd->cs_c_off_ecsa_proberesp = csa_pos - (u8 *) resp - 1;
+ pos = csa_pos;
+
+ pos = hostapd_eid_supported_op_classes(hapd, pos);
+
#ifdef CONFIG_IEEE80211N
+ /* Secondary Channel Offset element */
+ /* TODO: The standard doesn't specify a position for this element. */
+ pos = hostapd_eid_secondary_channel(hapd, pos);
+
pos = hostapd_eid_ht_capabilities(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
#endif /* CONFIG_IEEE80211N */
@@ -451,9 +476,6 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_adv_proto(hapd, pos);
pos = hostapd_eid_roaming_consortium(hapd, pos);
- pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
- &hapd->cs_c_off_proberesp);
-
#ifdef CONFIG_FST
if (hapd->iface->fst_ies) {
os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies),
@@ -464,8 +486,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
- pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
+ pos = hostapd_eid_txpower_envelope(hapd, pos);
+ pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
}
if (hapd->conf->vendor_vht)
pos = hostapd_eid_vendor_vht(hapd, pos);
@@ -501,6 +525,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_osen(hapd, pos);
#endif /* CONFIG_HS20 */
+ pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
+
if (hapd->conf->vendor_elements) {
os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
wpabuf_len(hapd->conf->vendor_elements));
@@ -537,8 +563,8 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
pos = ssid_list;
end = ssid_list + ssid_list_len;
- while (pos + 1 <= end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos >= 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[1] == 0)
wildcard = 1;
@@ -574,7 +600,7 @@ void sta_track_expire(struct hostapd_iface *iface, int force)
MAC2STR(info->addr));
dl_list_del(&info->list);
iface->num_sta_seen--;
- os_free(info);
+ sta_track_del(info);
}
}
@@ -607,6 +633,8 @@ void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
/* Add a new entry */
info = os_zalloc(sizeof(*info));
+ if (info == NULL)
+ return;
os_memcpy(info->addr, addr, ETH_ALEN);
os_get_reltime(&info->last_seen);
@@ -648,6 +676,23 @@ sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
}
+#ifdef CONFIG_TAXONOMY
+void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
+ struct wpabuf **probe_ie_taxonomy)
+{
+ struct hostapd_sta_info *info;
+
+ info = sta_track_get(iface, addr);
+ if (!info)
+ return;
+
+ wpabuf_free(*probe_ie_taxonomy);
+ *probe_ie_taxonomy = info->probe_ie_taxonomy;
+ info->probe_ie_taxonomy = NULL;
+}
+#endif /* CONFIG_TAXONOMY */
+
+
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int ssi_signal)
@@ -659,13 +704,16 @@ void handle_probe_req(struct hostapd_data *hapd,
size_t i, resp_len;
int noack;
enum ssid_match_result res;
+ int ret;
+ u16 csa_offs[2];
+ size_t csa_offs_len;
- ie = mgmt->u.probe_req.variable;
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+ if (len < IEEE80211_HDRLEN)
return;
+ ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
if (hapd->iconf->track_sta_max_num)
sta_track_add(hapd->iface, mgmt->sa);
- ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+ ie_len = len - IEEE80211_HDRLEN;
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
@@ -711,7 +759,7 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#ifdef CONFIG_P2P
- if (hapd->p2p && elems.wps_ie) {
+ if (hapd->p2p && hapd->p2p_group && 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)) {
@@ -724,7 +772,7 @@ void handle_probe_req(struct hostapd_data *hapd,
wpabuf_free(wps);
}
- if (hapd->p2p && elems.p2p) {
+ if (hapd->p2p && hapd->p2p_group && 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)) {
@@ -754,6 +802,21 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_TAXONOMY
+ {
+ struct sta_info *sta;
+ struct hostapd_sta_info *info;
+
+ if ((sta = ap_get_sta(hapd, mgmt->sa)) != NULL) {
+ taxonomy_sta_info_probe_req(hapd, sta, ie, ie_len);
+ } else if ((info = sta_track_get(hapd->iface,
+ mgmt->sa)) != NULL) {
+ taxonomy_hostapd_sta_info_probe_req(hapd, info,
+ ie, ie_len);
+ }
+ }
+#endif /* CONFIG_TAXONOMY */
+
res = ssid_match(hapd, elems.ssid, elems.ssid_len,
elems.ssid_list, elems.ssid_list_len);
if (res == NO_SSID_MATCH) {
@@ -825,6 +888,17 @@ void handle_probe_req(struct hostapd_data *hapd,
return;
}
+ if (hapd->conf->no_probe_resp_if_max_sta &&
+ is_multicast_ether_addr(mgmt->da) &&
+ is_multicast_ether_addr(mgmt->bssid) &&
+ hapd->num_sta >= hapd->conf->max_num_sta &&
+ !ap_get_sta(hapd, mgmt->sa)) {
+ wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR
+ " since no room for additional STA",
+ hapd->conf->iface, MAC2STR(mgmt->sa));
+ return;
+ }
+
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->iconf->ignore_probe_probability > 0.0 &&
drand48() < hapd->iconf->ignore_probe_probability) {
@@ -847,7 +921,22 @@ void handle_probe_req(struct hostapd_data *hapd,
noack = !!(res == WILDCARD_SSID_MATCH &&
is_broadcast_ether_addr(mgmt->da));
- if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
+ csa_offs_len = 0;
+ if (hapd->csa_in_progress) {
+ if (hapd->cs_c_off_proberesp)
+ csa_offs[csa_offs_len++] =
+ hapd->cs_c_off_proberesp;
+
+ if (hapd->cs_c_off_ecsa_proberesp)
+ csa_offs[csa_offs_len++] =
+ hapd->cs_c_off_ecsa_proberesp;
+ }
+
+ ret = hostapd_drv_send_mlme_csa(hapd, resp, resp_len, noack,
+ csa_offs_len ? csa_offs : NULL,
+ csa_offs_len);
+
+ if (ret < 0)
wpa_printf(MSG_INFO, "handle_probe_req: send failed");
os_free(resp);
@@ -896,6 +985,16 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
+void sta_track_del(struct hostapd_sta_info *info)
+{
+#ifdef CONFIG_TAXONOMY
+ wpabuf_free(info->probe_ie_taxonomy);
+ info->probe_ie_taxonomy = NULL;
+#endif /* CONFIG_TAXONOMY */
+ os_free(info);
+}
+
+
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
@@ -906,7 +1005,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
size_t resp_len = 0;
#ifdef NEED_AP_MLME
u16 capab_info;
- u8 *pos, *tailpos;
+ u8 *pos, *tailpos, *csa_pos;
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
@@ -934,6 +1033,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211AC */
+ tail_len += hostapd_mbo_ie_len(hapd);
+
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
wpa_printf(MSG_ERROR, "Failed to set beacon data");
@@ -987,6 +1088,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
/* Power Constraint element */
tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
+ /* CSA IE */
+ csa_pos = hostapd_eid_csa(hapd, tailpos);
+ if (csa_pos != tailpos)
+ hapd->cs_c_off_beacon = csa_pos - tail - 1;
+ tailpos = csa_pos;
+
/* ERP Information element */
tailpos = hostapd_eid_erp_info(hapd, tailpos);
@@ -1004,7 +1111,19 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_bss_load(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE - tailpos);
+ /* eCSA IE */
+ csa_pos = hostapd_eid_ecsa(hapd, tailpos);
+ if (csa_pos != tailpos)
+ hapd->cs_c_off_ecsa_beacon = csa_pos - tail - 1;
+ tailpos = csa_pos;
+
+ tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
+
#ifdef CONFIG_IEEE80211N
+ /* Secondary Channel Offset element */
+ /* TODO: The standard doesn't specify a position for this element. */
+ tailpos = hostapd_eid_secondary_channel(hapd, tailpos);
+
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
#endif /* CONFIG_IEEE80211N */
@@ -1020,8 +1139,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
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->cs_c_off_beacon);
#ifdef CONFIG_FST
if (hapd->iface->fst_ies) {
@@ -1033,8 +1150,10 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
- tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+ tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+ tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
+ tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
}
if (hapd->conf->vendor_vht)
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
@@ -1069,6 +1188,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_osen(hapd, tailpos);
#endif /* CONFIG_HS20 */
+ tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
+
if (hapd->conf->vendor_elements) {
os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
wpabuf_len(hapd->conf->vendor_elements));
@@ -1153,6 +1274,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
params->osen = 1;
}
#endif /* CONFIG_HS20 */
+ params->pbss = hapd->conf->pbss;
return 0;
}
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index d98f42e8157a..fc711815cf65 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -22,9 +22,12 @@ 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);
void sta_track_add(struct hostapd_iface *iface, const u8 *addr);
+void sta_track_del(struct hostapd_sta_info *info);
void sta_track_expire(struct hostapd_iface *iface, int force);
struct hostapd_data *
sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
const char *ifname);
+void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
+ struct wpabuf **probe_ie_taxonomy);
#endif /* BEACON_H */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index c98978f33d05..3680fda3153f 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -22,6 +22,8 @@
#include "p2p_hostapd.h"
#include "ctrl_iface_ap.h"
#include "ap_drv_ops.h"
+#include "mbo_ap.h"
+#include "taxonomy.h"
static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
@@ -35,9 +37,9 @@ static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
return 0;
ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
- "rx_bytes=%lu\ntx_bytes=%lu\n",
+ "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n",
data.rx_packets, data.tx_packets,
- data.rx_bytes, data.tx_bytes);
+ data.rx_bytes, data.tx_bytes, data.inactive_msec);
if (os_snprintf_error(buflen, ret))
return 0;
return ret;
@@ -161,6 +163,19 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
len += res;
}
+ res = mbo_ap_get_info(sta, buf + len, buflen - len);
+ if (res >= 0)
+ len += res;
+
+ if (sta->supp_op_classes &&
+ buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
+ len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
+ len += wpa_snprintf_hex(buf + len, buflen - len,
+ sta->supp_op_classes + 1,
+ sta->supp_op_classes[0]);
+ len += os_snprintf(buf + len, buflen - len, "\n");
+ }
+
return len;
}
@@ -244,7 +259,7 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
int ret;
u8 *pos;
- if (hapd->driver->send_frame == NULL)
+ if (!hapd->drv_priv || !hapd->driver->send_frame)
return -1;
mgmt = os_zalloc(sizeof(*mgmt) + 100);
@@ -255,7 +270,7 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
" with minor reason code %u (stype=%u (%s))",
MAC2STR(addr), minor_reason_code, stype,
- fc2str(mgmt->frame_control));
+ fc2str(le_to_host16(mgmt->frame_control)));
os_memcpy(mgmt->da, addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
@@ -311,7 +326,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (hapd->driver->send_frame == NULL)
+ if (!hapd->drv_priv || !hapd->driver->send_frame)
return -1;
pos += 6;
encrypt = atoi(pos);
@@ -338,7 +353,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
- hostapd_drv_sta_deauth(hapd, addr, reason);
+ if (os_strstr(txtaddr, " tx=0"))
+ hostapd_drv_sta_remove(hapd, addr);
+ else
+ hostapd_drv_sta_deauth(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
ap_sta_deauthenticate(hapd, sta, reason);
@@ -371,7 +389,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (hapd->driver->send_frame == NULL)
+ if (!hapd->drv_priv || !hapd->driver->send_frame)
return -1;
pos += 6;
encrypt = atoi(pos);
@@ -398,7 +416,10 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
- hostapd_drv_sta_disassoc(hapd, addr, reason);
+ if (os_strstr(txtaddr, " tx=0"))
+ hostapd_drv_sta_remove(hapd, addr);
+ else
+ hostapd_drv_sta_disassoc(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
ap_sta_disassociate(hapd, sta, reason);
@@ -409,6 +430,49 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
}
+#ifdef CONFIG_TAXONOMY
+int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
+ const char *txtaddr,
+ char *buf, size_t buflen)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return -1;
+
+ return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
+}
+#endif /* CONFIG_TAXONOMY */
+
+
+int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return -1;
+
+ hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
+ sta->flags & WLAN_STA_WMM);
+ return 0;
+}
+
+
int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
size_t buflen)
{
@@ -473,20 +537,28 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
"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",
+ "ieee80211ac=%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);
+ iface->conf->ieee80211n && !hapd->conf->disable_11n ?
+ iface->conf->secondary_channel : 0,
+ iface->conf->ieee80211n && !hapd->conf->disable_11n,
+ iface->conf->ieee80211ac &&
+ !hapd->conf->disable_11ac);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
+ if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "vht_oper_chwidth=%d\n"
+ "vht_oper_centr_freq_seg0_idx=%d\n"
+ "vht_oper_centr_freq_seg1_idx=%d\n",
+ iface->conf->vht_oper_chwidth,
+ iface->conf->vht_oper_centr_freq_seg0_idx,
+ iface->conf->vht_oper_centr_freq_seg1_idx);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *bss = iface->bss[i];
@@ -554,3 +626,16 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
{
return hostapd_drv_stop_ap(hapd);
}
+
+
+int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
+ size_t len)
+{
+ return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
+}
+
+
+void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
+{
+ wpa_auth_pmksa_flush(hapd->wpa_auth);
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index e5297d03e810..4f996800f132 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -19,10 +19,18 @@ 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_signature(struct hostapd_data *hapd,
+ const char *txtaddr,
+ char *buf, size_t buflen);
+int hostapd_ctrl_iface_poll_sta(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);
int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd);
+int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
+ size_t len);
+void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd);
#endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 715f19b6ac7b..47adba7ef726 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -450,7 +450,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
return NULL;
if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
- _rand = os_random();
+ return NULL;
chan_idx = _rand % num_available_chandefs;
dfs_find_channel(iface, &chan, chan_idx, skip_radar);
@@ -704,7 +704,8 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
skip_radar);
if (!channel) {
wpa_printf(MSG_ERROR, "could not get valid channel");
- return -1;
+ hostapd_set_state(iface, HAPD_IFACE_DFS);
+ return 0;
}
iface->freq = channel->freq;
@@ -793,7 +794,6 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
if (!channel) {
wpa_printf(MSG_ERROR, "No valid channel available");
- hostapd_setup_interface_complete(iface, err);
return err;
}
@@ -817,16 +817,6 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
}
-static int hostapd_csa_in_progress(struct hostapd_iface *iface)
-{
- unsigned int i;
- for (i = 0; i < iface->num_bss; i++)
- if (iface->bss[i]->csa_in_progress)
- return 1;
- return 0;
-}
-
-
static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
@@ -868,8 +858,9 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
&vht_oper_centr_freq_seg1_idx,
skip_radar);
if (!channel) {
- /* FIXME: Wait for channel(s) to become available */
- hostapd_disable_iface(iface);
+ wpa_printf(MSG_INFO,
+ "%s: no DFS channels left, waiting for NOP to finish",
+ __func__);
return err;
}
@@ -992,6 +983,11 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
/* TODO add correct implementation here */
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
+
+ /* Handle cases where all channels were initially unavailable */
+ if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
+ hostapd_handle_dfs(iface);
+
return 0;
}
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
index 3a77225f380e..f0212fb2a984 100644
--- a/src/ap/dhcp_snoop.c
+++ b/src/ap/dhcp_snoop.c
@@ -121,7 +121,8 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
wpa_printf(MSG_DEBUG, "dhcp_snoop: Found DHCPACK for " MACSTR
" @ IPv4 address %s/%d",
- MAC2STR(sta->addr), ipaddr_str(ntohl(b->your_ip)),
+ MAC2STR(sta->addr),
+ ipaddr_str(be_to_host32(b->your_ip)),
prefixlen);
if (sta->ipaddr == b->your_ip)
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index ca8b75c83906..3552b3e0d53b 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -22,6 +22,7 @@
#include "wnm_ap.h"
#include "hostapd.h"
#include "ieee802_11.h"
+#include "ieee802_11_auth.h"
#include "sta_info.h"
#include "accounting.h"
#include "tkip_countermeasures.h"
@@ -33,6 +34,7 @@
#include "hw_features.h"
#include "dfs.h"
#include "beacon.h"
+#include "mbo_ap.h"
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -114,6 +116,21 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
+ /*
+ * ACL configurations to the drivers (implementing AP SME and ACL
+ * offload) without hostapd's knowledge, can result in a disconnection
+ * though the driver accepts the connection. Skip the hostapd check for
+ * ACL if the driver supports ACL offload to avoid potentially
+ * conflicting ACL rules.
+ */
+ if (hapd->iface->drv_max_acl_mac_addrs == 0 &&
+ hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) {
+ wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect",
+ MAC2STR(addr));
+ reason = WLAN_REASON_UNSPECIFIED;
+ goto fail;
+ }
+
#ifdef CONFIG_P2P
if (elems.p2p) {
wpabuf_free(sta->p2p_ie);
@@ -164,6 +181,11 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->mb_ies = NULL;
#endif /* CONFIG_FST */
+ mbo_ap_check_sta_assoc(hapd, sta, &elems);
+
+ ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
+ elems.supp_op_classes_len);
+
if (hapd->conf->wpa) {
if (ie == NULL || ielen == 0) {
#ifdef CONFIG_WPS
@@ -338,6 +360,17 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
return WLAN_STATUS_INVALID_IE;
#endif /* CONFIG_HS20 */
}
+
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
+ elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
+ hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ wpa_printf(MSG_INFO,
+ "MBO: Reject WPA2 association without PMF");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+#endif /* CONFIG_MBO */
+
#ifdef CONFIG_WPS
skip_wpa_check:
#endif /* CONFIG_WPS */
@@ -447,7 +480,8 @@ 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, is_dfs;
+ int channel, chwidth, is_dfs;
+ u8 seg0_idx = 0, seg1_idx = 0;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
@@ -491,8 +525,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
seg1_idx = (cf2 - 5000) / 5;
break;
default:
- seg0_idx = hostapd_hw_get_channel(hapd, cf1);
- seg1_idx = hostapd_hw_get_channel(hapd, cf2);
+ ieee80211_freq_to_chan(cf1, &seg0_idx);
+ ieee80211_freq_to_chan(cf2, &seg1_idx);
break;
}
@@ -539,10 +573,11 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
#ifdef CONFIG_ACS
-static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
- struct acs_selected_channels *acs_res)
+void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+ struct acs_selected_channels *acs_res)
{
int ret, i;
+ int err = 0;
if (hapd->iconf->channel) {
wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
@@ -564,7 +599,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver selected to bad hw_mode");
- return;
+ err = 1;
+ goto out;
}
}
@@ -574,7 +610,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver switched to bad channel");
- return;
+ err = 1;
+ goto out;
}
hapd->iconf->channel = acs_res->pri_channel;
@@ -588,7 +625,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
hapd->iconf->secondary_channel = 1;
else {
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
- return;
+ err = 1;
+ goto out;
}
if (hapd->iface->conf->ieee80211ac) {
@@ -617,7 +655,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
}
}
- ret = hostapd_acs_completed(hapd->iface, 0);
+out:
+ ret = hostapd_acs_completed(hapd->iface, err);
if (ret) {
wpa_printf(MSG_ERROR,
"ACS: Possibly channel configuration is invalid");
@@ -884,11 +923,24 @@ static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
size_t len, u16 stype, int ok)
{
struct ieee80211_hdr *hdr;
+ struct hostapd_data *orig_hapd = hapd;
hdr = (struct ieee80211_hdr *) buf;
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
- if (hapd == NULL || hapd == HAPD_BROADCAST)
+ if (!hapd)
return;
+ if (hapd == HAPD_BROADCAST) {
+ if (stype != WLAN_FC_STYPE_ACTION || len <= 25 ||
+ buf[24] != WLAN_ACTION_PUBLIC)
+ return;
+ hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2);
+ if (!hapd || hapd == HAPD_BROADCAST)
+ return;
+ /*
+ * Allow processing of TX status for a Public Action frame that
+ * used wildcard BBSID.
+ */
+ }
ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
}
@@ -935,6 +987,8 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
ieee802_1x_receive(hapd, src, data, data_len);
}
+#endif /* HOSTAPD */
+
static struct hostapd_channel_data * hostapd_get_mode_channel(
struct hostapd_iface *iface, unsigned int freq)
@@ -944,8 +998,6 @@ static struct hostapd_channel_data * hostapd_get_mode_channel(
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;
}
@@ -1009,10 +1061,9 @@ static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
}
-static void hostapd_event_get_survey(struct hostapd_data *hapd,
- struct survey_results *survey_results)
+void hostapd_event_get_survey(struct hostapd_iface *iface,
+ struct survey_results *survey_results)
{
- struct hostapd_iface *iface = hapd->iface;
struct freq_survey *survey, *tmp;
struct hostapd_channel_data *chan;
@@ -1044,6 +1095,7 @@ static void hostapd_event_get_survey(struct hostapd_data *hapd,
}
+#ifdef HOSTAPD
#ifdef NEED_AP_MLME
static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
@@ -1251,7 +1303,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->connect_failed_reason.code);
break;
case EVENT_SURVEY:
- hostapd_event_get_survey(hapd, &data->survey_results);
+ hostapd_event_get_survey(hapd->iface, &data->survey_results);
break;
#ifdef NEED_AP_MLME
case EVENT_INTERFACE_UNAVAILABLE:
@@ -1321,4 +1373,31 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
}
+
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+ union wpa_event_data *data)
+{
+ struct hapd_interfaces *interfaces = ctx;
+ struct hostapd_data *hapd;
+
+ if (event != EVENT_INTERFACE_STATUS)
+ return;
+
+ hapd = hostapd_get_iface(interfaces, data->interface_status.ifname);
+ if (hapd && hapd->driver && hapd->driver->get_ifindex &&
+ hapd->drv_priv) {
+ unsigned int ifindex;
+
+ ifindex = hapd->driver->get_ifindex(hapd->drv_priv);
+ if (ifindex != data->interface_status.ifindex) {
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "interface status ifindex %d mismatch (%d)",
+ ifindex, data->interface_status.ifindex);
+ return;
+ }
+ }
+ if (hapd)
+ wpa_supplicant_event(hapd, event, data);
+}
+
#endif /* HOSTAPD */
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 9d19f98d0b7c..6ce178de3b29 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -101,6 +101,7 @@ gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
if (sta->gas_dialog[i].dialog_token != dialog_token ||
!sta->gas_dialog[i].valid)
continue;
+ ap_sta_replenish_timeout(hapd, sta, 5);
return &sta->gas_dialog[i];
}
wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
@@ -167,27 +168,107 @@ static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
#endif /* CONFIG_HS20 */
+static struct anqp_element * get_anqp_elem(struct hostapd_data *hapd,
+ u16 infoid)
+{
+ struct anqp_element *elem;
+
+ dl_list_for_each(elem, &hapd->conf->anqp_elem, struct anqp_element,
+ list) {
+ if (elem->infoid == infoid)
+ return elem;
+ }
+
+ return NULL;
+}
+
+
+static void anqp_add_elem(struct hostapd_data *hapd, struct wpabuf *buf,
+ u16 infoid)
+{
+ struct anqp_element *elem;
+
+ elem = get_anqp_elem(hapd, infoid);
+ if (!elem)
+ return;
+ if (wpabuf_tailroom(buf) < 2 + 2 + wpabuf_len(elem->payload)) {
+ wpa_printf(MSG_DEBUG, "ANQP: No room for InfoID %u payload",
+ infoid);
+ return;
+ }
+
+ wpabuf_put_le16(buf, infoid);
+ wpabuf_put_le16(buf, wpabuf_len(elem->payload));
+ wpabuf_put_buf(buf, elem->payload);
+}
+
+
+static int anqp_add_override(struct hostapd_data *hapd, struct wpabuf *buf,
+ u16 infoid)
+{
+ if (get_anqp_elem(hapd, infoid)) {
+ anqp_add_elem(hapd, buf, infoid);
+ return 1;
+ }
+
+ return 0;
+}
+
+
static void anqp_add_capab_list(struct hostapd_data *hapd,
struct wpabuf *buf)
{
u8 *len;
+ u16 id;
+
+ if (anqp_add_override(hapd, buf, ANQP_CAPABILITY_LIST))
+ return;
len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
- if (hapd->conf->venue_name)
+ if (hapd->conf->venue_name || get_anqp_elem(hapd, ANQP_VENUE_NAME))
wpabuf_put_le16(buf, ANQP_VENUE_NAME);
- if (hapd->conf->network_auth_type)
+ if (get_anqp_elem(hapd, ANQP_EMERGENCY_CALL_NUMBER))
+ wpabuf_put_le16(buf, ANQP_EMERGENCY_CALL_NUMBER);
+ if (hapd->conf->network_auth_type ||
+ get_anqp_elem(hapd, ANQP_NETWORK_AUTH_TYPE))
wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
- if (hapd->conf->roaming_consortium)
+ if (hapd->conf->roaming_consortium ||
+ get_anqp_elem(hapd, ANQP_ROAMING_CONSORTIUM))
wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
- if (hapd->conf->ipaddr_type_configured)
+ if (hapd->conf->ipaddr_type_configured ||
+ get_anqp_elem(hapd, ANQP_IP_ADDR_TYPE_AVAILABILITY))
wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
- if (hapd->conf->nai_realm_data)
+ if (hapd->conf->nai_realm_data ||
+ get_anqp_elem(hapd, ANQP_NAI_REALM))
wpabuf_put_le16(buf, ANQP_NAI_REALM);
- if (hapd->conf->anqp_3gpp_cell_net)
+ if (hapd->conf->anqp_3gpp_cell_net ||
+ get_anqp_elem(hapd, ANQP_3GPP_CELLULAR_NETWORK))
wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
- if (hapd->conf->domain_name)
+ if (get_anqp_elem(hapd, ANQP_AP_GEOSPATIAL_LOCATION))
+ wpabuf_put_le16(buf, ANQP_AP_GEOSPATIAL_LOCATION);
+ if (get_anqp_elem(hapd, ANQP_AP_CIVIC_LOCATION))
+ wpabuf_put_le16(buf, ANQP_AP_CIVIC_LOCATION);
+ if (get_anqp_elem(hapd, ANQP_AP_LOCATION_PUBLIC_URI))
+ wpabuf_put_le16(buf, ANQP_AP_LOCATION_PUBLIC_URI);
+ if (hapd->conf->domain_name || get_anqp_elem(hapd, ANQP_DOMAIN_NAME))
wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
+ if (get_anqp_elem(hapd, ANQP_EMERGENCY_ALERT_URI))
+ wpabuf_put_le16(buf, ANQP_EMERGENCY_ALERT_URI);
+ if (get_anqp_elem(hapd, ANQP_EMERGENCY_NAI))
+ wpabuf_put_le16(buf, ANQP_EMERGENCY_NAI);
+ if (get_anqp_elem(hapd, ANQP_NEIGHBOR_REPORT))
+ wpabuf_put_le16(buf, ANQP_NEIGHBOR_REPORT);
+ for (id = 273; id < 277; id++) {
+ if (get_anqp_elem(hapd, id))
+ wpabuf_put_le16(buf, id);
+ }
+ if (get_anqp_elem(hapd, ANQP_VENUE_URL))
+ wpabuf_put_le16(buf, ANQP_VENUE_URL);
+ if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE))
+ wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE);
+ if (get_anqp_elem(hapd, ANQP_LOCAL_CONTENT))
+ wpabuf_put_le16(buf, ANQP_LOCAL_CONTENT);
#ifdef CONFIG_HS20
anqp_add_hs_capab_list(hapd, buf);
#endif /* CONFIG_HS20 */
@@ -197,6 +278,9 @@ static void anqp_add_capab_list(struct hostapd_data *hapd,
static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
{
+ if (anqp_add_override(hapd, buf, ANQP_VENUE_NAME))
+ return;
+
if (hapd->conf->venue_name) {
u8 *len;
unsigned int i;
@@ -218,6 +302,9 @@ static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
static void anqp_add_network_auth_type(struct hostapd_data *hapd,
struct wpabuf *buf)
{
+ if (anqp_add_override(hapd, buf, ANQP_NETWORK_AUTH_TYPE))
+ return;
+
if (hapd->conf->network_auth_type) {
wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
@@ -233,6 +320,9 @@ static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
unsigned int i;
u8 *len;
+ if (anqp_add_override(hapd, buf, ANQP_ROAMING_CONSORTIUM))
+ return;
+
len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
struct hostapd_roaming_consortium *rc;
@@ -247,6 +337,9 @@ static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
struct wpabuf *buf)
{
+ if (anqp_add_override(hapd, buf, ANQP_IP_ADDR_TYPE_AVAILABILITY))
+ return;
+
if (hapd->conf->ipaddr_type_configured) {
wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
wpabuf_put_le16(buf, 1);
@@ -309,7 +402,7 @@ static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
pos = home_realm;
end = pos + home_realm_len;
- if (pos + 1 > end) {
+ if (end - pos < 1) {
wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
home_realm, home_realm_len);
return -1;
@@ -317,7 +410,7 @@ static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
num_realms = *pos++;
for (i = 0; i < num_realms && num_matching < 10; i++) {
- if (pos + 2 > end) {
+ if (end - pos < 2) {
wpa_hexdump(MSG_DEBUG,
"Truncated NAI Home Realm Query",
home_realm, home_realm_len);
@@ -325,7 +418,7 @@ static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
}
encoding = *pos++;
realm_len = *pos++;
- if (pos + realm_len > end) {
+ if (realm_len > end - pos) {
wpa_hexdump(MSG_DEBUG,
"Truncated NAI Home Realm Query",
home_realm, home_realm_len);
@@ -391,6 +484,10 @@ 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 && !nai_home_realm &&
+ anqp_add_override(hapd, buf, ANQP_NAI_REALM))
+ return;
+
if (nai_realm && hapd->conf->nai_realm_data) {
u8 *len;
unsigned int i, j;
@@ -424,6 +521,9 @@ static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
struct wpabuf *buf)
{
+ if (anqp_add_override(hapd, buf, ANQP_3GPP_CELLULAR_NETWORK))
+ return;
+
if (hapd->conf->anqp_3gpp_cell_net) {
wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
wpabuf_put_le16(buf,
@@ -436,6 +536,9 @@ static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
{
+ if (anqp_add_override(hapd, buf, ANQP_DOMAIN_NAME))
+ return;
+
if (hapd->conf->domain_name) {
wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
wpabuf_put_le16(buf, hapd->conf->domain_name_len);
@@ -683,20 +786,42 @@ static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
#endif /* CONFIG_HS20 */
+static size_t anqp_get_required_len(struct hostapd_data *hapd,
+ const u16 *infoid,
+ unsigned int num_infoid)
+{
+ size_t len = 0;
+ unsigned int i;
+
+ for (i = 0; i < num_infoid; i++) {
+ struct anqp_element *elem = get_anqp_elem(hapd, infoid[i]);
+
+ if (elem)
+ len += 2 + 2 + wpabuf_len(elem->payload);
+ }
+
+ return len;
+}
+
+
static struct wpabuf *
gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
unsigned int request,
const u8 *home_realm, size_t home_realm_len,
- const u8 *icon_name, size_t icon_name_len)
+ const u8 *icon_name, size_t icon_name_len,
+ const u16 *extra_req,
+ unsigned int num_extra_req)
{
struct wpabuf *buf;
size_t len;
+ unsigned int i;
len = 1400;
if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
len += 1000;
if (request & ANQP_REQ_ICON_REQUEST)
len += 65536;
+ len += anqp_get_required_len(hapd, extra_req, num_extra_req);
buf = wpabuf_alloc(len);
if (buf == NULL)
@@ -706,6 +831,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
anqp_add_capab_list(hapd, buf);
if (request & ANQP_REQ_VENUE_NAME)
anqp_add_venue_name(hapd, buf);
+ if (request & ANQP_REQ_EMERGENCY_CALL_NUMBER)
+ anqp_add_elem(hapd, buf, ANQP_EMERGENCY_CALL_NUMBER);
if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
anqp_add_network_auth_type(hapd, buf);
if (request & ANQP_REQ_ROAMING_CONSORTIUM)
@@ -718,8 +845,23 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
request & ANQP_REQ_NAI_HOME_REALM);
if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
anqp_add_3gpp_cellular_network(hapd, buf);
+ if (request & ANQP_REQ_AP_GEOSPATIAL_LOCATION)
+ anqp_add_elem(hapd, buf, ANQP_AP_GEOSPATIAL_LOCATION);
+ if (request & ANQP_REQ_AP_CIVIC_LOCATION)
+ anqp_add_elem(hapd, buf, ANQP_AP_CIVIC_LOCATION);
+ if (request & ANQP_REQ_AP_LOCATION_PUBLIC_URI)
+ anqp_add_elem(hapd, buf, ANQP_AP_LOCATION_PUBLIC_URI);
if (request & ANQP_REQ_DOMAIN_NAME)
anqp_add_domain_name(hapd, buf);
+ if (request & ANQP_REQ_EMERGENCY_ALERT_URI)
+ anqp_add_elem(hapd, buf, ANQP_EMERGENCY_ALERT_URI);
+ if (request & ANQP_REQ_TDLS_CAPABILITY)
+ anqp_add_elem(hapd, buf, ANQP_TDLS_CAPABILITY);
+ if (request & ANQP_REQ_EMERGENCY_NAI)
+ anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
+
+ for (i = 0; i < num_extra_req; i++)
+ anqp_add_elem(hapd, buf, extra_req[i]);
#ifdef CONFIG_HS20
if (request & ANQP_REQ_HS_CAPABILITY_LIST)
@@ -742,6 +884,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
}
+#define ANQP_MAX_EXTRA_REQ 20
+
struct anqp_query_info {
unsigned int request;
const u8 *home_realm_query;
@@ -749,6 +893,8 @@ struct anqp_query_info {
const u8 *icon_name;
size_t icon_name_len;
int p2p_sd;
+ u16 extra_req[ANQP_MAX_EXTRA_REQ];
+ unsigned int num_extra_req;
};
@@ -776,6 +922,11 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
hapd->conf->venue_name != NULL, qi);
break;
+ case ANQP_EMERGENCY_CALL_NUMBER:
+ set_anqp_req(ANQP_REQ_EMERGENCY_CALL_NUMBER,
+ "Emergency Call Number",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
case ANQP_NETWORK_AUTH_TYPE:
set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
hapd->conf->network_auth_type != NULL, qi);
@@ -798,13 +949,55 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
"3GPP Cellular Network",
hapd->conf->anqp_3gpp_cell_net != NULL, qi);
break;
+ case ANQP_AP_GEOSPATIAL_LOCATION:
+ set_anqp_req(ANQP_REQ_AP_GEOSPATIAL_LOCATION,
+ "AP Geospatial Location",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
+ case ANQP_AP_CIVIC_LOCATION:
+ set_anqp_req(ANQP_REQ_AP_CIVIC_LOCATION,
+ "AP Civic Location",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
+ case ANQP_AP_LOCATION_PUBLIC_URI:
+ set_anqp_req(ANQP_REQ_AP_LOCATION_PUBLIC_URI,
+ "AP Location Public URI",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
case ANQP_DOMAIN_NAME:
set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
hapd->conf->domain_name != NULL, qi);
break;
+ case ANQP_EMERGENCY_ALERT_URI:
+ set_anqp_req(ANQP_REQ_EMERGENCY_ALERT_URI,
+ "Emergency Alert URI",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
+ case ANQP_TDLS_CAPABILITY:
+ set_anqp_req(ANQP_REQ_TDLS_CAPABILITY,
+ "TDLS Capability",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
+ case ANQP_EMERGENCY_NAI:
+ set_anqp_req(ANQP_REQ_EMERGENCY_NAI,
+ "Emergency NAI",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
default:
- wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
- info_id);
+ if (!get_anqp_elem(hapd, info_id)) {
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
+ info_id);
+ break;
+ }
+ if (qi->num_extra_req == ANQP_MAX_EXTRA_REQ) {
+ wpa_printf(MSG_DEBUG,
+ "ANQP: No more room for extra requests - ignore Info Id %u",
+ info_id);
+ break;
+ }
+ wpa_printf(MSG_DEBUG, "ANQP: Info Id %u (local)", info_id);
+ qi->extra_req[qi->num_extra_req] = info_id;
+ qi->num_extra_req++;
break;
}
}
@@ -817,7 +1010,7 @@ static void rx_anqp_query_list(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
(unsigned int) (end - pos) / 2);
- while (pos + 2 <= end) {
+ while (end - pos >= 2) {
rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
pos += 2;
}
@@ -906,7 +1099,7 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
u32 oui;
u8 subtype;
- if (pos + 4 > end) {
+ if (end - pos < 4) {
wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
"Query element");
return;
@@ -942,7 +1135,7 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
}
pos++;
- if (pos + 1 >= end)
+ if (end - pos <= 1)
return;
subtype = *pos++;
@@ -973,14 +1166,16 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
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 anqp_query_info *qi, int prot,
+ int std_addr3)
{
struct wpabuf *buf, *tx_buf;
buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
qi->home_realm_query,
qi->home_realm_query_len,
- qi->icon_name, qi->icon_name_len);
+ qi->icon_name, qi->icon_name_len,
+ qi->extra_req, qi->num_extra_req);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
buf);
if (!buf)
@@ -1033,15 +1228,22 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
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));
+ if (std_addr3)
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
+ else
+ hostapd_drv_send_action_addr3_ap(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 *data, size_t len, int prot,
+ int std_addr3)
{
const u8 *pos = data;
const u8 *end = data + len;
@@ -1069,12 +1271,12 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
adv_proto = pos++;
slen = *pos++;
- next = pos + slen;
- if (next > end || slen < 2) {
+ if (slen > end - pos || slen < 2) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"GAS: Invalid IE in GAS Initial Request");
return;
}
+ next = pos + slen;
pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@@ -1093,19 +1295,26 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
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));
+ if (std_addr3)
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(buf),
+ wpabuf_len(buf));
+ else
+ hostapd_drv_send_action_addr3_ap(hapd,
+ hapd->iface->freq, 0,
+ sa, wpabuf_head(buf),
+ wpabuf_len(buf));
wpabuf_free(buf);
return;
}
pos = next;
/* Query Request */
- if (pos + 2 > end)
+ if (end - pos < 2)
return;
slen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + slen > end)
+ if (slen > end - pos)
return;
end = pos + slen;
@@ -1113,7 +1322,7 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
while (pos < end) {
u16 info_id, elen;
- if (pos + 4 > end)
+ if (end - pos < 4)
return;
info_id = WPA_GET_LE16(pos);
@@ -1121,7 +1330,7 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
elen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + elen > end) {
+ if (elen > end - pos) {
wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
return;
}
@@ -1144,13 +1353,15 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
pos += elen;
}
- gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot);
+ gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot,
+ std_addr3);
}
static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
const u8 *sa,
- const u8 *data, size_t len, int prot)
+ const u8 *data, size_t len, int prot,
+ int std_addr3)
{
struct gas_dialog_info *dialog;
struct wpabuf *buf, *tx_buf;
@@ -1226,8 +1437,14 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
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));
+ if (std_addr3)
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
+ else
+ hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
wpabuf_free(tx_buf);
}
@@ -1238,7 +1455,7 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
struct hostapd_data *hapd = ctx;
const struct ieee80211_mgmt *mgmt;
const u8 *sa, *data;
- int prot;
+ int prot, std_addr3;
mgmt = (const struct ieee80211_mgmt *) buf;
if (len < IEEE80211_HDRLEN + 2)
@@ -1253,14 +1470,22 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
*/
prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
sa = mgmt->sa;
+ if (hapd->conf->gas_address3 == 1)
+ std_addr3 = 1;
+ else if (hapd->conf->gas_address3 == 2)
+ std_addr3 = 0;
+ else
+ std_addr3 = is_broadcast_ether_addr(mgmt->bssid);
len -= IEEE80211_HDRLEN + 1;
data = buf + IEEE80211_HDRLEN + 1;
switch (data[0]) {
case WLAN_PA_GAS_INITIAL_REQ:
- gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
+ gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot,
+ std_addr3);
break;
case WLAN_PA_GAS_COMEBACK_REQ:
- gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot);
+ gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot,
+ std_addr3);
break;
}
}
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
index 4ec3201967c0..9051e4f90513 100644
--- a/src/ap/gas_serv.h
+++ b/src/ap/gas_serv.h
@@ -9,10 +9,13 @@
#ifndef GAS_SERV_H
#define GAS_SERV_H
+/* First 16 ANQP InfoIDs can be included in the optimized bitmap */
#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_EMERGENCY_CALL_NUMBER \
+ (1 << (ANQP_EMERGENCY_CALL_NUMBER - ANQP_QUERY_LIST))
#define ANQP_REQ_NETWORK_AUTH_TYPE \
(1 << (ANQP_NETWORK_AUTH_TYPE - ANQP_QUERY_LIST))
#define ANQP_REQ_ROAMING_CONSORTIUM \
@@ -23,8 +26,24 @@
(1 << (ANQP_NAI_REALM - ANQP_QUERY_LIST))
#define ANQP_REQ_3GPP_CELLULAR_NETWORK \
(1 << (ANQP_3GPP_CELLULAR_NETWORK - ANQP_QUERY_LIST))
+#define ANQP_REQ_AP_GEOSPATIAL_LOCATION \
+ (1 << (ANQP_AP_GEOSPATIAL_LOCATION - ANQP_QUERY_LIST))
+#define ANQP_REQ_AP_CIVIC_LOCATION \
+ (1 << (ANQP_AP_CIVIC_LOCATION - ANQP_QUERY_LIST))
+#define ANQP_REQ_AP_LOCATION_PUBLIC_URI \
+ (1 << (ANQP_AP_LOCATION_PUBLIC_URI - ANQP_QUERY_LIST))
#define ANQP_REQ_DOMAIN_NAME \
(1 << (ANQP_DOMAIN_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_EMERGENCY_ALERT_URI \
+ (1 << (ANQP_EMERGENCY_ALERT_URI - ANQP_QUERY_LIST))
+#define ANQP_REQ_TDLS_CAPABILITY \
+ (1 << (ANQP_TDLS_CAPABILITY - ANQP_QUERY_LIST))
+#define ANQP_REQ_EMERGENCY_NAI \
+ (1 << (ANQP_EMERGENCY_NAI - ANQP_QUERY_LIST))
+/*
+ * First 16 Hotspot 2.0 vendor specific ANQP-elements can be included in the
+ * optimized bitmap.
+ */
#define ANQP_REQ_HS_CAPABILITY_LIST \
(0x10000 << HS20_STYPE_CAPABILITY_LIST)
#define ANQP_REQ_OPERATOR_FRIENDLY_NAME \
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index c09c17a44696..9fafc7f457bb 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "common/hw_features_common.h"
#include "radius/radius_client.h"
#include "radius/radius_das.h"
#include "eap_server/tncs.h"
@@ -42,6 +43,8 @@
#include "x_snoop.h"
#include "dhcp_snoop.h"
#include "ndisc_snoop.h"
+#include "neighbor_db.h"
+#include "rrm.h"
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -203,10 +206,12 @@ int hostapd_reload_config(struct hostapd_iface *iface)
static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
- char *ifname)
+ const char *ifname)
{
int i;
+ if (!ifname)
+ return;
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)) {
@@ -334,6 +339,8 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
wpabuf_free(hapd->mesh_pending_auth);
hapd->mesh_pending_auth = NULL;
#endif /* CONFIG_MESH */
+
+ hostapd_clean_rrm(hapd);
}
@@ -367,7 +374,7 @@ static void sta_track_deinit(struct hostapd_iface *iface)
list))) {
dl_list_del(&info->list);
iface->num_sta_seen--;
- os_free(info);
+ sta_track_del(info);
}
}
@@ -511,6 +518,9 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
if (hostapd_drv_none(hapd))
return 0;
+ if (iface->conf->use_driver_iface_addr)
+ return 0;
+
/* Generate BSSID mask that is large enough to cover the BSSIDs. */
/* Determine the bits necessary to cover the number of BSSIDs. */
@@ -520,7 +530,7 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
/* 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 (is_zero_ether_addr(iface->conf->bss[j]->bssid)) {
if (j)
auto_addr++;
continue;
@@ -672,7 +682,7 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
if (attr->acct_session_id) {
num_attr++;
- if (attr->acct_session_id_len != 17) {
+ if (attr->acct_session_id_len != 16) {
wpa_printf(MSG_DEBUG,
"RADIUS DAS: Acct-Session-Id cannot match");
return NULL;
@@ -682,10 +692,9 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (!sta->radius_das_match)
continue;
- 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)
+ os_snprintf(buf, sizeof(buf), "%016llX",
+ (unsigned long long) sta->acct_session_id);
+ if (os_memcmp(attr->acct_session_id, buf, 16) != 0)
sta->radius_das_match = 0;
else
count++;
@@ -701,7 +710,7 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
if (attr->acct_multi_session_id) {
num_attr++;
- if (attr->acct_multi_session_id_len != 17) {
+ if (attr->acct_multi_session_id_len != 16) {
wpa_printf(MSG_DEBUG,
"RADIUS DAS: Acct-Multi-Session-Id cannot match");
return NULL;
@@ -712,14 +721,14 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
if (!sta->radius_das_match)
continue;
if (!sta->eapol_sm ||
- !sta->eapol_sm->acct_multi_session_id_hi) {
+ !sta->eapol_sm->acct_multi_session_id) {
sta->radius_das_match = 0;
continue;
}
- os_snprintf(buf, sizeof(buf), "%08X+%08X",
- sta->eapol_sm->acct_multi_session_id_hi,
- sta->eapol_sm->acct_multi_session_id_lo);
- if (os_memcmp(attr->acct_multi_session_id, buf, 17) !=
+ os_snprintf(buf, sizeof(buf), "%016llX",
+ (unsigned long long)
+ sta->eapol_sm->acct_multi_session_id);
+ if (os_memcmp(attr->acct_multi_session_id, buf, 16) !=
0)
sta->radius_das_match = 0;
else
@@ -905,12 +914,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
hapd->started = 1;
if (!first || first == -1) {
- if (hostapd_mac_comp_empty(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 {
+ u8 *addr = hapd->own_addr;
+
+ if (!is_zero_ether_addr(conf->bssid)) {
/* Allocate the configured BSSID. */
os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN);
@@ -922,11 +928,18 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
"the radio", conf->iface);
return -1;
}
+ } else if (hapd->iconf->use_driver_iface_addr) {
+ addr = NULL;
+ } else {
+ /* Allocate the next available BSSID. */
+ do {
+ inc_byte_array(hapd->own_addr, ETH_ALEN);
+ } while (mac_in_conf(hapd->iconf, hapd->own_addr));
}
hapd->interface_added = 1;
if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
- conf->iface, hapd->own_addr, hapd,
+ conf->iface, addr, hapd,
&hapd->drv_priv, force_ifname, if_addr,
conf->bridge[0] ? conf->bridge : NULL,
first == -1)) {
@@ -935,11 +948,19 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
hapd->interface_added = 0;
return -1;
}
+
+ if (!addr)
+ os_memcpy(hapd->own_addr, if_addr, ETH_ALEN);
}
if (conf->wmm_enabled < 0)
conf->wmm_enabled = hapd->iconf->ieee80211n;
+#ifdef CONFIG_IEEE80211R
+ if (is_zero_ether_addr(conf->r1_key_holder))
+ os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN);
+#endif /* CONFIG_IEEE80211R */
+
#ifdef CONFIG_MESH
if (hapd->iface->mconf == NULL)
flush_old_stations = 0;
@@ -1022,6 +1043,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
das_conf.time_window = conf->radius_das_time_window;
das_conf.require_event_timestamp =
conf->radius_das_require_event_timestamp;
+ das_conf.require_message_authenticator =
+ conf->radius_das_require_message_authenticator;
das_conf.ctx = hapd;
das_conf.disconnect = hostapd_das_disconnect;
hapd->radius_das = radius_das_init(&das_conf);
@@ -1509,15 +1532,128 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
-/**
- * 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)
+#ifdef NEED_AP_MLME
+static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
+ int ht, int vht)
+{
+ if (!ht && !vht)
+ return NR_CHAN_WIDTH_20;
+ if (!hapd->iconf->secondary_channel)
+ return NR_CHAN_WIDTH_20;
+ if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
+ return NR_CHAN_WIDTH_40;
+ if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
+ return NR_CHAN_WIDTH_80;
+ if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
+ return NR_CHAN_WIDTH_160;
+ if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
+ return NR_CHAN_WIDTH_80P80;
+ return NR_CHAN_WIDTH_20;
+}
+#endif /* NEED_AP_MLME */
+
+
+static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd)
+{
+#ifdef NEED_AP_MLME
+ u16 capab = hostapd_own_capab_info(hapd);
+ int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
+ int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
+ struct wpa_ssid_value ssid;
+ u8 channel, op_class;
+ int center_freq1 = 0, center_freq2 = 0;
+ enum nr_chan_width width;
+ u32 bssid_info;
+ struct wpabuf *nr;
+
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT))
+ return;
+
+ bssid_info = 3; /* AP is reachable */
+ bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */
+ bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */
+
+ if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT)
+ bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
+
+ bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */
+
+ if (hapd->conf->wmm_enabled) {
+ bssid_info |= NEI_REP_BSSID_INFO_QOS;
+
+ if (hapd->conf->wmm_uapsd &&
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
+ bssid_info |= NEI_REP_BSSID_INFO_APSD;
+ }
+
+ if (ht) {
+ bssid_info |= NEI_REP_BSSID_INFO_HT |
+ NEI_REP_BSSID_INFO_DELAYED_BA;
+
+ /* VHT bit added in IEEE P802.11-REVmc/D4.3 */
+ if (vht)
+ bssid_info |= NEI_REP_BSSID_INFO_VHT;
+ }
+
+ /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
+
+ ieee80211_freq_to_channel_ext(hapd->iface->freq,
+ hapd->iconf->secondary_channel,
+ hapd->iconf->vht_oper_chwidth,
+ &op_class, &channel);
+ width = hostapd_get_nr_chan_width(hapd, ht, vht);
+ if (vht) {
+ center_freq1 = ieee80211_chan_to_freq(
+ NULL, op_class,
+ hapd->iconf->vht_oper_centr_freq_seg0_idx);
+ if (width == NR_CHAN_WIDTH_80P80)
+ center_freq2 = ieee80211_chan_to_freq(
+ NULL, op_class,
+ hapd->iconf->vht_oper_centr_freq_seg1_idx);
+ } else if (ht) {
+ center_freq1 = hapd->iface->freq +
+ 10 * hapd->iconf->secondary_channel;
+ }
+
+ ssid.ssid_len = hapd->conf->ssid.ssid_len;
+ os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
+
+ /*
+ * Neighbor Report element size = BSSID + BSSID info + op_class + chan +
+ * phy type + wide bandwidth channel subelement.
+ */
+ nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5);
+ if (!nr)
+ return;
+
+ wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN);
+ wpabuf_put_le32(nr, bssid_info);
+ wpabuf_put_u8(nr, op_class);
+ wpabuf_put_u8(nr, channel);
+ wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht));
+
+ /*
+ * Wide Bandwidth Channel subelement may be needed to allow the
+ * receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0
+ * Figure 9-301.
+ */
+ wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN);
+ wpabuf_put_u8(nr, 3);
+ wpabuf_put_u8(nr, width);
+ wpabuf_put_u8(nr, center_freq1);
+ wpabuf_put_u8(nr, center_freq2);
+
+ hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
+ hapd->iconf->civic);
+
+ wpabuf_free(nr);
+#endif /* NEED_AP_MLME */
+}
+
+
+static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
+ int err)
{
struct hostapd_data *hapd = iface->bss[0];
size_t j;
@@ -1633,7 +1769,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
} while (j-- > 0);
goto fail;
}
- if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
+ if (is_zero_ether_addr(hapd->conf->bssid))
prev_addr = hapd->own_addr;
}
hapd = iface->bss[0];
@@ -1641,7 +1777,6 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
hostapd_tx_queue_params(iface);
ap_list_init(iface);
- dl_list_init(&iface->sta_seen);
hostapd_set_acl(hapd);
@@ -1701,6 +1836,9 @@ dfs_offload:
if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
iface->interfaces->terminate_on_error--;
+ for (j = 0; j < iface->num_bss; j++)
+ hostapd_set_own_neighbor_report(iface->bss[j]);
+
return 0;
fail:
@@ -1720,6 +1858,89 @@ fail:
/**
+ * 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 hapd_interfaces *interfaces = iface->interfaces;
+ struct hostapd_data *hapd = iface->bss[0];
+ unsigned int i;
+ int not_ready_in_sync_ifaces = 0;
+
+ if (!iface->need_to_start_in_sync)
+ return hostapd_setup_interface_complete_sync(iface, err);
+
+ if (err) {
+ wpa_printf(MSG_ERROR, "Interface initialization failed");
+ hostapd_set_state(iface, HAPD_IFACE_DISABLED);
+ iface->need_to_start_in_sync = 0;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
+ if (interfaces && interfaces->terminate_on_error)
+ eloop_terminate();
+ return -1;
+ }
+
+ if (iface->ready_to_start_in_sync) {
+ /* Already in ready and waiting. should never happpen */
+ return 0;
+ }
+
+ for (i = 0; i < interfaces->count; i++) {
+ if (interfaces->iface[i]->need_to_start_in_sync &&
+ !interfaces->iface[i]->ready_to_start_in_sync)
+ not_ready_in_sync_ifaces++;
+ }
+
+ /*
+ * Check if this is the last interface, if yes then start all the other
+ * waiting interfaces. If not, add this interface to the waiting list.
+ */
+ if (not_ready_in_sync_ifaces > 1 && iface->state == HAPD_IFACE_DFS) {
+ /*
+ * If this interface went through CAC, do not synchronize, just
+ * start immediately.
+ */
+ iface->need_to_start_in_sync = 0;
+ wpa_printf(MSG_INFO,
+ "%s: Finished CAC - bypass sync and start interface",
+ iface->bss[0]->conf->iface);
+ return hostapd_setup_interface_complete_sync(iface, err);
+ }
+
+ if (not_ready_in_sync_ifaces > 1) {
+ /* need to wait as there are other interfaces still coming up */
+ iface->ready_to_start_in_sync = 1;
+ wpa_printf(MSG_INFO,
+ "%s: Interface waiting to sync with other interfaces",
+ iface->bss[0]->conf->iface);
+ return 0;
+ }
+
+ wpa_printf(MSG_INFO,
+ "%s: Last interface to sync - starting all interfaces",
+ iface->bss[0]->conf->iface);
+ iface->need_to_start_in_sync = 0;
+ hostapd_setup_interface_complete_sync(iface, err);
+ for (i = 0; i < interfaces->count; i++) {
+ if (interfaces->iface[i]->need_to_start_in_sync &&
+ interfaces->iface[i]->ready_to_start_in_sync) {
+ hostapd_setup_interface_complete_sync(
+ interfaces->iface[i], 0);
+ /* Only once the interfaces are sync started */
+ interfaces->iface[i]->need_to_start_in_sync = 0;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
* hostapd_setup_interface - Setup of an interface
* @iface: Pointer to interface data.
* Returns: 0 on success, -1 on failure
@@ -1778,6 +1999,8 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
hapd->iface = hapd_iface;
hapd->driver = hapd->iconf->driver;
hapd->ctrl_sock = -1;
+ dl_list_init(&hapd->ctrl_dst);
+ dl_list_init(&hapd->nr_db);
return hapd;
}
@@ -1785,6 +2008,8 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
static void hostapd_bss_deinit(struct hostapd_data *hapd)
{
+ if (!hapd)
+ return;
wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
hapd->conf->iface);
hostapd_bss_deinit_no_free(hapd);
@@ -1819,8 +2044,11 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
}
#endif /* CONFIG_FST */
- for (j = iface->num_bss - 1; j >= 0; j--)
+ for (j = iface->num_bss - 1; j >= 0; j--) {
+ if (!iface->bss)
+ break;
hostapd_bss_deinit(iface->bss[j]);
+ }
}
@@ -1829,6 +2057,8 @@ 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++) {
+ if (!iface->bss)
+ break;
wpa_printf(MSG_DEBUG, "%s: free hapd %p",
__func__, iface->bss[j]);
os_free(iface->bss[j]);
@@ -1837,6 +2067,20 @@ void hostapd_interface_free(struct hostapd_iface *iface)
}
+struct hostapd_iface * hostapd_alloc_iface(void)
+{
+ struct hostapd_iface *hapd_iface;
+
+ hapd_iface = os_zalloc(sizeof(*hapd_iface));
+ if (!hapd_iface)
+ return NULL;
+
+ dl_list_init(&hapd_iface->sta_seen);
+
+ return hapd_iface;
+}
+
+
/**
* hostapd_init - Allocate and initialize per-interface data
* @config_file: Path to the configuration file
@@ -1854,7 +2098,7 @@ struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
struct hostapd_data *hapd;
size_t i;
- hapd_iface = os_zalloc(sizeof(*hapd_iface));
+ hapd_iface = hostapd_alloc_iface();
if (hapd_iface == NULL)
goto fail;
@@ -2190,7 +2434,7 @@ hostapd_iface_alloc(struct hapd_interfaces *interfaces)
return NULL;
interfaces->iface = iface;
hapd_iface = interfaces->iface[interfaces->count] =
- os_zalloc(sizeof(*hapd_iface));
+ hostapd_alloc_iface();
if (hapd_iface == NULL) {
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
"the interface", __func__);
@@ -2557,6 +2801,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
}
hostapd_prune_associations(hapd, sta->addr);
+ ap_sta_clear_disconnect_timeouts(hapd, sta);
/* IEEE 802.11F (IAPP) */
if (hapd->conf->ieee802_11f)
@@ -2590,9 +2835,10 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
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),
+ wpa_printf(MSG_DEBUG,
+ "%s: %s: reschedule ap_handle_timer timeout for "
+ MACSTR " (%d seconds - ap_max_inactivity)",
+ hapd->conf->iface, __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,
@@ -2627,12 +2873,23 @@ const char * hostapd_state_text(enum hostapd_iface_state s)
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->conf ? iface->conf->bss[0]->iface : "N/A",
+ hostapd_state_text(iface->state), hostapd_state_text(s));
iface->state = s;
}
+int hostapd_csa_in_progress(struct hostapd_iface *iface)
+{
+ unsigned int i;
+
+ for (i = 0; i < iface->num_bss; i++)
+ if (iface->bss[i]->csa_in_progress)
+ return 1;
+ return 0;
+}
+
+
#ifdef NEED_AP_MLME
static void free_beacon_data(struct beacon_data *beacon)
@@ -2744,9 +3001,9 @@ free_ap_params:
/*
- * 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.
+ * TODO: This flow currently supports only changing channel and width within
+ * the same hw_mode. Any other changes to MAC parameters or provided settings
+ * are not supported.
*/
static int hostapd_change_config_freq(struct hostapd_data *hapd,
struct hostapd_config *conf,
@@ -2765,15 +3022,44 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
return -1;
/* 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;
+ if (old_params &&
+ hostapd_set_freq_params(old_params, conf->hw_mode,
+ hostapd_hw_get_freq(hapd, conf->channel),
+ conf->channel, conf->ieee80211n,
+ conf->ieee80211ac,
+ conf->secondary_channel,
+ conf->vht_oper_chwidth,
+ conf->vht_oper_centr_freq_seg0_idx,
+ conf->vht_oper_centr_freq_seg1_idx,
+ conf->vht_capab))
+ return -1;
+
+ switch (params->bandwidth) {
+ case 0:
+ case 20:
+ case 40:
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ break;
+ case 80:
+ if (params->center_freq2)
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
+ else
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ break;
+ case 160:
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
+ break;
+ default:
+ return -1;
}
conf->channel = channel;
conf->ieee80211n = params->ht_enabled;
conf->secondary_channel = params->sec_channel_offset;
+ ieee80211_freq_to_chan(params->center_freq1,
+ &conf->vht_oper_centr_freq_seg0_idx);
+ ieee80211_freq_to_chan(params->center_freq2,
+ &conf->vht_oper_centr_freq_seg1_idx);
/* TODO: maybe call here hostapd_config_check here? */
@@ -2787,11 +3073,43 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
struct hostapd_iface *iface = hapd->iface;
struct hostapd_freq_params old_freq;
int ret;
+ u8 chan, vht_bandwidth;
os_memset(&old_freq, 0, sizeof(old_freq));
if (!iface || !iface->freq || hapd->csa_in_progress)
return -1;
+ switch (settings->freq_params.bandwidth) {
+ case 80:
+ if (settings->freq_params.center_freq2)
+ vht_bandwidth = VHT_CHANWIDTH_80P80MHZ;
+ else
+ vht_bandwidth = VHT_CHANWIDTH_80MHZ;
+ break;
+ case 160:
+ vht_bandwidth = VHT_CHANWIDTH_160MHZ;
+ break;
+ default:
+ vht_bandwidth = VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+
+ if (ieee80211_freq_to_channel_ext(
+ settings->freq_params.freq,
+ settings->freq_params.sec_channel_offset,
+ vht_bandwidth,
+ &hapd->iface->cs_oper_class,
+ &chan) == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_DEBUG,
+ "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d)",
+ settings->freq_params.freq,
+ settings->freq_params.sec_channel_offset,
+ settings->freq_params.vht_enabled);
+ return -1;
+ }
+
+ settings->freq_params.channel = chan;
+
ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
&settings->freq_params,
&old_freq);
@@ -2818,8 +3136,10 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
return ret;
}
- settings->counter_offset_beacon = hapd->cs_c_off_beacon;
- settings->counter_offset_presp = hapd->cs_c_off_proberesp;
+ settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon;
+ settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp;
+ settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon;
+ settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp;
return 0;
}
@@ -2833,6 +3153,8 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
hapd->cs_c_off_beacon = 0;
hapd->cs_c_off_proberesp = 0;
hapd->csa_in_progress = 0;
+ hapd->cs_c_off_ecsa_beacon = 0;
+ hapd->cs_c_off_ecsa_proberesp = 0;
}
@@ -2920,6 +3242,8 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
hostapd_enable_iface(iface);
}
+#endif /* NEED_AP_MLME */
+
struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
const char *ifname)
@@ -2940,8 +3264,6 @@ struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
return NULL;
}
-#endif /* NEED_AP_MLME */
-
void hostapd_periodic_iface(struct hostapd_iface *iface)
{
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index dcf51f00f78d..dec46f692206 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -41,7 +41,7 @@ struct hapd_interfaces {
size_t count;
int global_ctrl_sock;
- struct wpa_ctrl_dst *global_ctrl_dst;
+ struct dl_list global_ctrl_dst;
char *global_iface_path;
char *global_iface_name;
#ifndef CONFIG_NATIVE_WINDOWS
@@ -53,6 +53,7 @@ struct hapd_interfaces {
#ifndef CONFIG_NO_VLAN
struct dynamic_iface *vlan_priv;
#endif /* CONFIG_NO_VLAN */
+ int eloop_initialized;
};
enum hostapd_chan_status {
@@ -99,6 +100,16 @@ struct wps_stat {
u8 peer_addr[ETH_ALEN];
};
+struct hostapd_neighbor_entry {
+ struct dl_list list;
+ u8 bssid[ETH_ALEN];
+ struct wpa_ssid_value ssid;
+ struct wpabuf *nr;
+ struct wpabuf *lci;
+ struct wpabuf *civic;
+ /* LCI update time */
+ struct os_time lci_date;
+};
/**
* struct hostapd_data - hostapd per-BSS data structure
@@ -138,7 +149,7 @@ struct hostapd_data {
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;
+ u64 acct_session_id;
struct radius_das_data *radius_das;
struct iapp_data *iapp;
@@ -155,7 +166,7 @@ struct hostapd_data {
int tkip_countermeasures;
int ctrl_sock;
- struct wpa_ctrl_dst *ctrl_dst;
+ struct dl_list ctrl_dst;
void *ssl_ctx;
void *eap_sim_db_priv;
@@ -228,6 +239,8 @@ struct hostapd_data {
unsigned int cs_c_off_beacon;
unsigned int cs_c_off_proberesp;
int csa_in_progress;
+ unsigned int cs_c_off_ecsa_beacon;
+ unsigned int cs_c_off_ecsa_proberesp;
/* BSS Load */
unsigned int bss_load_update_timeout;
@@ -256,9 +269,11 @@ struct hostapd_data {
#ifdef CONFIG_MESH
int num_plinks;
int max_plinks;
- void (*mesh_sta_free_cb)(struct sta_info *sta);
+ void (*mesh_sta_free_cb)(struct hostapd_data *hapd,
+ struct sta_info *sta);
struct wpabuf *mesh_pending_auth;
struct os_reltime mesh_pending_auth_time;
+ u8 mesh_required_peer[ETH_ALEN];
#endif /* CONFIG_MESH */
#ifdef CONFIG_SQLITE
@@ -278,6 +293,17 @@ struct hostapd_data {
struct l2_packet_data *l2_test;
#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_MBO
+ unsigned int mbo_assoc_disallow;
+#endif /* CONFIG_MBO */
+
+ struct dl_list nr_db;
+
+ u8 lci_req_token;
+ u8 range_req_token;
+ unsigned int lci_req_active:1;
+ unsigned int range_req_active:1;
};
@@ -285,6 +311,9 @@ struct hostapd_sta_info {
struct dl_list list;
u8 addr[ETH_ALEN];
struct os_reltime last_seen;
+#ifdef CONFIG_TAXONOMY
+ struct wpabuf *probe_ie_taxonomy;
+#endif /* CONFIG_TAXONOMY */
};
/**
@@ -327,6 +356,15 @@ struct hostapd_iface {
*/
unsigned int driver_ap_teardown:1;
+ /*
+ * When set, indicates that this interface is part of list of
+ * interfaces that need to be started together (synchronously).
+ */
+ unsigned int need_to_start_in_sync:1;
+
+ /* Ready to start but waiting for other interfaces to become ready. */
+ unsigned int ready_to_start_in_sync: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];
@@ -402,6 +440,9 @@ struct hostapd_iface {
u64 last_channel_time_busy;
u8 channel_utilization;
+ /* eCSA IE will be added only if operating class is specified */
+ u8 cs_oper_class;
+
unsigned int dfs_cac_ms;
struct os_reltime dfs_cac_start;
@@ -433,6 +474,7 @@ 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_alloc_iface(void);
struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
const char *config_file);
struct hostapd_iface *
@@ -449,6 +491,7 @@ 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_csa_in_progress(struct hostapd_iface *iface);
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings);
void
@@ -478,6 +521,11 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2);
+struct survey_results;
+void hostapd_event_get_survey(struct hostapd_iface *iface,
+ struct survey_results *survey_results);
+void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+ struct acs_selected_channels *acs_res);
const struct hostapd_eap_user *
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index fc8786dc311c..16887acdfef4 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -329,6 +329,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
res = ieee80211n_allowed_ht40_channel_pair(iface);
if (!res) {
iface->conf->secondary_channel = 0;
+ res = 1;
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
}
@@ -472,8 +473,9 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
struct wpa_driver_scan_params params;
int ret;
- if (!iface->conf->secondary_channel)
- return 0; /* HT40 not used */
+ /* Check that HT40 is used and PRI / SEC switch is allowed */
+ if (!iface->conf->secondary_channel || iface->conf->no_pri_sec_switch)
+ return 0;
hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
index 99aa04dc3dd9..2556da30c82f 100644
--- a/src/ap/iapp.c
+++ b/src/ap/iapp.c
@@ -34,11 +34,7 @@
#include "utils/includes.h"
#include <net/if.h>
#include <sys/ioctl.h>
-#ifdef USE_KERNEL_HEADERS
-#include <linux/if_packet.h>
-#else /* USE_KERNEL_HEADERS */
#include <netpacket/packet.h>
-#endif /* USE_KERNEL_HEADERS */
#include "utils/common.h"
#include "utils/eloop.h"
@@ -385,6 +381,7 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
struct sockaddr_in *paddr, uaddr;
struct iapp_data *iapp;
struct ip_mreqn mreq;
+ int reuseaddr = 1;
iapp = os_zalloc(sizeof(*iapp));
if (iapp == NULL)
@@ -447,6 +444,18 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
os_memset(&uaddr, 0, sizeof(uaddr));
uaddr.sin_family = AF_INET;
uaddr.sin_port = htons(IAPP_UDP_PORT);
+
+ if (setsockopt(iapp->udp_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
+ sizeof(reuseaddr)) < 0) {
+ wpa_printf(MSG_INFO,
+ "iapp_init - setsockopt[UDP,SO_REUSEADDR]: %s",
+ strerror(errno));
+ /*
+ * Ignore this and try to continue. This is fine for single
+ * BSS cases, but may fail if multiple BSSes enable IAPP.
+ */
+ }
+
if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
sizeof(uaddr)) < 0) {
wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 7bb18c01d1a1..4e04169c73e6 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -42,6 +42,9 @@
#include "hw_features.h"
#include "ieee802_11.h"
#include "dfs.h"
+#include "mbo_ap.h"
+#include "rrm.h"
+#include "taxonomy.h"
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
@@ -139,6 +142,7 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
int capab = WLAN_CAPABILITY_ESS;
int privacy;
int dfs;
+ int i;
/* Check if any of configured channels require DFS */
dfs = hostapd_is_dfs_required(hapd->iface);
@@ -186,8 +190,12 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
(hapd->iconf->spectrum_mgmt_required || dfs))
capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
- if (hapd->conf->radio_measurements)
- capab |= IEEE80211_CAP_RRM;
+ for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
+ if (hapd->conf->radio_measurements[i]) {
+ capab |= IEEE80211_CAP_RRM;
+ break;
+ }
+ }
return capab;
}
@@ -207,16 +215,17 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
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);
+ if (os_get_random(key, sizeof(key)) < 0) {
+ os_free(sta->challenge);
+ sta->challenge = NULL;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
rc4_skip(key, sizeof(key), 0,
sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
}
@@ -250,19 +259,20 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_NO_RC4 */
-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)
+static int 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;
+ int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
buf = os_zalloc(rlen);
if (buf == NULL)
- return;
+ return -1;
reply = (struct ieee80211_mgmt *) buf;
reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -283,9 +293,13 @@ static void send_auth_reply(struct hostapd_data *hapd,
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");
+ wpa_printf(MSG_INFO, "send_auth_reply: send failed");
+ else
+ reply_res = WLAN_STATUS_SUCCESS;
os_free(buf);
+
+ return reply_res;
}
@@ -296,17 +310,25 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ int reply_res;
- send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, auth_transaction,
- status, ies, ies_len);
-
- if (status != WLAN_STATUS_SUCCESS)
- return;
+ reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
+ auth_transaction, status, ies, ies_len);
sta = ap_get_sta(hapd, dst);
if (sta == NULL)
return;
+ if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS ||
+ status != WLAN_STATUS_SUCCESS)) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ return;
+ }
+
+ if (status != WLAN_STATUS_SUCCESS)
+ return;
+
hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
sta->flags |= WLAN_STA_AUTH;
@@ -369,18 +391,19 @@ static int auth_sae_send_commit(struct hostapd_data *hapd,
const u8 *bssid, int update)
{
struct wpabuf *data;
+ int reply_res;
data = auth_build_sae_commit(hapd, sta, update);
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- send_auth_reply(hapd, sta->addr, bssid,
- WLAN_AUTH_SAE, 1, WLAN_STATUS_SUCCESS,
- wpabuf_head(data), wpabuf_len(data));
+ reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
+ WLAN_STATUS_SUCCESS, wpabuf_head(data),
+ wpabuf_len(data));
wpabuf_free(data);
- return WLAN_STATUS_SUCCESS;
+ return reply_res;
}
@@ -389,18 +412,19 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd,
const u8 *bssid)
{
struct wpabuf *data;
+ int reply_res;
data = auth_build_sae_confirm(hapd, sta);
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- send_auth_reply(hapd, sta->addr, bssid,
- WLAN_AUTH_SAE, 2, WLAN_STATUS_SUCCESS,
- wpabuf_head(data), wpabuf_len(data));
+ reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
+ WLAN_STATUS_SUCCESS, wpabuf_head(data),
+ wpabuf_len(data));
wpabuf_free(data);
- return WLAN_STATUS_SUCCESS;
+ return reply_res;
}
@@ -495,6 +519,9 @@ static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
if (sae_check_big_sync(sta))
return;
sta->sae->sync++;
+ wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
+ " (sync=%d state=%d)",
+ MAC2STR(sta->addr), sta->sae->sync, sta->sae->state);
switch (sta->sae->state) {
case SAE_COMMITTED:
@@ -537,6 +564,18 @@ static void sae_set_retransmit_timer(struct hostapd_data *hapd,
}
+void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ sta->flags |= WLAN_STA_AUTH;
+ sta->auth_alg = WLAN_AUTH_SAE;
+ mlme_authenticate_indication(hapd, sta);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ sta->sae->state = SAE_ACCEPTED;
+ wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+ sta->sae->pmk, sta->sae->pmkid);
+}
+
+
static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *bssid, u8 auth_transaction)
{
@@ -580,7 +619,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
* message now to get alternating sequence of
* Authentication frames between the AP and STA.
* Confirm will be sent in
- * Commited -> Confirmed/Accepted transition
+ * Committed -> Confirmed/Accepted transition
* when receiving Confirm from STA.
*/
}
@@ -659,13 +698,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
sae_set_retransmit_timer(hapd, sta);
} else {
- sta->flags |= WLAN_STA_AUTH;
- sta->auth_alg = WLAN_AUTH_SAE;
- mlme_authenticate_indication(hapd, sta);
- wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
- sta->sae->state = SAE_ACCEPTED;
- wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
- sta->sae->pmk);
+ sae_accept_sta(hapd, sta);
}
break;
case SAE_ACCEPTED:
@@ -674,6 +707,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
") doing reauthentication",
MAC2STR(sta->addr));
ap_free_sta(hapd, sta);
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
} else {
if (sae_check_big_sync(sta))
return WLAN_STATUS_SUCCESS;
@@ -694,23 +728,73 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
}
+static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ struct sae_data *sae = sta->sae;
+ int i, *groups = hapd->conf->sae_groups;
+
+ if (sae->state != SAE_COMMITTED)
+ return;
+
+ wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
+
+ for (i = 0; groups && groups[i] > 0; i++) {
+ if (sae->group == groups[i])
+ break;
+ }
+
+ if (!groups || groups[i] <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Previously selected group not found from the current configuration");
+ return;
+ }
+
+ for (;;) {
+ i++;
+ if (groups[i] <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: No alternative group enabled");
+ return;
+ }
+
+ if (sae_set_group(sae, groups[i]) < 0)
+ continue;
+
+ break;
+ }
+ wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
+}
+
+
static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
const struct ieee80211_mgmt *mgmt, size_t len,
u16 auth_transaction, u16 status_code)
{
- u16 resp = WLAN_STATUS_SUCCESS;
+ int resp = WLAN_STATUS_SUCCESS;
struct wpabuf *data = NULL;
if (!sta->sae) {
- if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
- return;
+ if (auth_transaction != 1 ||
+ status_code != WLAN_STATUS_SUCCESS) {
+ resp = -1;
+ goto remove_sta;
+ }
sta->sae = os_zalloc(sizeof(*sta->sae));
- if (sta->sae == NULL)
- return;
+ if (!sta->sae) {
+ resp = -1;
+ goto remove_sta;
+ }
sta->sae->state = SAE_NOTHING;
sta->sae->sync = 0;
}
+ if (sta->mesh_sae_pmksa_caching) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+ sta->mesh_sae_pmksa_caching = 0;
+ }
+
if (auth_transaction == 1) {
const u8 *token = NULL, *pos, *end;
size_t token_len = 0;
@@ -746,7 +830,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
if (sta->sae->tmp->anti_clogging_token == NULL) {
wpa_printf(MSG_ERROR,
"SAE: Failed to alloc for anti-clogging token");
- return;
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto remove_sta;
}
/*
@@ -756,10 +841,11 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
* Authentication frame, and the commit-scalar and
* COMMIT-ELEMENT previously sent.
*/
- if (auth_sae_send_commit(hapd, sta, mgmt->bssid, 0)) {
+ resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0);
+ if (resp != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_ERROR,
"SAE: Failed to send commit message");
- return;
+ goto remove_sta;
}
sta->sae->state = SAE_COMMITTED;
sta->sae->sync = 0;
@@ -767,8 +853,18 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
return;
}
+ if ((hapd->conf->mesh & MESH_ENABLED) &&
+ status_code ==
+ WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+ sta->sae->tmp) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Peer did not accept our SAE group");
+ sae_pick_next_group(hapd, sta);
+ goto remove_sta;
+ }
+
if (status_code != WLAN_STATUS_SUCCESS)
- return;
+ goto remove_sta;
resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
((const u8 *) mgmt) + len -
@@ -778,14 +874,15 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
MAC2STR(sta->addr));
- return;
+ goto remove_sta;
}
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;
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto remove_sta;
}
if (resp != WLAN_STATUS_SUCCESS)
@@ -810,7 +907,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
"SAE authentication (RX confirm, status=%u)",
status_code);
if (status_code != WLAN_STATUS_SUCCESS)
- return;
+ goto remove_sta;
if (sta->sae->state >= SAE_CONFIRMED ||
!(hapd->conf->mesh & MESH_ENABLED)) {
if (sae_check_confirm(sta->sae, mgmt->u.auth.variable,
@@ -827,7 +924,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
"unexpected SAE authentication transaction %u (status=%u)",
auth_transaction, status_code);
if (status_code != WLAN_STATUS_SUCCESS)
- return;
+ goto remove_sta;
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
}
@@ -838,6 +935,13 @@ reply:
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0);
}
+
+remove_sta:
+ if (sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
+ status_code != WLAN_STATUS_SUCCESS)) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
wpabuf_free(data);
}
@@ -882,11 +986,11 @@ static void handle_auth(struct hostapd_data *hapd,
u16 auth_alg, auth_transaction, status_code;
u16 resp = WLAN_STATUS_SUCCESS;
struct sta_info *sta = NULL;
- int res;
+ int res, reply_res;
u16 fc;
const u8 *challenge = NULL;
u32 session_timeout, acct_interim_interval;
- int vlan_id = 0;
+ struct vlan_description vlan_id;
struct hostapd_sta_wpa_psk_short *psk = NULL;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
@@ -894,6 +998,8 @@ static void handle_auth(struct hostapd_data *hapd,
char *radius_cui = NULL;
u16 seq_ctrl;
+ os_memset(&vlan_id, 0, sizeof(vlan_id));
+
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
(unsigned long) len);
@@ -1067,13 +1173,22 @@ static void handle_auth(struct hostapd_data *hapd,
seq_ctrl);
return;
}
+#ifdef CONFIG_MESH
+ if ((hapd->conf->mesh & MESH_ENABLED) &&
+ sta->plink_state == PLINK_BLOCKED) {
+ wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
+ " is blocked - drop Authentication frame",
+ MAC2STR(mgmt->sa));
+ return;
+ }
+#endif /* CONFIG_MESH */
} else {
#ifdef CONFIG_MESH
if (hapd->conf->mesh & MESH_ENABLED) {
/* if the mesh peer is not available, we don't do auth.
*/
wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
- " not yet known - drop Authentiation frame",
+ " not yet known - drop Authentication frame",
MAC2STR(mgmt->sa));
/*
* Save a copy of the frame so that it can be processed
@@ -1095,19 +1210,23 @@ static void handle_auth(struct hostapd_data *hapd,
sta->last_seq_ctrl = seq_ctrl;
sta->last_subtype = WLAN_FC_STYPE_AUTH;
- 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;
+ if (vlan_id.notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, &vlan_id)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
+ HOSTAPD_LEVEL_INFO,
+ "Invalid VLAN %d%s received from RADIUS server",
+ vlan_id.untagged,
+ vlan_id.tagged[0] ? "+" : "");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
}
+ if (ap_sta_set_vlan(hapd, sta, &vlan_id) < 0) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ if (sta->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) {
@@ -1132,6 +1251,46 @@ static void handle_auth(struct hostapd_data *hapd,
else
ap_sta_no_session_timeout(hapd, sta);
+ /*
+ * If the driver supports full AP client state, add a station to the
+ * driver before sending authentication reply to make sure the driver
+ * has resources, and not to go through the entire authentication and
+ * association handshake, and fail it at the end.
+ *
+ * If this is not the first transaction, in a multi-step authentication
+ * algorithm, the station already exists in the driver
+ * (sta->added_unassoc = 1) so skip it.
+ *
+ * In mesh mode, the station was already added to the driver when the
+ * NEW_PEER_CANDIDATE event is received.
+ */
+ if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
+ !(hapd->conf->mesh & MESH_ENABLED) &&
+ !(sta->added_unassoc)) {
+ /*
+ * If a station that is already associated to the AP, is trying
+ * to authenticate again, remove the STA entry, in order to make
+ * sure the STA PS state gets cleared and configuration gets
+ * updated. To handle this, station's added_unassoc flag is
+ * cleared once the station has completed association.
+ */
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
+ WLAN_STA_AUTHORIZED);
+
+ if (hostapd_sta_add(hapd, sta->addr, 0, 0, NULL, 0, 0,
+ NULL, NULL, sta->flags, 0, 0, 0, 0)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_NOTICE,
+ "Could not add STA to kernel driver");
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ goto fail;
+ }
+
+ sta->added_unassoc = 1;
+ }
+
switch (auth_alg) {
case WLAN_AUTH_OPEN:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -1205,12 +1364,19 @@ static void handle_auth(struct hostapd_data *hapd,
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);
+ reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
+ auth_transaction + 1, resp, resp_ies,
+ resp_ies_len);
+
+ if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
+ reply_res != WLAN_STATUS_SUCCESS)) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
}
-static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
{
int i, j = 32, aid;
@@ -1220,6 +1386,9 @@ static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
return 0;
}
+ if (TEST_FAIL())
+ return -1;
+
for (i = 0; i < AID_WORDS; i++) {
if (hapd->sta_aid[i] == (u32) -1)
continue;
@@ -1327,6 +1496,9 @@ static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_INTERWORKING */
+ if (ext_capab_ie_len > 0)
+ sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
+
return WLAN_STATUS_SUCCESS;
}
@@ -1617,6 +1789,27 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
sta->mb_ies = NULL;
#endif /* CONFIG_FST */
+#ifdef CONFIG_MBO
+ mbo_ap_check_sta_assoc(hapd, sta, &elems);
+
+ if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
+ elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
+ hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ wpa_printf(MSG_INFO,
+ "MBO: Reject WPA2 association without PMF");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+#endif /* CONFIG_MBO */
+
+ ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
+ elems.supp_op_classes_len);
+
+ if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
+ elems.rrm_enabled &&
+ elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
+ os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
+ sizeof(sta->rrm_enabled_capa));
+
return WLAN_STATUS_SUCCESS;
}
@@ -1643,9 +1836,66 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
}
-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)
+static int add_associated_sta(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct ieee80211_ht_capabilities ht_cap;
+ struct ieee80211_vht_capabilities vht_cap;
+
+ /*
+ * Remove the STA entry to ensure the STA PS state gets cleared and
+ * configuration gets updated. This is relevant for cases, such as
+ * FT-over-the-DS, where a station re-associates back to the same AP but
+ * skips the authentication flow, or if working with a driver that
+ * does not support full AP client state.
+ */
+ if (!sta->added_unassoc)
+ 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 */
+
+ /*
+ * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
+ * will be set when the ACK frame for the (Re)Association Response frame
+ * is processed (TX status driver event).
+ */
+ 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 | WLAN_STA_ASSOC, sta->qosinfo,
+ sta->vht_opmode, sta->p2p_ie ? 1 : 0,
+ sta->added_unassoc)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
+ "Could not %s STA to kernel driver",
+ sta->added_unassoc ? "set" : "add");
+
+ if (sta->added_unassoc) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
+
+ return -1;
+ }
+
+ sta->added_unassoc = 0;
+
+ return 0;
+}
+
+
+static u16 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];
@@ -1695,7 +1945,23 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
- p = hostapd_eid_vht_capabilities(hapd, p);
+ u32 nsts = 0, sta_nsts;
+
+ if (hapd->conf->use_sta_nsts && sta->vht_capabilities) {
+ struct ieee80211_vht_capabilities *capa;
+
+ nsts = (hapd->iface->conf->vht_capab >>
+ VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+ capa = sta->vht_capabilities;
+ sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
+ VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+
+ if (nsts < sta_nsts)
+ nsts = 0;
+ else
+ nsts = sta_nsts;
+ }
+ p = hostapd_eid_vht_capabilities(hapd, p, nsts);
p = hostapd_eid_vht_operation(hapd, p);
}
#endif /* CONFIG_IEEE80211AC */
@@ -1734,7 +2000,7 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
- if (sta->p2p_ie) {
+ if (sta->p2p_ie && hapd->p2p_group) {
struct wpabuf *p2p_resp_ie;
enum p2p_status_code status;
switch (status_code) {
@@ -1763,11 +2029,25 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
p = hostapd_eid_p2p_manage(hapd, p);
#endif /* CONFIG_P2P_MANAGER */
+ p = hostapd_eid_mbo(hapd, p, buf + sizeof(buf) - p);
+
+ if (hapd->conf->assocresp_elements &&
+ (size_t) (buf + sizeof(buf) - p) >=
+ wpabuf_len(hapd->conf->assocresp_elements)) {
+ os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
+ wpabuf_len(hapd->conf->assocresp_elements));
+ p += wpabuf_len(hapd->conf->assocresp_elements);
+ }
+
send_len += p - reply->u.assoc_resp.variable;
- if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
strerror(errno));
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ return WLAN_STATUS_SUCCESS;
}
@@ -1776,7 +2056,7 @@ static void handle_assoc(struct hostapd_data *hapd,
int reassoc)
{
u16 capab_info, listen_interval, seq_ctrl, fc;
- u16 resp = WLAN_STATUS_SUCCESS;
+ u16 resp = WLAN_STATUS_SUCCESS, reply_res;
const u8 *pos;
int left, i;
struct sta_info *sta;
@@ -1843,6 +2123,12 @@ static void handle_assoc(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
"prior to authentication since it is using "
"over-the-DS FT", MAC2STR(mgmt->sa));
+
+ /*
+ * Mark station as authenticated, to avoid adding station
+ * entry in the driver as associated and not authenticated
+ */
+ sta->flags |= WLAN_STA_AUTH;
} else
#endif /* CONFIG_IEEE80211R */
if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
@@ -1886,6 +2172,19 @@ static void handle_assoc(struct hostapd_data *hapd,
goto fail;
}
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ goto fail;
+ }
+#endif /* CONFIG_MBO */
+
+ /*
+ * sta->capability is used in check_assoc_ies() for RRM enabled
+ * capability element.
+ */
+ sta->capability = capab_info;
+
/* followed by SSID and Supported rates; and HT capabilities if 802.11n
* is used */
resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
@@ -1899,7 +2198,6 @@ static void handle_assoc(struct hostapd_data *hapd,
goto fail;
}
- sta->capability = capab_info;
sta->listen_interval = listen_interval;
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
@@ -1969,8 +2267,44 @@ static void handle_assoc(struct hostapd_data *hapd,
* remove the STA immediately. */
sta->timeout_next = STA_NULLFUNC;
+#ifdef CONFIG_TAXONOMY
+ taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
+#endif /* CONFIG_TAXONOMY */
+
fail:
- send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
+ /*
+ * In case of a successful response, add the station to the driver.
+ * Otherwise, the kernel may ignore Data frames before we process the
+ * ACK frame (TX status). In case of a failure, this station will be
+ * removed.
+ *
+ * Note that this is not compliant with the IEEE 802.11 standard that
+ * states that a non-AP station should transition into the
+ * authenticated/associated state only after the station acknowledges
+ * the (Re)Association Response frame. However, still do this as:
+ *
+ * 1. In case the station does not acknowledge the (Re)Association
+ * Response frame, it will be removed.
+ * 2. Data frames will be dropped in the kernel until the station is
+ * set into authorized state, and there are no significant known
+ * issues with processing other non-Data Class 3 frames during this
+ * window.
+ */
+ if (resp == WLAN_STATUS_SUCCESS && add_associated_sta(hapd, sta))
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+
+ reply_res = send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
+
+ /*
+ * Remove the station in case tranmission of a success response fails
+ * (the STA was added associated to the driver) or if the station was
+ * previously added unassociated.
+ */
+ if ((reply_res != WLAN_STATUS_SUCCESS &&
+ resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
}
@@ -2007,11 +2341,12 @@ static void handle_disassoc(struct hostapd_data *hapd,
/* Stop Accounting and IEEE 802.1X sessions, but leave the STA
* authenticated. */
accounting_sta_stop(hapd, sta);
- ieee802_1x_free_station(sta);
+ ieee802_1x_free_station(hapd, sta);
if (sta->ipaddr)
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
ap_sta_ip6addr_del(hapd, sta);
hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
if (sta->timeout_next == STA_NULLFUNC ||
sta->timeout_next == STA_DISASSOC) {
@@ -2233,6 +2568,9 @@ static int handle_action(struct hostapd_data *hapd,
return 1;
}
break;
+ case WLAN_ACTION_RADIO_MEASUREMENT:
+ hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
+ return 1;
}
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -2240,8 +2578,9 @@ static int handle_action(struct hostapd_data *hapd,
"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)) {
+ if (!is_multicast_ether_addr(mgmt->da) &&
+ !(mgmt->u.action.category & 0x80) &&
+ !is_multicast_ether_addr(mgmt->sa)) {
struct ieee80211_mgmt *resp;
/*
@@ -2288,7 +2627,6 @@ 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;
@@ -2304,11 +2642,7 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
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 &&
+ if (!is_broadcast_ether_addr(mgmt->bssid) &&
#ifdef CONFIG_P2P
/* Invitation responses can be sent with the peer MAC as BSSID */
!((hapd->conf->p2p & P2P_GROUP_OWNER) &&
@@ -2388,28 +2722,28 @@ static void handle_auth_cb(struct hostapd_data *hapd,
u16 auth_alg, auth_transaction, status_code;
struct sta_info *sta;
+ sta = ap_get_sta(hapd, mgmt->da);
+ if (!sta) {
+ wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
+ MAC2STR(mgmt->da));
+ 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);
+
if (!ok) {
hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
"did not acknowledge authentication response");
- return;
+ goto fail;
}
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;
+ goto fail;
}
if (status_code == WLAN_STATUS_SUCCESS &&
@@ -2418,6 +2752,15 @@ static void handle_auth_cb(struct hostapd_data *hapd,
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "authenticated");
sta->flags |= WLAN_STA_AUTH;
+ if (sta->added_unassoc)
+ hostapd_set_sta_flags(hapd, sta);
+ return;
+ }
+
+fail:
+ if (status_code != WLAN_STATUS_SUCCESS && sta->added_unassoc) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
}
}
@@ -2453,15 +2796,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
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) {
@@ -2470,11 +2804,12 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
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;
+ 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);
+ hostapd_drv_sta_remove(hapd, sta->addr);
return;
}
@@ -2483,6 +2818,18 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
else
status = le_to_host16(mgmt->u.assoc_resp.status_code);
+ 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;
+ /* The STA is added only in case of SUCCESS */
+ if (status == WLAN_STATUS_SUCCESS)
+ hostapd_drv_sta_remove(hapd, sta->addr);
+
+ return;
+ }
+
if (status != WLAN_STATUS_SUCCESS)
return;
@@ -2517,38 +2864,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
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, sta->vht_opmode)) {
- 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);
-
- return;
- }
-
if (sta->flags & WLAN_STA_WDS) {
int ret;
char ifname_wds[IFNAMSIZ + 1];
@@ -2580,8 +2895,26 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
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);
+
+ if (sta->pending_eapol_rx) {
+ struct os_reltime now, age;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
+ if (age.sec == 0 && age.usec < 200000) {
+ wpa_printf(MSG_DEBUG,
+ "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
+ MAC2STR(sta->addr));
+ ieee802_1x_receive(
+ hapd, mgmt->da,
+ wpabuf_head(sta->pending_eapol_rx->buf),
+ wpabuf_len(sta->pending_eapol_rx->buf));
+ }
+ wpabuf_free(sta->pending_eapol_rx->buf);
+ os_free(sta->pending_eapol_rx);
+ sta->pending_eapol_rx = NULL;
+ }
}
@@ -2590,7 +2923,7 @@ static void handle_deauth_cb(struct hostapd_data *hapd,
size_t len, int ok)
{
struct sta_info *sta;
- if (mgmt->da[0] & 0x01)
+ if (is_multicast_ether_addr(mgmt->da))
return;
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
@@ -2614,7 +2947,7 @@ static void handle_disassoc_cb(struct hostapd_data *hapd,
size_t len, int ok)
{
struct sta_info *sta;
- if (mgmt->da[0] & 0x01)
+ if (is_multicast_ether_addr(mgmt->da))
return;
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
@@ -2670,7 +3003,7 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
handle_assoc_cb(hapd, mgmt, len, 1, ok);
break;
case WLAN_FC_STYPE_PROBE_RESP:
- wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb");
+ wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok);
break;
case WLAN_FC_STYPE_DEAUTH:
wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
@@ -2681,7 +3014,7 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
handle_disassoc_cb(hapd, mgmt, len, ok);
break;
case WLAN_FC_STYPE_ACTION:
- wpa_printf(MSG_DEBUG, "mgmt::action cb");
+ wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
break;
default:
wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
@@ -2779,6 +3112,8 @@ void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
}
if (sta == NULL)
return;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR,
+ MAC2STR(sta->addr));
if (!(sta->flags & WLAN_STA_PENDING_POLL))
return;
@@ -2817,7 +3152,7 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
MACSTR, MAC2STR(src));
- if (src[0] & 0x01) {
+ if (is_multicast_ether_addr(src)) {
/* Broadcast bit set in SA?! Ignore the frame silently. */
return;
}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 44c1bff364ac..0327dec2a2bc 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -49,9 +49,13 @@ 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_secondary_channel(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_txpower_envelope(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);
@@ -61,6 +65,7 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
void hostapd_get_vht_capab(struct hostapd_data *hapd,
struct ieee80211_vht_capabilities *vht_cap,
struct ieee80211_vht_capabilities *neg_vht_cap);
+int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab);
u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
@@ -97,6 +102,7 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
#ifdef CONFIG_SAE
void sae_clear_retransmit_timer(struct hostapd_data *hapd,
struct sta_info *sta);
+void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta);
#else /* CONFIG_SAE */
static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
struct sta_info *sta)
@@ -104,4 +110,29 @@ static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
}
#endif /* CONFIG_SAE */
+#ifdef CONFIG_MBO
+
+u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len);
+
+u8 hostapd_mbo_ie_len(struct hostapd_data *hapd);
+
+#else /* CONFIG_MBO */
+
+static inline u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid,
+ size_t len)
+{
+ return eid;
+}
+
+static inline u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
+{
+ return 0;
+}
+
+#endif /* CONFIG_MBO */
+
+void ap_copy_sta_supp_op_classes(struct sta_info *sta,
+ const u8 *supp_op_classes,
+ size_t supp_op_classes_len);
+
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 531a67da412c..b8905373618d 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -15,7 +15,6 @@
#include "utils/common.h"
#include "utils/eloop.h"
-#include "crypto/sha1.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "hostapd.h"
@@ -35,7 +34,7 @@ struct hostapd_cached_radius_acl {
struct hostapd_cached_radius_acl *next;
u32 session_timeout;
u32 acct_interim_interval;
- int vlan_id;
+ struct vlan_description vlan_id;
struct hostapd_sta_wpa_psk_short *psk;
char *identity;
char *radius_cui;
@@ -77,29 +76,20 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
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;
+ if (!psk)
+ return;
+
+ if (src)
+ src->ref++;
+
+ *psk = src;
}
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui)
{
@@ -165,7 +155,10 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
if (msg == NULL)
return -1;
- radius_msg_make_authenticator(msg, addr, ETH_ALEN);
+ if (radius_msg_make_authenticator(msg) < 0) {
+ wpa_printf(MSG_INFO, "Could not make Request Authenticator");
+ goto fail;
+ }
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
@@ -213,6 +206,33 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
/**
+ * hostapd_check_acl - Check a specified STA against accept/deny ACLs
+ * @hapd: hostapd BSS data
+ * @addr: MAC address of the STA
+ * @vlan_id: Buffer for returning VLAN ID
+ * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
+ */
+int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
+ struct vlan_description *vlan_id)
+{
+ 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;
+
+ return HOSTAPD_ACL_PENDING;
+}
+
+
+/**
* hostapd_allowed_address - Check whether a specified STA can be authenticated
* @hapd: hostapd BSS data
* @addr: MAC address of the STA
@@ -231,16 +251,19 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
*/
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui)
{
+ int res;
+
if (session_timeout)
*session_timeout = 0;
if (acct_interim_interval)
*acct_interim_interval = 0;
if (vlan_id)
- *vlan_id = 0;
+ os_memset(vlan_id, 0, sizeof(*vlan_id));
if (psk)
*psk = NULL;
if (identity)
@@ -248,18 +271,9 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
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;
+ res = hostapd_check_acl(hapd, addr, vlan_id);
+ if (res != HOSTAPD_ACL_PENDING)
+ return res;
if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
#ifdef CONFIG_NO_RADIUS
@@ -268,10 +282,9 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
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);
+ 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;
@@ -419,7 +432,7 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
struct hostapd_cached_radius_acl *cache)
{
int passphraselen;
- char *passphrase, *strpassphrase;
+ char *passphrase;
size_t i;
struct hostapd_sta_wpa_psk_short *psk;
@@ -436,24 +449,42 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
*/
if (passphrase == NULL)
break;
+
+ /*
+ * Passphase should be 8..63 chars (to be hashed with SSID)
+ * or 64 chars hex string (no separate hashing with SSID).
+ */
+
+ if (passphraselen < MIN_PASSPHRASE_LEN ||
+ passphraselen > MAX_PASSPHRASE_LEN + 1)
+ goto free_pass;
+
/*
* 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);
+ if (psk) {
+ if ((passphraselen == MAX_PASSPHRASE_LEN + 1) &&
+ (hexstr2bin(passphrase, psk->psk, PMK_LEN) < 0)) {
+ hostapd_logger(hapd, cache->addr,
+ HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_WARNING,
+ "invalid hex string (%d chars) in Tunnel-Password",
+ passphraselen);
+ goto skip;
+ } else if (passphraselen <= MAX_PASSPHRASE_LEN) {
+ os_memcpy(psk->passphrase, passphrase,
+ passphraselen);
+ psk->is_passphrase = 1;
+ }
psk->next = cache->psk;
cache->psk = psk;
psk = NULL;
}
- os_free(strpassphrase);
+skip:
os_free(psk);
+free_pass:
os_free(passphrase);
}
}
@@ -478,6 +509,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+ int *untagged, *tagged, *notempty;
query = hapd->acl_queries;
prev = NULL;
@@ -535,7 +567,12 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
cache->acct_interim_interval = 0;
}
- cache->vlan_id = radius_msg_get_vlanid(msg);
+ notempty = &cache->vlan_id.notempty;
+ untagged = &cache->vlan_id.untagged;
+ tagged = cache->vlan_id.tagged;
+ *notempty = !!radius_msg_get_vlanid(msg, untagged,
+ MAX_NUM_TAGGED_VLAN,
+ tagged);
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
msg, req, cache);
@@ -558,17 +595,18 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
!cache->psk)
cache->accepted = HOSTAPD_ACL_REJECT;
- if (cache->vlan_id &&
- !hostapd_vlan_id_valid(hapd->conf->vlan, cache->vlan_id)) {
+ if (cache->vlan_id.notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) {
hostapd_logger(hapd, query->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
- "Invalid VLAN ID %d received from RADIUS server",
- cache->vlan_id);
- cache->vlan_id = 0;
+ "Invalid VLAN %d%s received from RADIUS server",
+ cache->vlan_id.untagged,
+ cache->vlan_id.tagged[0] ? "+" : "");
+ os_memset(&cache->vlan_id, 0, sizeof(cache->vlan_id));
}
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
- !cache->vlan_id)
+ !cache->vlan_id.notempty)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
@@ -640,6 +678,12 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
{
+ if (psk && psk->ref) {
+ /* This will be freed when the last reference is dropped. */
+ psk->ref--;
+ return;
+ }
+
while (psk) {
struct hostapd_sta_wpa_psk_short *prev = psk;
psk = psk->next;
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index b66f244b3ebc..71f53b9612fa 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -16,9 +16,12 @@ enum {
HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
};
+int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
+ struct vlan_description *vlan_id);
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui);
int hostapd_acl_init(struct hostapd_data *hapd);
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 11fde2a26394..5eb1060a2965 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -108,6 +108,29 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
}
+u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 sec_ch;
+
+ if (!hapd->cs_freq_params.channel ||
+ !hapd->cs_freq_params.sec_channel_offset)
+ return eid;
+
+ if (hapd->cs_freq_params.sec_channel_offset == -1)
+ sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
+ else if (hapd->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;
+}
+
+
/*
op_mode
Set to 0 (HT pure) under the followign conditions
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index d462ac8bf9cd..259413bd12ff 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -172,6 +172,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
case 0: /* Bits 0-7 */
if (hapd->iconf->obss_interval)
*pos |= 0x01; /* Bit 0 - Coexistence management */
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)
+ *pos |= 0x04; /* Bit 2 - Extended Channel Switching */
break;
case 1: /* Bits 8-15 */
if (hapd->conf->proxy_arp)
@@ -207,11 +209,21 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
if (hapd->conf->hs20)
*pos |= 0x40; /* Bit 46 - WNM-Notification */
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled)
+ *pos |= 0x40; /* Bit 46 - WNM-Notification */
+#endif /* CONFIG_MBO */
break;
case 6: /* Bits 48-55 */
if (hapd->conf->ssid.utf8_ssid)
*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
break;
+ case 8: /* Bits 64-71 */
+ if (hapd->conf->ftm_responder)
+ *pos |= 0x40; /* Bit 70 - FTM responder */
+ if (hapd->conf->ftm_initiator)
+ *pos |= 0x80; /* Bit 71 - FTM initiator */
+ break;
}
}
@@ -231,6 +243,9 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
len = 1;
if (len < 7 && hapd->conf->ssid.utf8_ssid)
len = 7;
+ if (len < 9 &&
+ (hapd->conf->ftm_initiator || hapd->conf->ftm_responder))
+ len = 9;
#ifdef CONFIG_WNM
if (len < 4)
len = 4;
@@ -239,6 +254,10 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
if (hapd->conf->hs20 && len < 6)
len = 6;
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled && len < 6)
+ len = 6;
+#endif /* CONFIG_MBO */
if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
if (len == 0)
@@ -506,3 +525,62 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
return pos;
}
+
+
+#ifdef CONFIG_MBO
+
+u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+ u8 mbo[6], *mbo_pos = mbo;
+ u8 *pos = eid;
+
+ if (!hapd->conf->mbo_enabled)
+ return eid;
+
+ *mbo_pos++ = MBO_ATTR_ID_AP_CAPA_IND;
+ *mbo_pos++ = 1;
+ /* Not Cellular aware */
+ *mbo_pos++ = 0;
+
+ if (hapd->mbo_assoc_disallow) {
+ *mbo_pos++ = MBO_ATTR_ID_ASSOC_DISALLOW;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = hapd->mbo_assoc_disallow;
+ }
+
+ pos += mbo_add_ie(pos, len, mbo, mbo_pos - mbo);
+
+ return pos;
+}
+
+
+u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
+{
+ if (!hapd->conf->mbo_enabled)
+ return 0;
+
+ /*
+ * MBO IE header (6) + Capability Indication attribute (3) +
+ * Association Disallowed attribute (3) = 12
+ */
+ return 6 + 3 + (hapd->mbo_assoc_disallow ? 3 : 0);
+}
+
+#endif /* CONFIG_MBO */
+
+
+void ap_copy_sta_supp_op_classes(struct sta_info *sta,
+ const u8 *supp_op_classes,
+ size_t supp_op_classes_len)
+{
+ if (!supp_op_classes)
+ return;
+ os_free(sta->supp_op_classes);
+ sta->supp_op_classes = os_malloc(1 + supp_op_classes_len);
+ if (!sta->supp_op_classes)
+ return;
+
+ sta->supp_op_classes[0] = supp_op_classes_len;
+ os_memcpy(sta->supp_op_classes + 1, supp_op_classes,
+ supp_op_classes_len);
+}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 5bf1b5d72002..f30f63bc5709 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -17,9 +17,10 @@
#include "sta_info.h"
#include "beacon.h"
#include "ieee802_11.h"
+#include "dfs.h"
-u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts)
{
struct ieee80211_vht_capabilities *cap;
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
@@ -49,6 +50,18 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
cap->vht_capabilities_info = host_to_le32(
hapd->iface->conf->vht_capab);
+ if (nsts != 0) {
+ u32 hapd_nsts;
+
+ hapd_nsts = le_to_host32(cap->vht_capabilities_info);
+ hapd_nsts = (hapd_nsts >> VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+ cap->vht_capabilities_info &=
+ ~(host_to_le32(hapd_nsts <<
+ VHT_CAP_BEAMFORMEE_STS_OFFSET));
+ cap->vht_capabilities_info |=
+ host_to_le32(nsts << VHT_CAP_BEAMFORMEE_STS_OFFSET);
+ }
+
/* Supported MCS set comes from hw */
os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
@@ -80,6 +93,26 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
hapd->iconf->vht_oper_centr_freq_seg1_idx;
oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
+ if (hapd->iconf->vht_oper_chwidth == 2) {
+ /*
+ * Convert 160 MHz channel width to new style as interop
+ * workaround.
+ */
+ oper->vht_op_info_chwidth = 1;
+ oper->vht_op_info_chan_center_freq_seg1_idx =
+ oper->vht_op_info_chan_center_freq_seg0_idx;
+ if (hapd->iconf->channel <
+ hapd->iconf->vht_oper_centr_freq_seg0_idx)
+ oper->vht_op_info_chan_center_freq_seg0_idx -= 8;
+ else
+ oper->vht_op_info_chan_center_freq_seg0_idx += 8;
+ } else if (hapd->iconf->vht_oper_chwidth == 3) {
+ /*
+ * Convert 80+80 MHz channel width to new style as interop
+ * workaround.
+ */
+ oper->vht_op_info_chwidth = 1;
+ }
/* VHT Basic MCS set comes from hw */
/* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
@@ -131,6 +164,171 @@ static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
}
+u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 bw, chan1, chan2 = 0;
+ int freq1;
+
+ if (!hapd->cs_freq_params.channel ||
+ !hapd->cs_freq_params.vht_enabled)
+ return eid;
+
+ /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
+ switch (hapd->cs_freq_params.bandwidth) {
+ case 40:
+ bw = 0;
+ break;
+ case 80:
+ /* check if it's 80+80 */
+ if (!hapd->cs_freq_params.center_freq2)
+ bw = 1;
+ else
+ bw = 3;
+ break;
+ case 160:
+ bw = 2;
+ break;
+ default:
+ /* not valid VHT bandwidth or not in CSA */
+ return eid;
+ }
+
+ freq1 = hapd->cs_freq_params.center_freq1 ?
+ hapd->cs_freq_params.center_freq1 :
+ hapd->cs_freq_params.freq;
+ if (ieee80211_freq_to_chan(freq1, &chan1) !=
+ HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ if (hapd->cs_freq_params.center_freq2 &&
+ ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
+ &chan2) != HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
+ *eid++ = 5; /* Length of Channel Switch Wrapper */
+ *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
+ *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
+ *eid++ = bw; /* New Channel Width */
+ *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
+ *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
+
+ return eid;
+}
+
+
+u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ struct hostapd_config *iconf = iface->conf;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ struct hostapd_channel_data *chan;
+ int dfs, i;
+ u8 channel, tx_pwr_count, local_pwr_constraint;
+ int max_tx_power;
+ u8 tx_pwr;
+
+ if (!mode)
+ return eid;
+
+ if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
+ return eid;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].freq == iface->freq)
+ break;
+ }
+ if (i == mode->num_channels)
+ return eid;
+
+ switch (iface->conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_USE_HT:
+ if (iconf->secondary_channel == 0) {
+ /* Max Transmit Power count = 0 (20 MHz) */
+ tx_pwr_count = 0;
+ } else {
+ /* Max Transmit Power count = 1 (20, 40 MHz) */
+ tx_pwr_count = 1;
+ }
+ break;
+ case VHT_CHANWIDTH_80MHZ:
+ /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
+ tx_pwr_count = 2;
+ break;
+ case VHT_CHANWIDTH_80P80MHZ:
+ case VHT_CHANWIDTH_160MHZ:
+ /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
+ tx_pwr_count = 3;
+ break;
+ default:
+ return eid;
+ }
+
+ /*
+ * Below local_pwr_constraint logic is referred from
+ * hostapd_eid_pwr_constraint.
+ *
+ * Check if DFS is required by regulatory.
+ */
+ dfs = hostapd_is_dfs_required(hapd->iface);
+ if (dfs < 0)
+ dfs = 0;
+
+ /*
+ * In order to meet regulations when TPC is not implemented using
+ * a transmit power that is below the legal maximum (including any
+ * mitigation factor) should help. In this case, indicate 3 dB below
+ * maximum allowed transmit power.
+ */
+ if (hapd->iconf->local_pwr_constraint == -1)
+ local_pwr_constraint = (dfs == 0) ? 0 : 3;
+ else
+ local_pwr_constraint = hapd->iconf->local_pwr_constraint;
+
+ /*
+ * A STA that is not an AP shall use a transmit power less than or
+ * equal to the local maximum transmit power level for the channel.
+ * The local maximum transmit power can be calculated from the formula:
+ * local max TX pwr = max TX pwr - local pwr constraint
+ * Where max TX pwr is maximum transmit power level specified for
+ * channel in Country element and local pwr constraint is specified
+ * for channel in this Power Constraint element.
+ */
+ chan = &mode->channels[i];
+ max_tx_power = chan->max_tx_power - local_pwr_constraint;
+
+ /*
+ * Local Maximum Transmit power is encoded as two's complement
+ * with a 0.5 dB step.
+ */
+ max_tx_power *= 2; /* in 0.5 dB steps */
+ if (max_tx_power > 127) {
+ /* 63.5 has special meaning of 63.5 dBm or higher */
+ max_tx_power = 127;
+ }
+ if (max_tx_power < -128)
+ max_tx_power = -128;
+ if (max_tx_power < 0)
+ tx_pwr = 0x80 + max_tx_power + 128;
+ else
+ tx_pwr = max_tx_power;
+
+ *eid++ = WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE;
+ *eid++ = 2 + tx_pwr_count;
+
+ /*
+ * Max Transmit Power count and
+ * Max Transmit Power units = 0 (EIRP)
+ */
+ *eid++ = tx_pwr_count;
+
+ for (i = 0; i <= tx_pwr_count; i++)
+ *eid++ = tx_pwr;
+
+ return eid;
+}
+
+
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab)
{
@@ -212,7 +410,7 @@ u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
pos += 4;
*pos++ = VENDOR_VHT_SUBTYPE;
- pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
return pos;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 0f2d428cf752..80ff996948f9 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -34,6 +34,9 @@
#include "ieee802_1x.h"
+#ifdef CONFIG_HS20
+static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx);
+#endif /* CONFIG_HS20 */
static void ieee802_1x_finished(struct hostapd_data *hapd,
struct sta_info *sta, int success,
int remediation);
@@ -219,7 +222,7 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
MAC2STR(sta->addr));
#ifndef CONFIG_NO_VLAN
- if (sta->vlan_id > 0 && sta->vlan_id <= MAX_VLAN_ID) {
+ if (sta->vlan_id > 0) {
wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported.");
return;
}
@@ -402,7 +405,16 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
char buf[128];
if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_SERVICE_TYPE) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE,
+ RADIUS_SERVICE_TYPE_FRAMED)) {
+ wpa_printf(MSG_ERROR, "Could not add Service-Type");
+ return -1;
+ }
+
+ if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_PORT) &&
+ sta->aid > 0 &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
wpa_printf(MSG_ERROR, "Could not add NAS-Port");
return -1;
@@ -435,9 +447,9 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
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 (sta->acct_session_id) {
+ os_snprintf(buf, sizeof(buf), "%016llX",
+ (unsigned long long) sta->acct_session_id);
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");
@@ -445,6 +457,21 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
}
}
+ if ((hapd->conf->wpa & 2) &&
+ !hapd->conf->disable_pmksa_caching &&
+ sta->eapol_sm && sta->eapol_sm->acct_multi_session_id) {
+ os_snprintf(buf, sizeof(buf), "%016llX",
+ (unsigned long long)
+ sta->eapol_sm->acct_multi_session_id);
+ if (!radius_msg_add_attr(
+ msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
+ (u8 *) buf, os_strlen(buf))) {
+ wpa_printf(MSG_INFO,
+ "Could not add Acct-Multi-Session-Id");
+ return -1;
+ }
+ }
+
#ifdef CONFIG_IEEE80211R
if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
sta->wpa_sm &&
@@ -475,6 +502,7 @@ int add_common_radius_attr(struct hostapd_data *hapd,
{
char buf[128];
struct hostapd_radius_attr *attr;
+ int len;
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_IP_ADDRESS) &&
@@ -506,15 +534,15 @@ int add_common_radius_attr(struct hostapd_data *hapd,
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';
+ len = os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":",
+ MAC2STR(hapd->own_addr));
+ os_memcpy(&buf[len], hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len);
+ len += hapd->conf->ssid.ssid_len;
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))) {
+ (u8 *) buf, len)) {
wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
return -1;
}
@@ -583,7 +611,10 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
return;
}
- radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
+ if (radius_msg_make_authenticator(msg) < 0) {
+ wpa_printf(MSG_INFO, "Could not make Request Authenticator");
+ goto fail;
+ }
if (sm->identity &&
!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
@@ -831,6 +862,29 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
}
+static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
+ size_t len)
+{
+ if (sta->pending_eapol_rx) {
+ wpabuf_free(sta->pending_eapol_rx->buf);
+ } else {
+ sta->pending_eapol_rx =
+ os_malloc(sizeof(*sta->pending_eapol_rx));
+ if (!sta->pending_eapol_rx)
+ return;
+ }
+
+ sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len);
+ if (!sta->pending_eapol_rx->buf) {
+ os_free(sta->pending_eapol_rx);
+ sta->pending_eapol_rx = NULL;
+ return;
+ }
+
+ os_get_reltime(&sta->pending_eapol_rx->rx_time);
+}
+
+
/**
* ieee802_1x_receive - Process the EAPOL frames from the Supplicant
* @hapd: hostapd BSS data
@@ -861,6 +915,13 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
"associated/Pre-authenticating STA");
+
+ if (sta && (sta->flags & WLAN_STA_AUTH)) {
+ wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
+ " for later use", MAC2STR(sta->addr));
+ ieee802_1x_save_eapol(sta, buf, len);
+ }
+
return;
}
@@ -1047,7 +1108,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
* Clear any possible EAPOL authenticator state to support
* reassociation change from WPS to PSK.
*/
- ieee802_1x_free_station(sta);
+ ieee802_1x_free_station(hapd, sta);
return;
}
@@ -1058,7 +1119,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
* Clear any possible EAPOL authenticator state to support
* reassociation change from WPA-EAP to PSK.
*/
- ieee802_1x_free_station(sta);
+ ieee802_1x_free_station(hapd, sta);
return;
}
@@ -1106,6 +1167,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
sta->eapol_sm->authSuccess = TRUE;
sta->eapol_sm->authFail = FALSE;
+ sta->eapol_sm->portValid = TRUE;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
/* TODO: get vlan_id from R0KH using RRB message */
@@ -1128,7 +1190,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
sta->eapol_sm->authFail = FALSE;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
- pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
+ pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm);
ap_sta_bind_vlan(hapd, sta);
} else {
if (reassoc) {
@@ -1144,10 +1206,20 @@ 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_free_station(struct hostapd_data *hapd, struct sta_info *sta)
{
struct eapol_state_machine *sm = sta->eapol_sm;
+#ifdef CONFIG_HS20
+ eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
+#endif /* CONFIG_HS20 */
+
+ if (sta->pending_eapol_rx) {
+ wpabuf_free(sta->pending_eapol_rx->buf);
+ os_free(sta->pending_eapol_rx);
+ sta->pending_eapol_rx = NULL;
+ }
+
if (sm == NULL)
return;
@@ -1156,10 +1228,8 @@ void ieee802_1x_free_station(struct sta_info *sta)
#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);
}
@@ -1592,10 +1662,16 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_data *hapd = data;
struct sta_info *sta;
u32 session_timeout = 0, termination_action, acct_interim_interval;
- int session_timeout_set, vlan_id = 0;
+ int session_timeout_set;
struct eapol_state_machine *sm;
int override_eapReq = 0;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+ struct vlan_description vlan_desc;
+#ifndef CONFIG_NO_VLAN
+ int *untagged, *tagged, *notempty;
+#endif /* CONFIG_NO_VLAN */
+
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
if (sm == NULL) {
@@ -1659,27 +1735,32 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
switch (hdr->code) {
case RADIUS_CODE_ACCESS_ACCEPT:
- if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- vlan_id = 0;
#ifndef CONFIG_NO_VLAN
- else
- vlan_id = radius_msg_get_vlanid(msg);
- if (vlan_id > 0 &&
- hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_INFO,
- "VLAN ID %d", vlan_id);
- } else if (vlan_id > 0) {
+ if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED) {
+ notempty = &vlan_desc.notempty;
+ untagged = &vlan_desc.untagged;
+ tagged = vlan_desc.tagged;
+ *notempty = !!radius_msg_get_vlanid(msg, untagged,
+ MAX_NUM_TAGGED_VLAN,
+ tagged);
+ }
+
+ if (vlan_desc.notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
sta->eapol_sm->authFail = TRUE;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
- "Invalid VLAN ID %d received from RADIUS server",
- vlan_id);
+ "Invalid VLAN %d%s received from RADIUS server",
+ vlan_desc.untagged,
+ vlan_desc.tagged[0] ? "+" : "");
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ ap_sta_set_vlan(hapd, sta, &vlan_desc);
break;
- } else if (hapd->conf->ssid.dynamic_vlan ==
- DYNAMIC_VLAN_REQUIRED) {
+ }
+
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
+ !vlan_desc.notempty) {
sta->eapol_sm->authFail = TRUE;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
@@ -1690,7 +1771,18 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
}
#endif /* CONFIG_NO_VLAN */
- sta->vlan_id = vlan_id;
+ if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0)
+ break;
+
+#ifndef CONFIG_NO_VLAN
+ if (sta->vlan_id > 0) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "VLAN ID %d", sta->vlan_id);
+ }
+#endif /* CONFIG_NO_VLAN */
+
if ((sta->flags & WLAN_STA_ASSOC) &&
ap_sta_bind_vlan(hapd, sta) < 0)
break;
@@ -1715,15 +1807,6 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
ieee802_1x_check_hs20(hapd, sta, msg,
session_timeout_set ?
(int) session_timeout : -1);
- if (sm->eap_if->eapKeyAvailable && !sta->remediation &&
- !sta->hs20_deauth_requested &&
- 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;
@@ -2190,7 +2273,7 @@ void ieee802_1x_deinit(struct hostapd_data *hapd)
{
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
- if (hapd->driver != NULL &&
+ if (hapd->driver && hapd->drv_priv &&
(hapd->conf->ieee802_1x || hapd->conf->wpa))
hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
@@ -2495,12 +2578,12 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
/* TODO: dot1xAuthSessionOctetsTx */
/* TODO: dot1xAuthSessionFramesRx */
/* TODO: dot1xAuthSessionFramesTx */
- "dot1xAuthSessionId=%08X-%08X\n"
+ "dot1xAuthSessionId=%016llX\n"
"dot1xAuthSessionAuthenticMethod=%d\n"
"dot1xAuthSessionTime=%u\n"
"dot1xAuthSessionTerminateCause=999\n"
"dot1xAuthSessionUserName=%s\n",
- sta->acct_session_id_hi, sta->acct_session_id_lo,
+ (unsigned long long) sta->acct_session_id,
(wpa_key_mgmt_wpa_ieee8021x(
wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
1 : 2,
@@ -2510,11 +2593,11 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
return len;
len += ret;
- if (sm->acct_multi_session_id_hi) {
+ if (sm->acct_multi_session_id) {
ret = os_snprintf(buf + len, buflen - len,
- "authMultiSessionId=%08X+%08X\n",
- sm->acct_multi_session_id_hi,
- sm->acct_multi_session_id_lo);
+ "authMultiSessionId=%016llX\n",
+ (unsigned long long)
+ sm->acct_multi_session_id);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2535,6 +2618,34 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
}
+#ifdef CONFIG_HS20
+static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = timeout_ctx;
+
+ if (sta->remediation) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
+ MACSTR " to indicate Subscription Remediation",
+ MAC2STR(sta->addr));
+ hs20_send_wnm_notification(hapd, sta->addr,
+ sta->remediation_method,
+ sta->remediation_url);
+ os_free(sta->remediation_url);
+ sta->remediation_url = NULL;
+ }
+
+ if (sta->hs20_deauth_req) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
+ MACSTR " to indicate imminent deauthentication",
+ MAC2STR(sta->addr));
+ hs20_send_wnm_notification_deauth_req(hapd, sta->addr,
+ sta->hs20_deauth_req);
+ }
+}
+#endif /* CONFIG_HS20 */
+
+
static void ieee802_1x_finished(struct hostapd_data *hapd,
struct sta_info *sta, int success,
int remediation)
@@ -2554,26 +2665,12 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
sta->remediation_method = 1; /* SOAP-XML SPP */
}
- if (success) {
- if (sta->remediation) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification "
- "to " MACSTR " to indicate Subscription "
- "Remediation",
- MAC2STR(sta->addr));
- hs20_send_wnm_notification(hapd, sta->addr,
- sta->remediation_method,
- sta->remediation_url);
- os_free(sta->remediation_url);
- sta->remediation_url = NULL;
- }
-
- if (sta->hs20_deauth_req) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification "
- "to " MACSTR " to indicate imminent "
- "deauthentication", MAC2STR(sta->addr));
- hs20_send_wnm_notification_deauth_req(
- hapd, sta->addr, sta->hs20_deauth_req);
- }
+ if (success && (sta->remediation || sta->hs20_deauth_req)) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to "
+ MACSTR " in 100 ms", MAC2STR(sta->addr));
+ eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
+ eloop_register_timeout(0, 100000, ieee802_1x_wnm_notif_send,
+ hapd, sta);
}
#endif /* CONFIG_HS20 */
@@ -2584,7 +2681,7 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
session_timeout = dot11RSNAConfigPMKLifetime;
if (success && key && len >= PMK_LEN && !sta->remediation &&
!sta->hs20_deauth_requested &&
- wpa_auth_pmksa_add(sta->wpa_sm, key, session_timeout,
+ wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout,
sta->eapol_sm) == 0) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_DEBUG,
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index 14d69556993c..ec80199007b6 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -21,7 +21,7 @@ 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_free_station(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,
diff --git a/src/ap/mbo_ap.c b/src/ap/mbo_ap.c
new file mode 100644
index 000000000000..43b0bf16934e
--- /dev/null
+++ b/src/ap/mbo_ap.c
@@ -0,0 +1,244 @@
+/*
+ * hostapd - MBO
+ * Copyright (c) 2016, 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/ieee802_11_common.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "mbo_ap.h"
+
+
+void mbo_ap_sta_free(struct sta_info *sta)
+{
+ struct mbo_non_pref_chan_info *info, *prev;
+
+ info = sta->non_pref_chan;
+ sta->non_pref_chan = NULL;
+ while (info) {
+ prev = info;
+ info = info->next;
+ os_free(prev);
+ }
+}
+
+
+static void mbo_ap_parse_non_pref_chan(struct sta_info *sta,
+ const u8 *buf, size_t len)
+{
+ struct mbo_non_pref_chan_info *info, *tmp;
+ char channels[200], *pos, *end;
+ size_t num_chan, i;
+ int ret;
+
+ if (len <= 3)
+ return; /* Not enough room for any channels */
+
+ num_chan = len - 3;
+ info = os_zalloc(sizeof(*info) + num_chan);
+ if (!info)
+ return;
+ info->op_class = buf[0];
+ info->pref = buf[len - 2];
+ info->reason_code = buf[len - 1];
+ info->num_channels = num_chan;
+ buf++;
+ os_memcpy(info->channels, buf, num_chan);
+ if (!sta->non_pref_chan) {
+ sta->non_pref_chan = info;
+ } else {
+ tmp = sta->non_pref_chan;
+ while (tmp->next)
+ tmp = tmp->next;
+ tmp->next = info;
+ }
+
+ pos = channels;
+ end = pos + sizeof(channels);
+ *pos = '\0';
+ for (i = 0; i < num_chan; i++) {
+ ret = os_snprintf(pos, end - pos, "%s%u",
+ i == 0 ? "" : " ", buf[i]);
+ if (os_snprintf_error(end - pos, ret)) {
+ *pos = '\0';
+ break;
+ }
+ pos += ret;
+ }
+
+ wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
+ " non-preferred channel list (op class %u, pref %u, reason code %u, channels %s)",
+ MAC2STR(sta->addr), info->op_class, info->pref,
+ info->reason_code, channels);
+}
+
+
+void mbo_ap_check_sta_assoc(struct hostapd_data *hapd, struct sta_info *sta,
+ struct ieee802_11_elems *elems)
+{
+ const u8 *pos, *attr, *end;
+ size_t len;
+
+ if (!hapd->conf->mbo_enabled || !elems->mbo)
+ return;
+
+ pos = elems->mbo + 4;
+ len = elems->mbo_len - 4;
+ wpa_hexdump(MSG_DEBUG, "MBO: Association Request attributes", pos, len);
+
+ attr = get_ie(pos, len, MBO_ATTR_ID_CELL_DATA_CAPA);
+ if (attr && attr[1] >= 1)
+ sta->cell_capa = attr[2];
+
+ mbo_ap_sta_free(sta);
+ end = pos + len;
+ while (end - pos > 1) {
+ u8 ie_len = pos[1];
+
+ if (2 + ie_len > end - pos)
+ break;
+
+ if (pos[0] == MBO_ATTR_ID_NON_PREF_CHAN_REPORT)
+ mbo_ap_parse_non_pref_chan(sta, pos + 2, ie_len);
+ pos += 2 + pos[1];
+ }
+}
+
+
+int mbo_ap_get_info(struct sta_info *sta, char *buf, size_t buflen)
+{
+ char *pos = buf, *end = buf + buflen;
+ int ret;
+ struct mbo_non_pref_chan_info *info;
+ u8 i;
+ unsigned int count = 0;
+
+ if (!sta->cell_capa)
+ return 0;
+
+ ret = os_snprintf(pos, end - pos, "mbo_cell_capa=%u\n", sta->cell_capa);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ for (info = sta->non_pref_chan; info; info = info->next) {
+ char *pos2 = pos;
+
+ ret = os_snprintf(pos2, end - pos2,
+ "non_pref_chan[%u]=%u:%u:%u:",
+ count, info->op_class, info->pref,
+ info->reason_code);
+ count++;
+ if (os_snprintf_error(end - pos2, ret))
+ break;
+ pos2 += ret;
+
+ for (i = 0; i < info->num_channels; i++) {
+ ret = os_snprintf(pos2, end - pos2, "%u%s",
+ info->channels[i],
+ i + 1 < info->num_channels ?
+ "," : "");
+ if (os_snprintf_error(end - pos2, ret)) {
+ pos2 = NULL;
+ break;
+ }
+ pos2 += ret;
+ }
+
+ if (!pos2)
+ break;
+ ret = os_snprintf(pos2, end - pos2, "\n");
+ if (os_snprintf_error(end - pos2, ret))
+ break;
+ pos2 += ret;
+ pos = pos2;
+ }
+
+ return pos - buf;
+}
+
+
+static void mbo_ap_wnm_notif_req_cell_capa(struct sta_info *sta,
+ const u8 *buf, size_t len)
+{
+ if (len < 1)
+ return;
+ wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
+ " updated cellular data capability: %u",
+ MAC2STR(sta->addr), buf[0]);
+ sta->cell_capa = buf[0];
+}
+
+
+static void mbo_ap_wnm_notif_req_elem(struct sta_info *sta, u8 type,
+ const u8 *buf, size_t len,
+ int *first_non_pref_chan)
+{
+ switch (type) {
+ case WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT:
+ if (*first_non_pref_chan) {
+ /*
+ * Need to free the previously stored entries now to
+ * allow the update to replace all entries.
+ */
+ *first_non_pref_chan = 0;
+ mbo_ap_sta_free(sta);
+ }
+ mbo_ap_parse_non_pref_chan(sta, buf, len);
+ break;
+ case WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA:
+ mbo_ap_wnm_notif_req_cell_capa(sta, buf, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "MBO: Ignore unknown WNM Notification WFA subelement %u",
+ type);
+ break;
+ }
+}
+
+
+void mbo_ap_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *buf, size_t len)
+{
+ const u8 *pos, *end;
+ u8 ie_len;
+ struct sta_info *sta;
+ int first_non_pref_chan = 1;
+
+ if (!hapd->conf->mbo_enabled)
+ return;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return;
+
+ pos = buf;
+ end = buf + len;
+
+ while (end - pos > 1) {
+ ie_len = pos[1];
+
+ if (2 + ie_len > end - pos)
+ break;
+
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+ ie_len >= 4 && WPA_GET_BE24(pos + 2) == OUI_WFA)
+ mbo_ap_wnm_notif_req_elem(sta, pos[5],
+ pos + 6, ie_len - 4,
+ &first_non_pref_chan);
+ else
+ wpa_printf(MSG_DEBUG,
+ "MBO: Ignore unknown WNM Notification element %u (len=%u)",
+ pos[0], pos[1]);
+
+ pos += 2 + pos[1];
+ }
+}
diff --git a/src/ap/mbo_ap.h b/src/ap/mbo_ap.h
new file mode 100644
index 000000000000..9f37f2802f3b
--- /dev/null
+++ b/src/ap/mbo_ap.h
@@ -0,0 +1,51 @@
+/*
+ * MBO related functions and structures
+ * Copyright (c) 2016, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MBO_AP_H
+#define MBO_AP_H
+
+struct hostapd_data;
+struct sta_info;
+struct ieee802_11_elems;
+
+#ifdef CONFIG_MBO
+
+void mbo_ap_check_sta_assoc(struct hostapd_data *hapd, struct sta_info *sta,
+ struct ieee802_11_elems *elems);
+int mbo_ap_get_info(struct sta_info *sta, char *buf, size_t buflen);
+void mbo_ap_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *buf, size_t len);
+void mbo_ap_sta_free(struct sta_info *sta);
+
+#else /* CONFIG_MBO */
+
+static inline void mbo_ap_check_sta_assoc(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct ieee802_11_elems *elems)
+{
+}
+
+static inline int mbo_ap_get_info(struct sta_info *sta, char *buf,
+ size_t buflen)
+{
+ return 0;
+}
+
+static inline void mbo_ap_wnm_notification_req(struct hostapd_data *hapd,
+ const u8 *addr,
+ const u8 *buf, size_t len)
+{
+}
+
+static inline void mbo_ap_sta_free(struct sta_info *sta)
+{
+}
+
+#endif /* CONFIG_MBO */
+
+#endif /* MBO_AP_H */
diff --git a/src/ap/ndisc_snoop.c b/src/ap/ndisc_snoop.c
index 4a87721e2ecf..3c086bfc7131 100644
--- a/src/ap/ndisc_snoop.c
+++ b/src/ap/ndisc_snoop.c
@@ -17,6 +17,7 @@
#include "ap_drv_ops.h"
#include "list.h"
#include "x_snoop.h"
+#include "ndisc_snoop.h"
struct ip6addr {
struct in6_addr addr;
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
new file mode 100644
index 000000000000..a2efff618286
--- /dev/null
+++ b/src/ap/neighbor_db.c
@@ -0,0 +1,133 @@
+/*
+ * hostapd / Neighboring APs DB
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * 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 "neighbor_db.h"
+
+
+struct hostapd_neighbor_entry *
+hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid)
+{
+ struct hostapd_neighbor_entry *nr;
+
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+ list) {
+ if (os_memcmp(bssid, nr->bssid, ETH_ALEN) == 0 &&
+ (!ssid ||
+ (ssid->ssid_len == nr->ssid.ssid_len &&
+ os_memcmp(ssid->ssid, nr->ssid.ssid,
+ ssid->ssid_len) == 0)))
+ return nr;
+ }
+ return NULL;
+}
+
+
+static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
+{
+ wpabuf_free(nr->nr);
+ nr->nr = NULL;
+ wpabuf_free(nr->lci);
+ nr->lci = NULL;
+ wpabuf_free(nr->civic);
+ nr->civic = NULL;
+ os_memset(nr->bssid, 0, sizeof(nr->bssid));
+ os_memset(&nr->ssid, 0, sizeof(nr->ssid));
+}
+
+
+static struct hostapd_neighbor_entry *
+hostapd_neighbor_add(struct hostapd_data *hapd)
+{
+ struct hostapd_neighbor_entry *nr;
+
+ nr = os_zalloc(sizeof(struct hostapd_neighbor_entry));
+ if (!nr)
+ return NULL;
+
+ dl_list_add(&hapd->nr_db, &nr->list);
+
+ return nr;
+}
+
+
+int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid,
+ const struct wpabuf *nr, const struct wpabuf *lci,
+ const struct wpabuf *civic)
+{
+ struct hostapd_neighbor_entry *entry;
+
+ entry = hostapd_neighbor_get(hapd, bssid, ssid);
+ if (!entry)
+ entry = hostapd_neighbor_add(hapd);
+ if (!entry)
+ return -1;
+
+ hostapd_neighbor_clear_entry(entry);
+
+ os_memcpy(entry->bssid, bssid, ETH_ALEN);
+ os_memcpy(&entry->ssid, ssid, sizeof(entry->ssid));
+
+ entry->nr = wpabuf_dup(nr);
+ if (!entry->nr)
+ goto fail;
+
+ if (lci) {
+ entry->lci = wpabuf_dup(lci);
+ if (!entry->lci || os_get_time(&entry->lci_date))
+ goto fail;
+ }
+
+ if (civic) {
+ entry->civic = wpabuf_dup(civic);
+ if (!entry->civic)
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ hostapd_neighbor_remove(hapd, bssid, ssid);
+ return -1;
+}
+
+
+int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid)
+{
+ struct hostapd_neighbor_entry *nr;
+
+ nr = hostapd_neighbor_get(hapd, bssid, ssid);
+ if (!nr)
+ return -1;
+
+ hostapd_neighbor_clear_entry(nr);
+ dl_list_del(&nr->list);
+ os_free(nr);
+
+ return 0;
+}
+
+
+void hostpad_free_neighbor_db(struct hostapd_data *hapd)
+{
+ struct hostapd_neighbor_entry *nr, *prev;
+
+ dl_list_for_each_safe(nr, prev, &hapd->nr_db,
+ struct hostapd_neighbor_entry, list) {
+ hostapd_neighbor_clear_entry(nr);
+ dl_list_del(&nr->list);
+ os_free(nr);
+ }
+}
diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
new file mode 100644
index 000000000000..c22e043c120e
--- /dev/null
+++ b/src/ap/neighbor_db.h
@@ -0,0 +1,24 @@
+/*
+ * hostapd / Neighboring APs DB
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NEIGHBOR_DB_H
+#define NEIGHBOR_DB_H
+
+struct hostapd_neighbor_entry *
+hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid);
+int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid,
+ const struct wpabuf *nr, const struct wpabuf *lci,
+ const struct wpabuf *civic);
+int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid);
+void hostpad_free_neighbor_db(struct hostapd_data *hapd);
+
+#endif /* NEIGHBOR_DB_H */
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 877affe4eadc..d610e7e5b005 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -38,6 +38,7 @@ 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->vlan_desc);
os_free(entry->identity);
wpabuf_free(entry->cui);
#ifndef CONFIG_NO_RADIUS
@@ -91,6 +92,20 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
}
+/**
+ * pmksa_cache_auth_flush - Flush all PMKSA cache entries
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ */
+void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa)
+{
+ while (pmksa->pmksa) {
+ wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry for "
+ MACSTR, MAC2STR(pmksa->pmksa->spa));
+ pmksa_cache_free_entry(pmksa, pmksa->pmksa);
+ }
+}
+
+
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
@@ -126,6 +141,8 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
+ struct vlan_description *vlan_desc;
+
if (eapol == NULL)
return;
@@ -146,14 +163,22 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
#endif /* CONFIG_NO_RADIUS */
entry->eap_type_authsrv = eapol->eap_type_authsrv;
- entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
- entry->acct_multi_session_id_hi = eapol->acct_multi_session_id_hi;
- entry->acct_multi_session_id_lo = eapol->acct_multi_session_id_lo;
+ vlan_desc = ((struct sta_info *) eapol->sta)->vlan_desc;
+ if (vlan_desc && vlan_desc->notempty) {
+ entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
+ if (entry->vlan_desc)
+ *entry->vlan_desc = *vlan_desc;
+ } else {
+ entry->vlan_desc = NULL;
+ }
+
+ entry->acct_multi_session_id = eapol->acct_multi_session_id;
}
-void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
+void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
+ struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
if (entry == NULL || eapol == NULL)
@@ -186,10 +211,11 @@ void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
}
eapol->eap_type_authsrv = entry->eap_type_authsrv;
- ((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
+#ifndef CONFIG_NO_VLAN
+ ap_sta_set_vlan(hapd, eapol->sta, entry->vlan_desc);
+#endif /* CONFIG_NO_VLAN */
- eapol->acct_multi_session_id_hi = entry->acct_multi_session_id_hi;
- eapol->acct_multi_session_id_lo = entry->acct_multi_session_id_lo;
+ eapol->acct_multi_session_id = entry->acct_multi_session_id;
}
@@ -234,6 +260,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
* @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)
+ * @pmkid: Calculated PMKID
* @kck: Key confirmation key or %NULL if not yet derived
* @kck_len: KCK length in bytes
* @aa: Authenticator address
@@ -250,7 +277,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
- const u8 *pmk, size_t pmk_len,
+ const u8 *pmk, size_t pmk_len, const u8 *pmkid,
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp)
@@ -258,7 +285,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry, *pos;
struct os_reltime now;
- if (pmk_len > PMK_LEN)
+ if (pmk_len > PMK_LEN_MAX)
return NULL;
if (wpa_key_mgmt_suite_b(akmp) && !kck)
@@ -269,7 +296,9 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
- if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ if (pmkid)
+ os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
+ else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
else if (wpa_key_mgmt_suite_b(akmp))
rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
@@ -337,7 +366,13 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
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;
+ if (old_entry->vlan_desc) {
+ entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
+ if (entry->vlan_desc)
+ *entry->vlan_desc = *old_entry->vlan_desc;
+ } else {
+ entry->vlan_desc = NULL;
+ }
entry->opportunistic = 1;
pmksa_cache_link_entry(pmksa, entry);
@@ -471,12 +506,11 @@ static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
if (attr->acct_multi_session_id) {
char buf[20];
- if (attr->acct_multi_session_id_len != 17)
+ if (attr->acct_multi_session_id_len != 16)
return 0;
- os_snprintf(buf, sizeof(buf), "%08X+%08X",
- entry->acct_multi_session_id_hi,
- entry->acct_multi_session_id_lo);
- if (os_memcmp(attr->acct_multi_session_id, buf, 17) != 0)
+ os_snprintf(buf, sizeof(buf), "%016llX",
+ (unsigned long long) entry->acct_multi_session_id);
+ if (os_memcmp(attr->acct_multi_session_id, buf, 16) != 0)
return 0;
match++;
}
@@ -526,3 +560,48 @@ int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
return found ? 0 : -1;
}
+
+
+/**
+ * pmksa_cache_auth_list - Dump text list of entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_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_auth_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 / SPA / PMKID / expiration (in seconds) / opportunistic\n");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ i = 0;
+ entry = pmksa->pmksa;
+ while (entry) {
+ ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
+ i, MAC2STR(entry->spa));
+ if (os_snprintf_error(buf + len - pos, ret))
+ 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 (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ entry = entry->next;
+ }
+ return pos - buf;
+}
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index 8b7be1291b53..d8d9c5a25c0e 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -17,7 +17,7 @@
struct rsn_pmksa_cache_entry {
struct rsn_pmksa_cache_entry *next, *hnext;
u8 pmkid[PMKID_LEN];
- u8 pmk[PMK_LEN];
+ u8 pmk[PMK_LEN_MAX];
size_t pmk_len;
os_time_t expiration;
int akmp; /* WPA_KEY_MGMT_* */
@@ -28,11 +28,10 @@ struct rsn_pmksa_cache_entry {
struct wpabuf *cui;
struct radius_class_data radius_class;
u8 eap_type_authsrv;
- int vlan_id;
+ struct vlan_description *vlan_desc;
int opportunistic;
- u32 acct_multi_session_id_hi;
- u32 acct_multi_session_id_lo;
+ u64 acct_multi_session_id;
};
struct rsn_pmksa_cache;
@@ -49,7 +48,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
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 *pmk, size_t pmk_len, const u8 *pmkid,
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp);
@@ -57,11 +56,14 @@ 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,
+void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
+ 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);
int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
struct radius_das_attrs *attr);
+int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
+void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa);
#endif /* PMKSA_CACHE_H */
diff --git a/src/ap/rrm.c b/src/ap/rrm.c
new file mode 100644
index 000000000000..3569f955bcd2
--- /dev/null
+++ b/src/ap/rrm.c
@@ -0,0 +1,544 @@
+/*
+ * hostapd / Radio Measurement (RRM)
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * 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_drv_ops.h"
+#include "sta_info.h"
+#include "eloop.h"
+#include "neighbor_db.h"
+#include "rrm.h"
+
+#define HOSTAPD_RRM_REQUEST_TIMEOUT 5
+
+
+static void hostapd_lci_rep_timeout_handler(void *eloop_data, void *user_ctx)
+{
+ struct hostapd_data *hapd = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "RRM: LCI request (token %u) timed out",
+ hapd->lci_req_token);
+ hapd->lci_req_active = 0;
+}
+
+
+static void hostapd_handle_lci_report(struct hostapd_data *hapd, u8 token,
+ const u8 *pos, size_t len)
+{
+ if (!hapd->lci_req_active || hapd->lci_req_token != token) {
+ wpa_printf(MSG_DEBUG, "Unexpected LCI report, token %u", token);
+ return;
+ }
+
+ hapd->lci_req_active = 0;
+ eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
+ wpa_printf(MSG_DEBUG, "LCI report token %u len %zu", token, len);
+}
+
+
+static void hostapd_range_rep_timeout_handler(void *eloop_data, void *user_ctx)
+{
+ struct hostapd_data *hapd = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "RRM: Range request (token %u) timed out",
+ hapd->range_req_token);
+ hapd->range_req_active = 0;
+}
+
+
+static void hostapd_handle_range_report(struct hostapd_data *hapd, u8 token,
+ const u8 *pos, size_t len)
+{
+ if (!hapd->range_req_active || hapd->range_req_token != token) {
+ wpa_printf(MSG_DEBUG, "Unexpected range report, token %u",
+ token);
+ return;
+ }
+
+ hapd->range_req_active = 0;
+ eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
+ wpa_printf(MSG_DEBUG, "Range report token %u len %zu", token, len);
+}
+
+
+static void hostapd_handle_radio_msmt_report(struct hostapd_data *hapd,
+ const u8 *buf, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+ const u8 *pos, *ie, *end;
+ u8 token;
+
+ end = buf + len;
+ token = mgmt->u.action.u.rrm.dialog_token;
+ pos = mgmt->u.action.u.rrm.variable;
+
+ while ((ie = get_ie(pos, end - pos, WLAN_EID_MEASURE_REPORT))) {
+ if (ie[1] < 5) {
+ wpa_printf(MSG_DEBUG, "Bad Measurement Report element");
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, "Measurement report type %u", ie[4]);
+
+ switch (ie[4]) {
+ case MEASURE_TYPE_LCI:
+ hostapd_handle_lci_report(hapd, token, ie + 2, ie[1]);
+ break;
+ case MEASURE_TYPE_FTM_RANGE:
+ hostapd_handle_range_report(hapd, token, ie + 2, ie[1]);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Measurement report type %u is not supported",
+ ie[4]);
+ break;
+ }
+
+ pos = ie + ie[1] + 2;
+ }
+}
+
+
+static u16 hostapd_parse_location_lci_req_age(const u8 *buf, size_t len)
+{
+ const u8 *subelem;
+
+ /* Range Request element + Location Subject + Maximum Age subelement */
+ if (len < 3 + 1 + 4)
+ return 0;
+
+ /* Subelements are arranged as IEs */
+ subelem = get_ie(buf + 4, len - 4, LCI_REQ_SUBELEM_MAX_AGE);
+ if (subelem && subelem[1] == 2)
+ return *(u16 *) (subelem + 2);
+
+ return 0;
+}
+
+
+static int hostapd_check_lci_age(struct hostapd_neighbor_entry *nr, u16 max_age)
+{
+ struct os_time curr, diff;
+ unsigned long diff_l;
+
+ if (!max_age)
+ return 0;
+
+ if (max_age == 0xffff)
+ return 1;
+
+ if (os_get_time(&curr))
+ return 0;
+
+ os_time_sub(&curr, &nr->lci_date, &diff);
+
+ /* avoid overflow */
+ if (diff.sec > 0xffff)
+ return 0;
+
+ /* LCI age is calculated in 10th of a second units. */
+ diff_l = diff.sec * 10 + diff.usec / 100000;
+
+ return max_age > diff_l;
+}
+
+
+static size_t hostapd_neighbor_report_len(struct wpabuf *buf,
+ struct hostapd_neighbor_entry *nr,
+ int send_lci, int send_civic)
+{
+ size_t len = 2 + wpabuf_len(nr->nr);
+
+ if (send_lci && nr->lci)
+ len += 2 + wpabuf_len(nr->lci);
+
+ if (send_civic && nr->civic)
+ len += 2 + wpabuf_len(nr->civic);
+
+ return len;
+}
+
+
+static void hostapd_send_nei_report_resp(struct hostapd_data *hapd,
+ const u8 *addr, u8 dialog_token,
+ struct wpa_ssid_value *ssid, u8 lci,
+ u8 civic, u16 lci_max_age)
+{
+ struct hostapd_neighbor_entry *nr;
+ struct wpabuf *buf;
+ u8 *msmt_token;
+
+ /*
+ * The number and length of the Neighbor Report elements in a Neighbor
+ * Report frame is limited by the maximum allowed MMPDU size; + 3 bytes
+ * of RRM header.
+ */
+ buf = wpabuf_alloc(3 + IEEE80211_MAX_MMPDU_SIZE);
+ if (!buf)
+ return;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_RESPONSE);
+ wpabuf_put_u8(buf, dialog_token);
+
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+ list) {
+ int send_lci;
+ size_t len;
+
+ if (ssid->ssid_len != nr->ssid.ssid_len ||
+ os_memcmp(ssid->ssid, nr->ssid.ssid, ssid->ssid_len) != 0)
+ continue;
+
+ send_lci = (lci != 0) && hostapd_check_lci_age(nr, lci_max_age);
+ len = hostapd_neighbor_report_len(buf, nr, send_lci, civic);
+
+ if (len - 2 > 0xff) {
+ wpa_printf(MSG_DEBUG,
+ "NR entry for " MACSTR " exceeds 0xFF bytes",
+ MAC2STR(nr->bssid));
+ continue;
+ }
+
+ if (len > wpabuf_tailroom(buf))
+ break;
+
+ wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
+ wpabuf_put_u8(buf, len - 2);
+ wpabuf_put_buf(buf, nr->nr);
+
+ if (send_lci && nr->lci) {
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
+ wpabuf_put_u8(buf, wpabuf_len(nr->lci));
+ /*
+ * Override measurement token - the first byte of the
+ * Measurement Report element.
+ */
+ msmt_token = wpabuf_put(buf, 0);
+ wpabuf_put_buf(buf, nr->lci);
+ *msmt_token = lci;
+ }
+
+ if (civic && nr->civic) {
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
+ wpabuf_put_u8(buf, wpabuf_len(nr->civic));
+ /*
+ * Override measurement token - the first byte of the
+ * Measurement Report element.
+ */
+ msmt_token = wpabuf_put(buf, 0);
+ wpabuf_put_buf(buf, nr->civic);
+ *msmt_token = civic;
+ }
+ }
+
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+}
+
+
+static void hostapd_handle_nei_report_req(struct hostapd_data *hapd,
+ const u8 *buf, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+ const u8 *pos, *ie, *end;
+ struct wpa_ssid_value ssid = {
+ .ssid_len = 0
+ };
+ u8 token;
+ u8 lci = 0, civic = 0; /* Measurement tokens */
+ u16 lci_max_age = 0;
+
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT))
+ return;
+
+ end = buf + len;
+
+ token = mgmt->u.action.u.rrm.dialog_token;
+ pos = mgmt->u.action.u.rrm.variable;
+ len = end - pos;
+
+ ie = get_ie(pos, len, WLAN_EID_SSID);
+ if (ie && ie[1] && ie[1] <= SSID_MAX_LEN) {
+ ssid.ssid_len = ie[1];
+ os_memcpy(ssid.ssid, ie + 2, ssid.ssid_len);
+ } else {
+ ssid.ssid_len = hapd->conf->ssid.ssid_len;
+ os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
+ }
+
+ while ((ie = get_ie(pos, len, WLAN_EID_MEASURE_REQUEST))) {
+ if (ie[1] < 3)
+ break;
+
+ wpa_printf(MSG_DEBUG,
+ "Neighbor report request, measure type %u",
+ ie[4]);
+
+ switch (ie[4]) { /* Measurement Type */
+ case MEASURE_TYPE_LCI:
+ lci = ie[2]; /* Measurement Token */
+ lci_max_age = hostapd_parse_location_lci_req_age(ie + 2,
+ ie[1]);
+ break;
+ case MEASURE_TYPE_LOCATION_CIVIC:
+ civic = ie[2]; /* Measurement token */
+ break;
+ }
+
+ pos = ie + ie[1] + 2;
+ len = end - pos;
+ }
+
+ hostapd_send_nei_report_resp(hapd, mgmt->sa, token, &ssid, lci, civic,
+ lci_max_age);
+}
+
+
+void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
+ const u8 *buf, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+
+ /*
+ * Check for enough bytes: header + (1B)Category + (1B)Action +
+ * (1B)Dialog Token.
+ */
+ if (len < IEEE80211_HDRLEN + 3)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Radio measurement frame, action %u from " MACSTR,
+ mgmt->u.action.u.rrm.action, MAC2STR(mgmt->sa));
+
+ switch (mgmt->u.action.u.rrm.action) {
+ case WLAN_RRM_RADIO_MEASUREMENT_REPORT:
+ hostapd_handle_radio_msmt_report(hapd, buf, len);
+ break;
+ case WLAN_RRM_NEIGHBOR_REPORT_REQUEST:
+ hostapd_handle_nei_report_req(hapd, buf, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "RRM action %u is not supported",
+ mgmt->u.action.u.rrm.action);
+ break;
+ }
+}
+
+
+int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr)
+{
+ struct wpabuf *buf;
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+ int ret;
+
+ if (!sta) {
+ wpa_printf(MSG_INFO,
+ "Request LCI: Destination address is not in station list");
+ return -1;
+ }
+
+ if (!(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_INFO,
+ "Request LCI: Destination address is not connected");
+ return -1;
+ }
+
+ if (!(sta->rrm_enabled_capa[1] & WLAN_RRM_CAPS_LCI_MEASUREMENT)) {
+ wpa_printf(MSG_INFO,
+ "Request LCI: Station does not support LCI in RRM");
+ return -1;
+ }
+
+ if (hapd->lci_req_active) {
+ wpa_printf(MSG_DEBUG,
+ "Request LCI: LCI request is already in process, overriding");
+ hapd->lci_req_active = 0;
+ eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd,
+ NULL);
+ }
+
+ /* Measurement request (5) + Measurement element with LCI (10) */
+ buf = wpabuf_alloc(5 + 10);
+ if (!buf)
+ return -1;
+
+ hapd->lci_req_token++;
+ /* For wraparounds - the token must be nonzero */
+ if (!hapd->lci_req_token)
+ hapd->lci_req_token++;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
+ wpabuf_put_u8(buf, hapd->lci_req_token);
+ wpabuf_put_le16(buf, 0); /* Number of repetitions */
+
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ wpabuf_put_u8(buf, 3 + 1 + 4);
+
+ wpabuf_put_u8(buf, 1); /* Measurement Token */
+ /*
+ * Parallel and Enable bits are 0, Duration, Request, and Report are
+ * reserved.
+ */
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_u8(buf, MEASURE_TYPE_LCI);
+
+ wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+
+ wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
+ wpabuf_put_u8(buf, 2);
+ wpabuf_put_le16(buf, 0xffff);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+ if (ret)
+ return ret;
+
+ hapd->lci_req_active = 1;
+
+ eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
+ hostapd_lci_rep_timeout_handler, hapd, NULL);
+
+ return 0;
+}
+
+
+int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
+ u16 random_interval, u8 min_ap,
+ const u8 *responders, unsigned int n_responders)
+{
+ struct wpabuf *buf;
+ struct sta_info *sta;
+ u8 *len;
+ unsigned int i;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "Request range: dest addr " MACSTR
+ " rand interval %u min AP %u n_responders %u", MAC2STR(addr),
+ random_interval, min_ap, n_responders);
+
+ if (min_ap == 0 || min_ap > n_responders) {
+ wpa_printf(MSG_INFO, "Request range: Wrong min AP count");
+ return -1;
+ }
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_INFO,
+ "Request range: Destination address is not connected");
+ return -1;
+ }
+
+ if (!(sta->rrm_enabled_capa[4] & WLAN_RRM_CAPS_FTM_RANGE_REPORT)) {
+ wpa_printf(MSG_ERROR,
+ "Request range: Destination station does not support FTM range report in RRM");
+ return -1;
+ }
+
+ if (hapd->range_req_active) {
+ wpa_printf(MSG_DEBUG,
+ "Request range: Range request is already in process; overriding");
+ hapd->range_req_active = 0;
+ eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
+ hostapd_range_rep_timeout_handler, hapd,
+ NULL);
+ }
+
+ /* Action + measurement type + token + reps + EID + len = 7 */
+ buf = wpabuf_alloc(7 + 255);
+ if (!buf)
+ return -1;
+
+ hapd->range_req_token++;
+ if (!hapd->range_req_token) /* For wraparounds */
+ hapd->range_req_token++;
+
+ /* IEEE P802.11-REVmc/D5.0, 9.6.7.2 */
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
+ wpabuf_put_u8(buf, hapd->range_req_token); /* Dialog Token */
+ wpabuf_put_le16(buf, 0); /* Number of Repetitions */
+
+ /* IEEE P802.11-REVmc/D5.0, 9.4.2.21 */
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ len = wpabuf_put(buf, 1); /* Length will be set later */
+
+ wpabuf_put_u8(buf, 1); /* Measurement Token */
+ /*
+ * Parallel and Enable bits are 0; Duration, Request, and Report are
+ * reserved.
+ */
+ wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+ wpabuf_put_u8(buf, MEASURE_TYPE_FTM_RANGE); /* Measurement Type */
+
+ /* IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 */
+ wpabuf_put_le16(buf, random_interval); /* Randomization Interval */
+ wpabuf_put_u8(buf, min_ap); /* Minimum AP Count */
+
+ /* FTM Range Subelements */
+
+ /*
+ * Taking the neighbor report part of the range request from neighbor
+ * database instead of requesting the separate bits of data from the
+ * user.
+ */
+ for (i = 0; i < n_responders; i++) {
+ struct hostapd_neighbor_entry *nr;
+
+ nr = hostapd_neighbor_get(hapd, responders + ETH_ALEN * i,
+ NULL);
+ if (!nr) {
+ wpa_printf(MSG_INFO, "Missing neighbor report for "
+ MACSTR, MAC2STR(responders + ETH_ALEN * i));
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ if (wpabuf_tailroom(buf) < 2 + wpabuf_len(nr->nr)) {
+ wpa_printf(MSG_ERROR, "Too long range request");
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
+ wpabuf_put_u8(buf, wpabuf_len(nr->nr));
+ wpabuf_put_buf(buf, nr->nr);
+ }
+
+ /* Action + measurement type + token + reps + EID + len = 7 */
+ *len = wpabuf_len(buf) - 7;
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+ if (ret)
+ return ret;
+
+ hapd->range_req_active = 1;
+
+ eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
+ hostapd_range_rep_timeout_handler, hapd, NULL);
+
+ return 0;
+}
+
+
+void hostapd_clean_rrm(struct hostapd_data *hapd)
+{
+ hostpad_free_neighbor_db(hapd);
+ eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
+ hapd->lci_req_active = 0;
+ eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
+ hapd->range_req_active = 0;
+}
diff --git a/src/ap/rrm.h b/src/ap/rrm.h
new file mode 100644
index 000000000000..f07fd41ac019
--- /dev/null
+++ b/src/ap/rrm.h
@@ -0,0 +1,28 @@
+/*
+ * hostapd / Radio Measurement (RRM)
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RRM_H
+#define RRM_H
+
+/*
+ * Max measure request length is 255, -6 of the body we have 249 for the
+ * neighbor report elements. Each neighbor report element is at least 2 + 13
+ * bytes, so we can't have more than 16 responders in the request.
+ */
+#define RRM_RANGE_REQ_MAX_RESPONDERS 16
+
+void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
+ const u8 *buf, size_t len);
+int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr);
+int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
+ u16 random_interval, u8 min_ap,
+ const u8 *responders, unsigned int n_responders);
+void hostapd_clean_rrm(struct hostapd_data *hapd);
+
+#endif /* RRM_H */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index d64307ccfd08..f12d4088b131 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -32,8 +32,10 @@
#include "ap_drv_ops.h"
#include "gas_serv.h"
#include "wnm_ap.h"
+#include "mbo_ap.h"
#include "ndisc_snoop.h"
#include "sta_info.h"
+#include "vlan.h"
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
struct sta_info *sta);
@@ -169,21 +171,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
ap_sta_ip6addr_del(hapd, sta);
if (!hapd->iface->driver_ap_teardown &&
- !(sta->flags & WLAN_STA_PREAUTH))
+ !(sta->flags & WLAN_STA_PREAUTH)) {
hostapd_drv_sta_remove(hapd, sta->addr);
-
-#ifndef CONFIG_NO_VLAN
- if (sta->vlan_id_bound) {
- /*
- * Need to remove the STA entry before potentially removing the
- * VLAN.
- */
- if (hapd->iface->driver_ap_teardown &&
- !(sta->flags & WLAN_STA_PREAUTH))
- hostapd_drv_sta_remove(hapd, sta->addr);
- vlan_remove_dynamic(hapd, sta->vlan_id_bound);
+ sta->added_unassoc = 0;
}
-#endif /* CONFIG_NO_VLAN */
ap_sta_hash_del(hapd, sta);
ap_sta_list_del(hapd, sta);
@@ -231,6 +222,13 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
hapd->iface->num_sta_ht_20mhz--;
}
+#ifdef CONFIG_TAXONOMY
+ wpabuf_free(sta->probe_ie_taxonomy);
+ sta->probe_ie_taxonomy = NULL;
+ wpabuf_free(sta->assoc_ie_taxonomy);
+ sta->assoc_ie_taxonomy = NULL;
+#endif /* CONFIG_TAXONOMY */
+
#ifdef CONFIG_IEEE80211N
ht40_intolerant_remove(hapd->iface, sta);
#endif /* CONFIG_IEEE80211N */
@@ -251,7 +249,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
#ifdef CONFIG_MESH
if (hapd->mesh_sta_free_cb)
- hapd->mesh_sta_free_cb(sta);
+ hapd->mesh_sta_free_cb(hapd, sta);
#endif /* CONFIG_MESH */
if (set_beacon)
@@ -262,11 +260,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
- eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
- eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+ ap_sta_clear_disconnect_timeouts(hapd, sta);
sae_clear_retransmit_timer(hapd, sta);
- ieee802_1x_free_station(sta);
+ ieee802_1x_free_station(hapd, sta);
wpa_auth_sta_deinit(sta->wpa_sm);
rsn_preauth_free_station(hapd, sta);
#ifndef CONFIG_NO_RADIUS
@@ -274,6 +271,28 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
radius_client_flush_auth(hapd->radius, sta->addr);
#endif /* CONFIG_NO_RADIUS */
+#ifndef CONFIG_NO_VLAN
+ /*
+ * sta->wpa_sm->group needs to be released before so that
+ * vlan_remove_dynamic() can check that no stations are left on the
+ * AP_VLAN netdev.
+ */
+ if (sta->vlan_id)
+ vlan_remove_dynamic(hapd, sta->vlan_id);
+ if (sta->vlan_id_bound) {
+ /*
+ * Need to remove the STA entry before potentially removing the
+ * VLAN.
+ */
+ if (hapd->iface->driver_ap_teardown &&
+ !(sta->flags & WLAN_STA_PREAUTH)) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
+ vlan_remove_dynamic(hapd, sta->vlan_id_bound);
+ }
+#endif /* CONFIG_NO_VLAN */
+
os_free(sta->challenge);
#ifdef CONFIG_IEEE80211W
@@ -315,6 +334,9 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->sae);
#endif /* CONFIG_SAE */
+ mbo_ap_sta_free(sta);
+ os_free(sta->supp_op_classes);
+
os_free(sta);
}
@@ -354,8 +376,8 @@ void ap_handle_timer(void *eloop_ctx, void *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,
+ wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
+ hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
sta->timeout_next);
if (sta->timeout_next == STA_REMOVE) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -482,7 +504,7 @@ skip_poll:
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
accounting_sta_stop(hapd, sta);
- ieee802_1x_free_station(sta);
+ ieee802_1x_free_station(hapd, sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated due to "
"inactivity");
@@ -519,6 +541,8 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
+ wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
if (!(sta->flags & WLAN_STA_AUTH)) {
if (sta->flags & WLAN_STA_GAS) {
wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
@@ -577,8 +601,8 @@ static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx)
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
- wpa_printf(MSG_DEBUG, "WNM: Session warning time reached for " MACSTR,
- MAC2STR(sta->addr));
+ wpa_printf(MSG_DEBUG, "%s: WNM: Session warning time reached for "
+ MACSTR, hapd->conf->iface, MAC2STR(sta->addr));
if (sta->hs20_session_info_url == NULL)
return;
@@ -619,7 +643,10 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
return NULL;
}
sta->acct_interim_interval = hapd->conf->acct_interim_interval;
- accounting_sta_get_id(hapd, sta);
+ if (accounting_sta_get_id(hapd, sta) < 0) {
+ os_free(sta);
+ return NULL;
+ }
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
@@ -640,6 +667,11 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
dl_list_init(&sta->ip6addr);
+#ifdef CONFIG_TAXONOMY
+ sta_track_claim_taxonomy_info(hapd->iface, addr,
+ &sta->probe_ie_taxonomy);
+#endif /* CONFIG_TAXONOMY */
+
return sta;
}
@@ -652,14 +684,16 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
ap_sta_ip6addr_del(hapd, sta);
- wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
- MAC2STR(sta->addr));
+ wpa_printf(MSG_DEBUG, "%s: Removing STA " MACSTR " from kernel driver",
+ hapd->conf->iface, 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));
+ wpa_printf(MSG_DEBUG, "%s: Could not remove station " MACSTR
+ " from kernel driver",
+ hapd->conf->iface, MAC2STR(sta->addr));
return -1;
}
+ sta->added_unassoc = 0;
return 0;
}
@@ -683,6 +717,10 @@ static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
if (!sta2)
continue;
+ wpa_printf(MSG_DEBUG, "%s: disconnect old STA " MACSTR
+ " association from another BSS %s",
+ hapd->conf->iface, MAC2STR(sta2->addr),
+ bss->conf->iface);
ap_sta_disconnect(bss, sta2, sta2->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
}
@@ -694,6 +732,8 @@ 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;
+ wpa_printf(MSG_DEBUG, "%s: Disassociation callback for STA " MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
ap_sta_remove(hapd, sta);
mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
}
@@ -717,7 +757,7 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *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);
+ ieee802_1x_free_station(hapd, sta);
sta->disassoc_reason = reason;
sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
@@ -733,6 +773,8 @@ 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;
+ wpa_printf(MSG_DEBUG, "%s: Deauthentication callback for STA " MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
ap_sta_remove(hapd, sta);
mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
}
@@ -756,7 +798,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *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);
+ ieee802_1x_free_station(hapd, sta);
sta->deauth_reason = reason;
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
@@ -784,6 +826,128 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
#endif /* CONFIG_WPS */
+static int ap_sta_get_free_vlan_id(struct hostapd_data *hapd)
+{
+ struct hostapd_vlan *vlan;
+ int vlan_id = MAX_VLAN_ID + 2;
+
+retry:
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ if (vlan->vlan_id == vlan_id) {
+ vlan_id++;
+ goto retry;
+ }
+ }
+ return vlan_id;
+}
+
+
+int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+ struct vlan_description *vlan_desc)
+{
+ struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
+ int old_vlan_id, vlan_id = 0, ret = 0;
+
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+ vlan_desc = NULL;
+
+ /* Check if there is something to do */
+ if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) {
+ /* This sta is lacking its own vif */
+ } else if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED &&
+ !hapd->conf->ssid.per_sta_vif && sta->vlan_id) {
+ /* sta->vlan_id needs to be reset */
+ } else if (!vlan_compare(vlan_desc, sta->vlan_desc)) {
+ return 0; /* nothing to change */
+ }
+
+ /* Now the real VLAN changed or the STA just needs its own vif */
+ if (hapd->conf->ssid.per_sta_vif) {
+ /* Assign a new vif, always */
+ /* find a free vlan_id sufficiently big */
+ vlan_id = ap_sta_get_free_vlan_id(hapd);
+ /* Get wildcard VLAN */
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ if (vlan->vlan_id == VLAN_ID_WILDCARD)
+ break;
+ }
+ if (!vlan) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "per_sta_vif missing wildcard");
+ vlan_id = 0;
+ ret = -1;
+ goto done;
+ }
+ } else if (vlan_desc && vlan_desc->notempty) {
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ if (!vlan_compare(&vlan->vlan_desc, vlan_desc))
+ break;
+ if (vlan->vlan_id == VLAN_ID_WILDCARD)
+ wildcard_vlan = vlan;
+ }
+ if (vlan) {
+ vlan_id = vlan->vlan_id;
+ } else if (wildcard_vlan) {
+ vlan = wildcard_vlan;
+ vlan_id = vlan_desc->untagged;
+ if (vlan_desc->tagged[0]) {
+ /* Tagged VLAN configuration */
+ vlan_id = ap_sta_get_free_vlan_id(hapd);
+ }
+ } else {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "missing vlan and wildcard for vlan=%d%s",
+ vlan_desc->untagged,
+ vlan_desc->tagged[0] ? "+" : "");
+ vlan_id = 0;
+ ret = -1;
+ goto done;
+ }
+ }
+
+ if (vlan && vlan->vlan_id == VLAN_ID_WILDCARD) {
+ vlan = vlan_add_dynamic(hapd, vlan, vlan_id, vlan_desc);
+ if (vlan == NULL) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "could not add dynamic VLAN interface for vlan=%d%s",
+ vlan_desc ? vlan_desc->untagged : -1,
+ (vlan_desc && vlan_desc->tagged[0]) ?
+ "+" : "");
+ vlan_id = 0;
+ ret = -1;
+ goto done;
+ }
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "added new dynamic VLAN interface '%s'",
+ vlan->ifname);
+ } else if (vlan && vlan->dynamic_vlan > 0) {
+ vlan->dynamic_vlan++;
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "updated existing dynamic VLAN interface '%s'",
+ vlan->ifname);
+ }
+done:
+ old_vlan_id = sta->vlan_id;
+ sta->vlan_id = vlan_id;
+ sta->vlan_desc = vlan ? &vlan->vlan_desc : NULL;
+
+ if (vlan_id != old_vlan_id && old_vlan_id)
+ vlan_remove_dynamic(hapd, old_vlan_id);
+
+ return ret;
+}
+
+
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
{
#ifndef CONFIG_NO_VLAN
@@ -796,20 +960,11 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
if (hapd->conf->ssid.vlan[0])
iface = hapd->conf->ssid.vlan;
- if (hapd->conf->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 (sta->vlan_id > 0) {
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
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;
}
@@ -829,54 +984,13 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
sta->vlan_id);
ret = -1;
goto done;
- } 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);
- ret = -1;
- goto done;
- }
-
- iface = vlan->ifname;
- if (vlan_setup_encryption_dyn(hapd, 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 (vlan->dynamic_vlan > 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, 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);
- }
+ } else if (vlan && vlan->dynamic_vlan > 0) {
+ vlan->dynamic_vlan++;
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "updated existing dynamic VLAN interface '%s'",
+ iface);
}
/* ref counters have been increased, so mark the station */
@@ -942,6 +1056,10 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
unsigned int timeout, sec, usec;
u8 *trans_id, *nbuf;
+ wpa_printf(MSG_DEBUG, "%s: SA Query timer for STA " MACSTR
+ " (count=%d)",
+ hapd->conf->iface, MAC2STR(sta->addr), sta->sa_query_count);
+
if (sta->sa_query_count > 0 &&
ap_check_sa_query_timeout(hapd, sta))
return;
@@ -1080,6 +1198,14 @@ void ap_sta_set_authorized(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)
{
+ if (sta)
+ wpa_printf(MSG_DEBUG, "%s: %s STA " MACSTR " reason=%u",
+ hapd->conf->iface, __func__, MAC2STR(sta->addr),
+ reason);
+ else if (addr)
+ wpa_printf(MSG_DEBUG, "%s: %s addr " MACSTR " reason=%u",
+ hapd->conf->iface, __func__, MAC2STR(addr),
+ reason);
if (sta == NULL && addr)
sta = ap_get_sta(hapd, addr);
@@ -1093,10 +1219,10 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
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 "
+ wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
- __func__, MAC2STR(sta->addr),
+ hapd->conf->iface, __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,
@@ -1136,6 +1262,22 @@ void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
}
+void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ if (eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta) > 0)
+ wpa_printf(MSG_DEBUG,
+ "%s: Removed ap_sta_deauth_cb_timeout timeout for "
+ MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
+ if (eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta) > 0)
+ wpa_printf(MSG_DEBUG,
+ "%s: Removed ap_sta_disassoc_cb_timeout timeout for "
+ MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
+}
+
+
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
{
int res;
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 420d64e5793b..099de62d1a9a 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -12,9 +12,11 @@
#ifdef CONFIG_MESH
/* needed for mesh_plink_state enum */
#include "common/defs.h"
+#include "common/wpa_common.h"
#endif /* CONFIG_MESH */
#include "list.h"
+#include "vlan.h"
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
@@ -45,6 +47,20 @@
#define WLAN_SUPP_RATES_MAX 32
+struct mbo_non_pref_chan_info {
+ struct mbo_non_pref_chan_info *next;
+ u8 op_class;
+ u8 pref;
+ u8 reason_code;
+ u8 num_channels;
+ u8 channels[];
+};
+
+struct pending_eapol_rx {
+ struct wpabuf *buf;
+ struct os_reltime rx_time;
+};
+
struct sta_info {
struct sta_info *next; /* next entry in sta list */
struct sta_info *hnext; /* next entry in hash table list */
@@ -63,13 +79,22 @@ struct sta_info {
enum mesh_plink_state plink_state;
u16 peer_lid;
u16 my_lid;
+ u16 peer_aid;
u16 mpm_close_reason;
int mpm_retries;
- u8 my_nonce[32];
- u8 peer_nonce[32];
+ u8 my_nonce[WPA_NONCE_LEN];
+ u8 peer_nonce[WPA_NONCE_LEN];
u8 aek[32]; /* SHA256 digest length */
- u8 mtk[16];
- u8 mgtk[16];
+ u8 mtk[WPA_TK_MAX_LEN];
+ size_t mtk_len;
+ u8 mgtk_rsc[6];
+ u8 mgtk_key_id;
+ u8 mgtk[WPA_TK_MAX_LEN];
+ size_t mgtk_len;
+ u8 igtk_rsc[6];
+ u8 igtk[WPA_TK_MAX_LEN];
+ size_t igtk_len;
+ u16 igtk_key_id;
u8 sae_auth_retry;
#endif /* CONFIG_MESH */
@@ -86,6 +111,8 @@ struct sta_info {
unsigned int hs20_deauth_requested:1;
unsigned int session_timeout_set:1;
unsigned int radius_das_match:1;
+ unsigned int ecsa_supported:1;
+ unsigned int added_unassoc:1;
u16 auth_alg;
@@ -100,17 +127,20 @@ struct sta_info {
/* IEEE 802.1X related data */
struct eapol_state_machine *eapol_sm;
- u32 acct_session_id_hi;
- u32 acct_session_id_lo;
+ struct pending_eapol_rx *pending_eapol_rx;
+
+ u64 acct_session_id;
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 int acct_interim_errors;
- unsigned long last_rx_bytes;
- unsigned long last_tx_bytes;
- u32 acct_input_gigawords; /* Acct-Input-Gigawords */
- u32 acct_output_gigawords; /* Acct-Output-Gigawords */
+ /* For extending 32-bit driver counters to 64-bit counters */
+ u32 last_rx_bytes_hi;
+ u32 last_rx_bytes_lo;
+ u32 last_tx_bytes_hi;
+ u32 last_tx_bytes_lo;
u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
@@ -118,6 +148,7 @@ struct sta_info {
struct rsn_preauth_interface *preauth_iface;
int vlan_id; /* 0: none, >0: VID */
+ struct vlan_description *vlan_desc;
int vlan_id_bound; /* updated by ap_sta_bind_vlan() */
/* PSKs from RADIUS authentication server */
struct hostapd_sta_wpa_psk_short *psk;
@@ -161,6 +192,7 @@ struct sta_info {
#ifdef CONFIG_SAE
struct sae_data *sae;
+ unsigned int mesh_sae_pmksa_caching:1;
#endif /* CONFIG_SAE */
u32 session_timeout; /* valid only if session_timeout_set == 1 */
@@ -170,6 +202,22 @@ struct sta_info {
u16 last_seq_ctrl;
/* Last Authentication/(Re)Association Request/Action frame subtype */
u8 last_subtype;
+
+#ifdef CONFIG_MBO
+ u8 cell_capa; /* 0 = unknown (not an MBO STA); otherwise,
+ * enum mbo_cellular_capa values */
+ struct mbo_non_pref_chan_info *non_pref_chan;
+#endif /* CONFIG_MBO */
+
+ u8 *supp_op_classes; /* Supported Operating Classes element, if
+ * received, starting from the Length field */
+
+ u8 rrm_enabled_capa[5];
+
+#ifdef CONFIG_TAXONOMY
+ struct wpabuf *probe_ie_taxonomy;
+ struct wpabuf *assoc_ie_taxonomy;
+#endif /* CONFIG_TAXONOMY */
};
@@ -180,7 +228,7 @@ struct sta_info {
* 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_DISASSOC_DELAY (3)
#define AP_DEAUTH_DELAY (1)
/* Number of seconds to keep STA entry with Authenticated flag after it has
* been disassociated. */
@@ -220,6 +268,8 @@ 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 ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+ struct vlan_description *vlan_desc);
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);
@@ -235,6 +285,8 @@ static inline int ap_sta_is_authorized(struct sta_info *sta)
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);
+void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
+ struct sta_info *sta);
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
diff --git a/src/ap/taxonomy.c b/src/ap/taxonomy.c
new file mode 100644
index 000000000000..cea8b726f47a
--- /dev/null
+++ b/src/ap/taxonomy.c
@@ -0,0 +1,291 @@
+/*
+ * hostapd / Client taxonomy
+ * Copyright (c) 2015 Google, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * Parse a series of IEs, as in Probe Request or (Re)Association Request frames,
+ * and render them to a descriptive string. The tag number of standard options
+ * is written to the string, while the vendor ID and subtag are written for
+ * vendor options.
+ *
+ * Example strings:
+ * 0,1,50,45,221(00904c,51)
+ * 0,1,33,36,48,45,221(00904c,51),221(0050f2,2)
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/wpa_ctrl.h"
+#include "hostapd.h"
+#include "sta_info.h"
+
+
+/* Copy a string with no funny schtuff allowed; only alphanumerics. */
+static void no_mischief_strncpy(char *dst, const char *src, size_t n)
+{
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ unsigned char s = src[i];
+ int is_lower = s >= 'a' && s <= 'z';
+ int is_upper = s >= 'A' && s <= 'Z';
+ int is_digit = s >= '0' && s <= '9';
+
+ if (is_lower || is_upper || is_digit) {
+ /* TODO: if any manufacturer uses Unicode within the
+ * WPS header, it will get mangled here. */
+ dst[i] = s;
+ } else {
+ /* Note that even spaces will be transformed to
+ * underscores, so 'Nexus 7' will turn into 'Nexus_7'.
+ * This is deliberate, to make the string easier to
+ * parse. */
+ dst[i] = '_';
+ }
+ }
+}
+
+
+static int get_wps_name(char *name, size_t name_len,
+ const u8 *data, size_t data_len)
+{
+ /* Inside the WPS IE are a series of attributes, using two byte IDs
+ * and two byte lengths. We're looking for the model name, if
+ * present. */
+ while (data_len >= 4) {
+ u16 id, elen;
+
+ id = WPA_GET_BE16(data);
+ elen = WPA_GET_BE16(data + 2);
+ data += 4;
+ data_len -= 4;
+
+ if (elen > data_len)
+ return 0;
+
+ if (id == 0x1023) {
+ /* Model name, like 'Nexus 7' */
+ size_t n = (elen < name_len) ? elen : name_len;
+ no_mischief_strncpy(name, (const char *) data, n);
+ return n;
+ }
+
+ data += elen;
+ data_len -= elen;
+ }
+
+ return 0;
+}
+
+
+static void ie_to_string(char *fstr, size_t fstr_len, const struct wpabuf *ies)
+{
+ char *fpos = fstr;
+ char *fend = fstr + fstr_len;
+ char htcap[7 + 4 + 1]; /* ",htcap:" + %04hx + trailing NUL */
+ char htagg[7 + 2 + 1]; /* ",htagg:" + %02hx + trailing NUL */
+ char htmcs[7 + 8 + 1]; /* ",htmcs:" + %08x + trailing NUL */
+ char vhtcap[8 + 8 + 1]; /* ",vhtcap:" + %08x + trailing NUL */
+ char vhtrxmcs[10 + 8 + 1]; /* ",vhtrxmcs:" + %08x + trailing NUL */
+ char vhttxmcs[10 + 8 + 1]; /* ",vhttxmcs:" + %08x + trailing NUL */
+#define MAX_EXTCAP 254
+ char extcap[8 + 2 * MAX_EXTCAP + 1]; /* ",extcap:" + hex + trailing NUL
+ */
+ char txpow[7 + 4 + 1]; /* ",txpow:" + %04hx + trailing NUL */
+#define WPS_NAME_LEN 32
+ char wps[WPS_NAME_LEN + 5 + 1]; /* room to prepend ",wps:" + trailing
+ * NUL */
+ int num = 0;
+ const u8 *ie;
+ size_t ie_len;
+ int ret;
+
+ os_memset(htcap, 0, sizeof(htcap));
+ os_memset(htagg, 0, sizeof(htagg));
+ os_memset(htmcs, 0, sizeof(htmcs));
+ os_memset(vhtcap, 0, sizeof(vhtcap));
+ os_memset(vhtrxmcs, 0, sizeof(vhtrxmcs));
+ os_memset(vhttxmcs, 0, sizeof(vhttxmcs));
+ os_memset(extcap, 0, sizeof(extcap));
+ os_memset(txpow, 0, sizeof(txpow));
+ os_memset(wps, 0, sizeof(wps));
+ *fpos = '\0';
+
+ if (!ies)
+ return;
+ ie = wpabuf_head(ies);
+ ie_len = wpabuf_len(ies);
+
+ while (ie_len >= 2) {
+ u8 id, elen;
+ char *sep = (num++ == 0) ? "" : ",";
+
+ id = *ie++;
+ elen = *ie++;
+ ie_len -= 2;
+
+ if (elen > ie_len)
+ break;
+
+ if (id == WLAN_EID_VENDOR_SPECIFIC && elen >= 4) {
+ /* Vendor specific */
+ if (WPA_GET_BE32(ie) == WPS_IE_VENDOR_TYPE) {
+ /* WPS */
+ char model_name[WPS_NAME_LEN + 1];
+ const u8 *data = &ie[4];
+ size_t data_len = elen - 4;
+
+ os_memset(model_name, 0, sizeof(model_name));
+ if (get_wps_name(model_name, WPS_NAME_LEN, data,
+ data_len)) {
+ os_snprintf(wps, sizeof(wps),
+ ",wps:%s", model_name);
+ }
+ }
+
+ ret = os_snprintf(fpos, fend - fpos,
+ "%s%d(%02x%02x%02x,%d)",
+ sep, id, ie[0], ie[1], ie[2], ie[3]);
+ } else {
+ if (id == WLAN_EID_HT_CAP && elen >= 2) {
+ /* HT Capabilities (802.11n) */
+ os_snprintf(htcap, sizeof(htcap),
+ ",htcap:%04hx",
+ WPA_GET_LE16(ie));
+ }
+ if (id == WLAN_EID_HT_CAP && elen >= 3) {
+ /* HT Capabilities (802.11n), A-MPDU information
+ */
+ os_snprintf(htagg, sizeof(htagg),
+ ",htagg:%02hx", (u16) ie[2]);
+ }
+ if (id == WLAN_EID_HT_CAP && elen >= 7) {
+ /* HT Capabilities (802.11n), MCS information */
+ os_snprintf(htmcs, sizeof(htmcs),
+ ",htmcs:%08hx",
+ (u16) WPA_GET_LE32(ie + 3));
+ }
+ if (id == WLAN_EID_VHT_CAP && elen >= 4) {
+ /* VHT Capabilities (802.11ac) */
+ os_snprintf(vhtcap, sizeof(vhtcap),
+ ",vhtcap:%08x",
+ WPA_GET_LE32(ie));
+ }
+ if (id == WLAN_EID_VHT_CAP && elen >= 8) {
+ /* VHT Capabilities (802.11ac), RX MCS
+ * information */
+ os_snprintf(vhtrxmcs, sizeof(vhtrxmcs),
+ ",vhtrxmcs:%08x",
+ WPA_GET_LE32(ie + 4));
+ }
+ if (id == WLAN_EID_VHT_CAP && elen >= 12) {
+ /* VHT Capabilities (802.11ac), TX MCS
+ * information */
+ os_snprintf(vhttxmcs, sizeof(vhttxmcs),
+ ",vhttxmcs:%08x",
+ WPA_GET_LE32(ie + 8));
+ }
+ if (id == WLAN_EID_EXT_CAPAB) {
+ /* Extended Capabilities */
+ int i;
+ int len = (elen < MAX_EXTCAP) ? elen :
+ MAX_EXTCAP;
+ char *p = extcap;
+
+ p += os_snprintf(extcap, sizeof(extcap),
+ ",extcap:");
+ for (i = 0; i < len; i++) {
+ int lim;
+
+ lim = sizeof(extcap) -
+ os_strlen(extcap);
+ if (lim <= 0)
+ break;
+ p += os_snprintf(p, lim, "%02x",
+ *(ie + i));
+ }
+ }
+ if (id == WLAN_EID_PWR_CAPABILITY && elen == 2) {
+ /* TX Power */
+ os_snprintf(txpow, sizeof(txpow),
+ ",txpow:%04hx",
+ WPA_GET_LE16(ie));
+ }
+
+ ret = os_snprintf(fpos, fend - fpos, "%s%d", sep, id);
+ }
+ if (os_snprintf_error(fend - fpos, ret))
+ goto fail;
+ fpos += ret;
+
+ ie += elen;
+ ie_len -= elen;
+ }
+
+ ret = os_snprintf(fpos, fend - fpos, "%s%s%s%s%s%s%s%s%s",
+ htcap, htagg, htmcs, vhtcap, vhtrxmcs, vhttxmcs,
+ txpow, extcap, wps);
+ if (os_snprintf_error(fend - fpos, ret)) {
+ fail:
+ fstr[0] = '\0';
+ }
+}
+
+
+int retrieve_sta_taxonomy(const struct hostapd_data *hapd,
+ struct sta_info *sta, char *buf, size_t buflen)
+{
+ int ret;
+ char *pos, *end;
+
+ if (!sta->probe_ie_taxonomy || !sta->assoc_ie_taxonomy)
+ return 0;
+
+ ret = os_snprintf(buf, buflen, "wifi4|probe:");
+ if (os_snprintf_error(buflen, ret))
+ return 0;
+ pos = buf + ret;
+ end = buf + buflen;
+
+ ie_to_string(pos, end - pos, sta->probe_ie_taxonomy);
+ pos = os_strchr(pos, '\0');
+ if (pos >= end)
+ return 0;
+ ret = os_snprintf(pos, end - pos, "|assoc:");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ ie_to_string(pos, end - pos, sta->assoc_ie_taxonomy);
+ pos = os_strchr(pos, '\0');
+ return pos - buf;
+}
+
+
+void taxonomy_sta_info_probe_req(const struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *ie, size_t ie_len)
+{
+ wpabuf_free(sta->probe_ie_taxonomy);
+ sta->probe_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
+}
+
+
+void taxonomy_hostapd_sta_info_probe_req(const struct hostapd_data *hapd,
+ struct hostapd_sta_info *info,
+ const u8 *ie, size_t ie_len)
+{
+ wpabuf_free(info->probe_ie_taxonomy);
+ info->probe_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
+}
+
+
+void taxonomy_sta_info_assoc_req(const struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *ie, size_t ie_len)
+{
+ wpabuf_free(sta->assoc_ie_taxonomy);
+ sta->assoc_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
+}
diff --git a/src/ap/taxonomy.h b/src/ap/taxonomy.h
new file mode 100644
index 000000000000..80f245c77c82
--- /dev/null
+++ b/src/ap/taxonomy.h
@@ -0,0 +1,24 @@
+/*
+ * hostapd / Station client taxonomy
+ * Copyright (c) 2015 Google, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TAXONOMY_H
+#define TAXONOMY_H
+
+void taxonomy_sta_info_probe_req(const struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *ie, size_t ie_len);
+void taxonomy_hostapd_sta_info_probe_req(const struct hostapd_data *hapd,
+ struct hostapd_sta_info *sta,
+ const u8 *ie, size_t ie_len);
+void taxonomy_sta_info_assoc_req(const struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *ie, size_t ie_len);
+int retrieve_sta_taxonomy(const struct hostapd_data *hapd,
+ struct sta_info *sta, char *buf, size_t buflen);
+
+#endif /* TAXONOMY_H */
diff --git a/src/ap/vlan.c b/src/ap/vlan.c
new file mode 100644
index 000000000000..b6f6bb1afe05
--- /dev/null
+++ b/src/ap/vlan.c
@@ -0,0 +1,34 @@
+/*
+ * hostapd / VLAN definition
+ * Copyright (c) 2016, Jouni Malinen <j@w1.fi>
+ *
+ * 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 "ap/vlan.h"
+
+/* compare the two arguments, NULL is treated as empty
+ * return zero iff they are equal
+ */
+int vlan_compare(struct vlan_description *a, struct vlan_description *b)
+{
+ int i;
+ const int a_empty = !a || !a->notempty;
+ const int b_empty = !b || !b->notempty;
+
+ if (a_empty && b_empty)
+ return 0;
+ if (a_empty || b_empty)
+ return 1;
+ if (a->untagged != b->untagged)
+ return 1;
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN; i++) {
+ if (a->tagged[i] != b->tagged[i])
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/ap/vlan.h b/src/ap/vlan.h
new file mode 100644
index 000000000000..af84929decdc
--- /dev/null
+++ b/src/ap/vlan.h
@@ -0,0 +1,30 @@
+/*
+ * hostapd / VLAN definition
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef VLAN_H
+#define VLAN_H
+
+#define MAX_NUM_TAGGED_VLAN 32
+
+struct vlan_description {
+ int notempty; /* 0 : no vlan information present, 1: else */
+ int untagged; /* >0 802.1q vid */
+ int tagged[MAX_NUM_TAGGED_VLAN]; /* first k items, ascending order */
+};
+
+#ifndef CONFIG_NO_VLAN
+int vlan_compare(struct vlan_description *a, struct vlan_description *b);
+#else /* CONFIG_NO_VLAN */
+static inline int
+vlan_compare(struct vlan_description *a, struct vlan_description *b)
+{
+ return 0;
+}
+#endif /* CONFIG_NO_VLAN */
+
+#endif /* VLAN_H */
diff --git a/src/ap/vlan_full.c b/src/ap/vlan_full.c
new file mode 100644
index 000000000000..aa42335b96a1
--- /dev/null
+++ b/src/ap/vlan_full.c
@@ -0,0 +1,752 @@
+/*
+ * hostapd / VLAN initialization - full dynamic VLAN
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <net/if.h>
+/* Avoid conflicts due to NetBSD net/if.h if_type define with driver.h */
+#undef if_type
+#include <sys/ioctl.h>
+
+#include "utils/common.h"
+#include "drivers/priv_netlink.h"
+#include "common/linux_bridge.h"
+#include "common/linux_vlan.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "wpa_auth.h"
+#include "vlan_init.h"
+#include "vlan_util.h"
+
+
+struct full_dynamic_vlan {
+ int s; /* socket on which to listen for new/removed interfaces. */
+};
+
+#define DVLAN_CLEAN_BR 0x1
+#define DVLAN_CLEAN_VLAN 0x2
+#define DVLAN_CLEAN_VLAN_PORT 0x4
+
+struct dynamic_iface {
+ char ifname[IFNAMSIZ + 1];
+ int usage;
+ int clean;
+ struct dynamic_iface *next;
+};
+
+
+/* Increment ref counter for ifname and add clean flag.
+ * If not in list, add it only if some flags are given.
+ */
+static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
+ int clean)
+{
+ struct dynamic_iface *next, **dynamic_ifaces;
+ struct hapd_interfaces *interfaces;
+
+ interfaces = hapd->iface->interfaces;
+ dynamic_ifaces = &interfaces->vlan_priv;
+
+ for (next = *dynamic_ifaces; next; next = next->next) {
+ if (os_strcmp(ifname, next->ifname) == 0)
+ break;
+ }
+
+ if (next) {
+ next->usage++;
+ next->clean |= clean;
+ return;
+ }
+
+ if (!clean)
+ return;
+
+ next = os_zalloc(sizeof(*next));
+ if (!next)
+ return;
+ os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
+ next->usage = 1;
+ next->clean = clean;
+ next->next = *dynamic_ifaces;
+ *dynamic_ifaces = next;
+}
+
+
+/* Decrement reference counter for given ifname.
+ * Return clean flag iff reference counter was decreased to zero, else zero
+ */
+static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
+{
+ struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
+ struct hapd_interfaces *interfaces;
+ int clean;
+
+ interfaces = hapd->iface->interfaces;
+ dynamic_ifaces = &interfaces->vlan_priv;
+
+ for (next = *dynamic_ifaces; next; next = next->next) {
+ if (os_strcmp(ifname, next->ifname) == 0)
+ break;
+ prev = next;
+ }
+
+ if (!next)
+ return 0;
+
+ next->usage--;
+ if (next->usage)
+ return 0;
+
+ if (prev)
+ prev->next = next->next;
+ else
+ *dynamic_ifaces = next->next;
+ clean = next->clean;
+ os_free(next);
+
+ return clean;
+}
+
+
+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);
+}
+
+
+/* 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 = (void *) 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;
+}
+
+
+/*