aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--COPYING340
-rw-r--r--FAQ181
-rw-r--r--README19
-rwxr-xr-xbuild_release143
-rw-r--r--eap_example/.gitignore3
-rw-r--r--eap_example/Makefile179
-rw-r--r--eap_example/README46
-rw-r--r--eap_example/ca.pem19
-rw-r--r--eap_example/eap_example.c55
-rw-r--r--eap_example/eap_example_peer.c270
-rw-r--r--eap_example/eap_example_server.c192
-rw-r--r--eap_example/server.keybin0 -> 608 bytes
-rw-r--r--eap_example/server.pem18
-rw-r--r--hostapd/.gitignore7
-rw-r--r--hostapd/ChangeLog477
-rw-r--r--hostapd/Makefile534
-rw-r--r--hostapd/README386
-rw-r--r--hostapd/accounting.c466
-rw-r--r--hostapd/accounting.h27
-rw-r--r--hostapd/ap.h111
-rw-r--r--hostapd/ap_list.c458
-rw-r--r--hostapd/ap_list.h68
-rw-r--r--hostapd/beacon.c418
-rw-r--r--hostapd/beacon.h24
-rw-r--r--hostapd/config.c2238
-rw-r--r--hostapd/config.h358
-rw-r--r--hostapd/ctrl_iface.c500
-rw-r--r--hostapd/ctrl_iface.h23
-rw-r--r--hostapd/defconfig119
-rw-r--r--hostapd/developer.txt219
-rw-r--r--hostapd/doc/.gitignore4
-rw-r--r--hostapd/doc/code_structure.doxygen5
-rw-r--r--hostapd/doc/ctrl_iface.doxygen66
-rw-r--r--hostapd/doc/doxygen.fast233
-rw-r--r--hostapd/doc/doxygen.full230
-rw-r--r--hostapd/doc/driver_wrapper.doxygen20
-rw-r--r--hostapd/doc/eap.doxygen56
-rw-r--r--hostapd/doc/hostapd.fig264
-rwxr-xr-xhostapd/doc/kerneldoc2doxygen.pl129
-rw-r--r--hostapd/doc/mainpage.doxygen52
-rw-r--r--hostapd/doc/porting.doxygen5
-rw-r--r--hostapd/driver.h681
-rw-r--r--hostapd/driver_bsd.c838
-rw-r--r--hostapd/driver_hostap.c1235
-rw-r--r--hostapd/driver_madwifi.c1363
-rw-r--r--hostapd/driver_nl80211.c2382
-rw-r--r--hostapd/driver_prism54.c1086
-rw-r--r--hostapd/driver_test.c1167
-rw-r--r--hostapd/driver_wired.c373
-rw-r--r--hostapd/drivers.c65
-rw-r--r--hostapd/eap_testing.txt74
-rw-r--r--hostapd/eapol_sm.c1290
-rw-r--r--hostapd/eapol_sm.h253
-rw-r--r--hostapd/hostap_common.h216
-rw-r--r--hostapd/hostapd.859
-rw-r--r--hostapd/hostapd.accept5
-rw-r--r--hostapd/hostapd.c2000
-rw-r--r--hostapd/hostapd.conf792
-rw-r--r--hostapd/hostapd.deny5
-rw-r--r--hostapd/hostapd.eap_user91
-rw-r--r--hostapd/hostapd.h239
-rw-r--r--hostapd/hostapd.radius_clients4
-rw-r--r--hostapd/hostapd.sim_db9
-rw-r--r--hostapd/hostapd.vlan9
-rw-r--r--hostapd/hostapd.wpa_psk9
-rw-r--r--hostapd/hostapd_cli.183
-rw-r--r--hostapd/hostapd_cli.c615
-rw-r--r--hostapd/hw_features.c432
-rw-r--r--hostapd/hw_features.h61
-rw-r--r--hostapd/iapp.c542
-rw-r--r--hostapd/iapp.h54
-rw-r--r--hostapd/ieee802_11.c1749
-rw-r--r--hostapd/ieee802_11.h95
-rw-r--r--hostapd/ieee802_11_auth.c471
-rw-r--r--hostapd/ieee802_11_auth.h33
-rw-r--r--hostapd/ieee802_11h.c33
-rw-r--r--hostapd/ieee802_11h.h27
-rw-r--r--hostapd/ieee802_1x.c1971
-rw-r--r--hostapd/ieee802_1x.h87
-rw-r--r--hostapd/logwatch/README9
-rw-r--r--hostapd/logwatch/hostapd.conf10
-rw-r--r--hostapd/mlme.c180
-rw-r--r--hostapd/mlme.h40
-rw-r--r--hostapd/nt_password_hash.c52
-rw-r--r--hostapd/peerkey.c396
-rw-r--r--hostapd/pmksa_cache.c368
-rw-r--r--hostapd/pmksa_cache.h54
-rw-r--r--hostapd/preauth.c275
-rw-r--r--hostapd/preauth.h58
-rw-r--r--hostapd/prism54.h177
-rw-r--r--hostapd/priv_netlink.h71
-rw-r--r--hostapd/radiotap.c287
-rw-r--r--hostapd/radiotap.h242
-rw-r--r--hostapd/radiotap_iter.h41
-rw-r--r--hostapd/reconfig.c712
-rw-r--r--hostapd/sta_info.c580
-rw-r--r--hostapd/sta_info.h40
-rw-r--r--hostapd/vlan_init.c832
-rw-r--r--hostapd/vlan_init.h31
-rw-r--r--hostapd/wired.conf40
-rw-r--r--hostapd/wme.c263
-rw-r--r--hostapd/wme.h147
-rw-r--r--hostapd/wpa.c2310
-rw-r--r--hostapd/wpa.h276
-rw-r--r--hostapd/wpa_auth_i.h212
-rw-r--r--hostapd/wpa_auth_ie.c785
-rw-r--r--hostapd/wpa_auth_ie.h54
-rw-r--r--hostapd/wpa_ft.c1432
-rw-r--r--patches/openssl-0.9.8-tls-extensions.patch429
-rw-r--r--patches/openssl-0.9.8d-tls-extensions.patch429
-rw-r--r--patches/openssl-0.9.8e-tls-extensions.patch353
-rw-r--r--patches/openssl-0.9.8g-tls-extensions.patch346
-rw-r--r--patches/openssl-0.9.9-session-ticket.patch342
-rw-r--r--radius_example/.gitignore2
-rw-r--r--radius_example/Makefile47
-rw-r--r--radius_example/README39
-rw-r--r--radius_example/radius_example.c161
-rw-r--r--src/Makefile8
-rw-r--r--src/common/.gitignore1
-rw-r--r--src/common/Makefile6
-rw-r--r--src/common/defs.h167
-rw-r--r--src/common/eapol_common.h47
-rw-r--r--src/common/ieee802_11_defs.h310
-rw-r--r--src/common/privsep_commands.h75
-rw-r--r--src/common/version.h6
-rw-r--r--src/common/wireless_copy.h1089
-rw-r--r--src/common/wpa_common.c556
-rw-r--r--src/common/wpa_common.h328
-rw-r--r--src/common/wpa_ctrl.c441
-rw-r--r--src/common/wpa_ctrl.h187
-rw-r--r--src/crypto/.gitignore1
-rw-r--r--src/crypto/Makefile6
-rw-r--r--src/crypto/aes.c1127
-rw-r--r--src/crypto/aes.h25
-rw-r--r--src/crypto/aes_wrap.c529
-rw-r--r--src/crypto/aes_wrap.h48
-rw-r--r--src/crypto/crypto.h431
-rw-r--r--src/crypto/crypto_cryptoapi.c801
-rw-r--r--src/crypto/crypto_gnutls.c165
-rw-r--r--src/crypto/crypto_internal.c721
-rw-r--r--src/crypto/crypto_libtomcrypt.c736
-rw-r--r--src/crypto/crypto_none.c28
-rw-r--r--src/crypto/crypto_openssl.c358
-rw-r--r--src/crypto/des.c479
-rw-r--r--src/crypto/dh_groups.c620
-rw-r--r--src/crypto/dh_groups.h32
-rw-r--r--src/crypto/md4.c282
-rw-r--r--src/crypto/md5.c394
-rw-r--r--src/crypto/md5.h34
-rw-r--r--src/crypto/ms_funcs.c446
-rw-r--r--src/crypto/ms_funcs.h64
-rw-r--r--src/crypto/rc4.c86
-rw-r--r--src/crypto/rc4.h22
-rw-r--r--src/crypto/sha1.c729
-rw-r--r--src/crypto/sha1.h42
-rw-r--r--src/crypto/sha256.c382
-rw-r--r--src/crypto/sha256.h27
-rw-r--r--src/crypto/tls.h527
-rw-r--r--src/crypto/tls_gnutls.c1362
-rw-r--r--src/crypto/tls_internal.c567
-rw-r--r--src/crypto/tls_none.c234
-rw-r--r--src/crypto/tls_openssl.c2494
-rw-r--r--src/crypto/tls_schannel.c789
-rw-r--r--src/drivers/.gitignore1
-rw-r--r--src/drivers/Apple80211.h154
-rw-r--r--src/drivers/Makefile6
-rw-r--r--src/drivers/MobileApple80211.c189
-rw-r--r--src/drivers/MobileApple80211.h43
-rw-r--r--src/drivers/driver.h1227
-rw-r--r--src/drivers/driver_atmel.c506
-rw-r--r--src/drivers/driver_broadcom.c599
-rw-r--r--src/drivers/driver_bsd.c789
-rw-r--r--src/drivers/driver_hostap.c513
-rw-r--r--src/drivers/driver_hostap.h153
-rw-r--r--src/drivers/driver_iphone.m466
-rw-r--r--src/drivers/driver_ipw.c463
-rw-r--r--src/drivers/driver_madwifi.c565
-rw-r--r--src/drivers/driver_ndis.c2832
-rw-r--r--src/drivers/driver_ndis.h64
-rw-r--r--src/drivers/driver_ndis_.c105
-rw-r--r--src/drivers/driver_ndiswrapper.c366
-rw-r--r--src/drivers/driver_osx.m432
-rw-r--r--src/drivers/driver_prism54.c381
-rw-r--r--src/drivers/driver_privsep.c774
-rw-r--r--src/drivers/driver_ralink.c1493
-rw-r--r--src/drivers/driver_ralink.h382
-rw-r--r--src/drivers/driver_test.c986
-rw-r--r--src/drivers/driver_wext.c2617
-rw-r--r--src/drivers/driver_wext.h46
-rw-r--r--src/drivers/driver_wired.c277
-rw-r--r--src/drivers/drivers.c120
-rw-r--r--src/drivers/ndis_events.c807
-rw-r--r--src/drivers/priv_netlink.h104
-rw-r--r--src/drivers/scan_helpers.c148
-rw-r--r--src/eap_common/.gitignore1
-rw-r--r--src/eap_common/Makefile6
-rw-r--r--src/eap_common/chap.c35
-rw-r--r--src/eap_common/chap.h23
-rw-r--r--src/eap_common/eap_common.c184
-rw-r--r--src/eap_common/eap_common.h28
-rw-r--r--src/eap_common/eap_defs.h84
-rw-r--r--src/eap_common/eap_fast_common.h85
-rw-r--r--src/eap_common/eap_gpsk_common.c426
-rw-r--r--src/eap_common/eap_gpsk_common.h66
-rw-r--r--src/eap_common/eap_ikev2_common.c132
-rw-r--r--src/eap_common/eap_ikev2_common.h42
-rw-r--r--src/eap_common/eap_pax_common.c150
-rw-r--r--src/eap_common/eap_pax_common.h97
-rw-r--r--src/eap_common/eap_psk_common.c74
-rw-r--r--src/eap_common/eap_psk_common.h78
-rw-r--r--src/eap_common/eap_sake_common.c393
-rw-r--r--src/eap_common/eap_sake_common.h102
-rw-r--r--src/eap_common/eap_sim_common.c867
-rw-r--r--src/eap_common/eap_sim_common.h172
-rw-r--r--src/eap_common/eap_tlv_common.h119
-rw-r--r--src/eap_common/eap_ttls.h71
-rw-r--r--src/eap_common/ikev2_common.c796
-rw-r--r--src/eap_common/ikev2_common.h344
-rw-r--r--src/eap_peer/.gitignore1
-rw-r--r--src/eap_peer/Makefile6
-rw-r--r--src/eap_peer/eap.c2030
-rw-r--r--src/eap_peer/eap.h288
-rw-r--r--src/eap_peer/eap_aka.c1097
-rw-r--r--src/eap_peer/eap_config.h572
-rw-r--r--src/eap_peer/eap_fast.c1859
-rw-r--r--src/eap_peer/eap_fast_pac.c916
-rw-r--r--src/eap_peer/eap_fast_pac.h56
-rw-r--r--src/eap_peer/eap_gpsk.c732
-rw-r--r--src/eap_peer/eap_gtc.c151
-rw-r--r--src/eap_peer/eap_i.h353
-rw-r--r--src/eap_peer/eap_ikev2.c506
-rw-r--r--src/eap_peer/eap_leap.c403
-rw-r--r--src/eap_peer/eap_md5.c120
-rw-r--r--src/eap_peer/eap_methods.c514
-rw-r--r--src/eap_peer/eap_methods.h87
-rw-r--r--src/eap_peer/eap_mschapv2.c891
-rw-r--r--src/eap_peer/eap_otp.c107
-rw-r--r--src/eap_peer/eap_pax.c532
-rw-r--r--src/eap_peer/eap_peap.c810
-rw-r--r--src/eap_peer/eap_psk.c482
-rw-r--r--src/eap_peer/eap_sake.c499
-rw-r--r--src/eap_peer/eap_sim.c1038
-rw-r--r--src/eap_peer/eap_tls.c288
-rw-r--r--src/eap_peer/eap_tls_common.c1007
-rw-r--r--src/eap_peer/eap_tls_common.h139
-rw-r--r--src/eap_peer/eap_tlv.c189
-rw-r--r--src/eap_peer/eap_tlv.h26
-rw-r--r--src/eap_peer/eap_tnc.c220
-rw-r--r--src/eap_peer/eap_ttls.c1976
-rw-r--r--src/eap_peer/eap_vendor_test.c195
-rw-r--r--src/eap_peer/ikev2.c1303
-rw-r--r--src/eap_peer/ikev2.h65
-rw-r--r--src/eap_peer/mschapv2.c119
-rw-r--r--src/eap_peer/mschapv2.h34
-rw-r--r--src/eap_peer/tncc.c1204
-rw-r--r--src/eap_peer/tncc.h40
-rw-r--r--src/eap_server/.gitignore1
-rw-r--r--src/eap_server/Makefile6
-rw-r--r--src/eap_server/eap.c1259
-rw-r--r--src/eap_server/eap.h114
-rw-r--r--src/eap_server/eap_aka.c1024
-rw-r--r--src/eap_server/eap_fast.c1716
-rw-r--r--src/eap_server/eap_gpsk.c627
-rw-r--r--src/eap_server/eap_gtc.c218
-rw-r--r--src/eap_server/eap_i.h181
-rw-r--r--src/eap_server/eap_identity.c178
-rw-r--r--src/eap_server/eap_ikev2.c535
-rw-r--r--src/eap_server/eap_md5.c176
-rw-r--r--src/eap_server/eap_methods.c287
-rw-r--r--src/eap_server/eap_methods.h29
-rw-r--r--src/eap_server/eap_mschapv2.c567
-rw-r--r--src/eap_server/eap_pax.c569
-rw-r--r--src/eap_server/eap_peap.c904
-rw-r--r--src/eap_server/eap_psk.c517
-rw-r--r--src/eap_server/eap_sake.c542
-rw-r--r--src/eap_server/eap_sim.c797
-rw-r--r--src/eap_server/eap_sim_db.c1277
-rw-r--r--src/eap_server/eap_sim_db.h99
-rw-r--r--src/eap_server/eap_tls.c283
-rw-r--r--src/eap_server/eap_tls_common.c293
-rw-r--r--src/eap_server/eap_tls_common.h63
-rw-r--r--src/eap_server/eap_tlv.c224
-rw-r--r--src/eap_server/eap_ttls.c1497
-rw-r--r--src/eap_server/eap_vendor_test.c198
-rw-r--r--src/eap_server/ikev2.c1205
-rw-r--r--src/eap_server/ikev2.h67
-rw-r--r--src/eapol_supp/.gitignore1
-rw-r--r--src/eapol_supp/Makefile6
-rw-r--r--src/eapol_supp/eapol_supp_sm.c1842
-rw-r--r--src/eapol_supp/eapol_supp_sm.h335
-rw-r--r--src/hlr_auc_gw/.gitignore1
-rw-r--r--src/hlr_auc_gw/Makefile6
-rw-r--r--src/hlr_auc_gw/hlr_auc_gw.c714
-rw-r--r--src/hlr_auc_gw/hlr_auc_gw.milenage_db9
-rw-r--r--src/hlr_auc_gw/milenage.c1071
-rw-r--r--src/hlr_auc_gw/milenage.h26
-rw-r--r--src/l2_packet/.gitignore1
-rw-r--r--src/l2_packet/Makefile6
-rw-r--r--src/l2_packet/l2_packet.h130
-rw-r--r--src/l2_packet/l2_packet_freebsd.c285
-rw-r--r--src/l2_packet/l2_packet_linux.c199
-rw-r--r--src/l2_packet/l2_packet_ndis.c516
-rw-r--r--src/l2_packet/l2_packet_none.c123
-rw-r--r--src/l2_packet/l2_packet_pcap.c386
-rw-r--r--src/l2_packet/l2_packet_privsep.c267
-rw-r--r--src/l2_packet/l2_packet_winpcap.c340
-rw-r--r--src/radius/.gitignore1
-rw-r--r--src/radius/Makefile6
-rw-r--r--src/radius/radius.c1230
-rw-r--r--src/radius/radius.h270
-rw-r--r--src/radius/radius_client.c1219
-rw-r--r--src/radius/radius_client.h105
-rw-r--r--src/radius/radius_server.c1237
-rw-r--r--src/radius/radius_server.h73
-rw-r--r--src/rsn_supp/.gitignore1
-rw-r--r--src/rsn_supp/Makefile6
-rw-r--r--src/rsn_supp/peerkey.c1163
-rw-r--r--src/rsn_supp/peerkey.h86
-rw-r--r--src/rsn_supp/pmksa_cache.c502
-rw-r--r--src/rsn_supp/pmksa_cache.h126
-rw-r--r--src/rsn_supp/preauth.c528
-rw-r--r--src/rsn_supp/preauth.h78
-rw-r--r--src/rsn_supp/wpa.c2347
-rw-r--r--src/rsn_supp/wpa.h320
-rw-r--r--src/rsn_supp/wpa_ft.c791
-rw-r--r--src/rsn_supp/wpa_i.h256
-rw-r--r--src/rsn_supp/wpa_ie.c530
-rw-r--r--src/rsn_supp/wpa_ie.h52
-rw-r--r--src/tls/.gitignore1
-rw-r--r--src/tls/Makefile6
-rw-r--r--src/tls/asn1.c209
-rw-r--r--src/tls/asn1.h71
-rw-r--r--src/tls/asn1_test.c210
-rw-r--r--src/tls/bignum.c230
-rw-r--r--src/tls/bignum.h38
-rw-r--r--src/tls/libtommath.c2370
-rw-r--r--src/tls/rsa.c359
-rw-r--r--src/tls/rsa.h29
-rw-r--r--src/tls/tlsv1_client.c658
-rw-r--r--src/tls/tlsv1_client.h59
-rw-r--r--src/tls/tlsv1_client_i.h87
-rw-r--r--src/tls/tlsv1_client_read.c976
-rw-r--r--src/tls/tlsv1_client_write.c802
-rw-r--r--src/tls/tlsv1_common.c241
-rw-r--r--src/tls/tlsv1_common.h216
-rw-r--r--src/tls/tlsv1_cred.c422
-rw-r--r--src/tls/tlsv1_cred.h46
-rw-r--r--src/tls/tlsv1_record.c409
-rw-r--r--src/tls/tlsv1_record.h74
-rw-r--r--src/tls/tlsv1_server.c596
-rw-r--r--src/tls/tlsv1_server.h54
-rw-r--r--src/tls/tlsv1_server_i.h77
-rw-r--r--src/tls/tlsv1_server_read.c1142
-rw-r--r--src/tls/tlsv1_server_write.c796
-rw-r--r--src/tls/x509v3.c1684
-rw-r--r--src/tls/x509v3.h154
-rw-r--r--src/utils/.gitignore1
-rw-r--r--src/utils/Makefile6
-rw-r--r--src/utils/base64.c187
-rw-r--r--src/utils/base64.h23
-rw-r--r--src/utils/build_config.h95
-rw-r--r--src/utils/common.c327
-rw-r--r--src/utils/common.h434
-rw-r--r--src/utils/eloop.c555
-rw-r--r--src/utils/eloop.h327
-rw-r--r--src/utils/eloop_none.c390
-rw-r--r--src/utils/eloop_win.c604
-rw-r--r--src/utils/includes.h59
-rw-r--r--src/utils/ip_addr.c84
-rw-r--r--src/utils/ip_addr.h33
-rw-r--r--src/utils/os.h501
-rw-r--r--src/utils/os_internal.c466
-rw-r--r--src/utils/os_none.c226
-rw-r--r--src/utils/os_unix.c258
-rw-r--r--src/utils/os_win32.c222
-rw-r--r--src/utils/pcsc_funcs.c1238
-rw-r--r--src/utils/pcsc_funcs.h68
-rw-r--r--src/utils/state_machine.h144
-rw-r--r--src/utils/uuid.c67
-rw-r--r--src/utils/uuid.h23
-rw-r--r--src/utils/wpa_debug.c326
-rw-r--r--src/utils/wpa_debug.h223
-rw-r--r--src/utils/wpabuf.c125
-rw-r--r--src/utils/wpabuf.h148
-rwxr-xr-xtesting/compile_wireless_versions39
-rw-r--r--testing/hostapd-config/arm29
-rw-r--r--testing/hostapd-config/arm-0.428
-rw-r--r--testing/hostapd-config/freebsd28
-rw-r--r--testing/hostapd-config/full27
-rw-r--r--testing/hostapd-config/full-0.426
-rw-r--r--testing/hostapd-config/gcc-cvs30
-rw-r--r--testing/hostapd-config/minimal10
-rw-r--r--testing/hostapd-config/minimal-0.49
-rw-r--r--testing/hostapd-config/noeap13
-rw-r--r--testing/hostapd-config/noeap-0.412
-rw-r--r--testing/hostapd-config/x86_6435
-rwxr-xr-xtesting/run-hostapd5
-rwxr-xr-xtesting/run-hostapd-0.36
-rwxr-xr-xtesting/run-hostapd-0.45
-rwxr-xr-xtesting/run-wpa_supplicant5
-rwxr-xr-xtesting/run-wpa_supplicant-0.36
-rwxr-xr-xtesting/run-wpa_supplicant-0.45
-rw-r--r--testing/wireless/iw_handler-2.h374
-rw-r--r--testing/wireless/iw_handler-3.h450
-rw-r--r--testing/wireless/iw_handler-4.h453
-rw-r--r--testing/wireless/iw_handler-5.h516
-rw-r--r--testing/wireless/iw_handler-6.h540
-rw-r--r--testing/wireless/iw_handler-7.h633
-rw-r--r--testing/wireless/wireless-10.h479
-rw-r--r--testing/wireless/wireless-11.h510
-rw-r--r--testing/wireless/wireless-12.h570
-rw-r--r--testing/wireless/wireless-13.h599
-rw-r--r--testing/wireless/wireless-14.h669
-rw-r--r--testing/wireless/wireless-15.h693
-rw-r--r--testing/wireless/wireless-16.h733
-rw-r--r--testing/wireless/wireless-17.h773
-rw-r--r--testing/wireless/wireless-18.h975
-rw-r--r--testing/wireless/wireless-19.h1066
-rw-r--r--testing/wireless/wireless-6.h347
-rw-r--r--testing/wireless/wireless-8.h397
-rw-r--r--testing/wireless/wireless-9.h448
-rw-r--r--testing/wpa_supplicant-config/arm34
-rw-r--r--testing/wpa_supplicant-config/default35
-rw-r--r--testing/wpa_supplicant-config/default-0.336
-rw-r--r--testing/wpa_supplicant-config/dyneap35
-rw-r--r--testing/wpa_supplicant-config/freebsd30
-rw-r--r--testing/wpa_supplicant-config/gcc-cvs40
-rw-r--r--testing/wpa_supplicant-config/minimal8
-rw-r--r--testing/wpa_supplicant-config/minimal-wpa7
-rw-r--r--testing/wpa_supplicant-config/windows48
-rw-r--r--testing/wpa_supplicant-config/windows-0.338
-rw-r--r--testing/wpa_supplicant-config/windows-0.438
-rw-r--r--testing/wpa_supplicant-config/windows245
-rw-r--r--testing/wpa_supplicant-config/windows2-0.338
-rw-r--r--testing/wpa_supplicant-config/windows2-0.438
-rw-r--r--testing/wpa_supplicant-config/x86_6442
-rw-r--r--wpa_supplicant/.gitignore8
-rw-r--r--wpa_supplicant/ChangeLog1089
-rw-r--r--wpa_supplicant/Makefile1158
-rw-r--r--wpa_supplicant/README1024
-rw-r--r--wpa_supplicant/README-Windows.txt448
-rw-r--r--wpa_supplicant/blacklist.c133
-rw-r--r--wpa_supplicant/blacklist.h30
-rw-r--r--wpa_supplicant/config.c1908
-rw-r--r--wpa_supplicant/config.h316
-rw-r--r--wpa_supplicant/config_file.c886
-rw-r--r--wpa_supplicant/config_none.c57
-rw-r--r--wpa_supplicant/config_ssid.h339
-rw-r--r--wpa_supplicant/config_winreg.c883
-rw-r--r--wpa_supplicant/ctrl_iface.c1656
-rw-r--r--wpa_supplicant/ctrl_iface.h159
-rw-r--r--wpa_supplicant/ctrl_iface_dbus.c1053
-rw-r--r--wpa_supplicant/ctrl_iface_dbus.h146
-rw-r--r--wpa_supplicant/ctrl_iface_dbus_handlers.c1330
-rw-r--r--wpa_supplicant/ctrl_iface_dbus_handlers.h83
-rw-r--r--wpa_supplicant/ctrl_iface_named_pipe.c834
-rw-r--r--wpa_supplicant/ctrl_iface_udp.c561
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c699
-rw-r--r--wpa_supplicant/dbus-wpa_supplicant.conf16
-rw-r--r--wpa_supplicant/dbus-wpa_supplicant.service4
-rw-r--r--wpa_supplicant/dbus_dict_helpers.c976
-rw-r--r--wpa_supplicant/dbus_dict_helpers.h135
-rw-r--r--wpa_supplicant/defconfig362
-rw-r--r--wpa_supplicant/doc/.gitignore4
-rw-r--r--wpa_supplicant/doc/code_structure.doxygen322
-rw-r--r--wpa_supplicant/doc/ctrl_iface.doxygen481
-rw-r--r--wpa_supplicant/doc/docbook/.gitignore6
-rw-r--r--wpa_supplicant/doc/docbook/Makefile27
-rw-r--r--wpa_supplicant/doc/docbook/wpa_background.sgml101
-rw-r--r--wpa_supplicant/doc/docbook/wpa_cli.sgml338
-rw-r--r--wpa_supplicant/doc/docbook/wpa_gui.sgml76
-rw-r--r--wpa_supplicant/doc/docbook/wpa_passphrase.sgml73
-rw-r--r--wpa_supplicant/doc/docbook/wpa_priv.sgml148
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml238
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.sgml795
-rw-r--r--wpa_supplicant/doc/doxygen.fast239
-rw-r--r--wpa_supplicant/doc/doxygen.full240
-rw-r--r--wpa_supplicant/doc/driver_wrapper.doxygen180
-rw-r--r--wpa_supplicant/doc/eap.doxygen87
-rwxr-xr-xwpa_supplicant/doc/kerneldoc2doxygen.pl129
-rw-r--r--wpa_supplicant/doc/mainpage.doxygen56
-rw-r--r--wpa_supplicant/doc/porting.doxygen208
-rw-r--r--wpa_supplicant/doc/testing_tools.doxygen295
-rw-r--r--wpa_supplicant/doc/wpa_supplicant.fig247
-rw-r--r--wpa_supplicant/eap_testing.txt396
-rw-r--r--wpa_supplicant/eapol_test.c1043
-rw-r--r--wpa_supplicant/events.c962
-rw-r--r--wpa_supplicant/examples/ieee8021x.conf13
-rw-r--r--wpa_supplicant/examples/plaintext.conf8
-rw-r--r--wpa_supplicant/examples/wep.conf11
-rw-r--r--wpa_supplicant/examples/wpa-psk-tkip.conf12
-rw-r--r--wpa_supplicant/examples/wpa2-eap-ccmp.conf15
-rwxr-xr-xwpa_supplicant/examples/wpas-test.py91
-rw-r--r--wpa_supplicant/main.c277
-rw-r--r--wpa_supplicant/main_none.c46
-rw-r--r--wpa_supplicant/main_symbian.cpp48
-rw-r--r--wpa_supplicant/main_winmain.c84
-rw-r--r--wpa_supplicant/main_winsvc.c445
-rw-r--r--wpa_supplicant/mlme.c3050
-rw-r--r--wpa_supplicant/mlme.h132
-rw-r--r--wpa_supplicant/nmake.mak227
-rw-r--r--wpa_supplicant/preauth_test.c389
-rw-r--r--wpa_supplicant/scan.c193
-rw-r--r--wpa_supplicant/symbian/README.symbian24
-rw-r--r--wpa_supplicant/symbian/bld.inf8
-rw-r--r--wpa_supplicant/symbian/wpa_supplicant.mmp38
-rw-r--r--wpa_supplicant/tests/link_test.c83
-rw-r--r--wpa_supplicant/tests/test_aes.c307
-rw-r--r--wpa_supplicant/tests/test_eap_sim_common.c53
-rw-r--r--wpa_supplicant/tests/test_md4.c99
-rw-r--r--wpa_supplicant/tests/test_md5.c99
-rw-r--r--wpa_supplicant/tests/test_ms_funcs.c119
-rw-r--r--wpa_supplicant/tests/test_sha1.c347
-rw-r--r--wpa_supplicant/tests/test_sha256.c330
-rw-r--r--wpa_supplicant/tests/test_wpa.c394
-rw-r--r--wpa_supplicant/tests/test_x509v3.c69
-rwxr-xr-xwpa_supplicant/tests/test_x509v3_nist.sh144
-rwxr-xr-xwpa_supplicant/tests/test_x509v3_nist2.sh165
-rw-r--r--wpa_supplicant/todo.txt93
-rwxr-xr-xwpa_supplicant/vs2005/win_if_list/win_if_list.vcproj203
-rwxr-xr-xwpa_supplicant/vs2005/wpa_supplicant.sln52
-rwxr-xr-xwpa_supplicant/vs2005/wpasvc/wpasvc.vcproj417
-rwxr-xr-xwpa_supplicant/win_example.reg32
-rw-r--r--wpa_supplicant/win_if_list.c179
-rw-r--r--wpa_supplicant/wpa_cli.c1720
-rw-r--r--wpa_supplicant/wpa_gui-qt4/.gitignore5
-rw-r--r--wpa_supplicant/wpa_gui-qt4/eventhistory.cpp130
-rw-r--r--wpa_supplicant/wpa_gui-qt4/eventhistory.h63
-rw-r--r--wpa_supplicant/wpa_gui-qt4/eventhistory.ui61
-rw-r--r--wpa_supplicant/wpa_gui-qt4/main.cpp44
-rw-r--r--wpa_supplicant/wpa_gui-qt4/networkconfig.cpp639
-rw-r--r--wpa_supplicant/wpa_gui-qt4/networkconfig.h58
-rw-r--r--wpa_supplicant/wpa_gui-qt4/networkconfig.ui400
-rw-r--r--wpa_supplicant/wpa_gui-qt4/scanresults.cpp142
-rw-r--r--wpa_supplicant/wpa_gui-qt4/scanresults.h46
-rw-r--r--wpa_supplicant/wpa_gui-qt4/scanresults.ui94
-rwxr-xr-xwpa_supplicant/wpa_gui-qt4/setup-mingw-cross-compiling11
-rw-r--r--wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp100
-rw-r--r--wpa_supplicant/wpa_gui-qt4/userdatarequest.h46
-rw-r--r--wpa_supplicant/wpa_gui-qt4/userdatarequest.ui109
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpa_gui.pro50
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpagui.cpp1094
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpagui.h92
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpagui.ui419
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpamsg.h41
-rw-r--r--wpa_supplicant/wpa_gui/.gitignore5
-rw-r--r--wpa_supplicant/wpa_gui/eventhistory.ui125
-rw-r--r--wpa_supplicant/wpa_gui/eventhistory.ui.h41
-rw-r--r--wpa_supplicant/wpa_gui/main.cpp30
-rw-r--r--wpa_supplicant/wpa_gui/networkconfig.ui475
-rw-r--r--wpa_supplicant/wpa_gui/networkconfig.ui.h551
-rw-r--r--wpa_supplicant/wpa_gui/scanresults.ui179
-rw-r--r--wpa_supplicant/wpa_gui/scanresults.ui.h101
-rwxr-xr-xwpa_supplicant/wpa_gui/setup-mingw-cross-compiling11
-rw-r--r--wpa_supplicant/wpa_gui/userdatarequest.ui163
-rw-r--r--wpa_supplicant/wpa_gui/userdatarequest.ui.h70
-rw-r--r--wpa_supplicant/wpa_gui/wpa_gui.pro50
-rw-r--r--wpa_supplicant/wpa_gui/wpagui.ui471
-rw-r--r--wpa_supplicant/wpa_gui/wpagui.ui.h729
-rw-r--r--wpa_supplicant/wpa_gui/wpamsg.h33
-rw-r--r--wpa_supplicant/wpa_passphrase.c73
-rw-r--r--wpa_supplicant/wpa_priv.c1140
-rw-r--r--wpa_supplicant/wpa_supplicant.c2057
-rw-r--r--wpa_supplicant/wpa_supplicant.conf762
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h721
-rw-r--r--wpa_supplicant/wpas_glue.c628
-rw-r--r--wpa_supplicant/wpas_glue.h23
-rw-r--r--www/Makefile13
-rw-r--r--www/cvs.html71
-rw-r--r--www/hostapd/index.html272
-rw-r--r--www/index.html307
-rw-r--r--www/links.html56
-rw-r--r--www/releases.html41
-rw-r--r--www/versions.dot96
-rw-r--r--www/wpa_supplicant/conf/auth_modes.html26
-rw-r--r--www/wpa_supplicant/conf/configure.css49
-rw-r--r--www/wpa_supplicant/conf/configure.html240
-rw-r--r--www/wpa_supplicant/conf/configure.js544
-rw-r--r--www/wpa_supplicant/conf/eap-peap.html27
-rw-r--r--www/wpa_supplicant/conf/eap-tls.html27
-rw-r--r--www/wpa_supplicant/conf/eap.html31
-rw-r--r--www/wpa_supplicant/conf/index.html29
-rw-r--r--www/wpa_supplicant/events.pngbin0 -> 25868 bytes
-rw-r--r--www/wpa_supplicant/index.html357
-rw-r--r--www/wpa_supplicant/main.pngbin0 -> 20852 bytes
-rw-r--r--www/wpa_supplicant/net_conf.pngbin0 -> 13656 bytes
-rw-r--r--www/wpa_supplicant/scan.pngbin0 -> 15747 bytes
-rw-r--r--www/wpa_supplicant/user_input.pngbin0 -> 11299 bytes
-rw-r--r--www/wpa_supplicant/wpa_gui.html36
589 files changed, 213408 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..14f5453
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/FAQ b/FAQ
new file mode 100644
index 0000000..ce65abb
--- /dev/null
+++ b/FAQ
@@ -0,0 +1,181 @@
+Host AP driver - Frequently Asked Questions
+===========================================
+
+1. What does "GetNextTuple: No more items" mean in hostap_cs initialization?
+2. Why RX does not work?
+ What does "NETDEV WATCHDOG: wlan0: transmit timed out" mean?
+ (interrupt delivery problems)
+3. What is wrong with Host AP mode in secondary (station) firmware v1.4.2?
+4. What is causing 'Unresolved symbols' in depmod/modprobe?
+5. How can I upgrade Prism2/2.5/3 firmware?
+6. Why did I get two network interfaces (wlan0 and wifi0) even when I have
+ only one wireless card?
+7. Why does my D-Link DWL-650 rev. P1 or D-Link DWL-520 rev. E1 (or any other
+ card with small flash) card fail?
+8. Does Host AP driver support IEEE 802.11a and 802.11g? Does it support
+ chipsets other than Prism 2/2.5/3?
+
+
+
+1. What does "GetNextTuple: No more items" mean in hostap_cs initialization?
+
+This is one of the most often reported problems in getting the
+hostap_cs.o driver working. It is usually reported for D-Link DWL-650
+PC Card, e.g., on ISA-to-PCMCIA adapter. Later versions of the driver
+report this also with "Vcc mismatch - skipping this entry".
+
+Most common reason for getting this is a mismatch in voltage
+configuration. The driver tries to make sure that the voltage (Vcc)
+configuration in CIS and the slot match each other. It refuses to
+initialize the card if the card CIS does not include a CFTABLE entry
+with a matching Vcc value. This seems to be a problem for some cases
+since the CIS is invalid or the reported voltage is incorrect.
+
+As a workaround, the driver supports a module parameter ignore_cis_vcc
+that can be used to skip this verification. This can be enabled by
+setting ignore_cis_vcc=1 in /etc/pcmcia/hostap_cs.conf (commented
+example line in the end of file). This can also be tested by manually
+loading the module with 'modprobe hostap_cs ignore_cis_vcc=1' before
+inserting the card).
+
+
+
+2. Why RX does not work?
+ What does "NETDEV WATCHDOG: wlan0: transmit timed out" mean?
+ (interrupt delivery problems)
+
+If the driver does not seem to receive any packets or sending packets
+results in "NETDEV WATCHDOG: wlan0: transmit timed out", the reason is
+probably in interrupt delivery problems. This is quite common with
+PCI-to-PCMCIA adapters. Newer than 2002-05-19 of the driver have a
+test that will report this after the initialization ("wlan: Possible
+interrupt delivery problem"). Another method for checking this is to
+observer whether interrupt counters in /proc/interrupts increase for
+hostap_cs/wlan0 entry.
+
+Adding suitable irq_mode=# setting in PCIC_OPTS line of
+pcmcia-configuration is the most common fix for this. pcmcia-cs HOWTO
+has more information on how to debug and fix interrupt delivery
+problems at
+http://pcmcia-cs.sourceforge.net/ftp/doc/PCMCIA-HOWTO-5.html#irqmode
+
+
+
+3. What is wrong with Host AP mode in secondary (station) firmware v1.4.2?
+
+It looks like secondary firmware v1.4.2 sends beacon frames properly,
+but does not respond to probe requests. With most station cards, this
+prevents authentication and association and thus, in practice, no data
+frames can be sent. It has been reported that at least some Cisco
+Aironet 350 cards can associate with Host AP mode even with firmware
+v1.4.2 (i.e., without receiving probe response), but Prism2 and
+Lucent/ORiNOCO/Agere seem to require probe response and they do not
+thus associate with AP using v1.4.2 firmware.
+
+This is fixed in later secondary firmware versions; probably already
+in 1.4.3, but at least 1.4.9 has been tested to work. In other words,
+this problem can be fixed by upgrading card firmware.
+
+
+
+4. What is causing 'Unresolved symbols' in depmod/modprobe?
+
+Installation of Host AP driver (e.g, 'make install_pccard') may report
+unresolved symbols when running depmod. These are usually caused with
+mismatch in kernel configuration for modversions.
+
+Example:
+
+depmod reports unresolved symbol 'eth_type_trans' (this is without
+modversions):
+depmod: eth_type_trans
+
+but kernel was really configured with CONFIG_MODVERSIONS:
+
+# grep eth_type_trans /proc/ksyms
+c01b66c0 eth_type_trans_Rdb9cd26f
+
+(notice the _R... postfix)
+
+This happens if the kernel configuration given to Host AP driver's
+Makefile (.config in KERNEL_PATH) has not CONFIG_MODVERSIONS, but the
+running kernel is compiled with it.
+If the kernel were configured without modversions, /proc/ksyms would
+show the symbols with _R... postfix:
+
+
+Mismatches in kernel configuration can be fixed by using the same
+configuration (i.e., Linux kernel .config) for both the kernel and the
+driver. If you are using a kernel from a distribution installation
+(i.e., you have not compiled it yourself), you will need to create a
+matching .config file somehow. This depends on the distribution you
+are using, but 'make oldconfig' in kernel source directory might work
+with some distributions. If you compile the kernel yourself, it will
+be easier, since you already have to have created the correct .config
+file.
+
+
+
+5. How can I upgrade Prism2/2.5/3 firmware?
+
+Prism2/2.5/3 cards and Host AP driver support two different mechanism
+of upgrading the card firmware. Firmware images (primary and station)
+can be downloaded either into volatile memory (RAM download) or
+non-volatile memory (flash upgrade). Firmware images downloaded into
+volatile memory are lost when the card is resetted, so they are quite
+safe. Flash upgrade with incorrect images may cause permanent problems
+(i.e., render the card useless), so certain amount of caution is
+always recommended for this.
+
+Note! Some of the older versions of Host AP driver or prism2_srec had
+fatal bugs in flash upgrade. Only versions 0.1.0 or newer should be
+used when performing non-volatile flash upgrade!
+
+utils/prism2_srec (run 'make' in utils directory to build this) is a
+tool that can be instructed Host AP driver to download firmware image
+into the wlan card. Brief usage information is available by running
+this program without any command line parameters. Please note, that
+the downloading support is disabled in the default Host AP driver
+build. You will need to change this by defining
+PRISM2_DOWNLOAD_SUPPORT (and PRISM2_NON_VOLATILE_DOWNLOAD if you want
+to update flash); see driver/modules/hostap_config.h for more details.
+
+Jun Sun has written a mini-howto on flashing Intersil Prism
+Chipsets. This is available at http://linux.junsun.net/intersil-prism/.
+
+
+
+6. Why did I get two network interfaces (wlan0 and wifi0) even when I have
+ only one wireless card?
+
+Host AP driver supports multiple virtual interfaces per wireless
+card. wifi0 is the master radio interface and wlan0 is the first
+virtual interface for this radio. Other virtual interfaces are wlan0ap
+(for hostapd), and one interface per WDS link.
+
+In most cases, one should ignore wifi0 interface and just use wlan0
+interface. In other words, assign IP address to wlan0, not wifi0 and
+in general, just ignore the wifi0 interface.
+
+
+
+7. Why does my D-Link DWL-650 rev. P1 or D-Link DWL-520 rev. E1 (or any other
+ card with small flash) card fail?
+
+Some of the new Prism3-based cards use a smaller flash chip that does
+not include full firmware for the card. For example, D-Link DWL-650
+rev. P1 and D-Link DWL-520 rev. E1 are such cards. These cards require
+that the firmware is downloaded to the card during initialization. See
+utils/hostap_fw_load for example commands on doing this.
+
+
+
+8. Does Host AP driver support IEEE 802.11a and 802.11g? Does it support
+ chipsets other than Prism 2/2.5/3?
+
+Host AP driver supports only Intersil Prism chipsets, versions 2, 2.5,
+and 3. Those chipsets support IEEE 802.11b only; other chipsets are
+not supported. All utilities distributed with Host AP driver except
+wpa_supplicant work only with Host AP driver, so they are limited to
+the same hardware. wpa_supplicant works with other drivers, including
+those that support 802.11a and 802.11g.
diff --git a/README b/README
new file mode 100644
index 0000000..9c6be85
--- /dev/null
+++ b/README
@@ -0,0 +1,19 @@
+wpa_supplicant and hostapd v0.6.x
+---------------------------------
+
+Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+These program is dual-licensed under both the GPL version 2 and BSD
+license. Either license may be used at your option.
+
+
+This package may include either wpa_supplicant, hostapd, or both. See
+README file respective subdirectories (wpa_supplicant/README or
+hostapd/README) for more details.
+
+Source code files have been moved around in v0.6.x releases and
+compared to earlier releases, the programs are now build by first
+going to a subdirectory (wpa_supplicant or hostapd) and creating
+build configuration (.config) and running 'make' there (for
+Linux/BSD/cygwin builds).
diff --git a/build_release b/build_release
new file mode 100755
index 0000000..66da32b
--- /dev/null
+++ b/build_release
@@ -0,0 +1,143 @@
+#!/bin/sh
+
+# Path to the Windows cross compiler (mingw)
+WINCROSS=/opt/xmingw/bin
+WINLOCAL=/home/jm/H-win/local
+
+set -e
+
+if [ -z "$1" ]; then
+ echo "build_release <version> [nobin]"
+ exit 1
+fi
+
+TMP=tmp.build_release
+RELDIR=`pwd`/Release
+VER=$1
+NOW=`date +%Y-%m-%d`
+
+echo "Version: $VER - $NOW"
+
+DATEw=`head -n 3 wpa_supplicant/ChangeLog | tail -n 1 | sed "s/ .*//"`
+DATEh=`head -n 3 hostapd/ChangeLog | tail -n 1 | sed "s/ .*//"`
+
+if [ "$DATEw" != "$NOW" -o "$DATEh" != "$NOW" ]; then
+ echo "NOTE! Date mismatch in ChangeLog: wpa_supplicant $DATEw hostapd $DATEh != $NOW"
+fi
+
+if [ -r $TMP ]; then
+ echo "Temporary directory '$TMP' exists. Remove it before running this."
+ exit 1
+fi
+
+mkdir $TMP
+mkdir -p $RELDIR
+
+git-archive --format=tar --prefix=wpa-$VER/ HEAD \
+ README COPYING patches src wpa_supplicant hostapd |
+ gzip > $RELDIR/wpa-$VER.tar.gz
+git-archive --format=tar --prefix=hostapd-$VER/ HEAD \
+ README COPYING patches src hostapd |
+ gzip > $RELDIR/hostapd-$VER.tar.gz
+git-archive --format=tar --prefix=wpa_supplicant-$VER/ HEAD \
+ README COPYING patches src wpa_supplicant |
+ tar --directory=$TMP -xf -
+
+cd $TMP
+make -C wpa_supplicant-$VER/wpa_supplicant/doc/docbook man
+rm -f wpa_supplicant-$VER/wpa_supplicant/doc/docbook/manpage.{links,refs}
+tar czf $RELDIR/wpa_supplicant-$VER.tar.gz wpa_supplicant-$VER
+cd ..
+rm -r $TMP
+
+if [ "$2" == "nobin" ]; then
+ exit 0
+fi
+
+if [ -d $WINCROSS ]; then
+ pushd $RELDIR
+
+ PDIR=wpa_supplicant-$VER
+ WDIR=wpa_supplicant-windows-bin-$VER
+ tar xzf $PDIR.tar.gz
+ mkdir "$WDIR"
+ cd "$PDIR/wpa_supplicant"
+ cat > .config <<EOF
+CONFIG_DRIVER_NDIS=y
+CONFIG_NATIVE_WINDOWS=y
+
+CFLAGS += -I/opt/xmingw/i386-mingw32msvc/include/ddk
+CC=i386-mingw32msvc-gcc
+STRIP=i386-mingw32msvc-strip
+PLATFORMSDKLIB=$WINLOCAL/lib
+CONFIG_NDIS_EVENTS_INTEGRATED=y
+
+CFLAGS += -I$WINLOCAL/include
+LIBS += -L$WINLOCAL/lib
+LIBS_w += -L$WINLOCAL/lib
+LIBS_p += -L$WINLOCAL/lib
+
+CONFIG_EAP_SIM=y
+CONFIG_EAP_AKA=y
+CONFIG_EAP_LEAP=y
+CONFIG_EAP_FAST=y
+CONFIG_EAP_TLS=y
+
+CONFIG_CTRL_IFACE=y
+CONFIG_EAP_FAST=y
+CONFIG_EAP_MSCHAPV2=y
+CONFIG_EAP_TTLS=y
+CONFIG_EAP_PEAP=y
+CONFIG_EAP_MD5=y
+CONFIG_EAP_GTC=y
+CONFIG_EAP_OTP=y
+CONFIG_EAP_PAX=y
+CONFIG_EAP_SAKE=y
+CONFIG_EAP_PSK=y
+CONFIG_EAP_TNC=y
+CONFIG_PKCS12=y
+CONFIG_PCSC=y
+
+CONFIG_L2_PACKET=winpcap
+CONFIG_MAIN=main_winsvc
+CONFIG_BACKEND=winreg
+CONFIG_ELOOP=eloop_win
+CFLAGS += -DCONFIG_DEBUG_FILE
+EOF
+
+ # First, build the Windows service & registry version and rename it
+ PATH=$PATH:$WINCROSS make windows-bin
+ mv wpa_supplicant.exe wpasvc.exe
+
+ # Then, build "the standard" wpa_supplicant.exe
+ cat >> .config <<EOF
+CONFIG_MAIN=main
+CONFIG_BACKEND=file
+EOF
+
+ PATH=$PATH:$WINCROSS make windows-bin
+
+ for i in COPYING; do
+ unix2dos < ../$i > ../../"$WDIR"/$i
+ done
+ for i in README README-Windows.txt wpa_supplicant.conf; do
+ unix2dos < $i > ../../"$WDIR"/$i
+ done
+ mv *.exe ../../"$WDIR"
+ cp win_example.reg ../../"$WDIR"
+
+ cd wpa_gui-qt4
+ PATH=$PATH:$WINCROSS ./setup-mingw-cross-compiling
+ PATH=$PATH:$WINCROSS make
+ cp release/wpa_gui.exe ../../../"$WDIR"
+ cd ../../..
+ rm -rf "$PDIR"
+ zip "$WDIR.zip" "$WDIR"/*
+ rm -rf "$WDIR"
+
+ popd
+fi
+
+ls -l $RELDIR/*$VER*
+
+exit 0
diff --git a/eap_example/.gitignore b/eap_example/.gitignore
new file mode 100644
index 0000000..82a12a5
--- /dev/null
+++ b/eap_example/.gitignore
@@ -0,0 +1,3 @@
+*.d
+eap_example
+libeap.so
diff --git a/eap_example/Makefile b/eap_example/Makefile
new file mode 100644
index 0000000..0a7ca78
--- /dev/null
+++ b/eap_example/Makefile
@@ -0,0 +1,179 @@
+ALL=eap_example
+
+all: $(ALL)
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+CONFIG_TLS=openssl
+#CONFIG_TLS=internal
+#CONFIG_INTERNAL_LIBTOMMATH=y
+
+
+CFLAGS += -I.
+CFLAGS += -I../src
+CFLAGS += -I../src/crypto
+CFLAGS += -I../src/utils
+CFLAGS += -I../src/common
+
+# at least for now, need to include config_ssid.h and config_blob.h from
+# wpa_supplicant directory
+CFLAGS += -I../wpa_supplicant
+
+
+OBJS_both += ../src/utils/common.o
+OBJS_both += ../src/utils/os_unix.o
+OBJS_both += ../src/utils/wpa_debug.o
+OBJS_both += ../src/utils/base64.o
+OBJS_both += ../src/utils/wpabuf.o
+OBJS_both += ../src/crypto/md5.o
+OBJS_both += ../src/crypto/rc4.o
+OBJS_both += ../src/crypto/md4.o
+OBJS_both += ../src/crypto/sha1.o
+OBJS_both += ../src/crypto/des.o
+OBJS_both += ../src/crypto/aes_wrap.o
+OBJS_both += ../src/crypto/aes.o
+OBJS_both += ../src/crypto/ms_funcs.o
+OBJS_both += ../src/crypto/sha256.o
+
+
+OBJS_both += ../src/eap_common/eap_psk_common.o
+OBJS_both += ../src/eap_common/eap_pax_common.o
+OBJS_both += ../src/eap_common/eap_sake_common.o
+OBJS_both += ../src/eap_common/eap_gpsk_common.o
+OBJS_both += ../src/eap_common/chap.o
+
+OBJS_peer += ../src/eap_peer/eap_tls.o
+OBJS_peer += ../src/eap_peer/eap_peap.o
+OBJS_peer += ../src/eap_peer/eap_ttls.o
+OBJS_peer += ../src/eap_peer/eap_md5.o
+OBJS_peer += ../src/eap_peer/eap_mschapv2.o
+OBJS_peer += ../src/eap_peer/mschapv2.o
+OBJS_peer += ../src/eap_peer/eap_otp.o
+OBJS_peer += ../src/eap_peer/eap_gtc.o
+OBJS_peer += ../src/eap_peer/eap_leap.o
+OBJS_peer += ../src/eap_peer/eap_psk.o
+OBJS_peer += ../src/eap_peer/eap_tlv.o
+OBJS_peer += ../src/eap_peer/eap_pax.o
+OBJS_peer += ../src/eap_peer/eap_sake.o
+OBJS_peer += ../src/eap_peer/eap_gpsk.o
+OBJS_peer += ../src/eap_peer/eap.o
+OBJS_peer += ../src/eap_common/eap_common.o
+OBJS_peer += ../src/eap_peer/eap_methods.o
+OBJS_peer += ../src/eap_peer/eap_tls_common.o
+
+CFLAGS += -DEAP_TLS
+CFLAGS += -DEAP_PEAP
+CFLAGS += -DEAP_TTLS
+CFLAGS += -DEAP_MD5
+CFLAGS += -DEAP_MSCHAPv2
+CFLAGS += -DEAP_GTC
+CFLAGS += -DEAP_OTP
+CFLAGS += -DEAP_LEAP
+CFLAGS += -DEAP_PSK
+CFLAGS += -DEAP_TLV
+CFLAGS += -DEAP_PAX
+CFLAGS += -DEAP_SAKE
+CFLAGS += -DEAP_GPSK -DEAP_GPSK_SHA256
+CFLAGS += -DEAP_TLS_FUNCS
+
+CFLAGS += -DIEEE8021X_EAPOL
+
+ifeq ($(CONFIG_TLS), openssl)
+CFLAGS += -DEAP_TLS_OPENSSL
+OBJS_both += ../src/crypto/tls_openssl.o
+OBJS_both += ../src/crypto/crypto_openssl.o
+LIBS += -lssl -lcrypto
+CFLAGS += -DINTERNAL_SHA256
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+OBJS_both += ../src/crypto/tls_internal.o
+OBJS_both += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_record.o
+OBJS_both += ../src/tls/tlsv1_cred.o
+OBJS_both += ../src/tls/asn1.o ../src/tls/x509v3.o
+OBJS_both += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o
+
+OBJS_peer += ../src/tls/tlsv1_client.o
+OBJS_peer += ../src/tls/tlsv1_client_write.o ../src/tls/tlsv1_client_read.o
+CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
+
+OBJS_server += ../src/tls/tlsv1_server.o
+OBJS_server += ../src/tls/tlsv1_server_write.o ../src/tls/tlsv1_server_read.o
+CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+
+CFLAGS += -DCONFIG_TLS_INTERNAL
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+CFLAGS += -DCONFIG_INTERNAL_X509
+CFLAGS += -DINTERNAL_AES
+CFLAGS += -DINTERNAL_SHA1
+CFLAGS += -DINTERNAL_SHA256
+CFLAGS += -DINTERNAL_MD5
+CFLAGS += -DINTERNAL_MD4
+CFLAGS += -DINTERNAL_DES
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+else
+LIBS += -ltommath
+endif
+endif
+
+
+
+# Optional components to add EAP server support
+OBJS_server += ../src/eap_server/eap_tls.o
+OBJS_server += ../src/eap_server/eap_peap.o
+OBJS_server += ../src/eap_server/eap_ttls.o
+OBJS_server += ../src/eap_server/eap_md5.o
+OBJS_server += ../src/eap_server/eap_mschapv2.o
+OBJS_server += ../src/eap_server/eap_gtc.o
+OBJS_server += ../src/eap_server/eap_psk.o
+OBJS_server += ../src/eap_server/eap_tlv.o
+OBJS_server += ../src/eap_server/eap_pax.o
+OBJS_server += ../src/eap_server/eap_sake.o
+OBJS_server += ../src/eap_server/eap_gpsk.o
+OBJS_server += ../src/eap_server/eap.o
+OBJS_server += ../src/eap_server/eap_identity.o
+OBJS_server += ../src/eap_server/eap_methods.o
+OBJS_server += ../src/eap_server/eap_tls_common.o
+CFLAGS += -DEAP_SERVER
+
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+
+OBJS_lib=$(OBJS_both) $(OBJS_peer) $(OBJS_server)
+
+OBJS_ex = eap_example.o eap_example_peer.o eap_example_server.o
+
+ifneq ($(CONFIG_SOLIB), yes)
+LIBEAP = libeap.a
+libeap.a: $(OBJS_lib)
+ ar rc libeap.a $(OBJS_lib)
+ ranlib libeap.a
+
+else
+CFLAGS += -fPIC -DPIC
+LDFLAGS += -shared
+
+LIBEAP = libeap.so
+libeap.so: $(OBJS_lib)
+ $(LDO) $(LDFLAGS) $(OBJS_lib) -o $(LIBEAP)
+
+endif
+
+eap_example: $(OBJS_ex) $(LIBEAP)
+ $(LDO) $(LDFLAGS) -o eap_example $(OBJS_ex) -L. -leap $(LIBS)
+
+clean:
+ $(MAKE) -C ../src clean
+ rm -f core *~ *.o *.d libeap.a libeap.so $(ALL)
+
+-include $(OBJS:%.o=%.d)
diff --git a/eap_example/README b/eap_example/README
new file mode 100644
index 0000000..b897ab5
--- /dev/null
+++ b/eap_example/README
@@ -0,0 +1,46 @@
+EAP peer/server library and example program
+Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+Alternatively, this software may be distributed under the terms of BSD
+license.
+
+
+The interfaces of the EAP server/peer implementation are based on RFC
+4137 (EAP State Machines). This RFC is coordinated with the state
+machines defined in IEEE 802.1X-2004. hostapd and wpa_supplicant
+include implementation of the IEEE 802.1X EAPOL state machines and the
+interface between them and EAP. However, the EAP implementation can be
+used with other protocols, too, by providing a compatible interface
+which maps the EAPOL<->EAP variables to another protocol.
+
+This directory contains an example showing how EAP peer and server
+code from wpa_supplicant and hostapd can be used as a library. The
+example program initializes both an EAP server and an EAP peer
+entities and then runs through an EAP-PEAP/MSCHAPv2 authentication.
+
+eap_example_peer.c shows the initialization and glue code needed to
+control the EAP peer implementation. eap_example_server.c does the
+same for EAP server. eap_example.c is an example that ties in both the
+EAP server and client parts to allow an EAP authentication to be
+shown.
+
+In this example, the EAP messages are passed between the server and
+the peer are passed by direct function calls within the same process.
+In practice, server and peer functionalities would likely reside in
+separate devices and the EAP messages would be transmitted between the
+devices based on an external protocol. For example, in IEEE 802.11
+uses IEEE 802.1X EAPOL state machines to control the transmission of
+EAP messages and WiMax supports optional PMK EAP authentication
+mechanism that transmits EAP messages as defined in IEEE 802.16e.
+
+
+The EAP library links in number of helper functions from src/utils and
+src/crypto directories. Most of these are suitable as-is, but it may
+be desirable to replace the debug output code in src/utils/wpa_debug.c
+by dropping this file from the library and re-implementing the
+functions there in a way that better fits in with the main
+application.
diff --git a/eap_example/ca.pem b/eap_example/ca.pem
new file mode 100644
index 0000000..bfae1cc
--- /dev/null
+++ b/eap_example/ca.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDBzCCAnCgAwIBAgIJAIb4NS4TdLXUMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ4wDAYDVQQKEwV3MS5maTEQMA4G
+A1UEAxMHVGVzdCBDQTEbMBkGCSqGSIb3DQEJARYMdGVzdGNhQHcxLmZpMB4XDTA3
+MTIwOTAzMTQzN1oXDTE3MTIwNjAzMTQzN1owYTELMAkGA1UEBhMCVVMxEzARBgNV
+BAgTCkNhbGlmb3JuaWExDjAMBgNVBAoTBXcxLmZpMRAwDgYDVQQDEwdUZXN0IENB
+MRswGQYJKoZIhvcNAQkBFgx0ZXN0Y2FAdzEuZmkwgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBAO6GoecRclnILh9FTvqnY/yUZmeJDgC+3/PQiicpMDhAzCkWAmi+
+a1LSnqakNN/GdCy3q053TFLFEzhEHkhhRwY/zzj2vZIcFZESoUhr67CzCpcPmTGa
+AfOzsGPjaH6xYcaOR4RZMfXd/EKfAauHxj3LuCusLL5hK/FwxWhQJNJrAgMBAAGj
+gcYwgcMwHQYDVR0OBBYEFKhJuSLJ6JhcB/dRgB8j0h9mOlpKMIGTBgNVHSMEgYsw
+gYiAFKhJuSLJ6JhcB/dRgB8j0h9mOlpKoWWkYzBhMQswCQYDVQQGEwJVUzETMBEG
+A1UECBMKQ2FsaWZvcm5pYTEOMAwGA1UEChMFdzEuZmkxEDAOBgNVBAMTB1Rlc3Qg
+Q0ExGzAZBgkqhkiG9w0BCQEWDHRlc3RjYUB3MS5maYIJAIb4NS4TdLXUMAwGA1Ud
+EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAuU+5Uerq+n8WgiIsiANT3wUoGe2Y
+cnoQi2nVjUHrivgMDufH0tgh1AVfc3wVNNREdGC136qr1KBNqalQx2rKZ76xeNqW
+sQa2LIC2wE7Q7LJsltUcUjPyZHGUhBqWjKsCvlonfNB6JHkEayTEvVvyupgzTsxW
+QuuRdZ0sNv/S8VI=
+-----END CERTIFICATE-----
diff --git a/eap_example/eap_example.c b/eap_example/eap_example.c
new file mode 100644
index 0000000..b8917c8
--- /dev/null
+++ b/eap_example/eap_example.c
@@ -0,0 +1,55 @@
+/*
+ * Example application showing how EAP peer and server code from
+ * wpa_supplicant/hostapd can be used as a library. This example program
+ * initializes both an EAP server and an EAP peer entities and then runs
+ * through an EAP-PEAP/MSCHAPv2 authentication.
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+
+
+int eap_example_peer_init(void);
+void eap_example_peer_deinit(void);
+int eap_example_peer_step(void);
+
+int eap_example_server_init(void);
+void eap_example_server_deinit(void);
+int eap_example_server_step(void);
+
+
+extern int wpa_debug_level;
+
+int main(int argc, char *argv[])
+{
+ int res_s, res_p;
+
+ wpa_debug_level = 0;
+
+ if (eap_example_peer_init() < 0 ||
+ eap_example_server_init() < 0)
+ return -1;
+
+ do {
+ printf("---[ server ]--------------------------------\n");
+ res_s = eap_example_server_step();
+ printf("---[ peer ]----------------------------------\n");
+ res_p = eap_example_peer_step();
+ } while (res_s || res_p);
+
+ eap_example_peer_deinit();
+ eap_example_server_deinit();
+
+ return 0;
+}
diff --git a/eap_example/eap_example_peer.c b/eap_example/eap_example_peer.c
new file mode 100644
index 0000000..c8b8415
--- /dev/null
+++ b/eap_example/eap_example_peer.c
@@ -0,0 +1,270 @@
+/*
+ * Example application showing how EAP peer code from wpa_supplicant can be
+ * used as a library.
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_peer/eap.h"
+#include "eap_peer/eap_config.h"
+#include "wpabuf.h"
+
+void eap_example_server_rx(const u8 *data, size_t data_len);
+
+
+struct eap_peer_ctx {
+ Boolean eapSuccess;
+ Boolean eapRestart;
+ Boolean eapFail;
+ Boolean eapResp;
+ Boolean eapNoResp;
+ Boolean eapReq;
+ Boolean portEnabled;
+ Boolean altAccept; /* for EAP */
+ Boolean altReject; /* for EAP */
+
+ struct wpabuf *eapReqData; /* for EAP */
+
+ unsigned int idleWhile; /* for EAP state machine */
+
+ struct eap_peer_config eap_config;
+ struct eap_sm *eap;
+};
+
+
+static struct eap_peer_ctx eap_ctx;
+
+
+static struct eap_peer_config * peer_get_config(void *ctx)
+{
+ struct eap_peer_ctx *peer = ctx;
+ return &peer->eap_config;
+}
+
+
+static Boolean peer_get_bool(void *ctx, enum eapol_bool_var variable)
+{
+ struct eap_peer_ctx *peer = ctx;
+ if (peer == NULL)
+ return FALSE;
+ switch (variable) {
+ case EAPOL_eapSuccess:
+ return peer->eapSuccess;
+ case EAPOL_eapRestart:
+ return peer->eapRestart;
+ case EAPOL_eapFail:
+ return peer->eapFail;
+ case EAPOL_eapResp:
+ return peer->eapResp;
+ case EAPOL_eapNoResp:
+ return peer->eapNoResp;
+ case EAPOL_eapReq:
+ return peer->eapReq;
+ case EAPOL_portEnabled:
+ return peer->portEnabled;
+ case EAPOL_altAccept:
+ return peer->altAccept;
+ case EAPOL_altReject:
+ return peer->altReject;
+ }
+ return FALSE;
+}
+
+
+static void peer_set_bool(void *ctx, enum eapol_bool_var variable,
+ Boolean value)
+{
+ struct eap_peer_ctx *peer = ctx;
+ if (peer == NULL)
+ return;
+ switch (variable) {
+ case EAPOL_eapSuccess:
+ peer->eapSuccess = value;
+ break;
+ case EAPOL_eapRestart:
+ peer->eapRestart = value;
+ break;
+ case EAPOL_eapFail:
+ peer->eapFail = value;
+ break;
+ case EAPOL_eapResp:
+ peer->eapResp = value;
+ break;
+ case EAPOL_eapNoResp:
+ peer->eapNoResp = value;
+ break;
+ case EAPOL_eapReq:
+ peer->eapReq = value;
+ break;
+ case EAPOL_portEnabled:
+ peer->portEnabled = value;
+ break;
+ case EAPOL_altAccept:
+ peer->altAccept = value;
+ break;
+ case EAPOL_altReject:
+ peer->altReject = value;
+ break;
+ }
+}
+
+
+static unsigned int peer_get_int(void *ctx, enum eapol_int_var variable)
+{
+ struct eap_peer_ctx *peer = ctx;
+ if (peer == NULL)
+ return 0;
+ switch (variable) {
+ case EAPOL_idleWhile:
+ return peer->idleWhile;
+ }
+ return 0;
+}
+
+
+static void peer_set_int(void *ctx, enum eapol_int_var variable,
+ unsigned int value)
+{
+ struct eap_peer_ctx *peer = ctx;
+ if (peer == NULL)
+ return;
+ switch (variable) {
+ case EAPOL_idleWhile:
+ peer->idleWhile = value;
+ break;
+ }
+}
+
+
+static struct wpabuf * peer_get_eapReqData(void *ctx)
+{
+ struct eap_peer_ctx *peer = ctx;
+ if (peer == NULL || peer->eapReqData == NULL)
+ return NULL;
+
+ return peer->eapReqData;
+}
+
+
+static void peer_set_config_blob(void *ctx, struct wpa_config_blob *blob)
+{
+ printf("TODO: %s\n", __func__);
+}
+
+
+static const struct wpa_config_blob *
+peer_get_config_blob(void *ctx, const char *name)
+{
+ printf("TODO: %s\n", __func__);
+ return NULL;
+}
+
+
+static void peer_notify_pending(void *ctx)
+{
+ printf("TODO: %s\n", __func__);
+}
+
+
+static struct eapol_callbacks eap_cb;
+static struct eap_config eap_conf;
+
+int eap_example_peer_init(void)
+{
+ if (eap_peer_register_methods() < 0)
+ return -1;
+
+ os_memset(&eap_ctx, 0, sizeof(eap_ctx));
+
+ eap_ctx.eap_config.identity = (u8 *) os_strdup("user");
+ eap_ctx.eap_config.identity_len = 4;
+ eap_ctx.eap_config.password = (u8 *) os_strdup("password");
+ eap_ctx.eap_config.password_len = 8;
+ eap_ctx.eap_config.ca_cert = (u8 *) os_strdup("ca.pem");
+ eap_ctx.eap_config.fragment_size = 1398;
+
+ os_memset(&eap_cb, 0, sizeof(eap_cb));
+ eap_cb.get_config = peer_get_config;
+ eap_cb.get_bool = peer_get_bool;
+ eap_cb.set_bool = peer_set_bool;
+ eap_cb.get_int = peer_get_int;
+ eap_cb.set_int = peer_set_int;
+ eap_cb.get_eapReqData = peer_get_eapReqData;
+ eap_cb.set_config_blob = peer_set_config_blob;
+ eap_cb.get_config_blob = peer_get_config_blob;
+ eap_cb.notify_pending = peer_notify_pending;
+
+ os_memset(&eap_conf, 0, sizeof(eap_conf));
+ eap_ctx.eap = eap_peer_sm_init(&eap_ctx, &eap_cb, &eap_ctx, &eap_conf);
+ if (eap_ctx.eap == NULL)
+ return -1;
+
+ /* Enable "port" to allow authentication */
+ eap_ctx.portEnabled = TRUE;
+
+ return 0;
+}
+
+
+void eap_example_peer_deinit(void)
+{
+ eap_peer_sm_deinit(eap_ctx.eap);
+ eap_peer_unregister_methods();
+ wpabuf_free(eap_ctx.eapReqData);
+ os_free(eap_ctx.eap_config.identity);
+ os_free(eap_ctx.eap_config.password);
+ os_free(eap_ctx.eap_config.ca_cert);
+}
+
+
+int eap_example_peer_step(void)
+{
+ int res;
+ res = eap_peer_sm_step(eap_ctx.eap);
+
+ if (eap_ctx.eapResp) {
+ struct wpabuf *resp;
+ printf("==> Response\n");
+ eap_ctx.eapResp = FALSE;
+ resp = eap_get_eapRespData(eap_ctx.eap);
+ if (resp) {
+ /* Send EAP response to the server */
+ eap_example_server_rx(wpabuf_head(resp),
+ wpabuf_len(resp));
+ wpabuf_free(resp);
+ }
+ }
+
+ if (eap_ctx.eapSuccess) {
+ res = 0;
+ if (eap_key_available(eap_ctx.eap)) {
+ const u8 *key;
+ size_t key_len;
+ key = eap_get_eapKeyData(eap_ctx.eap, &key_len);
+ wpa_hexdump(MSG_DEBUG, "EAP keying material",
+ key, key_len);
+ }
+ }
+
+ return res;
+}
+
+
+void eap_example_peer_rx(const u8 *data, size_t data_len)
+{
+ /* Make received EAP message available to the EAP library */
+ eap_ctx.eapReq = TRUE;
+ wpabuf_free(eap_ctx.eapReqData);
+ eap_ctx.eapReqData = wpabuf_alloc_copy(data, data_len);
+}
diff --git a/eap_example/eap_example_server.c b/eap_example/eap_example_server.c
new file mode 100644
index 0000000..897aa26
--- /dev/null
+++ b/eap_example/eap_example_server.c
@@ -0,0 +1,192 @@
+/*
+ * Example application showing how EAP server code from hostapd can be used as
+ * a library.
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_server/eap.h"
+#include "tls.h"
+#include "wpabuf.h"
+
+void eap_example_peer_rx(const u8 *data, size_t data_len);
+
+
+struct eap_server_ctx {
+ struct eap_eapol_interface *eap_if;
+ struct eap_sm *eap;
+ void *tls_ctx;
+};
+
+static struct eap_server_ctx eap_ctx;
+
+
+static int server_get_eap_user(void *ctx, const u8 *identity,
+ size_t identity_len, int phase2,
+ struct eap_user *user)
+{
+ os_memset(user, 0, sizeof(*user));
+
+ if (!phase2) {
+ /* Only allow EAP-PEAP as the Phase 1 method */
+ user->methods[0].vendor = EAP_VENDOR_IETF;
+ user->methods[0].method = EAP_TYPE_PEAP;
+ return 0;
+ }
+
+ if (identity_len != 4 || identity == NULL ||
+ os_memcmp(identity, "user", 4) != 0) {
+ printf("Unknown user\n");
+ return -1;
+ }
+
+ /* Only allow EAP-MSCHAPv2 as the Phase 2 method */
+ user->methods[0].vendor = EAP_VENDOR_IETF;
+ user->methods[0].method = EAP_TYPE_MSCHAPV2;
+ user->password = (u8 *) os_strdup("password");
+ user->password_len = 8;
+
+ return 0;
+}
+
+
+static const char * server_get_eap_req_id_text(void *ctx, size_t *len)
+{
+ *len = 0;
+ return NULL;
+}
+
+
+static struct eapol_callbacks eap_cb;
+static struct eap_config eap_conf;
+
+static int eap_example_server_init_tls(void)
+{
+ struct tls_config tconf;
+ struct tls_connection_params tparams;
+
+ os_memset(&tconf, 0, sizeof(tconf));
+ eap_ctx.tls_ctx = tls_init(&tconf);
+ if (eap_ctx.tls_ctx == NULL)
+ return -1;
+
+ os_memset(&tparams, 0, sizeof(tparams));
+ tparams.ca_cert = "ca.pem";
+ tparams.client_cert = "server.pem";
+ tparams.private_key = "server.key";
+ tparams.private_key_passwd = "whatever";
+
+ if (tls_global_set_params(eap_ctx.tls_ctx, &tparams)) {
+ printf("Failed to set TLS parameters\n");
+ return -1;
+ }
+
+ if (tls_global_set_verify(eap_ctx.tls_ctx, 0)) {
+ printf("Failed to set check_crl\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int eap_example_server_init(void)
+{
+ if (eap_server_register_methods() < 0)
+ return -1;
+
+ os_memset(&eap_ctx, 0, sizeof(eap_ctx));
+
+ if (eap_example_server_init_tls() < 0)
+ return -1;
+
+ os_memset(&eap_cb, 0, sizeof(eap_cb));
+ eap_cb.get_eap_user = server_get_eap_user;
+ eap_cb.get_eap_req_id_text = server_get_eap_req_id_text;
+
+ os_memset(&eap_conf, 0, sizeof(eap_conf));
+ eap_conf.eap_server = 1;
+ eap_conf.ssl_ctx = eap_ctx.tls_ctx;
+
+ eap_ctx.eap = eap_server_sm_init(&eap_ctx, &eap_cb, &eap_conf);
+ if (eap_ctx.eap == NULL)
+ return -1;
+
+ eap_ctx.eap_if = eap_get_interface(eap_ctx.eap);
+
+ /* Enable "port" and request EAP to start authentication. */
+ eap_ctx.eap_if->portEnabled = TRUE;
+ eap_ctx.eap_if->eapRestart = TRUE;
+
+ return 0;
+}
+
+
+void eap_example_server_deinit(void)
+{
+ eap_server_sm_deinit(eap_ctx.eap);
+ eap_server_unregister_methods();
+ tls_deinit(eap_ctx.tls_ctx);
+}
+
+
+int eap_example_server_step(void)
+{
+ int res, process = 0;
+
+ res = eap_server_sm_step(eap_ctx.eap);
+
+ if (eap_ctx.eap_if->eapReq) {
+ printf("==> Request\n");
+ process = 1;
+ eap_ctx.eap_if->eapReq = 0;
+ }
+
+ if (eap_ctx.eap_if->eapSuccess) {
+ printf("==> Success\n");
+ process = 1;
+ res = 0;
+ eap_ctx.eap_if->eapSuccess = 0;
+
+ if (eap_ctx.eap_if->eapKeyAvailable) {
+ wpa_hexdump(MSG_DEBUG, "EAP keying material",
+ eap_ctx.eap_if->eapKeyData,
+ eap_ctx.eap_if->eapKeyDataLen);
+ }
+ }
+
+ if (eap_ctx.eap_if->eapFail) {
+ printf("==> Fail\n");
+ process = 1;
+ eap_ctx.eap_if->eapFail = 0;
+ }
+
+ if (process && eap_ctx.eap_if->eapReqData) {
+ /* Send EAP response to the server */
+ eap_example_peer_rx(wpabuf_head(eap_ctx.eap_if->eapReqData),
+ wpabuf_len(eap_ctx.eap_if->eapReqData));
+ }
+
+ return res;
+}
+
+
+void eap_example_server_rx(const u8 *data, size_t data_len)
+{
+ /* Make received EAP message available to the EAP library */
+ wpabuf_free(eap_ctx.eap_if->eapRespData);
+ eap_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len);
+ if (eap_ctx.eap_if->eapRespData)
+ eap_ctx.eap_if->eapResp = TRUE;
+}
diff --git a/eap_example/server.key b/eap_example/server.key
new file mode 100644
index 0000000..4f32591
--- /dev/null
+++ b/eap_example/server.key
Binary files differ
diff --git a/eap_example/server.pem b/eap_example/server.pem
new file mode 100644
index 0000000..02f6e7b
--- /dev/null
+++ b/eap_example/server.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAjygAwIBAgIJAIb4NS4TdLXVMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ4wDAYDVQQKEwV3MS5maTEQMA4G
+A1UEAxMHVGVzdCBDQTEbMBkGCSqGSIb3DQEJARYMdGVzdGNhQHcxLmZpMB4XDTA3
+MTIwOTAzMTUwOFoXDTE3MTIwNjAzMTUwOFoweTELMAkGA1UEBhMCVVMxEzARBgNV
+BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDjAMBgNVBAoT
+BXcxLmZpMRAwDgYDVQQDEwdUZXN0IEFTMRswGQYJKoZIhvcNAQkBFgx0ZXN0YXNA
+dzEuZmkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOhi4M+aMRa778CPRFV
+ZNJvTuxfp0CQ+etNpSNkAbkCGNGolbPMPnSQWZUqL5HsaBLm2UbMtS2iR3CO5JQC
+bPy0xfAjCZV5LQeW4UNVKL3hdtVFzMT6fKgOKCDVEbLLWZze3lEbzhu81q2r3w5x
+4lqDieCHwvwjiTWpMtEyXIEnAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4
+QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBRb
+xGTC3mPimgyGb5vYLLV5wyc9ITAfBgNVHSMEGDAWgBSoSbkiyeiYXAf3UYAfI9If
+ZjpaSjANBgkqhkiG9w0BAQUFAAOBgQA9wVGtroz/rsx1EeALJejW01SAr4kpTxoS
+WP6zuWFb+J/lJd7DeVM6/QBYAwZb0fB6nwSpJJCj6XDRZtN/yLeaTd/rCZrfom4Z
+8gbkWMTXDn2Cea2VnCe5W0gK+4dIj5DD5CpPvgt4lYqlwN0WAih6twd7Q4x/tiiJ
+ejNQzlTHOg==
+-----END CERTIFICATE-----
diff --git a/hostapd/.gitignore b/hostapd/.gitignore
new file mode 100644
index 0000000..6dd2c2f
--- /dev/null
+++ b/hostapd/.gitignore
@@ -0,0 +1,7 @@
+*.d
+.config
+driver_conf.c
+hostapd
+hostapd_cli
+hlr_auc_gw
+nt_password_hash
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
new file mode 100644
index 0000000..ce41c58
--- /dev/null
+++ b/hostapd/ChangeLog
@@ -0,0 +1,477 @@
+ChangeLog for hostapd
+
+2008-02-22 - v0.6.3
+ * fixed Reassociation Response callback processing when using internal
+ MLME (driver_{hostap,nl80211,test}.c)
+ * updated FT support to use the latest draft, IEEE 802.11r/D9.0
+ * copy optional Proxy-State attributes into RADIUS response when acting
+ as a RADIUS authentication server
+ * fixed EAPOL state machine to handle a case in which no response is
+ received from the RADIUS authentication server; previous version
+ could have triggered a crash in some cases after a timeout
+ * fixed EAP-SIM/AKA realm processing to allow decorated usernames to
+ be used
+ * added a workaround for EAP-SIM/AKA peers that include incorrect null
+ termination in the username
+ * fixed EAP-SIM/AKA protected result indication to include AT_COUNTER
+ attribute in notification messages only when using fast
+ reauthentication
+ * fixed EAP-SIM Start response processing for fast reauthentication
+ case
+ * added support for pending EAP processing in EAP-{PEAP,TTLS,FAST}
+ phase 2 to allow EAP-SIM and EAP-AKA to be used as the Phase 2 method
+
+2008-01-01 - v0.6.2
+ * fixed EAP-SIM and EAP-AKA message parser to validate attribute
+ lengths properly to avoid potential crash caused by invalid messages
+ * added data structure for storing allocated buffers (struct wpabuf);
+ this does not affect hostapd usage, but many of the APIs changed
+ and various interfaces (e.g., EAP) is not compatible with old
+ versions
+ * added support for protecting EAP-AKA/Identity messages with
+ AT_CHECKCODE (optional feature in RFC 4187)
+ * added support for protected result indication with AT_RESULT_IND for
+ EAP-SIM and EAP-AKA (eap_sim_aka_result_ind=1)
+ * added support for configuring EAP-TTLS phase 2 non-EAP methods in
+ EAP server configuration; previously all four were enabled for every
+ phase 2 user, now all four are disabled by default and need to be
+ enabled with new method names TTLS-PAP, TTLS-CHAP, TTLS-MSCHAP,
+ TTLS-MSCHAPV2
+ * removed old debug printing mechanism and the related 'debug'
+ parameter in the configuration file; debug verbosity is now set with
+ -d (or -dd) command line arguments
+ * added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt);
+ only shared key/password authentication is supported in this version
+
+2007-11-24 - v0.6.1
+ * added experimental, integrated TLSv1 server implementation with the
+ needed X.509/ASN.1/RSA/bignum processing (this can be enabled by
+ setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in
+ .config); this can be useful, e.g., if the target system does not
+ have a suitable TLS library and a minimal code size is required
+ * added support for EAP-FAST server method to the integrated EAP
+ server
+ * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+ draft (draft-ietf-emu-eap-gpsk-07.txt)
+ * added a new configuration parameter, rsn_pairwise, to allow different
+ pairwise cipher suites to be enabled for WPA and RSN/WPA2
+ (note: if wpa_pairwise differs from rsn_pairwise, the driver will
+ either need to support this or will have to use the WPA/RSN IEs from
+ hostapd; currently, the included madwifi and bsd driver interfaces do
+ not have support for this)
+ * updated FT support to use the latest draft, IEEE 802.11r/D8.0
+
+2007-05-28 - v0.6.0
+ * added experimental IEEE 802.11r/D6.0 support
+ * updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48
+ * updated EAP-PSK to use the IANA-allocated EAP type 47
+ * fixed EAP-PSK bit ordering of the Flags field
+ * fixed configuration reloading (SIGHUP) to re-initialize WPA PSKs
+ by reading wpa_psk_file [Bug 181]
+ * fixed EAP-TTLS AVP parser processing for too short AVP lengths
+ * fixed IPv6 connection to RADIUS accounting server
+ * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+ draft (draft-ietf-emu-eap-gpsk-04.txt)
+ * hlr_auc_gw: read GSM triplet file into memory and rotate through the
+ entries instead of only using the same three triplets every time
+ (this does not work properly with tests using multiple clients, but
+ provides bit better triplet data for testing a single client; anyway,
+ if a better quality triplets are needed, GSM-Milenage should be used
+ instead of hardcoded triplet file)
+ * fixed EAP-MSCHAPv2 server to use a space between S and M parameters
+ in Success Request [Bug 203]
+ * added support for sending EAP-AKA Notifications in error cases
+ * updated to use IEEE 802.11w/D2.0 for management frame protection
+ (still experimental)
+ * RADIUS server: added support for processing duplicate messages
+ (retransmissions from RADIUS client) by replying with the previous
+ reply
+
+2006-11-24 - v0.5.6
+ * added support for configuring and controlling multiple BSSes per
+ radio interface (bss=<ifname> in hostapd.conf); this is only
+ available with Devicescape and test driver interfaces
+ * fixed PMKSA cache update in the end of successful RSN
+ pre-authentication
+ * added support for dynamic VLAN configuration (i.e., selecting VLAN-ID
+ for each STA based on RADIUS Access-Accept attributes); this requires
+ VLAN support from the kernel driver/802.11 stack and this is
+ currently only available with Devicescape and test driver interfaces
+ * driver_madwifi: fixed configuration of unencrypted modes (plaintext
+ and IEEE 802.1X without WEP)
+ * removed STAKey handshake since PeerKey handshake has replaced it in
+ IEEE 802.11ma and there are no known deployments of STAKey
+ * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+ draft (draft-ietf-emu-eap-gpsk-01.txt)
+ * added preliminary implementation of IEEE 802.11w/D1.0 (management
+ frame protection)
+ (Note: this requires driver support to work properly.)
+ (Note2: IEEE 802.11w is an unapproved draft and subject to change.)
+ * hlr_auc_gw: added support for GSM-Milenage (for EAP-SIM)
+ * hlr_auc_gw: added support for reading per-IMSI Milenage keys and
+ parameters from a text file to make it possible to implement proper
+ GSM/UMTS authentication server for multiple SIM/USIM cards using
+ EAP-SIM/EAP-AKA
+ * fixed session timeout processing with drivers that do not use
+ ieee802_11.c (e.g., madwifi)
+
+2006-08-27 - v0.5.5
+ * added 'hostapd_cli new_sta <addr>' command for adding a new STA into
+ hostapd (e.g., to initialize wired network authentication based on an
+ external signal)
+ * fixed hostapd to add PMKID KDE into 4-Way Handshake Message 1 when
+ using WPA2 even if PMKSA caching is not used
+ * added -P<pid file> argument for hostapd to write the current process
+ id into a file
+ * added support for RADIUS Authentication Server MIB (RFC 2619)
+
+2006-06-20 - v0.5.4
+ * fixed nt_password_hash build [Bug 144]
+ * added PeerKey handshake implementation for IEEE 802.11e
+ direct link setup (DLS) to replace STAKey handshake
+ * added support for EAP Generalized Pre-Shared Key (EAP-GPSK,
+ draft-clancy-emu-eap-shared-secret-00.txt)
+ * fixed a segmentation fault when RSN pre-authentication was completed
+ successfully [Bug 152]
+
+2006-04-27 - v0.5.3
+ * do not build nt_password_hash and hlr_auc_gw by default to avoid
+ requiring a TLS library for a successful build; these programs can be
+ build with 'make nt_password_hash' and 'make hlr_auc_gw'
+ * added a new configuration option, eapol_version, that can be used to
+ set EAPOL version to 1 (default is 2) to work around broken client
+ implementations that drop EAPOL frames which use version number 2
+ [Bug 89]
+ * added support for EAP-SAKE (no EAP method number allocated yet, so
+ this is using the same experimental type 255 as EAP-PSK)
+ * fixed EAP-MSCHAPv2 message length validation
+
+2006-03-19 - v0.5.2
+ * fixed stdarg use in hostapd_logger(): if both stdout and syslog
+ logging was enabled, hostapd could trigger a segmentation fault in
+ vsyslog on some CPU -- C library combinations
+ * moved HLR/AuC gateway implementation for EAP-SIM/AKA into an external
+ program to make it easier to use for implementing real SS7 gateway;
+ eap_sim_db is not anymore used as a file name for GSM authentication
+ triplets; instead, it is path to UNIX domain socket that will be used
+ to communicate with the external gateway program (e.g., hlr_auc_gw)
+ * added example HLR/AuC gateway implementation, hlr_auc_gw, that uses
+ local information (GSM authentication triplets from a text file and
+ hardcoded AKA authentication data); this can be used to test EAP-SIM
+ and EAP-AKA
+ * added Milenage algorithm (example 3GPP AKA algorithm) to hlr_auc_gw
+ to make it possible to test EAP-AKA with real USIM cards (this is
+ disabled by default; define AKA_USE_MILENAGE when building hlr_auc_gw
+ to enable this)
+ * driver_madwifi: added support for getting station RSN IE from
+ madwifi-ng svn r1453 and newer; this fixes RSN that was apparently
+ broken with earlier change (r1357) in the driver
+ * changed EAP method registration to use a dynamic list of methods
+ instead of a static list generated at build time
+ * fixed WPA message 3/4 not to encrypt Key Data field (WPA IE)
+ [Bug 125]
+ * added ap_max_inactivity configuration parameter
+
+2006-01-29 - v0.5.1
+ * driver_test: added better support for multiple APs and STAs by using
+ a directory with sockets that include MAC address for each device in
+ the name (test_socket=DIR:/tmp/test)
+ * added support for EAP expanded type (vendor specific EAP methods)
+
+2005-12-18 - v0.5.0 (beginning of 0.5.x development releases)
+ * added experimental STAKey handshake implementation for IEEE 802.11e
+ direct link setup (DLS); note: this is disabled by default in both
+ build and runtime configuration (can be enabled with CONFIG_STAKEY=y
+ and stakey=1)
+ * added support for EAP methods to use callbacks to external programs
+ by buffering a pending request and processing it after the EAP method
+ is ready to continue
+ * improved EAP-SIM database interface to allow external request to GSM
+ HLR/AuC without blocking hostapd process
+ * added support for using EAP-SIM pseudonyms and fast re-authentication
+ * added support for EAP-AKA in the integrated EAP authenticator
+ * added support for matching EAP identity prefixes (e.g., "1"*) in EAP
+ user database to allow EAP-SIM/AKA selection without extra roundtrip
+ for EAP-Nak negotiation
+ * added support for storing EAP user password as NtPasswordHash instead
+ of plaintext password when using MSCHAP or MSCHAPv2 for
+ authentication (hash:<16-octet hex value>); added nt_password_hash
+ tool for hashing password to generate NtPasswordHash
+
+2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
+ * driver_wired: fixed EAPOL sending to optionally use PAE group address
+ as the destination instead of supplicant MAC address; this is
+ disabled by default, but should be enabled with use_pae_group_addr=1
+ in configuration file if the wired interface is used by only one
+ device at the time (common switch configuration)
+ * driver_madwifi: configure driver to use TKIP countermeasures in order
+ to get correct behavior (IEEE 802.11 association failing; previously,
+ association succeeded, but hostpad forced disassociation immediately)
+ * driver_madwifi: added support for madwifi-ng
+
+2005-10-27 - v0.4.6
+ * added support for replacing user identity from EAP with RADIUS
+ User-Name attribute from Access-Accept message, if that is included,
+ for the RADIUS accounting messages (e.g., for EAP-PEAP/TTLS to get
+ tunneled identity into accounting messages when the RADIUS server
+ does not support better way of doing this with Class attribute)
+ * driver_madwifi: fixed EAPOL packet receive for configuration where
+ ath# is part of a bridge interface
+ * added a configuration file and log analyzer script for logwatch
+ * fixed EAPOL state machine step function to process all state
+ transitions before processing new events; this resolves a race
+ condition in which EAPOL-Start message could trigger hostapd to send
+ two EAP-Response/Identity frames to the authentication server
+
+2005-09-25 - v0.4.5
+ * added client CA list to the TLS certificate request in order to make
+ it easier for the client to select which certificate to use
+ * added experimental support for EAP-PSK
+ * added support for WE-19 (hostap, madwifi)
+
+2005-08-21 - v0.4.4
+ * fixed build without CONFIG_RSN_PREAUTH
+ * fixed FreeBSD build
+
+2005-06-26 - v0.4.3
+ * fixed PMKSA caching to copy User-Name and Class attributes so that
+ RADIUS accounting gets correct information
+ * start RADIUS accounting only after successful completion of WPA
+ 4-Way Handshake if WPA-PSK is used
+ * fixed PMKSA caching for the case where STA (re)associates without
+ first disassociating
+
+2005-06-12 - v0.4.2
+ * EAP-PAX is now registered as EAP type 46
+ * fixed EAP-PAX MAC calculation
+ * fixed EAP-PAX CK and ICK key derivation
+ * renamed eap_authenticator configuration variable to eap_server to
+ better match with RFC 3748 (EAP) terminology
+ * driver_test: added support for testing hostapd with wpa_supplicant
+ by using test driver interface without any kernel drivers or network
+ cards
+
+2005-05-22 - v0.4.1
+ * fixed RADIUS server initialization when only auth or acct server
+ is configured and the other one is left empty
+ * driver_madwifi: added support for RADIUS accounting
+ * driver_madwifi: added preliminary support for compiling against 'BSD'
+ branch of madwifi CVS tree
+ * driver_madwifi: fixed pairwise key removal to allow WPA reauth
+ without disassociation
+ * added support for reading additional certificates from PKCS#12 files
+ and adding them to the certificate chain
+ * fixed RADIUS Class attribute processing to only use Access-Accept
+ packets to update Class; previously, other RADIUS authentication
+ packets could have cleared Class attribute
+ * added support for more than one Class attribute in RADIUS packets
+ * added support for verifying certificate revocation list (CRL) when
+ using integrated EAP authenticator for EAP-TLS; new hostapd.conf
+ options 'check_crl'; CRL must be included in the ca_cert file for now
+
+2005-04-25 - v0.4.0 (beginning of 0.4.x development releases)
+ * added support for including network information into
+ EAP-Request/Identity message (ASCII-0 (nul) in eap_message)
+ (e.g., to implement draft-adrange-eap-network-discovery-07.txt)
+ * fixed a bug which caused some RSN pre-authentication cases to use
+ freed memory and potentially crash hostapd
+ * fixed private key loading for cases where passphrase is not set
+ * added support for sending TLS alerts and aborting authentication
+ when receiving a TLS alert
+ * fixed WPA2 to add PMKSA cache entry when using integrated EAP
+ authenticator
+ * fixed PMKSA caching (EAP authentication was not skipped correctly
+ with the new state machine changes from IEEE 802.1X draft)
+ * added support for RADIUS over IPv6; own_ip_addr, auth_server_addr,
+ and acct_server_addr can now be IPv6 addresses (CONFIG_IPV6=y needs
+ to be added to .config to include IPv6 support); for RADIUS server,
+ radius_server_ipv6=1 needs to be set in hostapd.conf and addresses
+ in RADIUS clients file can then use IPv6 format
+ * added experimental support for EAP-PAX
+ * replaced hostapd control interface library (hostapd_ctrl.[ch]) with
+ the same implementation that wpa_supplicant is using (wpa_ctrl.[ch])
+
+2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
+
+2005-01-23 - v0.3.5
+ * added support for configuring a forced PEAP version based on the
+ Phase 1 identity
+ * fixed PEAPv1 to use tunneled EAP-Success/Failure instead of EAP-TLV
+ to terminate authentication
+ * fixed EAP identifier duplicate processing with the new IEEE 802.1X
+ draft
+ * clear accounting data in the driver when starting a new accounting
+ session
+ * driver_madwifi: filter wireless events based on ifindex to allow more
+ than one network interface to be used
+ * fixed WPA message 2/4 processing not to cancel timeout for TimeoutEvt
+ setting if the packet does not pass MIC verification (e.g., due to
+ incorrect PSK); previously, message 1/4 was not tried again if an
+ invalid message 2/4 was received
+ * fixed reconfiguration of RADIUS client retransmission timer when
+ adding a new message to the pending list; previously, timer was not
+ updated at this point and if there was a pending message with long
+ time for the next retry, the new message needed to wait that long for
+ its first retry, too
+
+2005-01-09 - v0.3.4
+ * added support for configuring multiple allowed EAP types for Phase 2
+ authentication (EAP-PEAP, EAP-TTLS)
+ * fixed EAPOL-Start processing to trigger WPA reauthentication
+ (previously, only EAPOL authentication was done)
+
+2005-01-02 - v0.3.3
+ * added support for EAP-PEAP in the integrated EAP authenticator
+ * added support for EAP-GTC in the integrated EAP authenticator
+ * added support for configuring list of EAP methods for Phase 1 so that
+ the integrated EAP authenticator can, e.g., use the wildcard entry
+ for EAP-TLS and EAP-PEAP
+ * added support for EAP-TTLS in the integrated EAP authenticator
+ * added support for EAP-SIM in the integrated EAP authenticator
+ * added support for using hostapd as a RADIUS authentication server
+ with the integrated EAP authenticator taking care of EAP
+ authentication (new hostapd.conf options: radius_server_clients and
+ radius_server_auth_port); this is not included in default build; use
+ CONFIG_RADIUS_SERVER=y in .config to include
+
+2004-12-19 - v0.3.2
+ * removed 'daemonize' configuration file option since it has not really
+ been used at all for more than year
+ * driver_madwifi: fixed group key setup and added get_ssid method
+ * added support for EAP-MSCHAPv2 in the integrated EAP authenticator
+
+2004-12-12 - v0.3.1
+ * added support for integrated EAP-TLS authentication (new hostapd.conf
+ variables: ca_cert, server_cert, private_key, private_key_passwd);
+ this enabled dynamic keying (WPA2/WPA/IEEE 802.1X/WEP) without
+ external RADIUS server
+ * added support for reading PKCS#12 (PFX) files (as a replacement for
+ PEM/DER) to get certificate and private key (CONFIG_PKCS12)
+
+2004-12-05 - v0.3.0 (beginning of 0.3.x development releases)
+ * added support for Acct-{Input,Output}-Gigawords
+ * added support for Event-Timestamp (in RADIUS Accounting-Requests)
+ * added support for RADIUS Authentication Client MIB (RFC2618)
+ * added support for RADIUS Accounting Client MIB (RFC2620)
+ * made EAP re-authentication period configurable (eap_reauth_period)
+ * fixed EAPOL reauthentication to trigger WPA/WPA2 reauthentication
+ * fixed EAPOL state machine to stop if STA is removed during
+ eapol_sm_step(); this fixes at least one segfault triggering bug with
+ IEEE 802.11i pre-authentication
+ * added support for multiple WPA pre-shared keys (e.g., one for each
+ client MAC address or keys shared by a group of clients);
+ new hostapd.conf field wpa_psk_file for setting path to a text file
+ containing PSKs, see hostapd.wpa_psk for an example
+ * added support for multiple driver interfaces to allow hostapd to be
+ used with other drivers
+ * added wired authenticator driver interface (driver=wired in
+ hostapd.conf, see wired.conf for example configuration)
+ * added madwifi driver interface (driver=madwifi in hostapd.conf, see
+ madwifi.conf for example configuration; Note: include files from
+ madwifi project is needed for building and a configuration file,
+ .config, needs to be created in hostapd directory with
+ CONFIG_DRIVER_MADWIFI=y to include this driver interface in hostapd
+ build)
+ * fixed an alignment issue that could cause SHA-1 to fail on some
+ platforms (e.g., Intel ixp425 with a compiler that does not 32-bit
+ align variables)
+ * fixed RADIUS reconnection after an error in sending interim
+ accounting packets
+ * added hostapd control interface for external programs and an example
+ CLI, hostapd_cli (like wpa_cli for wpa_supplicant)
+ * started adding dot11, dot1x, radius MIBs ('hostapd_cli mib',
+ 'hostapd_cli sta <addr>')
+ * finished update from IEEE 802.1X-2001 to IEEE 802.1X-REV (now d11)
+ * added support for strict GTK rekeying (wpa_strict_rekey in
+ hostapd.conf)
+ * updated IAPP to use UDP port 3517 and multicast address 224.0.1.178
+ (instead of broadcast) for IAPP ADD-notify (moved from draft 3 to
+ IEEE 802.11F-2003)
+ * added Prism54 driver interface (driver=prism54 in hostapd.conf;
+ note: .config needs to be created in hostapd directory with
+ CONFIG_DRIVER_PRISM54=y to include this driver interface in hostapd
+ build)
+ * dual-licensed hostapd (GPLv2 and BSD licenses)
+ * fixed RADIUS accounting to generate a new session id for cases where
+ a station reassociates without first being complete deauthenticated
+ * fixed STA disassociation handler to mark next timeout state to
+ deauthenticate the station, i.e., skip long wait for inactivity poll
+ and extra disassociation, if the STA disassociates without
+ deauthenticating
+ * added integrated EAP authenticator that can be used instead of
+ external RADIUS authentication server; currently, only EAP-MD5 is
+ supported, so this cannot yet be used for key distribution; the EAP
+ method interface is generic, though, so adding new EAP methods should
+ be straightforward; new hostapd.conf variables: 'eap_authenticator'
+ and 'eap_user_file'; this obsoletes "minimal authentication server"
+ ('minimal_eap' in hostapd.conf) which is now removed
+ * added support for FreeBSD and driver interface for the BSD net80211
+ layer (driver=bsd in hostapd.conf and CONFIG_DRIVER_BSD=y in
+ .config); please note that some of the required kernel mods have not
+ yet been committed
+
+2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases)
+ * fixed some accounting cases where Accounting-Start was sent when
+ IEEE 802.1X port was being deauthorized
+
+2004-06-20 - v0.2.3
+ * modified RADIUS client to re-connect the socket in case of certain
+ error codes that are generated when a network interface state is
+ changes (e.g., when IP address changes or the interface is set UP)
+ * fixed couple of cases where EAPOL state for a station was freed
+ twice causing a segfault for hostapd
+ * fixed couple of bugs in processing WPA deauthentication (freed data
+ was used)
+
+2004-05-31 - v0.2.2
+ * fixed WPA/WPA2 group rekeying to use key index correctly (GN/GM)
+ * fixed group rekeying to send zero TSC in EAPOL-Key messages to fix
+ cases where STAs dropped multicast frames as replay attacks
+ * added support for copying RADIUS Attribute 'Class' from
+ authentication messages into accounting messages
+ * send canned EAP failure if RADIUS server sends Access-Reject without
+ EAP message (previously, Supplicant was not notified in this case)
+ * fixed mixed WPA-PSK and WPA-EAP mode to work with WPA-PSK (i.e., do
+ not start EAPOL state machines if the STA selected to use WPA-PSK)
+
+2004-05-06 - v0.2.1
+ * added WPA and IEEE 802.11i/RSN (WPA2) Authenticator functionality
+ - based on IEEE 802.11i/D10.0 but modified to interoperate with WPA
+ (i.e., IEEE 802.11i/D3.0)
+ - supports WPA-only, RSN-only, and mixed WPA/RSN mode
+ - both WPA-PSK and WPA-RADIUS/EAP are supported
+ - PMKSA caching and pre-authentication
+ - new hostapd.conf variables: wpa, wpa_psk, wpa_passphrase,
+ wpa_key_mgmt, wpa_pairwise, wpa_group_rekey, wpa_gmk_rekey,
+ rsn_preauth, rsn_preauth_interfaces
+ * fixed interim accounting to remove any pending accounting messages
+ to the STA before sending a new one
+
+2004-02-15 - v0.2.0
+ * added support for Acct-Interim-Interval:
+ - draft-ietf-radius-acct-interim-01.txt
+ - use Acct-Interim-Interval attribute from Access-Accept if local
+ 'radius_acct_interim_interval' is not set
+ - allow different update intervals for each STA
+ * fixed event loop to call signal handlers only after returning from
+ the real signal handler
+ * reset sta->timeout_next after successful association to make sure
+ that the previously registered inactivity timer will not remove the
+ STA immediately (e.g., if STA deauthenticates and re-associates
+ before the timer is triggered).
+ * added new hostapd.conf variable, nas_identifier, that can be used to
+ add an optional RADIUS Attribute, NAS-Identifier, into authentication
+ and accounting messages
+ * added support for Accounting-On and Accounting-Off messages
+ * fixed accounting session handling to send Accounting-Start only once
+ per session and not to send Accounting-Stop if the session was not
+ initialized properly
+ * fixed Accounting-Stop statistics in cases where the message was
+ previously sent after the kernel entry for the STA (and/or IEEE
+ 802.1X data) was removed
+
+
+Note:
+
+Older changes up to and including v0.1.0 are included in the ChangeLog
+of the Host AP driver.
diff --git a/hostapd/Makefile b/hostapd/Makefile
new file mode 100644
index 0000000..123b098
--- /dev/null
+++ b/hostapd/Makefile
@@ -0,0 +1,534 @@
+ifndef CC
+CC=gcc
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
+# a file (undefine it, if you want to save in binary size)
+CFLAGS += -DHOSTAPD_DUMP_STATE
+
+CFLAGS += -I../src
+CFLAGS += -I../src/crypto
+CFLAGS += -I../src/utils
+CFLAGS += -I../src/common
+
+# 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_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32
+endif
+
+OBJS = hostapd.o ieee802_1x.o eapol_sm.o \
+ ieee802_11.o config.o ieee802_11_auth.o accounting.o \
+ sta_info.o wpa.o ctrl_iface.o \
+ drivers.o preauth.o pmksa_cache.o beacon.o \
+ hw_features.o wme.o ap_list.o reconfig.o \
+ mlme.o vlan_init.o ieee802_11h.o wpa_auth_ie.o
+
+OBJS += ../src/utils/eloop.o
+OBJS += ../src/utils/common.o
+OBJS += ../src/utils/wpa_debug.o
+OBJS += ../src/utils/wpabuf.o
+OBJS += ../src/utils/os_$(CONFIG_OS).o
+OBJS += ../src/utils/ip_addr.o
+
+OBJS += ../src/common/wpa_common.o
+
+OBJS += ../src/radius/radius.o
+OBJS += ../src/radius/radius_client.o
+
+OBJS += ../src/crypto/md5.o
+OBJS += ../src/crypto/rc4.o
+OBJS += ../src/crypto/md4.o
+OBJS += ../src/crypto/sha1.o
+OBJS += ../src/crypto/des.o
+OBJS += ../src/crypto/aes_wrap.o
+OBJS += ../src/crypto/aes.o
+
+HOBJS=../src/hlr_auc_gw/hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/hlr_auc_gw/milenage.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o
+
+CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
+
+ifdef CONFIG_IAPP
+CFLAGS += -DCONFIG_IAPP
+OBJS += iapp.o
+endif
+
+ifdef CONFIG_RSN_PREAUTH
+CFLAGS += -DCONFIG_RSN_PREAUTH
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_PEERKEY
+CFLAGS += -DCONFIG_PEERKEY
+OBJS += peerkey.o
+endif
+
+ifdef CONFIG_IEEE80211W
+CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211R
+OBJS += wpa_ft.o
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_DRIVER_HOSTAP
+CFLAGS += -DCONFIG_DRIVER_HOSTAP
+OBJS += driver_hostap.o
+endif
+
+ifdef CONFIG_DRIVER_WIRED
+CFLAGS += -DCONFIG_DRIVER_WIRED
+OBJS += driver_wired.o
+endif
+
+ifdef CONFIG_DRIVER_MADWIFI
+CFLAGS += -DCONFIG_DRIVER_MADWIFI
+OBJS += driver_madwifi.o
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_DRIVER_PRISM54
+CFLAGS += -DCONFIG_DRIVER_PRISM54
+OBJS += driver_prism54.o
+endif
+
+ifdef CONFIG_DRIVER_NL80211
+CFLAGS += -DCONFIG_DRIVER_NL80211
+OBJS += driver_nl80211.o radiotap.o
+LIBS += -lnl
+endif
+
+ifdef CONFIG_DRIVER_BSD
+CFLAGS += -DCONFIG_DRIVER_BSD
+OBJS += driver_bsd.o
+CONFIG_L2_PACKET=y
+CONFIG_DNET_PCAP=y
+CONFIG_L2_FREEBSD=y
+endif
+
+ifdef CONFIG_DRIVER_TEST
+CFLAGS += -DCONFIG_DRIVER_TEST
+OBJS += driver_test.o
+endif
+
+ifdef CONFIG_L2_PACKET
+ifdef CONFIG_DNET_PCAP
+ifdef CONFIG_L2_FREEBSD
+LIBS += -lpcap
+OBJS += ../src/l2_packet/l2_packet_freebsd.o
+else
+LIBS += -ldnet -lpcap
+OBJS += ../src/l2_packet/l2_packet_pcap.o
+endif
+else
+OBJS += ../src/l2_packet/l2_packet_linux.o
+endif
+endif
+
+
+ifdef CONFIG_EAP_MD5
+CFLAGS += -DEAP_MD5
+OBJS += ../src/eap_server/eap_md5.o
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_TLS
+CFLAGS += -DEAP_TLS
+OBJS += ../src/eap_server/eap_tls.o
+TLS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_PEAP
+CFLAGS += -DEAP_PEAP
+OBJS += ../src/eap_server/eap_peap.o
+TLS_FUNCS=y
+CONFIG_EAP_TLV=y
+CONFIG_EAP_MSCHAPV2=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+CFLAGS += -DEAP_TTLS
+OBJS += ../src/eap_server/eap_ttls.o
+TLS_FUNCS=y
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+CFLAGS += -DEAP_MSCHAPv2
+OBJS += ../src/eap_server/eap_mschapv2.o
+MS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_GTC
+CFLAGS += -DEAP_GTC
+OBJS += ../src/eap_server/eap_gtc.o
+endif
+
+ifdef CONFIG_EAP_SIM
+CFLAGS += -DEAP_SIM
+OBJS += ../src/eap_server/eap_sim.o
+CONFIG_EAP_SIM_COMMON=y
+endif
+
+ifdef CONFIG_EAP_AKA
+CFLAGS += -DEAP_AKA
+OBJS += ../src/eap_server/eap_aka.o
+CONFIG_EAP_SIM_COMMON=y
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += ../src/eap_common/eap_sim_common.o
+# 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.o
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+CFLAGS += -DEAP_PAX
+OBJS += ../src/eap_server/eap_pax.o ../src/eap_common/eap_pax_common.o
+endif
+
+ifdef CONFIG_EAP_PSK
+CFLAGS += -DEAP_PSK
+OBJS += ../src/eap_server/eap_psk.o ../src/eap_common/eap_psk_common.o
+endif
+
+ifdef CONFIG_EAP_SAKE
+CFLAGS += -DEAP_SAKE
+OBJS += ../src/eap_server/eap_sake.o ../src/eap_common/eap_sake_common.o
+endif
+
+ifdef CONFIG_EAP_GPSK
+CFLAGS += -DEAP_GPSK
+OBJS += ../src/eap_server/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o
+ifdef CONFIG_EAP_GPSK_SHA256
+CFLAGS += -DEAP_GPSK_SHA256
+endif
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+CFLAGS += -DEAP_VENDOR_TEST
+OBJS += ../src/eap_server/eap_vendor_test.o
+endif
+
+ifdef CONFIG_EAP_TLV
+CFLAGS += -DEAP_TLV
+OBJS += ../src/eap_server/eap_tlv.o
+endif
+
+ifdef CONFIG_EAP_FAST
+CFLAGS += -DEAP_FAST
+OBJS += ../src/eap_server/eap_fast.o
+TLS_FUNCS=y
+NEED_T_PRF=y
+endif
+
+ifdef CONFIG_EAP_IKEV2
+CFLAGS += -DEAP_IKEV2
+OBJS += ../src/eap_server/eap_ikev2.o ../src/eap_server/ikev2.o
+OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
+NEED_DH_GROUPS=y
+endif
+
+# Basic EAP functionality is needed for EAPOL
+OBJS += ../src/eap_server/eap.o
+OBJS += ../src/eap_common/eap_common.o
+OBJS += ../src/eap_server/eap_methods.o
+OBJS += ../src/eap_server/eap_identity.o
+
+ifdef CONFIG_EAP
+CFLAGS += -DEAP_SERVER
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+CFLAGS += -DCONFIG_INTERNAL_X509
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+CFLAGS += -DCONFIG_INTERNAL_X509
+endif
+
+
+ifdef TLS_FUNCS
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
+CFLAGS += -DEAP_TLS_FUNCS
+OBJS += ../src/eap_server/eap_tls_common.o
+ifeq ($(CONFIG_TLS), openssl)
+OBJS += ../src/crypto/tls_openssl.o
+LIBS += -lssl -lcrypto
+LIBS_p += -lcrypto
+LIBS_h += -lcrypto
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS += ../src/crypto/tls_gnutls.o
+LIBS += -lgnutls -lgcrypt -lgpg-error
+LIBS_p += -lgcrypt
+LIBS_h += -lgcrypt
+endif
+ifdef CONFIG_GNUTLS_EXTRA
+CFLAGS += -DCONFIG_GNUTLS_EXTRA
+LIBS += -lgnutls-extra
+endif
+ifeq ($(CONFIG_TLS), internal)
+OBJS += ../src/crypto/tls_internal.o
+OBJS += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_record.o
+OBJS += ../src/tls/tlsv1_cred.o ../src/tls/tlsv1_server.o
+OBJS += ../src/tls/tlsv1_server_write.o ../src/tls/tlsv1_server_read.o
+OBJS += ../src/tls/asn1.o ../src/tls/x509v3.o
+OBJS_p += ../src/tls/asn1.o
+OBJS_p += ../src/crypto/rc4.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o
+NEED_BASE64=y
+CFLAGS += -DCONFIG_TLS_INTERNAL
+CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+ifeq ($(CONFIG_CRYPTO), internal)
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+else
+LIBS += -ltommath
+LIBS_p += -ltommath
+endif
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+LIBS += -ltomcrypt -ltfm
+LIBS_p += -ltomcrypt -ltfm
+endif
+endif
+NEED_CRYPTO=y
+else
+OBJS += ../src/crypto/tls_none.o
+endif
+
+ifdef CONFIG_PKCS12
+CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef MS_FUNCS
+OBJS += ../src/crypto/ms_funcs.o
+NEED_CRYPTO=y
+endif
+
+ifdef CHAP
+OBJS += ../src/eap_common/chap.o
+endif
+
+ifdef NEED_CRYPTO
+ifndef TLS_FUNCS
+ifeq ($(CONFIG_TLS), openssl)
+LIBS += -lcrypto
+LIBS_p += -lcrypto
+LIBS_h += -lcrypto
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+LIBS += -lgcrypt
+LIBS_p += -lgcrypt
+LIBS_h += -lgcrypt
+endif
+ifeq ($(CONFIG_TLS), internal)
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+LIBS += -ltomcrypt -ltfm
+LIBS_p += -ltomcrypt -ltfm
+endif
+endif
+endif
+ifeq ($(CONFIG_TLS), openssl)
+OBJS += ../src/crypto/crypto_openssl.o
+OBJS_p += ../src/crypto/crypto_openssl.o
+HOBJS += ../src/crypto/crypto_openssl.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS += ../src/crypto/crypto_gnutls.o
+OBJS_p += ../src/crypto/crypto_gnutls.o
+HOBJS += ../src/crypto/crypto_gnutls.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_TLS), internal)
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += ../src/crypto/crypto_libtomcrypt.o
+OBJS_p += ../src/crypto/crypto_libtomcrypt.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o
+OBJS_p += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+endif
+endif
+else
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+endif
+
+ifdef CONFIG_INTERNAL_AES
+CFLAGS += -DINTERNAL_AES
+endif
+ifdef CONFIG_INTERNAL_SHA1
+CFLAGS += -DINTERNAL_SHA1
+endif
+ifdef CONFIG_INTERNAL_SHA256
+CFLAGS += -DINTERNAL_SHA256
+endif
+ifdef CONFIG_INTERNAL_MD5
+CFLAGS += -DINTERNAL_MD5
+endif
+ifdef CONFIG_INTERNAL_MD4
+CFLAGS += -DINTERNAL_MD4
+endif
+ifdef CONFIG_INTERNAL_DES
+CFLAGS += -DINTERNAL_DES
+endif
+
+ifdef NEED_SHA256
+OBJS += ../src/crypto/sha256.o
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_groups.o
+endif
+
+ifndef NEED_FIPS186_2_PRF
+CFLAGS += -DCONFIG_NO_FIPS186_2_PRF
+endif
+
+ifndef NEED_T_PRF
+CFLAGS += -DCONFIG_NO_T_PRF
+endif
+
+ifdef CONFIG_RADIUS_SERVER
+CFLAGS += -DRADIUS_SERVER
+OBJS += ../src/radius/radius_server.o
+endif
+
+ifdef CONFIG_IPV6
+CFLAGS += -DCONFIG_IPV6
+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
+
+ALL=hostapd hostapd_cli
+
+all: verify_config $(ALL)
+
+verify_config:
+ @if [ ! -r .config ]; then \
+ echo 'Building hostapd requires a configuration file'; \
+ echo '(.config). See README for more instructions. You can'; \
+ echo 'run "cp defconfig .config" to create an example'; \
+ echo 'configuration.'; \
+ exit 1; \
+ fi
+
+install: all
+ for i in $(ALL); do cp $$i /usr/local/bin/$$i; done
+
+hostapd: $(OBJS)
+ $(CC) -o hostapd $(OBJS) $(LIBS)
+
+OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
+hostapd_cli: $(OBJS_c)
+ $(CC) -o hostapd_cli $(OBJS_c)
+
+NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o ../src/crypto/sha1.o ../src/crypto/rc4.o ../src/crypto/md5.o
+NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o
+ifdef TLS_FUNCS
+LIBS_n += -lcrypto
+endif
+
+nt_password_hash: $(NOBJS)
+ $(CC) -o nt_password_hash $(NOBJS) $(LIBS_n)
+
+hlr_auc_gw: $(HOBJS)
+ $(CC) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
+
+clean:
+ $(MAKE) -C ../src clean
+ rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
+ rm -f *.d
+
+%.eps: %.fig
+ fig2dev -L eps $*.fig $*.eps
+
+%.png: %.fig
+ fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \
+ > $*.png
+
+docs-pics: doc/hostapd.png doc/hostapd.eps
+
+docs: docs-pics
+ doxygen doc/doxygen.full
+ $(MAKE) -C doc/latex
+ cp doc/latex/refman.pdf hostapd-devel.pdf
+
+docs-fast: docs-pics
+ doxygen doc/doxygen.fast
+
+clean-docs:
+ rm -rf doc/latex doc/html
+ rm -f doc/hosta.d{eps,png} hostapd-devel.pdf
+
+TEST_SRC_MILENAGE = ../src/hlr_auc_gw/milenage.c ../src/crypto/aes_wrap.c ../src/crypto/aes.c ../src/utils/common.c ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).c
+test-milenage: $(TEST_SRC_MILENAGE)
+ $(CC) -o test-milenage -Wall -Werror $(TEST_SRC_MILENAGE) \
+ -DTEST_MAIN_MILENAGE -I. -DINTERNAL_AES \
+ -I../src/crypto -I../src/utils
+ ./test-milenage
+ rm test-milenage
+
+hostapd-sparse: $(OBJS)
+ @echo Sparse run completed
+
+run-sparse:
+ CC="sparse -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -D__INT_MAX__=2147483647 -D__SHRT_MAX__=32767 -D__LONG_MAX__=2147483647 -D__SCHAR_MAX__=127 -Wbitwise" $(MAKE) hostapd-sparse
+
+-include $(OBJS:%.o=%.d)
diff --git a/hostapd/README b/hostapd/README
new file mode 100644
index 0000000..dd24204
--- /dev/null
+++ b/hostapd/README
@@ -0,0 +1,386 @@
+hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
+ Authenticator and RADIUS authentication server
+================================================================
+
+Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+This program is dual-licensed under both the GPL version 2 and BSD
+license. Either license may be used at your option.
+
+
+
+License
+-------
+
+GPL v2:
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+(this copy of the license is in COPYING file)
+
+
+Alternatively, this software may be distributed, used, and modified
+under the terms of BSD license:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+Introduction
+============
+
+Originally, hostapd was an optional user space component for Host AP
+driver. It adds more features to the basic IEEE 802.11 management
+included in the kernel driver: using external RADIUS authentication
+server for MAC address based access control, IEEE 802.1X Authenticator
+and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN)
+Authenticator and dynamic TKIP/CCMP keying.
+
+The current version includes support for other drivers, an integrated
+EAP server (i.e., allow full authentication without requiring
+an external RADIUS authentication server), and RADIUS authentication
+server for EAP authentication.
+
+
+Requirements
+------------
+
+Current hardware/software requirements:
+- drivers:
+ Host AP driver for Prism2/2.5/3.
+ (http://hostap.epitest.fi/)
+ Please note that station firmware version needs to be 1.7.0 or newer
+ to work in WPA mode.
+
+ madwifi driver for cards based on Atheros chip set (ar521x)
+ (http://sourceforge.net/projects/madwifi/)
+ Please note that you will need to add the correct path for
+ madwifi driver root directory in .config (see defconfig file for
+ an example: CFLAGS += -I<path>)
+
+ Prism54 driver for Intersil/Conexant Prism GT/Duette/Indigo
+ (http://www.prism54.org/)
+
+ Any wired Ethernet driver for wired IEEE 802.1X authentication
+ (experimental code)
+
+ FreeBSD -current (with some kernel mods that have not yet been
+ committed when hostapd v0.3.0 was released)
+ BSD net80211 layer (e.g., Atheros driver)
+
+
+Build configuration
+-------------------
+
+In order to be able to build hostapd, you will need to create a build
+time configuration file, .config that selects which optional
+components are included. See defconfig file for example configuration
+and list of available options.
+
+
+
+IEEE 802.1X
+===========
+
+IEEE Std 802.1X-2001 is a standard for port-based network access
+control. In case of IEEE 802.11 networks, a "virtual port" is used
+between each associated station and the AP. IEEE 802.11 specifies
+minimal authentication mechanism for stations, whereas IEEE 802.1X
+introduces a extensible mechanism for authenticating and authorizing
+users.
+
+IEEE 802.1X uses elements called Supplicant, Authenticator, Port
+Access Entity, and Authentication Server. Supplicant is a component in
+a station and it performs the authentication with the Authentication
+Server. An access point includes an Authenticator that relays the packets
+between a Supplicant and an Authentication Server. In addition, it has a
+Port Access Entity (PAE) with Authenticator functionality for
+controlling the virtual port authorization, i.e., whether to accept
+packets from or to the station.
+
+IEEE 802.1X uses Extensible Authentication Protocol (EAP). The frames
+between a Supplicant and an Authenticator are sent using EAP over LAN
+(EAPOL) and the Authenticator relays these frames to the Authentication
+Server (and similarly, relays the messages from the Authentication
+Server to the Supplicant). The Authentication Server can be colocated with the
+Authenticator, in which case there is no need for additional protocol
+for EAP frame transmission. However, a more common configuration is to
+use an external Authentication Server and encapsulate EAP frame in the
+frames used by that server. RADIUS is suitable for this, but IEEE
+802.1X would also allow other mechanisms.
+
+Host AP driver includes PAE functionality in the kernel driver. It
+is a relatively simple mechanism for denying normal frames going to
+or coming from an unauthorized port. PAE allows IEEE 802.1X related
+frames to be passed between the Supplicant and the Authenticator even
+on an unauthorized port.
+
+User space daemon, hostapd, includes Authenticator functionality. It
+receives 802.1X (EAPOL) frames from the Supplicant using the wlan#ap
+device that is also used with IEEE 802.11 management frames. The
+frames to the Supplicant are sent using the same device.
+
+The normal configuration of the Authenticator would use an external
+Authentication Server. hostapd supports RADIUS encapsulation of EAP
+packets, so the Authentication Server should be a RADIUS server, like
+FreeRADIUS (http://www.freeradius.org/). The Authenticator in hostapd
+relays the frames between the Supplicant and the Authentication
+Server. It also controls the PAE functionality in the kernel driver by
+controlling virtual port authorization, i.e., station-AP
+connection, based on the IEEE 802.1X state.
+
+When a station would like to use the services of an access point, it
+will first perform IEEE 802.11 authentication. This is normally done
+with open systems authentication, so there is no security. After
+this, IEEE 802.11 association is performed. If IEEE 802.1X is
+configured to be used, the virtual port for the station is set in
+Unauthorized state and only IEEE 802.1X frames are accepted at this
+point. The Authenticator will then ask the Supplicant to authenticate
+with the Authentication Server. After this is completed successfully,
+the virtual port is set to Authorized state and frames from and to the
+station are accepted.
+
+Host AP configuration for IEEE 802.1X
+-------------------------------------
+
+The user space daemon has its own configuration file that can be used to
+define AP options. Distribution package contains an example
+configuration file (hostapd/hostapd.conf) that can be used as a basis
+for configuration. It includes examples of all supported configuration
+options and short description of each option. hostapd should be started
+with full path to the configuration file as the command line argument,
+e.g., './hostapd /etc/hostapd.conf'. If you have more that one wireless
+LAN card, you can use one hostapd process for multiple interfaces by
+giving a list of configuration files (one per interface) in the command
+line.
+
+hostapd includes a minimal co-located IEEE 802.1X server which can be
+used to test IEEE 802.1X authentication. However, it should not be
+used in normal use since it does not provide any security. This can be
+configured by setting ieee8021x and minimal_eap options in the
+configuration file.
+
+An external Authentication Server (RADIUS) is configured with
+auth_server_{addr,port,shared_secret} options. In addition,
+ieee8021x and own_ip_addr must be set for this mode. With such
+configuration, the co-located Authentication Server is not used and EAP
+frames will be relayed using EAPOL between the Supplicant and the
+Authenticator and RADIUS encapsulation between the Authenticator and
+the Authentication Server. Other than this, the functionality is similar
+to the case with the co-located Authentication Server.
+
+Authentication Server and Supplicant
+------------------------------------
+
+Any RADIUS server supporting EAP should be usable as an IEEE 802.1X
+Authentication Server with hostapd Authenticator. FreeRADIUS
+(http://www.freeradius.org/) has been successfully tested with hostapd
+Authenticator and both Xsupplicant (http://www.open1x.org) and Windows
+XP Supplicants. EAP/TLS was used with Xsupplicant and
+EAP/MD5-Challenge with Windows XP.
+
+http://www.missl.cs.umd.edu/wireless/eaptls/ has useful information
+about using EAP/TLS with FreeRADIUS and Xsupplicant (just replace
+Cisco access point with Host AP driver, hostapd daemon, and a Prism2
+card ;-). http://www.freeradius.org/doc/EAP-MD5.html has information
+about using EAP/MD5 with FreeRADIUS, including instructions for WinXP
+configuration. http://www.denobula.com/EAPTLS.pdf has a HOWTO on
+EAP/TLS use with WinXP Supplicant.
+
+Automatic WEP key configuration
+-------------------------------
+
+EAP/TLS generates a session key that can be used to send WEP keys from
+an AP to authenticated stations. The Authenticator in hostapd can be
+configured to automatically select a random default/broadcast key
+(shared by all authenticated stations) with wep_key_len_broadcast
+option (5 for 40-bit WEP or 13 for 104-bit WEP). In addition,
+wep_key_len_unicast option can be used to configure individual unicast
+keys for stations. This requires support for individual keys in the
+station driver.
+
+WEP keys can be automatically updated by configuring rekeying. This
+will improve security of the network since same WEP key will only be
+used for a limited period of time. wep_rekey_period option sets the
+interval for rekeying in seconds.
+
+
+WPA/WPA2
+========
+
+Features
+--------
+
+Supported WPA/IEEE 802.11i features:
+- WPA-PSK ("WPA-Personal")
+- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
+- key management for CCMP, TKIP, WEP104, WEP40
+- RSN/WPA2 (IEEE 802.11i), including PMKSA caching and pre-authentication
+
+WPA
+---
+
+The original security mechanism of IEEE 802.11 standard was not
+designed to be strong and has proved to be insufficient for most
+networks that require some kind of security. Task group I (Security)
+of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
+to address the flaws of the base standard and has in practice
+completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
+802.11 standard was approved in June 2004 and this amendment is likely
+to be published in July 2004.
+
+Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
+IEEE 802.11i work (draft 3.0) to define a subset of the security
+enhancements that can be implemented with existing wlan hardware. This
+is called Wi-Fi Protected Access<TM> (WPA). This has now become a
+mandatory component of interoperability testing and certification done
+by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
+site (http://www.wi-fi.org/OpenSection/protected_access.asp).
+
+IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
+for protecting wireless networks. WEP uses RC4 with 40-bit keys,
+24-bit initialization vector (IV), and CRC32 to protect against packet
+forgery. All these choices have proven to be insufficient: key space is
+too small against current attacks, RC4 key scheduling is insufficient
+(beginning of the pseudorandom stream should be skipped), IV space is
+too small and IV reuse makes attacks easier, there is no replay
+protection, and non-keyed authentication does not protect against bit
+flipping packet data.
+
+WPA is an intermediate solution for the security issues. It uses
+Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a
+compromise on strong security and possibility to use existing
+hardware. It still uses RC4 for the encryption like WEP, but with
+per-packet RC4 keys. In addition, it implements replay protection,
+keyed packet authentication mechanism (Michael MIC).
+
+Keys can be managed using two different mechanisms. WPA can either use
+an external authentication server (e.g., RADIUS) and EAP just like
+IEEE 802.1X is using or pre-shared keys without need for additional
+servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal",
+respectively. Both mechanisms will generate a master session key for
+the Authenticator (AP) and Supplicant (client station).
+
+WPA implements a new key handshake (4-Way Handshake and Group Key
+Handshake) for generating and exchanging data encryption keys between
+the Authenticator and Supplicant. This handshake is also used to
+verify that both Authenticator and Supplicant know the master session
+key. These handshakes are identical regardless of the selected key
+management mechanism (only the method for generating master session
+key changes).
+
+
+IEEE 802.11i / WPA2
+-------------------
+
+The design for parts of IEEE 802.11i that were not included in WPA has
+finished (May 2004) and this amendment to IEEE 802.11 was approved in
+June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new
+version of WPA called WPA2. This includes, e.g., support for more
+robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
+to replace TKIP and optimizations for handoff (reduced number of
+messages in initial key handshake, pre-authentication, and PMKSA caching).
+
+Some wireless LAN vendors are already providing support for CCMP in
+their WPA products. There is no "official" interoperability
+certification for CCMP and/or mixed modes using both TKIP and CCMP, so
+some interoperability issues can be expected even though many
+combinations seem to be working with equipment from different vendors.
+Testing for WPA2 is likely to start during the second half of 2004.
+
+hostapd configuration for WPA/WPA2
+----------------------------------
+
+TODO
+
+# Enable WPA. Setting this variable configures the AP to require WPA (either
+# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
+# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
+# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
+# RADIUS authentication server must be configured, and WPA-EAP must be included
+# in wpa_key_mgmt.
+# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
+# and/or WPA2 (full IEEE 802.11i/RSN):
+# bit0 = WPA
+# bit1 = IEEE 802.11i/RSN (WPA2)
+#wpa=1
+
+# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
+# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
+# (8..63 characters) that will be converted to PSK. This conversion uses SSID
+# so the PSK changes when ASCII passphrase is used and the SSID is changed.
+#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+#wpa_passphrase=secret passphrase
+
+# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
+# entries are separated with a space.
+#wpa_key_mgmt=WPA-PSK WPA-EAP
+
+# Set of accepted cipher suites (encryption algorithms) for pairwise keys
+# (unicast packets). This is a space separated list of algorithms:
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i]
+# Group cipher suite (encryption algorithm for broadcast and multicast frames)
+# is automatically selected based on this configuration. If only CCMP is
+# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
+# TKIP will be used as the group cipher.
+#wpa_pairwise=TKIP CCMP
+
+# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
+# seconds.
+#wpa_group_rekey=600
+
+# Time interval for rekeying GMK (master key used internally to generate GTKs
+# (in seconds).
+#wpa_gmk_rekey=86400
+
+# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
+# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
+# authentication and key handshake before actually associating with a new AP.
+#rsn_preauth=1
+#
+# Space separated list of interfaces from which pre-authentication frames are
+# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
+# interface that are used for connections to other APs. This could include
+# wired interfaces and WDS links. The normal wireless data interface towards
+# associated stations (e.g., wlan0) should not be added, since
+# pre-authentication is only used with APs other than the currently associated
+# one.
+#rsn_preauth_interfaces=eth0
diff --git a/hostapd/accounting.c b/hostapd/accounting.c
new file mode 100644
index 0000000..7fda7bc
--- /dev/null
+++ b/hostapd/accounting.c
@@ -0,0 +1,466 @@
+/*
+ * hostapd / RADIUS Accounting
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "hostapd.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "eloop.h"
+#include "accounting.h"
+#include "ieee802_1x.h"
+#include "driver.h"
+
+
+/* Default interval in seconds for polling TX/RX octets from the driver if
+ * STA is not using interim accounting. This detects wrap arounds for
+ * input/output octets and updates Acct-{Input,Output}-Gigawords. */
+#define ACCT_DEFAULT_UPDATE_INTERVAL 300
+
+/* from ieee802_1x.c */
+const char *radius_mode_txt(struct hostapd_data *hapd);
+int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
+
+
+static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ int status_type)
+{
+ struct radius_msg *msg;
+ char buf[128];
+ u8 *val;
+ size_t len;
+ int i;
+
+ msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
+ radius_client_get_id(hapd->radius));
+ if (msg == NULL) {
+ printf("Could not create net RADIUS packet\n");
+ return NULL;
+ }
+
+ if (sta) {
+ radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
+
+ os_snprintf(buf, sizeof(buf), "%08X-%08X",
+ sta->acct_session_id_hi, sta->acct_session_id_lo);
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+ (u8 *) buf, os_strlen(buf))) {
+ printf("Could not add Acct-Session-Id\n");
+ 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)) {
+ printf("Could not add Acct-Status-Type\n");
+ goto fail;
+ }
+
+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
+ hapd->conf->ieee802_1x ?
+ RADIUS_ACCT_AUTHENTIC_RADIUS :
+ RADIUS_ACCT_AUTHENTIC_LOCAL)) {
+ printf("Could not add Acct-Authentic\n");
+ goto fail;
+ }
+
+ if (sta) {
+ val = ieee802_1x_get_identity(sta->eapol_sm, &len);
+ if (!val) {
+ os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
+ MAC2STR(sta->addr));
+ val = (u8 *) buf;
+ len = os_strlen(buf);
+ }
+
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
+ len)) {
+ printf("Could not add User-Name\n");
+ goto fail;
+ }
+ }
+
+ if (hapd->conf->own_ip_addr.af == AF_INET &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
+ (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
+ printf("Could not add NAS-IP-Address\n");
+ goto fail;
+ }
+
+#ifdef CONFIG_IPV6
+ if (hapd->conf->own_ip_addr.af == AF_INET6 &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
+ (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
+ printf("Could not add NAS-IPv6-Address\n");
+ goto fail;
+ }
+#endif /* CONFIG_IPV6 */
+
+ if (hapd->conf->nas_identifier &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
+ (u8 *) hapd->conf->nas_identifier,
+ os_strlen(hapd->conf->nas_identifier))) {
+ printf("Could not add NAS-Identifier\n");
+ goto fail;
+ }
+
+ if (sta &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
+ printf("Could not add NAS-Port\n");
+ goto fail;
+ }
+
+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
+ MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
+ (u8 *) buf, os_strlen(buf))) {
+ printf("Could not add Called-Station-Id\n");
+ goto fail;
+ }
+
+ if (sta) {
+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
+ MAC2STR(sta->addr));
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+ (u8 *) buf, os_strlen(buf))) {
+ printf("Could not add Calling-Station-Id\n");
+ goto fail;
+ }
+
+ if (!radius_msg_add_attr_int32(
+ msg, RADIUS_ATTR_NAS_PORT_TYPE,
+ RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
+ printf("Could not add NAS-Port-Type\n");
+ goto fail;
+ }
+
+ os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
+ radius_sta_rate(hapd, sta) / 2,
+ (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
+ radius_mode_txt(hapd));
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+ (u8 *) buf, os_strlen(buf))) {
+ printf("Could not add Connect-Info\n");
+ goto fail;
+ }
+
+ for (i = 0; ; i++) {
+ val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
+ i);
+ if (val == NULL)
+ break;
+
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
+ val, len)) {
+ printf("Could not add Class\n");
+ goto fail;
+ }
+ }
+ }
+
+ return msg;
+
+ fail:
+ radius_msg_free(msg);
+ os_free(msg);
+ return NULL;
+}
+
+
+static int accounting_sta_update_stats(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct hostap_sta_driver_data *data)
+{
+ if (hostapd_read_sta_data(hapd, data, sta->addr))
+ return -1;
+
+ if (sta->last_rx_bytes > data->rx_bytes)
+ sta->acct_input_gigawords++;
+ if (sta->last_tx_bytes > data->tx_bytes)
+ sta->acct_output_gigawords++;
+ sta->last_rx_bytes = data->rx_bytes;
+ sta->last_tx_bytes = data->tx_bytes;
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
+ "Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
+ "Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
+ sta->last_rx_bytes, sta->acct_input_gigawords,
+ sta->last_tx_bytes, sta->acct_output_gigawords);
+
+ return 0;
+}
+
+
+static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = timeout_ctx;
+ int interval;
+
+ if (sta->acct_interim_interval) {
+ accounting_sta_interim(hapd, sta);
+ interval = sta->acct_interim_interval;
+ } else {
+ struct hostap_sta_driver_data data;
+ accounting_sta_update_stats(hapd, sta, &data);
+ interval = ACCT_DEFAULT_UPDATE_INTERVAL;
+ }
+
+ eloop_register_timeout(interval, 0, accounting_interim_update,
+ hapd, sta);
+}
+
+
+void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ struct radius_msg *msg;
+ int interval;
+
+ if (sta->acct_session_started)
+ return;
+
+ time(&sta->acct_session_start);
+ sta->last_rx_bytes = sta->last_tx_bytes = 0;
+ sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
+ hostapd_sta_clear_stats(hapd, sta->addr);
+
+ if (!hapd->conf->radius->acct_server)
+ return;
+
+ if (sta->acct_interim_interval)
+ interval = sta->acct_interim_interval;
+ else
+ interval = ACCT_DEFAULT_UPDATE_INTERVAL;
+ eloop_register_timeout(interval, 0, accounting_interim_update,
+ hapd, sta);
+
+ msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
+ if (msg)
+ radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr);
+
+ sta->acct_session_started = 1;
+}
+
+
+void accounting_sta_report(struct hostapd_data *hapd, struct sta_info *sta,
+ int stop)
+{
+ struct radius_msg *msg;
+ int cause = sta->acct_terminate_cause;
+ struct hostap_sta_driver_data data;
+ u32 gigawords;
+
+ if (!hapd->conf->radius->acct_server)
+ return;
+
+ msg = accounting_msg(hapd, sta,
+ stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
+ RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
+ if (!msg) {
+ printf("Could not create RADIUS Accounting message\n");
+ return;
+ }
+
+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
+ time(NULL) - sta->acct_session_start)) {
+ printf("Could not add Acct-Session-Time\n");
+ goto fail;
+ }
+
+ if (accounting_sta_update_stats(hapd, sta, &data) == 0) {
+ if (!radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_ACCT_INPUT_PACKETS,
+ data.rx_packets)) {
+ printf("Could not add Acct-Input-Packets\n");
+ goto fail;
+ }
+ if (!radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
+ data.tx_packets)) {
+ printf("Could not add Acct-Output-Packets\n");
+ goto fail;
+ }
+ if (!radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_ACCT_INPUT_OCTETS,
+ data.rx_bytes)) {
+ printf("Could not add Acct-Input-Octets\n");
+ 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)) {
+ printf("Could not add Acct-Input-Gigawords\n");
+ goto fail;
+ }
+ if (!radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
+ data.tx_bytes)) {
+ printf("Could not add Acct-Output-Octets\n");
+ 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)) {
+ printf("Could not add Acct-Output-Gigawords\n");
+ goto fail;
+ }
+ }
+
+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+ time(NULL))) {
+ printf("Could not add Event-Timestamp\n");
+ goto fail;
+ }
+
+ if (eloop_terminated())
+ cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
+
+ if (stop && cause &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
+ cause)) {
+ printf("Could not add Acct-Terminate-Cause\n");
+ goto fail;
+ }
+
+ radius_client_send(hapd->radius, msg,
+ stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
+ sta->addr);
+ return;
+
+ fail:
+ radius_msg_free(msg);
+ os_free(msg);
+}
+
+
+void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if (sta->acct_session_started)
+ accounting_sta_report(hapd, sta, 0);
+}
+
+
+void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if (sta->acct_session_started) {
+ accounting_sta_report(hapd, sta, 1);
+ eloop_cancel_timeout(accounting_interim_update, hapd, sta);
+ sta->acct_session_started = 0;
+ }
+}
+
+
+void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ sta->acct_session_id_lo = hapd->acct_session_id_lo++;
+ if (hapd->acct_session_id_lo == 0) {
+ hapd->acct_session_id_hi++;
+ }
+ sta->acct_session_id_hi = hapd->acct_session_id_hi;
+}
+
+
+/* Process the RADIUS frames from Accounting Server */
+static RadiusRxResult
+accounting_receive(struct radius_msg *msg, struct radius_msg *req,
+ u8 *shared_secret, size_t shared_secret_len, void *data)
+{
+ if (msg->hdr->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
+ printf("Unknown RADIUS message code\n");
+ return RADIUS_RX_UNKNOWN;
+ }
+
+ if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
+ printf("Incoming RADIUS packet did not have correct "
+ "Authenticator - dropped\n");
+ return RADIUS_RX_INVALID_AUTHENTICATOR;
+ }
+
+ return RADIUS_RX_PROCESSED;
+}
+
+
+static void accounting_report_state(struct hostapd_data *hapd, int on)
+{
+ struct radius_msg *msg;
+
+ if (!hapd->conf->radius->acct_server || hapd->radius == NULL)
+ return;
+
+ /* Inform RADIUS server that accounting will start/stop so that the
+ * server can close old accounting sessions. */
+ msg = accounting_msg(hapd, NULL,
+ on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON :
+ RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF);
+ if (!msg)
+ return;
+
+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
+ RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
+ {
+ printf("Could not add Acct-Terminate-Cause\n");
+ radius_msg_free(msg);
+ os_free(msg);
+ return;
+ }
+
+ radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
+}
+
+
+int accounting_init(struct hostapd_data *hapd)
+{
+ /* Acct-Session-Id should be unique over reboots. If reliable clock is
+ * not available, this could be replaced with reboot counter, etc. */
+ hapd->acct_session_id_hi = time(NULL);
+
+ if (radius_client_register(hapd->radius, RADIUS_ACCT,
+ accounting_receive, hapd))
+ return -1;
+
+ accounting_report_state(hapd, 1);
+
+ return 0;
+}
+
+
+void accounting_deinit(struct hostapd_data *hapd)
+{
+ accounting_report_state(hapd, 0);
+}
+
+
+int accounting_reconfig(struct hostapd_data *hapd,
+ struct hostapd_config *oldconf)
+{
+ if (!hapd->radius_client_reconfigured)
+ return 0;
+
+ accounting_deinit(hapd);
+ return accounting_init(hapd);
+}
diff --git a/hostapd/accounting.h b/hostapd/accounting.h
new file mode 100644
index 0000000..ee2ee64
--- /dev/null
+++ b/hostapd/accounting.h
@@ -0,0 +1,27 @@
+/*
+ * hostapd / RADIUS Accounting
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef ACCOUNTING_H
+#define ACCOUNTING_H
+
+void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
+void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta);
+void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
+void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
+int accounting_init(struct hostapd_data *hapd);
+void accounting_deinit(struct hostapd_data *hapd);
+int accounting_reconfig(struct hostapd_data *hapd,
+ struct hostapd_config *oldconf);
+
+#endif /* ACCOUNTING_H */
diff --git a/hostapd/ap.h b/hostapd/ap.h
new file mode 100644
index 0000000..b73c5b4
--- /dev/null
+++ b/hostapd/ap.h
@@ -0,0 +1,111 @@
+/*
+ * hostapd / Station table data structures
+ * Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef AP_H
+#define AP_H
+
+/* STA flags */
+#define WLAN_STA_AUTH BIT(0)
+#define WLAN_STA_ASSOC BIT(1)
+#define WLAN_STA_PS BIT(2)
+#define WLAN_STA_TIM BIT(3)
+#define WLAN_STA_PERM BIT(4)
+#define WLAN_STA_AUTHORIZED BIT(5)
+#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
+#define WLAN_STA_SHORT_PREAMBLE BIT(7)
+#define WLAN_STA_PREAUTH BIT(8)
+#define WLAN_STA_WME BIT(9)
+#define WLAN_STA_NONERP BIT(31)
+
+/* Maximum number of supported rates (from both Supported Rates and Extended
+ * Supported Rates IEs). */
+#define WLAN_SUPP_RATES_MAX 32
+
+
+struct sta_info {
+ struct sta_info *next; /* next entry in sta list */
+ struct sta_info *hnext; /* next entry in hash table list */
+ u8 addr[6];
+ u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
+ u32 flags;
+ u16 capability;
+ u16 listen_interval; /* or beacon_int for APs */
+ u8 supported_rates[WLAN_SUPP_RATES_MAX];
+ int supported_rates_len;
+
+ unsigned int nonerp_set:1;
+ unsigned int no_short_slot_time_set:1;
+ unsigned int no_short_preamble_set:1;
+
+ u16 auth_alg;
+ u8 previous_ap[6];
+
+ enum {
+ STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
+ } timeout_next;
+
+ /* IEEE 802.1X related data */
+ struct eapol_state_machine *eapol_sm;
+
+ /* IEEE 802.11f (IAPP) related data */
+ struct ieee80211_mgmt *last_assoc_req;
+
+ u32 acct_session_id_hi;
+ u32 acct_session_id_lo;
+ time_t acct_session_start;
+ int acct_session_started;
+ int acct_terminate_cause; /* Acct-Terminate-Cause */
+ int acct_interim_interval; /* Acct-Interim-Interval */
+
+ unsigned long last_rx_bytes;
+ unsigned long last_tx_bytes;
+ u32 acct_input_gigawords; /* Acct-Input-Gigawords */
+ u32 acct_output_gigawords; /* Acct-Output-Gigawords */
+
+ u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
+
+ struct wpa_state_machine *wpa_sm;
+ struct rsn_preauth_interface *preauth_iface;
+
+ struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
+ struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
+
+ int vlan_id;
+};
+
+
+/* Maximum number of AIDs to use for STAs; must be 2007 or lower
+ * (8802.11 limitation) */
+#define MAX_AID_TABLE_SIZE 128
+
+#define STA_HASH_SIZE 256
+#define STA_HASH(sta) (sta[5])
+
+
+/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has
+ * passed since last received frame from the station, a nullfunc data frame is
+ * sent to the station. If this frame is not acknowledged and no other frames
+ * have been received, the station will be disassociated after
+ * AP_DISASSOC_DELAY seconds. Similarily, the station will be deauthenticated
+ * after AP_DEAUTH_DELAY seconds has passed after disassociation. */
+#define AP_MAX_INACTIVITY (5 * 60)
+#define AP_DISASSOC_DELAY (1)
+#define AP_DEAUTH_DELAY (1)
+/* Number of seconds to keep STA entry with Authenticated flag after it has
+ * been disassociated. */
+#define AP_MAX_INACTIVITY_AFTER_DISASSOC (1 * 30)
+/* Number of seconds to keep STA entry after it has been deauthenticated. */
+#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5)
+
+#endif /* AP_H */
diff --git a/hostapd/ap_list.c b/hostapd/ap_list.c
new file mode 100644
index 0000000..5f5b5d4
--- /dev/null
+++ b/hostapd/ap_list.c
@@ -0,0 +1,458 @@
+/*
+ * hostapd / AP table
+ * Copyright 2002-2003, Jouni Malinen <j@w1.fi>
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2006, Devicescape Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "eloop.h"
+#include "ap_list.h"
+#include "hw_features.h"
+#include "beacon.h"
+
+
+struct ieee80211_frame_info {
+ u32 version;
+ u32 length;
+ u64 mactime;
+ u64 hosttime;
+ u32 phytype;
+ u32 channel;
+ u32 datarate;
+ u32 antenna;
+ u32 priority;
+ u32 ssi_type;
+ u32 ssi_signal;
+ u32 ssi_noise;
+ u32 preamble;
+ u32 encoding;
+
+ /* Note: this structure is otherwise identical to capture format used
+ * in linux-wlan-ng, but this additional field is used to provide meta
+ * data about the frame to hostapd. This was the easiest method for
+ * providing this information, but this might change in the future. */
+ u32 msg_type;
+} __attribute__ ((packed));
+
+
+enum ieee80211_phytype {
+ ieee80211_phytype_fhss_dot11_97 = 1,
+ ieee80211_phytype_dsss_dot11_97 = 2,
+ ieee80211_phytype_irbaseband = 3,
+ ieee80211_phytype_dsss_dot11_b = 4,
+ ieee80211_phytype_pbcc_dot11_b = 5,
+ ieee80211_phytype_ofdm_dot11_g = 6,
+ ieee80211_phytype_pbcc_dot11_g = 7,
+ ieee80211_phytype_ofdm_dot11_a = 8,
+ ieee80211_phytype_dsss_dot11_turbog = 255,
+ ieee80211_phytype_dsss_dot11_turbo = 256,
+};
+
+
+/* AP list is a double linked list with head->prev pointing to the end of the
+ * list and tail->next = NULL. Entries are moved to the head of the list
+ * whenever a beacon has been received from the AP in question. The tail entry
+ * in this link will thus be the least recently used entry. */
+
+
+static void ap_list_new_ap(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ wpa_printf(MSG_DEBUG, "New AP detected: " MACSTR, MAC2STR(ap->addr));
+
+ /* TODO: could send a notification message to an external program that
+ * would then determine whether a rogue AP has been detected */
+}
+
+
+static void ap_list_expired_ap(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ wpa_printf(MSG_DEBUG, "AP info expired: " MACSTR, MAC2STR(ap->addr));
+
+ /* TODO: could send a notification message to an external program */
+}
+
+
+static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ int i;
+
+ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
+ ap->phytype != ieee80211_phytype_pbcc_dot11_g ||
+ iface->conf->channel != ap->channel)
+ return 0;
+
+ if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
+ return 1;
+
+ for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
+ int rate = (ap->supported_rates[i] & 0x7f) * 5;
+ if (rate == 60 || rate == 90 || rate > 110)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *ap)
+{
+ struct ap_info *s;
+
+ s = iface->ap_hash[STA_HASH(ap)];
+ while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
+ s = s->hnext;
+ return s;
+}
+
+
+static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ if (iface->ap_list) {
+ ap->prev = iface->ap_list->prev;
+ iface->ap_list->prev = ap;
+ } else
+ ap->prev = ap;
+ ap->next = iface->ap_list;
+ iface->ap_list = ap;
+}
+
+
+static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ if (iface->ap_list == ap)
+ iface->ap_list = ap->next;
+ else
+ ap->prev->next = ap->next;
+
+ if (ap->next)
+ ap->next->prev = ap->prev;
+ else if (iface->ap_list)
+ iface->ap_list->prev = ap->prev;
+}
+
+
+static void ap_ap_iter_list_add(struct hostapd_iface *iface,
+ struct ap_info *ap)
+{
+ if (iface->ap_iter_list) {
+ ap->iter_prev = iface->ap_iter_list->iter_prev;
+ iface->ap_iter_list->iter_prev = ap;
+ } else
+ ap->iter_prev = ap;
+ ap->iter_next = iface->ap_iter_list;
+ iface->ap_iter_list = ap;
+}
+
+
+static void ap_ap_iter_list_del(struct hostapd_iface *iface,
+ struct ap_info *ap)
+{
+ if (iface->ap_iter_list == ap)
+ iface->ap_iter_list = ap->iter_next;
+ else
+ ap->iter_prev->iter_next = ap->iter_next;
+
+ if (ap->iter_next)
+ ap->iter_next->iter_prev = ap->iter_prev;
+ else if (iface->ap_iter_list)
+ iface->ap_iter_list->iter_prev = ap->iter_prev;
+}
+
+
+static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
+ iface->ap_hash[STA_HASH(ap->addr)] = ap;
+}
+
+
+static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ struct ap_info *s;
+
+ s = iface->ap_hash[STA_HASH(ap->addr)];
+ if (s == NULL) return;
+ if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
+ iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
+ return;
+ }
+
+ while (s->hnext != NULL &&
+ os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
+ s = s->hnext;
+ if (s->hnext != NULL)
+ s->hnext = s->hnext->hnext;
+ else
+ printf("AP: could not remove AP " MACSTR " from hash table\n",
+ MAC2STR(ap->addr));
+}
+
+
+static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ ap_ap_hash_del(iface, ap);
+ ap_ap_list_del(iface, ap);
+ ap_ap_iter_list_del(iface, ap);
+
+ iface->num_ap--;
+ os_free(ap);
+}
+
+
+static void hostapd_free_aps(struct hostapd_iface *iface)
+{
+ struct ap_info *ap, *prev;
+
+ ap = iface->ap_list;
+
+ while (ap) {
+ prev = ap;
+ ap = ap->next;
+ ap_free_ap(iface, prev);
+ }
+
+ iface->ap_list = NULL;
+}
+
+
+int ap_ap_for_each(struct hostapd_iface *iface,
+ int (*func)(struct ap_info *s, void *data), void *data)
+{
+ struct ap_info *s;
+ int ret = 0;
+
+ s = iface->ap_list;
+
+ while (s) {
+ ret = func(s, data);
+ if (ret)
+ break;
+ s = s->next;
+ }
+
+ return ret;
+}
+
+
+static struct ap_info * ap_ap_add(struct hostapd_iface *iface, u8 *addr)
+{
+ struct ap_info *ap;
+
+ ap = os_zalloc(sizeof(struct ap_info));
+ if (ap == NULL)
+ return NULL;
+
+ /* initialize AP info data */
+ os_memcpy(ap->addr, addr, ETH_ALEN);
+ ap_ap_list_add(iface, ap);
+ iface->num_ap++;
+ ap_ap_hash_add(iface, ap);
+ ap_ap_iter_list_add(iface, ap);
+
+ if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
+ wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
+ MACSTR " from AP table", MAC2STR(ap->prev->addr));
+ if (iface->conf->passive_scan_interval > 0)
+ ap_list_expired_ap(iface, ap->prev);
+ ap_free_ap(iface, ap->prev);
+ }
+
+ return ap;
+}
+
+
+void ap_list_process_beacon(struct hostapd_iface *iface,
+ struct ieee80211_mgmt *mgmt,
+ struct ieee802_11_elems *elems,
+ struct hostapd_frame_info *fi)
+{
+ struct ap_info *ap;
+ int new_ap = 0;
+ size_t len;
+
+ if (iface->conf->ap_table_max_size < 1)
+ return;
+
+ ap = ap_get_ap(iface, mgmt->bssid);
+ if (!ap) {
+ ap = ap_ap_add(iface, mgmt->bssid);
+ if (!ap) {
+ printf("Failed to allocate AP information entry\n");
+ return;
+ }
+ new_ap = 1;
+ }
+
+ ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
+ ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
+
+ if (elems->ssid) {
+ len = elems->ssid_len;
+ if (len >= sizeof(ap->ssid))
+ len = sizeof(ap->ssid) - 1;
+ os_memcpy(ap->ssid, elems->ssid, len);
+ ap->ssid[len] = '\0';
+ ap->ssid_len = len;
+ }
+
+ os_memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX);
+ len = 0;
+ if (elems->supp_rates) {
+ len = elems->supp_rates_len;
+ if (len > WLAN_SUPP_RATES_MAX)
+ len = WLAN_SUPP_RATES_MAX;
+ os_memcpy(ap->supported_rates, elems->supp_rates, len);
+ }
+ if (elems->ext_supp_rates) {
+ int len2;
+ if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX)
+ len2 = WLAN_SUPP_RATES_MAX - len;
+ else
+ len2 = elems->ext_supp_rates_len;
+ os_memcpy(ap->supported_rates + len, elems->ext_supp_rates,
+ len2);
+ }
+
+ ap->wpa = elems->wpa_ie != NULL;
+
+ if (elems->erp_info && elems->erp_info_len == 1)
+ ap->erp = elems->erp_info[0];
+ else
+ ap->erp = -1;
+
+ if (elems->ds_params && elems->ds_params_len == 1)
+ ap->channel = elems->ds_params[0];
+ else if (fi)
+ ap->channel = fi->channel;
+
+ ap->num_beacons++;
+ time(&ap->last_beacon);
+ if (fi) {
+ ap->phytype = fi->phytype;
+ ap->ssi_signal = fi->ssi_signal;
+ ap->datarate = fi->datarate;
+ }
+
+ if (new_ap) {
+ if (iface->conf->passive_scan_interval > 0)
+ ap_list_new_ap(iface, ap);
+ } else if (ap != iface->ap_list) {
+ /* move AP entry into the beginning of the list so that the
+ * oldest entry is always in the end of the list */
+ ap_ap_list_del(iface, ap);
+ ap_ap_list_add(iface, ap);
+ }
+
+ if (!iface->olbc &&
+ ap_list_beacon_olbc(iface, ap)) {
+ struct hostapd_data *hapd = iface->bss[0];
+ iface->olbc = 1;
+ wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
+ "protection", MAC2STR(ap->addr));
+ ieee802_11_set_beacons(hapd->iface);
+ }
+}
+
+
+static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_iface *iface = eloop_ctx;
+ time_t now;
+ struct ap_info *ap;
+
+ eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
+
+ if (!iface->ap_list)
+ return;
+
+ time(&now);
+
+ /* FIX: it looks like jkm-Purina ended up in busy loop in this
+ * function. Apparently, something can still cause a loop in the AP
+ * list.. */
+
+ while (iface->ap_list) {
+ ap = iface->ap_list->prev;
+ if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
+ now)
+ break;
+
+ if (iface->conf->passive_scan_interval > 0)
+ ap_list_expired_ap(iface, ap);
+ ap_free_ap(iface, ap);
+ }
+
+ if (iface->olbc) {
+ int olbc = 0;
+ ap = iface->ap_list;
+ while (ap) {
+ if (ap_list_beacon_olbc(iface, ap)) {
+ olbc = 1;
+ break;
+ }
+ ap = ap->next;
+ }
+ if (!olbc) {
+ struct hostapd_data *hapd = iface->bss[0];
+ wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
+ iface->olbc = 0;
+ ieee802_11_set_beacons(hapd->iface);
+ }
+ }
+}
+
+
+int ap_list_init(struct hostapd_iface *iface)
+{
+ eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
+ return 0;
+}
+
+
+void ap_list_deinit(struct hostapd_iface *iface)
+{
+ eloop_cancel_timeout(ap_list_timer, iface, NULL);
+ hostapd_free_aps(iface);
+}
+
+
+int ap_list_reconfig(struct hostapd_iface *iface,
+ struct hostapd_config *oldconf)
+{
+ time_t now;
+ struct ap_info *ap;
+
+ if (iface->conf->ap_table_max_size == oldconf->ap_table_max_size &&
+ iface->conf->ap_table_expiration_time ==
+ oldconf->ap_table_expiration_time)
+ return 0;
+
+ time(&now);
+
+ while (iface->ap_list) {
+ ap = iface->ap_list->prev;
+ if (iface->num_ap <= iface->conf->ap_table_max_size &&
+ ap->last_beacon + iface->conf->ap_table_expiration_time >=
+ now)
+ break;
+
+ if (iface->conf->passive_scan_interval > 0)
+ ap_list_expired_ap(iface, iface->ap_list->prev);
+ ap_free_ap(iface, iface->ap_list->prev);
+ }
+
+ return 0;
+}
diff --git a/hostapd/ap_list.h b/hostapd/ap_list.h
new file mode 100644
index 0000000..668d909
--- /dev/null
+++ b/hostapd/ap_list.h
@@ -0,0 +1,68 @@
+/*
+ * hostapd / AP table
+ * Copyright 2002-2003, Jouni Malinen <j@w1.fi>
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2006, Devicescape Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef AP_LIST_H
+#define AP_LIST_H
+
+struct ap_info {
+ /* Note: next/prev pointers are updated whenever a new beacon is
+ * received because these are used to find the least recently used
+ * entries. iter_next/iter_prev are updated only when adding new BSSes
+ * and when removing old ones. These should be used when iterating
+ * through the table in a manner that allows beacons to be received
+ * during the iteration. */
+ struct ap_info *next; /* next entry in AP list */
+ struct ap_info *prev; /* previous entry in AP list */
+ struct ap_info *hnext; /* next entry in hash table list */
+ struct ap_info *iter_next; /* next entry in AP iteration list */
+ struct ap_info *iter_prev; /* previous entry in AP iteration list */
+ u8 addr[6];
+ u16 beacon_int;
+ u16 capability;
+ u8 supported_rates[WLAN_SUPP_RATES_MAX];
+ u8 ssid[33];
+ size_t ssid_len;
+ int wpa;
+ int erp; /* ERP Info or -1 if ERP info element not present */
+
+ int phytype; /* .11a / .11b / .11g / Atheros Turbo */
+ int channel;
+ int datarate; /* in 100 kbps */
+ int ssi_signal;
+
+ unsigned int num_beacons; /* number of beacon frames received */
+ time_t last_beacon;
+
+ int already_seen; /* whether API call AP-NEW has already fetched
+ * information about this AP */
+};
+
+struct ieee802_11_elems;
+struct hostapd_frame_info;
+
+struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *sta);
+int ap_ap_for_each(struct hostapd_iface *iface,
+ int (*func)(struct ap_info *s, void *data), void *data);
+void ap_list_process_beacon(struct hostapd_iface *iface,
+ struct ieee80211_mgmt *mgmt,
+ struct ieee802_11_elems *elems,
+ struct hostapd_frame_info *fi);
+int ap_list_init(struct hostapd_iface *iface);
+void ap_list_deinit(struct hostapd_iface *iface);
+int ap_list_reconfig(struct hostapd_iface *iface,
+ struct hostapd_config *oldconf);
+
+#endif /* AP_LIST_H */
diff --git a/hostapd/beacon.c b/hostapd/beacon.c
new file mode 100644
index 0000000..d005559
--- /dev/null
+++ b/hostapd/beacon.c
@@ -0,0 +1,418 @@
+/*
+ * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
+ * Copyright (c) 2002-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "wpa.h"
+#include "wme.h"
+#include "beacon.h"
+#include "hw_features.h"
+#include "driver.h"
+#include "sta_info.h"
+#include "ieee802_11h.h"
+
+
+static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
+{
+ u8 erp = 0;
+
+ if (hapd->iface->current_mode == NULL ||
+ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+ return 0;
+
+ switch (hapd->iconf->cts_protection_type) {
+ case CTS_PROTECTION_FORCE_ENABLED:
+ erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION;
+ break;
+ case CTS_PROTECTION_FORCE_DISABLED:
+ erp = 0;
+ break;
+ case CTS_PROTECTION_AUTOMATIC:
+ if (hapd->iface->olbc)
+ erp |= ERP_INFO_USE_PROTECTION;
+ /* continue */
+ case CTS_PROTECTION_AUTOMATIC_NO_OLBC:
+ if (hapd->iface->num_sta_non_erp > 0) {
+ erp |= ERP_INFO_NON_ERP_PRESENT |
+ ERP_INFO_USE_PROTECTION;
+ }
+ break;
+ }
+ if (hapd->iface->num_sta_no_short_preamble > 0)
+ erp |= ERP_INFO_BARKER_PREAMBLE_MODE;
+
+ return erp;
+}
+
+
+static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid)
+{
+ *eid++ = WLAN_EID_DS_PARAMS;
+ *eid++ = 1;
+ *eid++ = hapd->iconf->channel;
+ return eid;
+}
+
+
+static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
+{
+ if (hapd->iface->current_mode == NULL ||
+ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+ return eid;
+
+ /* Set NonERP_present and use_protection bits if there
+ * are any associated NonERP stations. */
+ /* TODO: use_protection bit can be set to zero even if
+ * there are NonERP stations present. This optimization
+ * might be useful if NonERP stations are "quiet".
+ * See 802.11g/D6 E-1 for recommended practice.
+ * In addition, Non ERP present might be set, if AP detects Non ERP
+ * operation on other APs. */
+
+ /* Add ERP Information element */
+ *eid++ = WLAN_EID_ERP_INFO;
+ *eid++ = 1;
+ *eid++ = ieee802_11_erp_info(hapd);
+
+ return eid;
+}
+
+
+static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
+ int max_len)
+{
+ u8 *pos = eid;
+
+ if ((!hapd->iconf->ieee80211d && !hapd->iface->dfs_enable) ||
+ max_len < 6)
+ return eid;
+
+ *pos++ = WLAN_EID_COUNTRY;
+ pos++; /* length will be set later */
+ os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
+ pos += 3;
+
+ if ((pos - eid) & 1)
+ *pos++ = 0; /* pad for 16-bit alignment */
+
+ eid[1] = (pos - eid) - 2;
+
+ return pos;
+}
+
+
+static u8 * hostapd_eid_power_constraint(struct hostapd_data *hapd, u8 *eid)
+
+{
+ if (!hapd->iface->dfs_enable)
+ return eid;
+ *eid++ = WLAN_EID_PWR_CONSTRAINT;
+ *eid++ = 1;
+ *eid++ = hapd->iface->pwr_const;
+ return eid;
+}
+
+
+static u8 * hostapd_eid_tpc_report(struct hostapd_data *hapd, u8 *eid)
+
+{
+ if (!hapd->iface->dfs_enable)
+ return eid;
+ *eid++ = WLAN_EID_TPC_REPORT;
+ *eid++ = 2;
+ *eid++ = hapd->iface->tx_power; /* TX POWER */
+ *eid++ = 0; /* Link Margin */
+ return eid;
+}
+
+static u8 * hostapd_eid_channel_switch(struct hostapd_data *hapd, u8 *eid)
+
+{
+ if (!hapd->iface->dfs_enable || !hapd->iface->channel_switch)
+ return eid;
+ *eid++ = WLAN_EID_CHANNEL_SWITCH;
+ *eid++ = 3;
+ *eid++ = CHAN_SWITCH_MODE_QUIET;
+ *eid++ = hapd->iface->channel_switch; /* New channel */
+ /* 0 - very soon; 1 - before next TBTT; num - after num beacons */
+ *eid++ = 0;
+ return eid;
+}
+
+
+static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
+ struct sta_info *sta)
+{
+ const u8 *ie;
+ size_t ielen;
+
+ ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
+ if (ie == NULL || ielen > len)
+ return eid;
+
+ os_memcpy(eid, ie, ielen);
+ return eid + ielen;
+}
+
+
+void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ struct ieee80211_mgmt *resp;
+ struct ieee802_11_elems elems;
+ char *ssid;
+ u8 *pos, *epos, *ie;
+ size_t ssid_len, ie_len;
+ struct sta_info *sta = NULL;
+
+ ie = mgmt->u.probe_req.variable;
+ ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+
+ if (!hapd->iconf->send_probe_response)
+ return;
+
+ if (ieee802_11_parse_elems(hapd, ie, ie_len, &elems, 0) == ParseFailed)
+ {
+ wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR,
+ MAC2STR(mgmt->sa));
+ return;
+ }
+
+ ssid = NULL;
+ ssid_len = 0;
+
+ if ((!elems.ssid || !elems.supp_rates)) {
+ wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
+ "without SSID or supported rates element",
+ MAC2STR(mgmt->sa));
+ return;
+ }
+
+ if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) {
+ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
+ "broadcast SSID ignored", MAC2STR(mgmt->sa));
+ return;
+ }
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+
+ if (elems.ssid_len == 0 ||
+ (elems.ssid_len == hapd->conf->ssid.ssid_len &&
+ os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) ==
+ 0)) {
+ ssid = hapd->conf->ssid.ssid;
+ ssid_len = hapd->conf->ssid.ssid_len;
+ if (sta)
+ sta->ssid_probe = &hapd->conf->ssid;
+ }
+
+ if (!ssid) {
+ if (!(mgmt->da[0] & 0x01)) {
+ char ssid_txt[33];
+ ieee802_11_print_ssid(ssid_txt, elems.ssid,
+ elems.ssid_len);
+ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+ " for foreign SSID '%s'",
+ MAC2STR(mgmt->sa), ssid_txt);
+ }
+ return;
+ }
+
+ /* TODO: verify that supp_rates contains at least one matching rate
+ * with AP configuration */
+#define MAX_PROBERESP_LEN 768
+ resp = os_zalloc(MAX_PROBERESP_LEN);
+ if (resp == NULL)
+ return;
+ epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
+
+ resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_PROBE_RESP);
+ os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
+ os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+
+ os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+ resp->u.probe_resp.beacon_int =
+ host_to_le16(hapd->iconf->beacon_int);
+
+ /* hardware or low-level driver will setup seq_ctrl and timestamp */
+ resp->u.probe_resp.capab_info =
+ host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
+
+ pos = resp->u.probe_resp.variable;
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = ssid_len;
+ os_memcpy(pos, ssid, ssid_len);
+ pos += ssid_len;
+
+ /* Supported rates */
+ pos = hostapd_eid_supp_rates(hapd, pos);
+
+ /* DS Params */
+ pos = hostapd_eid_ds_params(hapd, pos);
+
+ pos = hostapd_eid_country(hapd, pos, epos - pos);
+
+ pos = hostapd_eid_power_constraint(hapd, pos);
+ pos = hostapd_eid_tpc_report(hapd, pos);
+
+ /* ERP Information element */
+ pos = hostapd_eid_erp_info(hapd, pos);
+
+ /* Extended supported rates */
+ pos = hostapd_eid_ext_supp_rates(hapd, pos);
+
+ pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
+
+ /* Wi-Fi Wireless Multimedia Extensions */
+ if (hapd->conf->wme_enabled)
+ pos = hostapd_eid_wme(hapd, pos);
+
+ if (hostapd_send_mgmt_frame(hapd, resp, pos - (u8 *) resp, 0) < 0)
+ perror("handle_probe_req: send");
+
+ os_free(resp);
+
+ wpa_printf(MSG_MSGDUMP, "STA " MACSTR " sent probe request for %s "
+ "SSID", MAC2STR(mgmt->sa),
+ elems.ssid_len == 0 ? "broadcast" : "our");
+}
+
+
+void ieee802_11_set_beacon(struct hostapd_data *hapd)
+{
+ struct ieee80211_mgmt *head;
+ u8 *pos, *tail, *tailpos;
+ int preamble;
+ u16 capab_info;
+ size_t head_len, tail_len;
+ int cts_protection = ((ieee802_11_erp_info(hapd) &
+ ERP_INFO_USE_PROTECTION) ? 1 : 0);
+
+#define BEACON_HEAD_BUF_SIZE 256
+#define BEACON_TAIL_BUF_SIZE 512
+ head = os_zalloc(BEACON_HEAD_BUF_SIZE);
+ tailpos = tail = os_malloc(BEACON_TAIL_BUF_SIZE);
+ if (head == NULL || tail == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to set beacon data");
+ os_free(head);
+ os_free(tail);
+ return;
+ }
+
+ head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_BEACON);
+ head->duration = host_to_le16(0);
+ os_memset(head->da, 0xff, ETH_ALEN);
+
+ os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
+ head->u.beacon.beacon_int =
+ host_to_le16(hapd->iconf->beacon_int);
+
+ /* hardware or low-level driver will setup seq_ctrl and timestamp */
+ capab_info = hostapd_own_capab_info(hapd, NULL, 0);
+ head->u.beacon.capab_info = host_to_le16(capab_info);
+ pos = &head->u.beacon.variable[0];
+
+ /* SSID */
+ *pos++ = WLAN_EID_SSID;
+ if (hapd->conf->ignore_broadcast_ssid == 2) {
+ /* clear the data, but keep the correct length of the SSID */
+ *pos++ = hapd->conf->ssid.ssid_len;
+ os_memset(pos, 0, hapd->conf->ssid.ssid_len);
+ pos += hapd->conf->ssid.ssid_len;
+ } else if (hapd->conf->ignore_broadcast_ssid) {
+ *pos++ = 0; /* empty SSID */
+ } else {
+ *pos++ = hapd->conf->ssid.ssid_len;
+ os_memcpy(pos, hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len);
+ pos += hapd->conf->ssid.ssid_len;
+ }
+
+ /* Supported rates */
+ pos = hostapd_eid_supp_rates(hapd, pos);
+
+ /* DS Params */
+ pos = hostapd_eid_ds_params(hapd, pos);
+
+ head_len = pos - (u8 *) head;
+
+ tailpos = hostapd_eid_country(hapd, tailpos,
+ tail + BEACON_TAIL_BUF_SIZE - tailpos);
+
+ tailpos = hostapd_eid_power_constraint(hapd, tailpos);
+ tailpos = hostapd_eid_channel_switch(hapd, tailpos);
+ tailpos = hostapd_eid_tpc_report(hapd, tailpos);
+
+ /* ERP Information element */
+ tailpos = hostapd_eid_erp_info(hapd, tailpos);
+
+ /* Extended supported rates */
+ tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
+
+ tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
+ tailpos, NULL);
+
+ /* Wi-Fi Wireless Multimedia Extensions */
+ if (hapd->conf->wme_enabled)
+ tailpos = hostapd_eid_wme(hapd, tailpos);
+
+ tail_len = tailpos > tail ? tailpos - tail : 0;
+
+ if (hostapd_set_beacon(hapd->conf->iface, hapd, (u8 *) head, head_len,
+ tail, tail_len))
+ wpa_printf(MSG_ERROR, "Failed to set beacon head/tail");
+
+ os_free(tail);
+ os_free(head);
+
+ if (hostapd_set_cts_protect(hapd, cts_protection))
+ wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel "
+ "driver");
+
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
+ hostapd_set_short_slot_time(hapd,
+ hapd->iface->num_sta_no_short_slot_time
+ > 0 ? 0 : 1))
+ wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option "
+ "in kernel driver");
+
+ if (hapd->iface->num_sta_no_short_preamble == 0 &&
+ hapd->iconf->preamble == SHORT_PREAMBLE)
+ preamble = SHORT_PREAMBLE;
+ else
+ preamble = LONG_PREAMBLE;
+ if (hostapd_set_preamble(hapd, preamble))
+ wpa_printf(MSG_ERROR, "Could not set preamble for kernel "
+ "driver");
+}
+
+
+void ieee802_11_set_beacons(struct hostapd_iface *iface)
+{
+ size_t i;
+ for (i = 0; i < iface->num_bss; i++)
+ ieee802_11_set_beacon(iface->bss[i]);
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/hostapd/beacon.h b/hostapd/beacon.h
new file mode 100644
index 0000000..18e0da2
--- /dev/null
+++ b/hostapd/beacon.h
@@ -0,0 +1,24 @@
+/*
+ * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
+ * Copyright (c) 2002-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef BEACON_H
+#define BEACON_H
+
+void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+ size_t len);
+void ieee802_11_set_beacon(struct hostapd_data *hapd);
+void ieee802_11_set_beacons(struct hostapd_iface *iface);
+
+#endif /* BEACON_H */
diff --git a/hostapd/config.c b/hostapd/config.c
new file mode 100644
index 0000000..4280453
--- /dev/null
+++ b/hostapd/config.c
@@ -0,0 +1,2238 @@
+/*
+ * hostapd / Configuration file
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <grp.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "hostapd.h"
+#include "driver.h"
+#include "sha1.h"
+#include "eap_server/eap.h"
+#include "radius/radius_client.h"
+#include "wpa_common.h"
+#include "wpa.h"
+#include "uuid.h"
+
+
+#define MAX_STA_COUNT 2007
+
+extern struct wpa_driver_ops *hostapd_drivers[];
+
+
+static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
+ const char *fname)
+{
+ FILE *f;
+ char buf[128], *pos, *pos2;
+ int line = 0, vlan_id;
+ struct hostapd_vlan *vlan;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ printf("VLAN file '%s' not readable.\n", fname);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ if (buf[0] == '\0')
+ continue;
+
+ if (buf[0] == '*') {
+ vlan_id = VLAN_ID_WILDCARD;
+ pos = buf + 1;
+ } else {
+ vlan_id = strtol(buf, &pos, 10);
+ if (buf == pos || vlan_id < 1 ||
+ vlan_id > MAX_VLAN_ID) {
+ printf("Invalid VLAN ID at line %d in '%s'\n",
+ line, fname);
+ fclose(f);
+ return -1;
+ }
+ }
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ pos2 = pos;
+ while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
+ pos2++;
+ *pos2 = '\0';
+ if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) {
+ printf("Invalid VLAN ifname at line %d in '%s'\n",
+ line, fname);
+ fclose(f);
+ return -1;
+ }
+
+ vlan = os_malloc(sizeof(*vlan));
+ if (vlan == NULL) {
+ printf("Out of memory while reading VLAN interfaces "
+ "from '%s'\n", fname);
+ fclose(f);
+ return -1;
+ }
+
+ os_memset(vlan, 0, sizeof(*vlan));
+ vlan->vlan_id = vlan_id;
+ os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
+ if (bss->vlan_tail)
+ bss->vlan_tail->next = vlan;
+ else
+ bss->vlan = vlan;
+ bss->vlan_tail = vlan;
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+
+static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
+{
+ struct hostapd_vlan *vlan, *prev;
+
+ vlan = bss->vlan;
+ prev = NULL;
+ while (vlan) {
+ prev = vlan;
+ vlan = vlan->next;
+ os_free(prev);
+ }
+
+ bss->vlan = NULL;
+}
+
+
+/* convert floats with one decimal place to value*10 int, i.e.,
+ * "1.5" will return 15 */
+static int hostapd_config_read_int10(const char *value)
+{
+ int i, d;
+ char *pos;
+
+ i = atoi(value);
+ pos = os_strchr(value, '.');
+ d = 0;
+ if (pos) {
+ pos++;
+ if (*pos >= '0' && *pos <= '9')
+ d = *pos - '0';
+ }
+
+ return i * 10 + d;
+}
+
+
+static void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
+{
+ bss->logger_syslog_level = HOSTAPD_LEVEL_INFO;
+ bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
+ bss->logger_syslog = (unsigned int) -1;
+ bss->logger_stdout = (unsigned int) -1;
+
+ bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
+
+ bss->wep_rekeying_period = 300;
+ /* use key0 in individual key and key1 in broadcast key */
+ bss->broadcast_key_idx_min = 1;
+ bss->broadcast_key_idx_max = 2;
+ bss->eap_reauth_period = 3600;
+
+ bss->wpa_group_rekey = 600;
+ bss->wpa_gmk_rekey = 86400;
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+ bss->wpa_pairwise = WPA_CIPHER_TKIP;
+ bss->wpa_group = WPA_CIPHER_TKIP;
+ bss->rsn_pairwise = 0;
+
+ bss->max_num_sta = MAX_STA_COUNT;
+
+ bss->dtim_period = 2;
+
+ bss->radius_server_auth_port = 1812;
+ bss->ap_max_inactivity = AP_MAX_INACTIVITY;
+ bss->eapol_version = EAPOL_VERSION;
+}
+
+
+static struct hostapd_config * hostapd_config_defaults(void)
+{
+ struct hostapd_config *conf;
+ struct hostapd_bss_config *bss;
+ int i;
+ const int aCWmin = 15, aCWmax = 1024;
+ const struct hostapd_wme_ac_params ac_bk =
+ { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
+ const struct hostapd_wme_ac_params ac_be =
+ { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
+ const struct hostapd_wme_ac_params ac_vi = /* video traffic */
+ { aCWmin >> 1, aCWmin, 2, 3000 / 32, 1 };
+ const struct hostapd_wme_ac_params ac_vo = /* voice traffic */
+ { aCWmin >> 2, aCWmin >> 1, 2, 1500 / 32, 1 };
+
+ conf = os_zalloc(sizeof(*conf));
+ bss = os_zalloc(sizeof(*bss));
+ if (conf == NULL || bss == NULL) {
+ printf("Failed to allocate memory for configuration data.\n");
+ os_free(conf);
+ os_free(bss);
+ return NULL;
+ }
+
+ /* set default driver based on configuration */
+ conf->driver = hostapd_drivers[0];
+ if (conf->driver == NULL) {
+ printf("No driver wrappers registered!\n");
+ os_free(conf);
+ os_free(bss);
+ return NULL;
+ }
+
+ bss->radius = os_zalloc(sizeof(*bss->radius));
+ if (bss->radius == NULL) {
+ os_free(conf);
+ os_free(bss);
+ return NULL;
+ }
+
+ hostapd_config_defaults_bss(bss);
+
+ conf->num_bss = 1;
+ conf->bss = bss;
+
+ conf->beacon_int = 100;
+ conf->rts_threshold = -1; /* use driver default: 2347 */
+ conf->fragm_threshold = -1; /* user driver default: 2346 */
+ conf->send_probe_response = 1;
+ conf->bridge_packets = INTERNAL_BRIDGE_DO_NOT_CONTROL;
+
+ os_memcpy(conf->country, "US ", 3);
+
+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ conf->tx_queue[i].aifs = -1; /* use hw default */
+
+ conf->wme_ac_params[0] = ac_be;
+ conf->wme_ac_params[1] = ac_bk;
+ conf->wme_ac_params[2] = ac_vi;
+ conf->wme_ac_params[3] = ac_vo;
+
+ return conf;
+}
+
+
+int hostapd_mac_comp(const void *a, const void *b)
+{
+ return os_memcmp(a, b, sizeof(macaddr));
+}
+
+
+int hostapd_mac_comp_empty(const void *a)
+{
+ macaddr empty = { 0 };
+ return os_memcmp(a, empty, sizeof(macaddr));
+}
+
+
+static int hostapd_config_read_maclist(const char *fname, macaddr **acl,
+ int *num)
+{
+ FILE *f;
+ char buf[128], *pos;
+ int line = 0;
+ u8 addr[ETH_ALEN];
+ macaddr *newacl;
+
+ if (!fname)
+ return 0;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ printf("MAC list file '%s' not found.\n", fname);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ if (buf[0] == '\0')
+ continue;
+
+ if (hwaddr_aton(buf, addr)) {
+ printf("Invalid MAC address '%s' at line %d in '%s'\n",
+ buf, line, fname);
+ fclose(f);
+ return -1;
+ }
+
+ newacl = os_realloc(*acl, (*num + 1) * ETH_ALEN);
+ if (newacl == NULL) {
+ printf("MAC list reallocation failed\n");
+ fclose(f);
+ return -1;
+ }
+
+ *acl = newacl;
+ os_memcpy((*acl)[*num], addr, ETH_ALEN);
+ (*num)++;
+ }
+
+ fclose(f);
+
+ qsort(*acl, *num, sizeof(macaddr), hostapd_mac_comp);
+
+ return 0;
+}
+
+
+static int hostapd_config_read_wpa_psk(const char *fname,
+ struct hostapd_ssid *ssid)
+{
+ FILE *f;
+ char buf[128], *pos;
+ int line = 0, ret = 0, len, ok;
+ u8 addr[ETH_ALEN];
+ struct hostapd_wpa_psk *psk;
+
+ if (!fname)
+ return 0;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ printf("WPA PSK file '%s' not found.\n", fname);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ if (buf[0] == '\0')
+ continue;
+
+ if (hwaddr_aton(buf, addr)) {
+ printf("Invalid MAC address '%s' on line %d in '%s'\n",
+ buf, line, fname);
+ ret = -1;
+ break;
+ }
+
+ psk = os_zalloc(sizeof(*psk));
+ if (psk == NULL) {
+ printf("WPA PSK allocation failed\n");
+ ret = -1;
+ break;
+ }
+ if (os_memcmp(addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+ psk->group = 1;
+ else
+ os_memcpy(psk->addr, addr, ETH_ALEN);
+
+ pos = buf + 17;
+ if (pos == '\0') {
+ printf("No PSK on line %d in '%s'\n", line, fname);
+ os_free(psk);
+ ret = -1;
+ break;
+ }
+ pos++;
+
+ ok = 0;
+ len = os_strlen(pos);
+ if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
+ ok = 1;
+ else if (len >= 8 && len < 64) {
+ pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
+ 4096, psk->psk, PMK_LEN);
+ ok = 1;
+ }
+ if (!ok) {
+ printf("Invalid PSK '%s' on line %d in '%s'\n",
+ pos, line, fname);
+ os_free(psk);
+ ret = -1;
+ break;
+ }
+
+ psk->next = ssid->wpa_psk;
+ ssid->wpa_psk = psk;
+ }
+
+ fclose(f);
+
+ return ret;
+}
+
+
+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
+{
+ struct hostapd_ssid *ssid = &conf->ssid;
+
+ if (ssid->wpa_passphrase != NULL) {
+ if (ssid->wpa_psk != NULL) {
+ printf("Warning: both WPA PSK and passphrase set. "
+ "Using passphrase.\n");
+ os_free(ssid->wpa_psk);
+ }
+ ssid->wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
+ if (ssid->wpa_psk == NULL) {
+ printf("Unable to alloc space for PSK\n");
+ return -1;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "SSID",
+ (u8 *) ssid->ssid, ssid->ssid_len);
+ wpa_hexdump_ascii(MSG_DEBUG, "PSK (ASCII passphrase)",
+ (u8 *) ssid->wpa_passphrase,
+ os_strlen(ssid->wpa_passphrase));
+ pbkdf2_sha1(ssid->wpa_passphrase,
+ ssid->ssid, ssid->ssid_len,
+ 4096, ssid->wpa_psk->psk, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "PSK (from passphrase)",
+ ssid->wpa_psk->psk, PMK_LEN);
+ ssid->wpa_psk->group = 1;
+
+ os_memset(ssid->wpa_passphrase, 0,
+ os_strlen(ssid->wpa_passphrase));
+ os_free(ssid->wpa_passphrase);
+ ssid->wpa_passphrase = NULL;
+ }
+
+ if (ssid->wpa_psk_file) {
+ if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
+ &conf->ssid))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#ifdef EAP_SERVER
+static int hostapd_config_read_eap_user(const char *fname,
+ struct hostapd_bss_config *conf)
+{
+ FILE *f;
+ char buf[512], *pos, *start, *pos2;
+ int line = 0, ret = 0, num_methods;
+ struct hostapd_eap_user *user, *tail = NULL;
+
+ if (!fname)
+ return 0;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ printf("EAP user file '%s' not found.\n", fname);
+ return -1;
+ }
+
+ /* Lines: "user" METHOD,METHOD2 "password" (password optional) */
+ while (fgets(buf, sizeof(buf), f)) {
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ if (buf[0] == '\0')
+ continue;
+
+ user = NULL;
+
+ if (buf[0] != '"' && buf[0] != '*') {
+ printf("Invalid EAP identity (no \" in start) on "
+ "line %d in '%s'\n", line, fname);
+ goto failed;
+ }
+
+ user = os_zalloc(sizeof(*user));
+ if (user == NULL) {
+ printf("EAP user allocation failed\n");
+ goto failed;
+ }
+ user->force_version = -1;
+
+ if (buf[0] == '*') {
+ pos = buf;
+ } else {
+ pos = buf + 1;
+ start = pos;
+ while (*pos != '"' && *pos != '\0')
+ pos++;
+ if (*pos == '\0') {
+ printf("Invalid EAP identity (no \" in end) on"
+ " line %d in '%s'\n", line, fname);
+ goto failed;
+ }
+
+ user->identity = os_malloc(pos - start);
+ if (user->identity == NULL) {
+ printf("Failed to allocate memory for EAP "
+ "identity\n");
+ goto failed;
+ }
+ os_memcpy(user->identity, start, pos - start);
+ user->identity_len = pos - start;
+
+ if (pos[0] == '"' && pos[1] == '*') {
+ user->wildcard_prefix = 1;
+ pos++;
+ }
+ }
+ pos++;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ if (*pos == '\0') {
+ printf("No EAP method on line %d in '%s'\n",
+ line, fname);
+ goto failed;
+ }
+
+ start = pos;
+ while (*pos != ' ' && *pos != '\t' && *pos != '\0')
+ pos++;
+ if (*pos == '\0') {
+ pos = NULL;
+ } else {
+ *pos = '\0';
+ pos++;
+ }
+ num_methods = 0;
+ while (*start) {
+ char *pos3 = os_strchr(start, ',');
+ if (pos3) {
+ *pos3++ = '\0';
+ }
+ user->methods[num_methods].method =
+ eap_server_get_type(
+ start,
+ &user->methods[num_methods].vendor);
+ if (user->methods[num_methods].vendor ==
+ EAP_VENDOR_IETF &&
+ user->methods[num_methods].method == EAP_TYPE_NONE)
+ {
+ if (os_strcmp(start, "TTLS-PAP") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_PAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-CHAP") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
+ user->ttls_auth |=
+ EAP_TTLS_AUTH_MSCHAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
+ user->ttls_auth |=
+ EAP_TTLS_AUTH_MSCHAPV2;
+ goto skip_eap;
+ }
+ printf("Unsupported EAP type '%s' on line %d "
+ "in '%s'\n", start, line, fname);
+ goto failed;
+ }
+
+ num_methods++;
+ if (num_methods >= EAP_USER_MAX_METHODS)
+ break;
+ skip_eap:
+ if (pos3 == NULL)
+ break;
+ start = pos3;
+ }
+ if (num_methods == 0 && user->ttls_auth == 0) {
+ printf("No EAP types configured on line %d in '%s'\n",
+ line, fname);
+ goto failed;
+ }
+
+ if (pos == NULL)
+ goto done;
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (*pos == '\0')
+ goto done;
+
+ if (os_strncmp(pos, "[ver=0]", 7) == 0) {
+ user->force_version = 0;
+ goto done;
+ }
+
+ if (os_strncmp(pos, "[ver=1]", 7) == 0) {
+ user->force_version = 1;
+ goto done;
+ }
+
+ if (os_strncmp(pos, "[2]", 3) == 0) {
+ user->phase2 = 1;
+ goto done;
+ }
+
+ if (*pos == '"') {
+ pos++;
+ start = pos;
+ while (*pos != '"' && *pos != '\0')
+ pos++;
+ if (*pos == '\0') {
+ printf("Invalid EAP password (no \" in end) "
+ "on line %d in '%s'\n", line, fname);
+ goto failed;
+ }
+
+ user->password = os_malloc(pos - start);
+ if (user->password == NULL) {
+ printf("Failed to allocate memory for EAP "
+ "password\n");
+ goto failed;
+ }
+ os_memcpy(user->password, start, pos - start);
+ user->password_len = pos - start;
+
+ pos++;
+ } else if (os_strncmp(pos, "hash:", 5) == 0) {
+ pos += 5;
+ pos2 = pos;
+ while (*pos2 != '\0' && *pos2 != ' ' &&
+ *pos2 != '\t' && *pos2 != '#')
+ pos2++;
+ if (pos2 - pos != 32) {
+ printf("Invalid password hash on line %d in "
+ "'%s'\n", line, fname);
+ goto failed;
+ }
+ user->password = os_malloc(16);
+ if (user->password == NULL) {
+ printf("Failed to allocate memory for EAP "
+ "password hash\n");
+ goto failed;
+ }
+ if (hexstr2bin(pos, user->password, 16) < 0) {
+ printf("Invalid hash password on line %d in "
+ "'%s'\n", line, fname);
+ goto failed;
+ }
+ user->password_len = 16;
+ user->password_hash = 1;
+ pos = pos2;
+ } else {
+ pos2 = pos;
+ while (*pos2 != '\0' && *pos2 != ' ' &&
+ *pos2 != '\t' && *pos2 != '#')
+ pos2++;
+ if ((pos2 - pos) & 1) {
+ printf("Invalid hex password on line %d in "
+ "'%s'\n", line, fname);
+ goto failed;
+ }
+ user->password = os_malloc((pos2 - pos) / 2);
+ if (user->password == NULL) {
+ printf("Failed to allocate memory for EAP "
+ "password\n");
+ goto failed;
+ }
+ if (hexstr2bin(pos, user->password,
+ (pos2 - pos) / 2) < 0) {
+ printf("Invalid hex password on line %d in "
+ "'%s'\n", line, fname);
+ goto failed;
+ }
+ user->password_len = (pos2 - pos) / 2;
+ pos = pos2;
+ }
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (os_strncmp(pos, "[2]", 3) == 0) {
+ user->phase2 = 1;
+ }
+
+ done:
+ if (tail == NULL) {
+ tail = conf->eap_user = user;
+ } else {
+ tail->next = user;
+ tail = user;
+ }
+ continue;
+
+ failed:
+ if (user) {
+ os_free(user->password);
+ os_free(user->identity);
+ os_free(user);
+ }
+ ret = -1;
+ break;
+ }
+
+ fclose(f);
+
+ return ret;
+}
+#endif /* EAP_SERVER */
+
+
+static int
+hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
+ int *num_server, const char *val, int def_port,
+ struct hostapd_radius_server **curr_serv)
+{
+ struct hostapd_radius_server *nserv;
+ int ret;
+ static int server_index = 1;
+
+ nserv = os_realloc(*server, (*num_server + 1) * sizeof(*nserv));
+ if (nserv == NULL)
+ return -1;
+
+ *server = nserv;
+ nserv = &nserv[*num_server];
+ (*num_server)++;
+ (*curr_serv) = nserv;
+
+ os_memset(nserv, 0, sizeof(*nserv));
+ nserv->port = def_port;
+ ret = hostapd_parse_ip_addr(val, &nserv->addr);
+ nserv->index = server_index++;
+
+ return ret;
+}
+
+
+static int hostapd_config_parse_key_mgmt(int line, const char *value)
+{
+ int val = 0, last;
+ char *start, *end, *buf;
+
+ buf = os_strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (os_strcmp(start, "WPA-PSK") == 0)
+ val |= WPA_KEY_MGMT_PSK;
+ else if (os_strcmp(start, "WPA-EAP") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X;
+#ifdef CONFIG_IEEE80211R
+ else if (os_strcmp(start, "FT-PSK") == 0)
+ val |= WPA_KEY_MGMT_FT_PSK;
+ else if (os_strcmp(start, "FT-EAP") == 0)
+ val |= WPA_KEY_MGMT_FT_IEEE8021X;
+#endif /* CONFIG_IEEE80211R */
+ else {
+ printf("Line %d: invalid key_mgmt '%s'\n",
+ line, start);
+ os_free(buf);
+ return -1;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+
+ os_free(buf);
+ if (val == 0) {
+ printf("Line %d: no key_mgmt values configured.\n", line);
+ return -1;
+ }
+
+ return val;
+}
+
+
+static int hostapd_config_parse_cipher(int line, const char *value)
+{
+ int val = 0, last;
+ char *start, *end, *buf;
+
+ buf = os_strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (os_strcmp(start, "CCMP") == 0)
+ val |= WPA_CIPHER_CCMP;
+ else if (os_strcmp(start, "TKIP") == 0)
+ val |= WPA_CIPHER_TKIP;
+ else if (os_strcmp(start, "WEP104") == 0)
+ val |= WPA_CIPHER_WEP104;
+ else if (os_strcmp(start, "WEP40") == 0)
+ val |= WPA_CIPHER_WEP40;
+ else if (os_strcmp(start, "NONE") == 0)
+ val |= WPA_CIPHER_NONE;
+ else {
+ printf("Line %d: invalid cipher '%s'.", line, start);
+ os_free(buf);
+ return -1;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+ os_free(buf);
+
+ if (val == 0) {
+ printf("Line %d: no cipher values configured.", line);
+ return -1;
+ }
+ return val;
+}
+
+
+static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
+ struct hostapd_config *conf)
+{
+ if (bss->ieee802_1x && !bss->eap_server &&
+ !bss->radius->auth_servers) {
+ printf("Invalid IEEE 802.1X configuration (no EAP "
+ "authenticator configured).\n");
+ return -1;
+ }
+
+ if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+ bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
+ bss->ssid.wpa_psk_file == NULL) {
+ printf("WPA-PSK enabled, but PSK or passphrase is not "
+ "configured.\n");
+ return -1;
+ }
+
+ if (hostapd_mac_comp_empty(bss->bssid) != 0) {
+ size_t i;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ if ((&conf->bss[i] != bss) &&
+ (hostapd_mac_comp(conf->bss[i].bssid,
+ bss->bssid) == 0)) {
+ printf("Duplicate BSSID " MACSTR
+ " on interface '%s' and '%s'.\n",
+ MAC2STR(bss->bssid),
+ conf->bss[i].iface, bss->iface);
+ return -1;
+ }
+ }
+ }
+
+#ifdef CONFIG_IEEE80211R
+ if ((bss->wpa_key_mgmt &
+ (WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X)) &&
+ (bss->nas_identifier == NULL ||
+ os_strlen(bss->nas_identifier) < 1 ||
+ os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
+ printf("FT (IEEE 802.11r) requires nas_identifier to be "
+ "configured as a 1..48 octet string\n");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211R */
+
+ return 0;
+}
+
+
+static int hostapd_config_check(struct hostapd_config *conf)
+{
+ size_t i;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ if (hostapd_config_check_bss(&conf->bss[i], conf))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
+ char *val)
+{
+ size_t len = os_strlen(val);
+
+ if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
+ return -1;
+
+ if (val[0] == '"') {
+ if (len < 2 || val[len - 1] != '"')
+ return -1;
+ len -= 2;
+ wep->key[keyidx] = os_malloc(len);
+ if (wep->key[keyidx] == NULL)
+ return -1;
+ os_memcpy(wep->key[keyidx], val + 1, len);
+ wep->len[keyidx] = len;
+ } else {
+ if (len & 1)
+ return -1;
+ len /= 2;
+ wep->key[keyidx] = os_malloc(len);
+ if (wep->key[keyidx] == NULL)
+ return -1;
+ wep->len[keyidx] = len;
+ if (hexstr2bin(val, wep->key[keyidx], len) < 0)
+ return -1;
+ }
+
+ wep->keys_set++;
+
+ return 0;
+}
+
+
+static int hostapd_parse_rates(int **rate_list, char *val)
+{
+ int *list;
+ int count;
+ char *pos, *end;
+
+ os_free(*rate_list);
+ *rate_list = NULL;
+
+ pos = val;
+ count = 0;
+ while (*pos != '\0') {
+ if (*pos == ' ')
+ count++;
+ pos++;
+ }
+
+ list = os_malloc(sizeof(int) * (count + 2));
+ if (list == NULL)
+ return -1;
+ pos = val;
+ count = 0;
+ while (*pos != '\0') {
+ end = os_strchr(pos, ' ');
+ if (end)
+ *end = '\0';
+
+ list[count++] = atoi(pos);
+ if (!end)
+ break;
+ pos = end + 1;
+ }
+ list[count] = -1;
+
+ *rate_list = list;
+ return 0;
+}
+
+
+static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
+{
+ struct hostapd_bss_config *bss;
+
+ if (*ifname == '\0')
+ return -1;
+
+ bss = os_realloc(conf->bss, (conf->num_bss + 1) *
+ sizeof(struct hostapd_bss_config));
+ if (bss == NULL) {
+ printf("Failed to allocate memory for multi-BSS entry\n");
+ return -1;
+ }
+ conf->bss = bss;
+
+ bss = &(conf->bss[conf->num_bss]);
+ os_memset(bss, 0, sizeof(*bss));
+ bss->radius = os_zalloc(sizeof(*bss->radius));
+ if (bss->radius == NULL) {
+ printf("Failed to allocate memory for multi-BSS RADIUS "
+ "data\n");
+ return -1;
+ }
+
+ conf->num_bss++;
+ conf->last_bss = bss;
+
+ hostapd_config_defaults_bss(bss);
+ os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
+ os_memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1);
+
+ return 0;
+}
+
+
+static int valid_cw(int cw)
+{
+ return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
+ cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
+}
+
+
+enum {
+ IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
+ IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
+ IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
+ IEEE80211_TX_QUEUE_DATA3 = 3, /* used for EDCA AC_BK data */
+ IEEE80211_TX_QUEUE_DATA4 = 4,
+ IEEE80211_TX_QUEUE_AFTER_BEACON = 6,
+ IEEE80211_TX_QUEUE_BEACON = 7
+};
+
+static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
+ char *val)
+{
+ int num;
+ char *pos;
+ struct hostapd_tx_queue_params *queue;
+
+ /* skip 'tx_queue_' prefix */
+ pos = name + 9;
+ if (os_strncmp(pos, "data", 4) == 0 &&
+ pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
+ num = pos[4] - '0';
+ pos += 6;
+ } else if (os_strncmp(pos, "after_beacon_", 13) == 0) {
+ num = IEEE80211_TX_QUEUE_AFTER_BEACON;
+ pos += 13;
+ } else if (os_strncmp(pos, "beacon_", 7) == 0) {
+ num = IEEE80211_TX_QUEUE_BEACON;
+ pos += 7;
+ } else {
+ printf("Unknown tx_queue name '%s'\n", pos);
+ return -1;
+ }
+
+ queue = &conf->tx_queue[num];
+
+ if (os_strcmp(pos, "aifs") == 0) {
+ queue->aifs = atoi(val);
+ if (queue->aifs < 0 || queue->aifs > 255) {
+ printf("Invalid AIFS value %d\n", queue->aifs);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "cwmin") == 0) {
+ queue->cwmin = atoi(val);
+ if (!valid_cw(queue->cwmin)) {
+ printf("Invalid cwMin value %d\n", queue->cwmin);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "cwmax") == 0) {
+ queue->cwmax = atoi(val);
+ if (!valid_cw(queue->cwmax)) {
+ printf("Invalid cwMax value %d\n", queue->cwmax);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "burst") == 0) {
+ queue->burst = hostapd_config_read_int10(val);
+ } else {
+ printf("Unknown tx_queue field '%s'\n", pos);
+ return -1;
+ }
+
+ queue->configured = 1;
+
+ return 0;
+}
+
+
+static int hostapd_config_wme_ac(struct hostapd_config *conf, char *name,
+ char *val)
+{
+ int num, v;
+ char *pos;
+ struct hostapd_wme_ac_params *ac;
+
+ /* skip 'wme_ac_' prefix */
+ pos = name + 7;
+ if (os_strncmp(pos, "be_", 3) == 0) {
+ num = 0;
+ pos += 3;
+ } else if (os_strncmp(pos, "bk_", 3) == 0) {
+ num = 1;
+ pos += 3;
+ } else if (os_strncmp(pos, "vi_", 3) == 0) {
+ num = 2;
+ pos += 3;
+ } else if (os_strncmp(pos, "vo_", 3) == 0) {
+ num = 3;
+ pos += 3;
+ } else {
+ printf("Unknown wme name '%s'\n", pos);
+ return -1;
+ }
+
+ ac = &conf->wme_ac_params[num];
+
+ if (os_strcmp(pos, "aifs") == 0) {
+ v = atoi(val);
+ if (v < 1 || v > 255) {
+ printf("Invalid AIFS value %d\n", v);
+ return -1;
+ }
+ ac->aifs = v;
+ } else if (os_strcmp(pos, "cwmin") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 12) {
+ printf("Invalid cwMin value %d\n", v);
+ return -1;
+ }
+ ac->cwmin = v;
+ } else if (os_strcmp(pos, "cwmax") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 12) {
+ printf("Invalid cwMax value %d\n", v);
+ return -1;
+ }
+ ac->cwmax = v;
+ } else if (os_strcmp(pos, "txop_limit") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 0xffff) {
+ printf("Invalid txop value %d\n", v);
+ return -1;
+ }
+ ac->txopLimit = v;
+ } else if (os_strcmp(pos, "acm") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 1) {
+ printf("Invalid acm value %d\n", v);
+ return -1;
+ }
+ ac->admission_control_mandatory = v;
+ } else {
+ printf("Unknown wme_ac_ field '%s'\n", pos);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static int add_r0kh(struct hostapd_bss_config *bss, char *value)
+{
+ struct ft_remote_r0kh *r0kh;
+ char *pos, *next;
+
+ r0kh = os_zalloc(sizeof(*r0kh));
+ if (r0kh == NULL)
+ return -1;
+
+ /* 02:01:02:03:04:05 a.example.com 000102030405060708090a0b0c0d0e0f */
+ pos = value;
+ next = os_strchr(pos, ' ');
+ if (next)
+ *next++ = '\0';
+ if (next == NULL || hwaddr_aton(pos, r0kh->addr)) {
+ printf("Invalid R0KH MAC address: '%s'\n", pos);
+ os_free(r0kh);
+ return -1;
+ }
+
+ pos = next;
+ next = os_strchr(pos, ' ');
+ if (next)
+ *next++ = '\0';
+ if (next == NULL || next - pos > FT_R0KH_ID_MAX_LEN) {
+ printf("Invalid R0KH-ID: '%s'\n", pos);
+ os_free(r0kh);
+ return -1;
+ }
+ r0kh->id_len = next - pos - 1;
+ os_memcpy(r0kh->id, pos, r0kh->id_len);
+
+ pos = next;
+ if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) {
+ printf("Invalid R0KH key: '%s'\n", pos);
+ os_free(r0kh);
+ return -1;
+ }
+
+ r0kh->next = bss->r0kh_list;
+ bss->r0kh_list = r0kh;
+
+ return 0;
+}
+
+
+static int add_r1kh(struct hostapd_bss_config *bss, char *value)
+{
+ struct ft_remote_r1kh *r1kh;
+ char *pos, *next;
+
+ r1kh = os_zalloc(sizeof(*r1kh));
+ if (r1kh == NULL)
+ return -1;
+
+ /* 02:01:02:03:04:05 02:01:02:03:04:05
+ * 000102030405060708090a0b0c0d0e0f */
+ pos = value;
+ next = os_strchr(pos, ' ');
+ if (next)
+ *next++ = '\0';
+ if (next == NULL || hwaddr_aton(pos, r1kh->addr)) {
+ printf("Invalid R1KH MAC address: '%s'\n", pos);
+ os_free(r1kh);
+ return -1;
+ }
+
+ pos = next;
+ next = os_strchr(pos, ' ');
+ if (next)
+ *next++ = '\0';
+ if (next == NULL || hwaddr_aton(pos, r1kh->id)) {
+ printf("Invalid R1KH-ID: '%s'\n", pos);
+ os_free(r1kh);
+ return -1;
+ }
+
+ pos = next;
+ if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) {
+ printf("Invalid R1KH key: '%s'\n", pos);
+ os_free(r1kh);
+ return -1;
+ }
+
+ r1kh->next = bss->r1kh_list;
+ bss->r1kh_list = r1kh;
+
+ return 0;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+struct hostapd_config * hostapd_config_read(const char *fname)
+{
+ struct hostapd_config *conf;
+ struct hostapd_bss_config *bss;
+ FILE *f;
+ char buf[256], *pos;
+ int line = 0;
+ int errors = 0;
+ int pairwise;
+ size_t i;
+
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ printf("Could not open configuration file '%s' for reading.\n",
+ fname);
+ return NULL;
+ }
+
+ conf = hostapd_config_defaults();
+ if (conf == NULL) {
+ fclose(f);
+ return NULL;
+ }
+ bss = conf->last_bss = conf->bss;
+
+ while (fgets(buf, sizeof(buf), f)) {
+ bss = conf->last_bss;
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ if (buf[0] == '\0')
+ continue;
+
+ pos = os_strchr(buf, '=');
+ if (pos == NULL) {
+ printf("Line %d: invalid line '%s'\n", line, buf);
+ errors++;
+ continue;
+ }
+ *pos = '\0';
+ pos++;
+
+ if (os_strcmp(buf, "interface") == 0) {
+ os_strlcpy(conf->bss[0].iface, pos,
+ sizeof(conf->bss[0].iface));
+ } else if (os_strcmp(buf, "bridge") == 0) {
+ os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
+ } else if (os_strcmp(buf, "driver") == 0) {
+ int i;
+ /* clear to get error below if setting is invalid */
+ conf->driver = NULL;
+ for (i = 0; hostapd_drivers[i]; i++) {
+ if (os_strcmp(pos, hostapd_drivers[i]->name) ==
+ 0) {
+ conf->driver = hostapd_drivers[i];
+ break;
+ }
+ }
+ if (conf->driver == NULL) {
+ printf("Line %d: invalid/unknown driver "
+ "'%s'\n", line, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "debug") == 0) {
+ wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' "
+ "configuration variable is not used "
+ "anymore", line);
+ } else if (os_strcmp(buf, "logger_syslog_level") == 0) {
+ bss->logger_syslog_level = atoi(pos);
+ } else if (os_strcmp(buf, "logger_stdout_level") == 0) {
+ bss->logger_stdout_level = atoi(pos);
+ } else if (os_strcmp(buf, "logger_syslog") == 0) {
+ bss->logger_syslog = atoi(pos);
+ } else if (os_strcmp(buf, "logger_stdout") == 0) {
+ bss->logger_stdout = atoi(pos);
+ } else if (os_strcmp(buf, "dump_file") == 0) {
+ bss->dump_log_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "ssid") == 0) {
+ bss->ssid.ssid_len = os_strlen(pos);
+ if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
+ bss->ssid.ssid_len < 1) {
+ printf("Line %d: invalid SSID '%s'\n", line,
+ pos);
+ errors++;
+ } else {
+ os_memcpy(bss->ssid.ssid, pos,
+ bss->ssid.ssid_len);
+ bss->ssid.ssid[bss->ssid.ssid_len] = '\0';
+ bss->ssid.ssid_set = 1;
+ }
+ } else if (os_strcmp(buf, "macaddr_acl") == 0) {
+ bss->macaddr_acl = atoi(pos);
+ if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
+ bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
+ bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+ printf("Line %d: unknown macaddr_acl %d\n",
+ line, bss->macaddr_acl);
+ }
+ } else if (os_strcmp(buf, "accept_mac_file") == 0) {
+ if (hostapd_config_read_maclist(pos, &bss->accept_mac,
+ &bss->num_accept_mac))
+ {
+ printf("Line %d: Failed to read "
+ "accept_mac_file '%s'\n",
+ line, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "deny_mac_file") == 0) {
+ if (hostapd_config_read_maclist(pos, &bss->deny_mac,
+ &bss->num_deny_mac))
+ {
+ printf("Line %d: Failed to read "
+ "deny_mac_file '%s'\n",
+ line, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
+ bss->ap_max_inactivity = atoi(pos);
+ } else if (os_strcmp(buf, "country_code") == 0) {
+ os_memcpy(conf->country, pos, 2);
+ /* FIX: make this configurable */
+ conf->country[2] = ' ';
+ } else if (os_strcmp(buf, "ieee80211d") == 0) {
+ conf->ieee80211d = atoi(pos);
+ } else if (os_strcmp(buf, "ieee80211h") == 0) {
+ conf->ieee80211h = atoi(pos);
+ } else if (os_strcmp(buf, "assoc_ap_addr") == 0) {
+ if (hwaddr_aton(pos, bss->assoc_ap_addr)) {
+ printf("Line %d: invalid MAC address '%s'\n",
+ line, pos);
+ errors++;
+ }
+ bss->assoc_ap = 1;
+ } else if (os_strcmp(buf, "ieee8021x") == 0) {
+ bss->ieee802_1x = atoi(pos);
+ } else if (os_strcmp(buf, "eapol_version") == 0) {
+ bss->eapol_version = atoi(pos);
+ if (bss->eapol_version < 1 ||
+ bss->eapol_version > 2) {
+ printf("Line %d: invalid EAPOL "
+ "version (%d): '%s'.\n",
+ line, bss->eapol_version, pos);
+ errors++;
+ } else
+ wpa_printf(MSG_DEBUG, "eapol_version=%d",
+ bss->eapol_version);
+#ifdef EAP_SERVER
+ } else if (os_strcmp(buf, "eap_authenticator") == 0) {
+ bss->eap_server = atoi(pos);
+ printf("Line %d: obsolete eap_authenticator used; "
+ "this has been renamed to eap_server\n", line);
+ } else if (os_strcmp(buf, "eap_server") == 0) {
+ bss->eap_server = atoi(pos);
+ } else if (os_strcmp(buf, "eap_user_file") == 0) {
+ if (hostapd_config_read_eap_user(pos, bss))
+ errors++;
+ } else if (os_strcmp(buf, "ca_cert") == 0) {
+ os_free(bss->ca_cert);
+ bss->ca_cert = os_strdup(pos);
+ } else if (os_strcmp(buf, "server_cert") == 0) {
+ os_free(bss->server_cert);
+ bss->server_cert = os_strdup(pos);
+ } else if (os_strcmp(buf, "private_key") == 0) {
+ os_free(bss->private_key);
+ bss->private_key = os_strdup(pos);
+ } else if (os_strcmp(buf, "private_key_passwd") == 0) {
+ os_free(bss->private_key_passwd);
+ bss->private_key_passwd = os_strdup(pos);
+ } else if (os_strcmp(buf, "check_crl") == 0) {
+ bss->check_crl = atoi(pos);
+ } else if (os_strcmp(buf, "dh_file") == 0) {
+ os_free(bss->dh_file);
+ bss->dh_file = os_strdup(pos);
+#ifdef EAP_FAST
+ } else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) {
+ os_free(bss->pac_opaque_encr_key);
+ bss->pac_opaque_encr_key = os_malloc(16);
+ if (bss->pac_opaque_encr_key == NULL) {
+ printf("Line %d: No memory for "
+ "pac_opque_encr_key\n", line);
+ errors++;
+ } else if (hexstr2bin(pos, bss->pac_opaque_encr_key,
+ 16)) {
+ printf("Line %d: Invalid pac_opque_encr_key\n",
+ line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
+ os_free(bss->eap_fast_a_id);
+ bss->eap_fast_a_id = os_strdup(pos);
+#endif /* EAP_FAST */
+#ifdef EAP_SIM
+ } else if (os_strcmp(buf, "eap_sim_db") == 0) {
+ os_free(bss->eap_sim_db);
+ bss->eap_sim_db = os_strdup(pos);
+ } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
+ bss->eap_sim_aka_result_ind = atoi(pos);
+#endif /* EAP_SIM */
+#endif /* EAP_SERVER */
+ } else if (os_strcmp(buf, "eap_message") == 0) {
+ char *term;
+ bss->eap_req_id_text = os_strdup(pos);
+ if (bss->eap_req_id_text == NULL) {
+ printf("Line %d: Failed to allocate memory "
+ "for eap_req_id_text\n", line);
+ errors++;
+ continue;
+ }
+ bss->eap_req_id_text_len =
+ os_strlen(bss->eap_req_id_text);
+ term = os_strstr(bss->eap_req_id_text, "\\0");
+ if (term) {
+ *term++ = '\0';
+ os_memmove(term, term + 1,
+ bss->eap_req_id_text_len -
+ (term - bss->eap_req_id_text) - 1);
+ bss->eap_req_id_text_len--;
+ }
+ } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
+ bss->default_wep_key_len = atoi(pos);
+ if (bss->default_wep_key_len > 13) {
+ printf("Line %d: invalid WEP key len %lu "
+ "(= %lu bits)\n", line,
+ (unsigned long)
+ bss->default_wep_key_len,
+ (unsigned long)
+ bss->default_wep_key_len * 8);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
+ bss->individual_wep_key_len = atoi(pos);
+ if (bss->individual_wep_key_len < 0 ||
+ bss->individual_wep_key_len > 13) {
+ printf("Line %d: invalid WEP key len %d "
+ "(= %d bits)\n", line,
+ bss->individual_wep_key_len,
+ bss->individual_wep_key_len * 8);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wep_rekey_period") == 0) {
+ bss->wep_rekeying_period = atoi(pos);
+ if (bss->wep_rekeying_period < 0) {
+ printf("Line %d: invalid period %d\n",
+ line, bss->wep_rekeying_period);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "eap_reauth_period") == 0) {
+ bss->eap_reauth_period = atoi(pos);
+ if (bss->eap_reauth_period < 0) {
+ printf("Line %d: invalid period %d\n",
+ line, bss->eap_reauth_period);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
+ bss->eapol_key_index_workaround = atoi(pos);
+#ifdef CONFIG_IAPP
+ } else if (os_strcmp(buf, "iapp_interface") == 0) {
+ bss->ieee802_11f = 1;
+ os_strlcpy(bss->iapp_iface, pos,
+ sizeof(bss->iapp_iface));
+#endif /* CONFIG_IAPP */
+ } else if (os_strcmp(buf, "own_ip_addr") == 0) {
+ if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
+ printf("Line %d: invalid IP address '%s'\n",
+ line, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "nas_identifier") == 0) {
+ bss->nas_identifier = os_strdup(pos);
+ } else if (os_strcmp(buf, "auth_server_addr") == 0) {
+ if (hostapd_config_read_radius_addr(
+ &bss->radius->auth_servers,
+ &bss->radius->num_auth_servers, pos, 1812,
+ &bss->radius->auth_server)) {
+ printf("Line %d: invalid IP address '%s'\n",
+ line, pos);
+ errors++;
+ }
+ } else if (bss->radius->auth_server &&
+ os_strcmp(buf, "auth_server_port") == 0) {
+ bss->radius->auth_server->port = atoi(pos);
+ } else if (bss->radius->auth_server &&
+ os_strcmp(buf, "auth_server_shared_secret") == 0) {
+ int len = os_strlen(pos);
+ if (len == 0) {
+ /* RFC 2865, Ch. 3 */
+ printf("Line %d: empty shared secret is not "
+ "allowed.\n", line);
+ errors++;
+ }
+ bss->radius->auth_server->shared_secret =
+ (u8 *) os_strdup(pos);
+ bss->radius->auth_server->shared_secret_len = len;
+ } else if (os_strcmp(buf, "acct_server_addr") == 0) {
+ if (hostapd_config_read_radius_addr(
+ &bss->radius->acct_servers,
+ &bss->radius->num_acct_servers, pos, 1813,
+ &bss->radius->acct_server)) {
+ printf("Line %d: invalid IP address '%s'\n",
+ line, pos);
+ errors++;
+ }
+ } else if (bss->radius->acct_server &&
+ os_strcmp(buf, "acct_server_port") == 0) {
+ bss->radius->acct_server->port = atoi(pos);
+ } else if (bss->radius->acct_server &&
+ os_strcmp(buf, "acct_server_shared_secret") == 0) {
+ int len = os_strlen(pos);
+ if (len == 0) {
+ /* RFC 2865, Ch. 3 */
+ printf("Line %d: empty shared secret is not "
+ "allowed.\n", line);
+ errors++;
+ }
+ bss->radius->acct_server->shared_secret =
+ (u8 *) os_strdup(pos);
+ bss->radius->acct_server->shared_secret_len = len;
+ } else if (os_strcmp(buf, "radius_retry_primary_interval") ==
+ 0) {
+ bss->radius->retry_primary_interval = atoi(pos);
+ } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
+ {
+ bss->radius->acct_interim_interval = atoi(pos);
+ } else if (os_strcmp(buf, "auth_algs") == 0) {
+ bss->auth_algs = atoi(pos);
+ if (bss->auth_algs == 0) {
+ printf("Line %d: no authentication algorithms "
+ "allowed\n",
+ line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "max_num_sta") == 0) {
+ bss->max_num_sta = atoi(pos);
+ if (bss->max_num_sta < 0 ||
+ bss->max_num_sta > MAX_STA_COUNT) {
+ printf("Line %d: Invalid max_num_sta=%d; "
+ "allowed range 0..%d\n", line,
+ bss->max_num_sta, MAX_STA_COUNT);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wpa") == 0) {
+ bss->wpa = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
+ bss->wpa_group_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
+ bss->wpa_strict_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
+ bss->wpa_gmk_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_passphrase") == 0) {
+ int len = os_strlen(pos);
+ if (len < 8 || len > 63) {
+ printf("Line %d: invalid WPA passphrase length"
+ " %d (expected 8..63)\n", line, len);
+ errors++;
+ } else {
+ os_free(bss->ssid.wpa_passphrase);
+ bss->ssid.wpa_passphrase = os_strdup(pos);
+ }
+ } else if (os_strcmp(buf, "wpa_psk") == 0) {
+ os_free(bss->ssid.wpa_psk);
+ bss->ssid.wpa_psk =
+ os_zalloc(sizeof(struct hostapd_wpa_psk));
+ if (bss->ssid.wpa_psk == NULL)
+ errors++;
+ else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk,
+ PMK_LEN) ||
+ pos[PMK_LEN * 2] != '\0') {
+ printf("Line %d: Invalid PSK '%s'.\n", line,
+ pos);
+ errors++;
+ } else {
+ bss->ssid.wpa_psk->group = 1;
+ }
+ } else if (os_strcmp(buf, "wpa_psk_file") == 0) {
+ os_free(bss->ssid.wpa_psk_file);
+ bss->ssid.wpa_psk_file = os_strdup(pos);
+ if (!bss->ssid.wpa_psk_file) {
+ printf("Line %d: allocation failed\n", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
+ bss->wpa_key_mgmt =
+ hostapd_config_parse_key_mgmt(line, pos);
+ if (bss->wpa_key_mgmt == -1)
+ errors++;
+ } else if (os_strcmp(buf, "wpa_pairwise") == 0) {
+ bss->wpa_pairwise =
+ hostapd_config_parse_cipher(line, pos);
+ if (bss->wpa_pairwise == -1 ||
+ bss->wpa_pairwise == 0)
+ errors++;
+ else if (bss->wpa_pairwise &
+ (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
+ WPA_CIPHER_WEP104)) {
+ printf("Line %d: unsupported pairwise "
+ "cipher suite '%s'\n",
+ bss->wpa_pairwise, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "rsn_pairwise") == 0) {
+ bss->rsn_pairwise =
+ hostapd_config_parse_cipher(line, pos);
+ if (bss->rsn_pairwise == -1 ||
+ bss->rsn_pairwise == 0)
+ errors++;
+ else if (bss->rsn_pairwise &
+ (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
+ WPA_CIPHER_WEP104)) {
+ printf("Line %d: unsupported pairwise "
+ "cipher suite '%s'\n",
+ bss->rsn_pairwise, pos);
+ errors++;
+ }
+#ifdef CONFIG_RSN_PREAUTH
+ } else if (os_strcmp(buf, "rsn_preauth") == 0) {
+ bss->rsn_preauth = atoi(pos);
+ } else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) {
+ bss->rsn_preauth_interfaces = os_strdup(pos);
+#endif /* CONFIG_RSN_PREAUTH */
+#ifdef CONFIG_PEERKEY
+ } else if (os_strcmp(buf, "peerkey") == 0) {
+ bss->peerkey = atoi(pos);
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211R
+ } else if (os_strcmp(buf, "mobility_domain") == 0) {
+ if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
+ hexstr2bin(pos, bss->mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+ "mobility_domain '%s'", line, pos);
+ errors++;
+ continue;
+ }
+ } else if (os_strcmp(buf, "r1_key_holder") == 0) {
+ if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
+ hexstr2bin(pos, bss->r1_key_holder,
+ FT_R1KH_ID_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+ "r1_key_holder '%s'", line, pos);
+ errors++;
+ continue;
+ }
+ } else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
+ bss->r0_key_lifetime = atoi(pos);
+ } else if (os_strcmp(buf, "reassociation_deadline") == 0) {
+ bss->reassociation_deadline = atoi(pos);
+ } else if (os_strcmp(buf, "r0kh") == 0) {
+ if (add_r0kh(bss, pos) < 0) {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+ "r0kh '%s'", line, pos);
+ errors++;
+ continue;
+ }
+ } else if (os_strcmp(buf, "r1kh") == 0) {
+ if (add_r1kh(bss, pos) < 0) {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+ "r1kh '%s'", line, pos);
+ errors++;
+ continue;
+ }
+ } else if (os_strcmp(buf, "pmk_r1_push") == 0) {
+ bss->pmk_r1_push = atoi(pos);
+#endif /* CONFIG_IEEE80211R */
+ } else if (os_strcmp(buf, "ctrl_interface") == 0) {
+ os_free(bss->ctrl_interface);
+ bss->ctrl_interface = os_strdup(pos);
+ } else if (os_strcmp(buf, "ctrl_interface_group") == 0) {
+#ifndef CONFIG_NATIVE_WINDOWS
+ struct group *grp;
+ char *endp;
+ const char *group = pos;
+
+ grp = getgrnam(group);
+ if (grp) {
+ bss->ctrl_interface_gid = grp->gr_gid;
+ bss->ctrl_interface_gid_set = 1;
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+ " (from group name '%s')",
+ bss->ctrl_interface_gid, group);
+ continue;
+ }
+
+ /* Group name not found - try to parse this as gid */
+ bss->ctrl_interface_gid = strtol(group, &endp, 10);
+ if (*group == '\0' || *endp != '\0') {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
+ "'%s'", line, group);
+ errors++;
+ continue;
+ }
+ bss->ctrl_interface_gid_set = 1;
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+ bss->ctrl_interface_gid);
+#endif /* CONFIG_NATIVE_WINDOWS */
+#ifdef RADIUS_SERVER
+ } else if (os_strcmp(buf, "radius_server_clients") == 0) {
+ os_free(bss->radius_server_clients);
+ bss->radius_server_clients = os_strdup(pos);
+ } else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
+ bss->radius_server_auth_port = atoi(pos);
+ } else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
+ bss->radius_server_ipv6 = atoi(pos);
+#endif /* RADIUS_SERVER */
+ } else if (os_strcmp(buf, "test_socket") == 0) {
+ os_free(bss->test_socket);
+ bss->test_socket = os_strdup(pos);
+ } else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
+ bss->use_pae_group_addr = atoi(pos);
+ } else if (os_strcmp(buf, "hw_mode") == 0) {
+ if (os_strcmp(pos, "a") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
+ else if (os_strcmp(pos, "b") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
+ else if (os_strcmp(pos, "g") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+ else {
+ printf("Line %d: unknown hw_mode '%s'\n",
+ line, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "channel") == 0) {
+ conf->channel = atoi(pos);
+ } else if (os_strcmp(buf, "beacon_int") == 0) {
+ int val = atoi(pos);
+ /* MIB defines range as 1..65535, but very small values
+ * cause problems with the current implementation.
+ * Since it is unlikely that this small numbers are
+ * useful in real life scenarios, do not allow beacon
+ * period to be set below 15 TU. */
+ if (val < 15 || val > 65535) {
+ printf("Line %d: invalid beacon_int %d "
+ "(expected 15..65535)\n",
+ line, val);
+ errors++;
+ } else
+ conf->beacon_int = val;
+ } else if (os_strcmp(buf, "dtim_period") == 0) {
+ bss->dtim_period = atoi(pos);
+ if (bss->dtim_period < 1 || bss->dtim_period > 255) {
+ printf("Line %d: invalid dtim_period %d\n",
+ line, bss->dtim_period);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "rts_threshold") == 0) {
+ conf->rts_threshold = atoi(pos);
+ if (conf->rts_threshold < 0 ||
+ conf->rts_threshold > 2347) {
+ printf("Line %d: invalid rts_threshold %d\n",
+ line, conf->rts_threshold);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "fragm_threshold") == 0) {
+ conf->fragm_threshold = atoi(pos);
+ if (conf->fragm_threshold < 256 ||
+ conf->fragm_threshold > 2346) {
+ printf("Line %d: invalid fragm_threshold %d\n",
+ line, conf->fragm_threshold);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "send_probe_response") == 0) {
+ int val = atoi(pos);
+ if (val != 0 && val != 1) {
+ printf("Line %d: invalid send_probe_response "
+ "%d (expected 0 or 1)\n", line, val);
+ } else
+ conf->send_probe_response = val;
+ } else if (os_strcmp(buf, "supported_rates") == 0) {
+ if (hostapd_parse_rates(&conf->supported_rates, pos)) {
+ printf("Line %d: invalid rate list\n", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "basic_rates") == 0) {
+ if (hostapd_parse_rates(&conf->basic_rates, pos)) {
+ printf("Line %d: invalid rate list\n", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
+ bss->ignore_broadcast_ssid = atoi(pos);
+ } else if (os_strcmp(buf, "bridge_packets") == 0) {
+ conf->bridge_packets = atoi(pos);
+ } else if (os_strcmp(buf, "wep_default_key") == 0) {
+ bss->ssid.wep.idx = atoi(pos);
+ if (bss->ssid.wep.idx > 3) {
+ printf("Invalid wep_default_key index %d\n",
+ bss->ssid.wep.idx);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wep_key0") == 0 ||
+ os_strcmp(buf, "wep_key1") == 0 ||
+ os_strcmp(buf, "wep_key2") == 0 ||
+ os_strcmp(buf, "wep_key3") == 0) {
+ if (hostapd_config_read_wep(&bss->ssid.wep,
+ buf[7] - '0', pos)) {
+ printf("Line %d: invalid WEP key '%s'\n",
+ line, buf);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "dynamic_vlan") == 0) {
+ bss->ssid.dynamic_vlan = atoi(pos);
+ } else if (os_strcmp(buf, "vlan_file") == 0) {
+ if (hostapd_config_read_vlan_file(bss, pos)) {
+ printf("Line %d: failed to read VLAN file "
+ "'%s'\n", line, pos);
+ errors++;
+ }
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ } else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
+ bss->ssid.vlan_tagged_interface = os_strdup(pos);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+ } else if (os_strcmp(buf, "passive_scan_interval") == 0) {
+ conf->passive_scan_interval = atoi(pos);
+ } else if (os_strcmp(buf, "passive_scan_listen") == 0) {
+ conf->passive_scan_listen = atoi(pos);
+ } else if (os_strcmp(buf, "passive_scan_mode") == 0) {
+ conf->passive_scan_mode = atoi(pos);
+ } else if (os_strcmp(buf, "ap_table_max_size") == 0) {
+ conf->ap_table_max_size = atoi(pos);
+ } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
+ conf->ap_table_expiration_time = atoi(pos);
+ } else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
+ if (hostapd_config_tx_queue(conf, buf, pos)) {
+ printf("Line %d: invalid TX queue item\n",
+ line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wme_enabled") == 0) {
+ bss->wme_enabled = atoi(pos);
+ } else if (os_strncmp(buf, "wme_ac_", 7) == 0) {
+ if (hostapd_config_wme_ac(conf, buf, pos)) {
+ printf("Line %d: invalid wme ac item\n",
+ line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "bss") == 0) {
+ if (hostapd_config_bss(conf, pos)) {
+ printf("Line %d: invalid bss item\n", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "bssid") == 0) {
+ if (bss == conf->bss &&
+ (!conf->driver || !conf->driver->init_bssid)) {
+ printf("Line %d: bssid item not allowed "
+ "for the default interface and this "
+ "driver\n", line);
+ errors++;
+ } else if (hwaddr_aton(pos, bss->bssid)) {
+ printf("Line %d: invalid bssid item\n", line);
+ errors++;
+ }
+#ifdef CONFIG_IEEE80211W
+ } else if (os_strcmp(buf, "ieee80211w") == 0) {
+ bss->ieee80211w = atoi(pos);
+#endif /* CONFIG_IEEE80211W */
+ } else {
+ printf("Line %d: unknown configuration item '%s'\n",
+ line, buf);
+ errors++;
+ }
+ }
+
+ fclose(f);
+
+ if (bss->individual_wep_key_len == 0) {
+ /* individual keys are not use; can use key idx0 for broadcast
+ * keys */
+ bss->broadcast_key_idx_min = 0;
+ }
+
+ /* Select group cipher based on the enabled pairwise cipher suites */
+ pairwise = 0;
+ if (bss->wpa & 1)
+ pairwise |= bss->wpa_pairwise;
+ if (bss->wpa & 2) {
+ if (bss->rsn_pairwise == 0)
+ bss->rsn_pairwise = bss->wpa_pairwise;
+ pairwise |= bss->rsn_pairwise;
+ }
+ if (pairwise & WPA_CIPHER_TKIP)
+ bss->wpa_group = WPA_CIPHER_TKIP;
+ else
+ bss->wpa_group = WPA_CIPHER_CCMP;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ bss = &conf->bss[i];
+
+ bss->radius->auth_server = bss->radius->auth_servers;
+ bss->radius->acct_server = bss->radius->acct_servers;
+
+ if (bss->wpa && bss->ieee802_1x) {
+ bss->ssid.security_policy = SECURITY_WPA;
+ } else if (bss->wpa) {
+ bss->ssid.security_policy = SECURITY_WPA_PSK;
+ } else if (bss->ieee802_1x) {
+ bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+ bss->ssid.wep.default_len = bss->default_wep_key_len;
+ } else if (bss->ssid.wep.keys_set)
+ bss->ssid.security_policy = SECURITY_STATIC_WEP;
+ else
+ bss->ssid.security_policy = SECURITY_PLAINTEXT;
+ }
+
+ if (hostapd_config_check(conf))
+ errors++;
+
+ if (errors) {
+ printf("%d errors found in configuration file '%s'\n",
+ errors, fname);
+ hostapd_config_free(conf);
+ conf = NULL;
+ }
+
+ return conf;
+}
+
+
+int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b)
+{
+ int i;
+
+ if (a->idx != b->idx || a->default_len != b->default_len)
+ return 1;
+ for (i = 0; i < NUM_WEP_KEYS; i++)
+ if (a->len[i] != b->len[i] ||
+ os_memcmp(a->key[i], b->key[i], a->len[i]) != 0)
+ return 1;
+ return 0;
+}
+
+
+static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
+ int num_servers)
+{
+ int i;
+
+ for (i = 0; i < num_servers; i++) {
+ os_free(servers[i].shared_secret);
+ }
+ os_free(servers);
+}
+
+
+static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
+{
+ os_free(user->identity);
+ os_free(user->password);
+ os_free(user);
+}
+
+
+static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
+{
+ int i;
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ os_free(keys->key[i]);
+ keys->key[i] = NULL;
+ }
+}
+
+
+static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
+{
+ struct hostapd_wpa_psk *psk, *prev;
+ struct hostapd_eap_user *user, *prev_user;
+
+ if (conf == NULL)
+ return;
+
+ psk = conf->ssid.wpa_psk;
+ while (psk) {
+ prev = psk;
+ psk = psk->next;
+ os_free(prev);
+ }
+
+ os_free(conf->ssid.wpa_passphrase);
+ os_free(conf->ssid.wpa_psk_file);
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ os_free(conf->ssid.vlan_tagged_interface);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+ user = conf->eap_user;
+ while (user) {
+ prev_user = user;
+ user = user->next;
+ hostapd_config_free_eap_user(prev_user);
+ }
+
+ os_free(conf->dump_log_name);
+ os_free(conf->eap_req_id_text);
+ os_free(conf->accept_mac);
+ os_free(conf->deny_mac);
+ os_free(conf->nas_identifier);
+ hostapd_config_free_radius(conf->radius->auth_servers,
+ conf->radius->num_auth_servers);
+ hostapd_config_free_radius(conf->radius->acct_servers,
+ conf->radius->num_acct_servers);
+ os_free(conf->rsn_preauth_interfaces);
+ os_free(conf->ctrl_interface);
+ os_free(conf->ca_cert);
+ os_free(conf->server_cert);
+ os_free(conf->private_key);
+ os_free(conf->private_key_passwd);
+ os_free(conf->dh_file);
+ os_free(conf->pac_opaque_encr_key);
+ os_free(conf->eap_fast_a_id);
+ os_free(conf->eap_sim_db);
+ os_free(conf->radius_server_clients);
+ os_free(conf->test_socket);
+ os_free(conf->radius);
+ hostapd_config_free_vlan(conf);
+ if (conf->ssid.dyn_vlan_keys) {
+ struct hostapd_ssid *ssid = &conf->ssid;
+ size_t i;
+ for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
+ if (ssid->dyn_vlan_keys[i] == NULL)
+ continue;
+ hostapd_config_free_wep(ssid->dyn_vlan_keys[i]);
+ os_free(ssid->dyn_vlan_keys[i]);
+ }
+ os_free(ssid->dyn_vlan_keys);
+ ssid->dyn_vlan_keys = NULL;
+ }
+
+#ifdef CONFIG_IEEE80211R
+ {
+ struct ft_remote_r0kh *r0kh, *r0kh_prev;
+ struct ft_remote_r1kh *r1kh, *r1kh_prev;
+
+ r0kh = conf->r0kh_list;
+ conf->r0kh_list = NULL;
+ while (r0kh) {
+ r0kh_prev = r0kh;
+ r0kh = r0kh->next;
+ os_free(r0kh_prev);
+ }
+
+ r1kh = conf->r1kh_list;
+ conf->r1kh_list = NULL;
+ while (r1kh) {
+ r1kh_prev = r1kh;
+ r1kh = r1kh->next;
+ os_free(r1kh_prev);
+ }
+ }
+#endif /* CONFIG_IEEE80211R */
+}
+
+
+void hostapd_config_free(struct hostapd_config *conf)
+{
+ size_t i;
+
+ if (conf == NULL)
+ return;
+
+ for (i = 0; i < conf->num_bss; i++)
+ hostapd_config_free_bss(&conf->bss[i]);
+ os_free(conf->bss);
+
+ os_free(conf);
+}
+
+
+/* Perform a binary search for given MAC address from a pre-sorted list.
+ * Returns 1 if address is in the list or 0 if not. */
+int hostapd_maclist_found(macaddr *list, int num_entries, const u8 *addr)
+{
+ int start, end, middle, res;
+
+ start = 0;
+ end = num_entries - 1;
+
+ while (start <= end) {
+ middle = (start + end) / 2;
+ res = os_memcmp(list[middle], addr, ETH_ALEN);
+ if (res == 0)
+ return 1;
+ if (res < 0)
+ start = middle + 1;
+ else
+ end = middle - 1;
+ }
+
+ return 0;
+}
+
+
+int hostapd_rate_found(int *list, int rate)
+{
+ int i;
+
+ if (list == NULL)
+ return 0;
+
+ for (i = 0; list[i] >= 0; i++)
+ if (list[i] == rate)
+ return 1;
+
+ return 0;
+}
+
+
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+{
+ struct hostapd_vlan *v = vlan;
+ while (v) {
+ if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
+ return v->ifname;
+ v = v->next;
+ }
+ return NULL;
+}
+
+
+const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
+ const u8 *addr, const u8 *prev_psk)
+{
+ struct hostapd_wpa_psk *psk;
+ int next_ok = prev_psk == NULL;
+
+ for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
+ if (next_ok &&
+ (psk->group || os_memcmp(psk->addr, addr, ETH_ALEN) == 0))
+ return psk->psk;
+
+ if (psk->psk == prev_psk)
+ next_ok = 1;
+ }
+
+ return NULL;
+}
+
+
+const struct hostapd_eap_user *
+hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
+ size_t identity_len, int phase2)
+{
+ struct hostapd_eap_user *user = conf->eap_user;
+
+ while (user) {
+ if (!phase2 && user->identity == NULL) {
+ /* Wildcard match */
+ break;
+ }
+
+ if (user->phase2 == !!phase2 && user->wildcard_prefix &&
+ identity_len >= user->identity_len &&
+ os_memcmp(user->identity, identity, user->identity_len) ==
+ 0) {
+ /* Wildcard prefix match */
+ break;
+ }
+
+ if (user->phase2 == !!phase2 &&
+ user->identity_len == identity_len &&
+ os_memcmp(user->identity, identity, identity_len) == 0)
+ break;
+ user = user->next;
+ }
+
+ return user;
+}
diff --git a/hostapd/config.h b/hostapd/config.h
new file mode 100644
index 0000000..8f7777e
--- /dev/null
+++ b/hostapd/config.h
@@ -0,0 +1,358 @@
+/*
+ * hostapd / Configuration file
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include "defs.h"
+#include "ip_addr.h"
+#include "wpa_common.h"
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+
+typedef u8 macaddr[ETH_ALEN];
+
+struct hostapd_radius_servers;
+struct ft_remote_r0kh;
+struct ft_remote_r1kh;
+
+#define HOSTAPD_MAX_SSID_LEN 32
+
+#define NUM_WEP_KEYS 4
+struct hostapd_wep_keys {
+ u8 idx;
+ u8 *key[NUM_WEP_KEYS];
+ size_t len[NUM_WEP_KEYS];
+ int keys_set;
+ size_t default_len; /* key length used for dynamic key generation */
+};
+
+typedef enum hostap_security_policy {
+ SECURITY_PLAINTEXT = 0,
+ SECURITY_STATIC_WEP = 1,
+ SECURITY_IEEE_802_1X = 2,
+ SECURITY_WPA_PSK = 3,
+ SECURITY_WPA = 4
+} secpolicy;
+
+struct hostapd_ssid {
+ char ssid[HOSTAPD_MAX_SSID_LEN + 1];
+ size_t ssid_len;
+ int ssid_set;
+
+ char vlan[IFNAMSIZ + 1];
+ secpolicy security_policy;
+
+ struct hostapd_wpa_psk *wpa_psk;
+ char *wpa_passphrase;
+ char *wpa_psk_file;
+
+ struct hostapd_wep_keys wep;
+
+#define DYNAMIC_VLAN_DISABLED 0
+#define DYNAMIC_VLAN_OPTIONAL 1
+#define DYNAMIC_VLAN_REQUIRED 2
+ int dynamic_vlan;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ char *vlan_tagged_interface;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+ struct hostapd_wep_keys **dyn_vlan_keys;
+ size_t max_dyn_vlan_keys;
+};
+
+
+#define VLAN_ID_WILDCARD -1
+
+struct hostapd_vlan {
+ struct hostapd_vlan *next;
+ int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
+ char ifname[IFNAMSIZ + 1];
+ int dynamic_vlan;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+
+#define DVLAN_CLEAN_BR 0x1
+#define DVLAN_CLEAN_VLAN 0x2
+#define DVLAN_CLEAN_VLAN_PORT 0x4
+#define DVLAN_CLEAN_WLAN_PORT 0x8
+ int clean;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+};
+
+#define PMK_LEN 32
+struct hostapd_wpa_psk {
+ struct hostapd_wpa_psk *next;
+ int group;
+ u8 psk[PMK_LEN];
+ u8 addr[ETH_ALEN];
+};
+
+#define EAP_USER_MAX_METHODS 8
+struct hostapd_eap_user {
+ struct hostapd_eap_user *next;
+ u8 *identity;
+ size_t identity_len;
+ struct {
+ int vendor;
+ u32 method;
+ } methods[EAP_USER_MAX_METHODS];
+ u8 *password;
+ size_t password_len;
+ int phase2;
+ int force_version;
+ unsigned int wildcard_prefix:1;
+ unsigned int password_hash:1; /* whether password is hashed with
+ * nt_password_hash() */
+ int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
+};
+
+
+#define NUM_TX_QUEUES 8
+
+struct hostapd_tx_queue_params {
+ int aifs;
+ int cwmin;
+ int cwmax;
+ int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
+ int configured;
+};
+
+struct hostapd_wme_ac_params {
+ int cwmin;
+ int cwmax;
+ int aifs;
+ int txopLimit; /* in units of 32us */
+ int admission_control_mandatory;
+};
+
+
+/**
+ * struct hostapd_bss_config - Per-BSS configuration
+ */
+struct hostapd_bss_config {
+ char iface[IFNAMSIZ + 1];
+ char bridge[IFNAMSIZ + 1];
+
+ enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
+
+ unsigned int logger_syslog; /* module bitfield */
+ unsigned int logger_stdout; /* module bitfield */
+
+ char *dump_log_name; /* file name for state dump (SIGUSR1) */
+
+ int max_num_sta; /* maximum number of STAs in station table */
+
+ int dtim_period;
+
+ int ieee802_1x; /* use IEEE 802.1X */
+ int eapol_version;
+ int eap_server; /* Use internal EAP server instead of external
+ * RADIUS server */
+ struct hostapd_eap_user *eap_user;
+ char *eap_sim_db;
+ struct hostapd_ip_addr own_ip_addr;
+ char *nas_identifier;
+ struct hostapd_radius_servers *radius;
+
+ struct hostapd_ssid ssid;
+
+ char *eap_req_id_text; /* optional displayable message sent with
+ * EAP Request-Identity */
+ size_t eap_req_id_text_len;
+ int eapol_key_index_workaround;
+
+ size_t default_wep_key_len;
+ int individual_wep_key_len;
+ int wep_rekeying_period;
+ int broadcast_key_idx_min, broadcast_key_idx_max;
+ int eap_reauth_period;
+
+ int ieee802_11f; /* use IEEE 802.11f (IAPP) */
+ char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
+ * frames */
+
+ u8 assoc_ap_addr[ETH_ALEN];
+ int assoc_ap; /* whether assoc_ap_addr is set */
+
+ enum {
+ ACCEPT_UNLESS_DENIED = 0,
+ DENY_UNLESS_ACCEPTED = 1,
+ USE_EXTERNAL_RADIUS_AUTH = 2
+ } macaddr_acl;
+ macaddr *accept_mac;
+ int num_accept_mac;
+ macaddr *deny_mac;
+ int num_deny_mac;
+
+ int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
+ * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
+
+ int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
+ int wpa_key_mgmt;
+#ifdef CONFIG_IEEE80211W
+ enum {
+ NO_IEEE80211W = 0,
+ IEEE80211W_OPTIONAL = 1,
+ IEEE80211W_REQUIRED = 2
+ } ieee80211w;
+#endif /* CONFIG_IEEE80211W */
+ int wpa_pairwise;
+ int wpa_group;
+ int wpa_group_rekey;
+ int wpa_strict_rekey;
+ int wpa_gmk_rekey;
+ int rsn_pairwise;
+ int rsn_preauth;
+ char *rsn_preauth_interfaces;
+ int peerkey;
+
+#ifdef CONFIG_IEEE80211R
+ /* IEEE 802.11r - Fast BSS Transition */
+ u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+ u8 r1_key_holder[FT_R1KH_ID_LEN];
+ u32 r0_key_lifetime;
+ u32 reassociation_deadline;
+ struct ft_remote_r0kh *r0kh_list;
+ struct ft_remote_r1kh *r1kh_list;
+ int pmk_r1_push;
+#endif /* CONFIG_IEEE80211R */
+
+ char *ctrl_interface; /* directory for UNIX domain sockets */
+ gid_t ctrl_interface_gid;
+ int ctrl_interface_gid_set;
+
+ char *ca_cert;
+ char *server_cert;
+ char *private_key;
+ char *private_key_passwd;
+ int check_crl;
+ char *dh_file;
+ u8 *pac_opaque_encr_key;
+ char *eap_fast_a_id;
+ int eap_sim_aka_result_ind;
+
+ char *radius_server_clients;
+ int radius_server_auth_port;
+ int radius_server_ipv6;
+
+ char *test_socket; /* UNIX domain socket path for driver_test */
+
+ int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
+ * address instead of individual address
+ * (for driver_wired.c).
+ */
+
+ int ap_max_inactivity;
+ int ignore_broadcast_ssid;
+
+ int wme_enabled;
+
+ struct hostapd_vlan *vlan, *vlan_tail;
+
+ macaddr bssid;
+};
+
+
+typedef enum {
+ HOSTAPD_MODE_IEEE80211B,
+ HOSTAPD_MODE_IEEE80211G,
+ HOSTAPD_MODE_IEEE80211A,
+ NUM_HOSTAPD_MODES
+} hostapd_hw_mode;
+
+
+/**
+ * struct hostapd_config - Per-radio interface configuration
+ */
+struct hostapd_config {
+ struct hostapd_bss_config *bss, *last_bss;
+ struct hostapd_radius_servers *radius;
+ size_t num_bss;
+
+ u16 beacon_int;
+ int rts_threshold;
+ int fragm_threshold;
+ u8 send_probe_response;
+ u8 channel;
+ hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
+ enum {
+ LONG_PREAMBLE = 0,
+ SHORT_PREAMBLE = 1
+ } preamble;
+ enum {
+ CTS_PROTECTION_AUTOMATIC = 0,
+ CTS_PROTECTION_FORCE_ENABLED = 1,
+ CTS_PROTECTION_FORCE_DISABLED = 2,
+ CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3,
+ } cts_protection_type;
+
+ int *supported_rates;
+ int *basic_rates;
+
+ const struct wpa_driver_ops *driver;
+
+ int passive_scan_interval; /* seconds, 0 = disabled */
+ int passive_scan_listen; /* usec */
+ int passive_scan_mode;
+ int ap_table_max_size;
+ int ap_table_expiration_time;
+
+ char country[3]; /* first two octets: country code as described in
+ * ISO/IEC 3166-1. Third octet:
+ * ' ' (ascii 32): all environments
+ * 'O': Outdoor environemnt only
+ * 'I': Indoor environment only
+ */
+
+ int ieee80211d;
+ unsigned int ieee80211h; /* Enable/Disable 80211h */
+
+ struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
+
+ /*
+ * WME AC parameters, in same order as 802.1D, i.e.
+ * 0 = BE (best effort)
+ * 1 = BK (background)
+ * 2 = VI (video)
+ * 3 = VO (voice)
+ */
+ struct hostapd_wme_ac_params wme_ac_params[4];
+
+ enum {
+ INTERNAL_BRIDGE_DO_NOT_CONTROL = -1,
+ INTERNAL_BRIDGE_DISABLED = 0,
+ INTERNAL_BRIDGE_ENABLED = 1
+ } bridge_packets;
+};
+
+
+int hostapd_mac_comp(const void *a, const void *b);
+int hostapd_mac_comp_empty(const void *a);
+struct hostapd_config * hostapd_config_read(const char *fname);
+void hostapd_config_free(struct hostapd_config *conf);
+int hostapd_maclist_found(macaddr *list, int num_entries, const u8 *addr);
+int hostapd_rate_found(int *list, int rate);
+int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
+ struct hostapd_wep_keys *b);
+const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
+ const u8 *addr, const u8 *prev_psk);
+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
+ int vlan_id);
+const struct hostapd_eap_user *
+hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
+ size_t identity_len, int phase2);
+
+#endif /* CONFIG_H */
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
new file mode 100644
index 0000000..781c9f3
--- /dev/null
+++ b/hostapd/ctrl_iface.c
@@ -0,0 +1,500 @@
+/*
+ * hostapd / UNIX domain socket -based control interface
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+#include <sys/un.h>
+#include <sys/stat.h>
+
+#include "hostapd.h"
+#include "eloop.h"
+#include "config.h"
+#include "ieee802_1x.h"
+#include "wpa.h"
+#include "radius/radius_client.h"
+#include "ieee802_11.h"
+#include "ctrl_iface.h"
+#include "sta_info.h"
+#include "accounting.h"
+
+
+struct wpa_ctrl_dst {
+ struct wpa_ctrl_dst *next;
+ struct sockaddr_un addr;
+ socklen_t addrlen;
+ int debug_level;
+ int errors;
+};
+
+
+static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
+ struct sockaddr_un *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst;
+
+ dst = os_zalloc(sizeof(*dst));
+ if (dst == NULL)
+ return -1;
+ os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
+ dst->addrlen = fromlen;
+ dst->debug_level = MSG_INFO;
+ dst->next = hapd->ctrl_dst;
+ hapd->ctrl_dst = dst;
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
+ (u8 *) from->sun_path, fromlen);
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
+ struct sockaddr_un *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst, *prev = NULL;
+
+ dst = hapd->ctrl_dst;
+ while (dst) {
+ if (fromlen == dst->addrlen &&
+ os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
+ 0) {
+ if (prev == NULL)
+ hapd->ctrl_dst = dst->next;
+ else
+ prev->next = dst->next;
+ os_free(dst);
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+ (u8 *) from->sun_path, fromlen);
+ return 0;
+ }
+ prev = dst;
+ dst = dst->next;
+ }
+ return -1;
+}
+
+
+static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
+ struct sockaddr_un *from,
+ socklen_t fromlen,
+ char *level)
+{
+ struct wpa_ctrl_dst *dst;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
+
+ dst = hapd->ctrl_dst;
+ while (dst) {
+ if (fromlen == dst->addrlen &&
+ os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
+ 0) {
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
+ "level", (u8 *) from->sun_path, fromlen);
+ dst->debug_level = atoi(level);
+ return 0;
+ }
+ dst = dst->next;
+ }
+
+ return -1;
+}
+
+
+static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ char *buf, size_t buflen)
+{
+ int len, res, ret;
+
+ if (sta == NULL) {
+ ret = os_snprintf(buf, buflen, "FAIL\n");
+ if (ret < 0 || (size_t) ret >= buflen)
+ return 0;
+ return ret;
+ }
+
+ len = 0;
+ ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
+ MAC2STR(sta->addr));
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
+ if (res >= 0)
+ len += res;
+ res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
+ if (res >= 0)
+ len += res;
+ res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
+ if (res >= 0)
+ len += res;
+
+ return len;
+}
+
+
+static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+ return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
+}
+
+
+static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
+ const char *txtaddr,
+ char *buf, size_t buflen)
+{
+ u8 addr[ETH_ALEN];
+ int ret;
+
+ if (hwaddr_aton(txtaddr, addr)) {
+ ret = os_snprintf(buf, buflen, "FAIL\n");
+ if (ret < 0 || (size_t) ret >= buflen)
+ return 0;
+ return ret;
+ }
+ return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
+ buf, buflen);
+}
+
+
+static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
+ const char *txtaddr,
+ char *buf, size_t buflen)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+ int ret;
+
+ if (hwaddr_aton(txtaddr, addr) ||
+ (sta = ap_get_sta(hapd, addr)) == NULL) {
+ ret = os_snprintf(buf, buflen, "FAIL\n");
+ if (ret < 0 || (size_t) ret >= buflen)
+ return 0;
+ return ret;
+ }
+ return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
+}
+
+
+static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
+ "notification", MAC2STR(addr));
+ sta = ap_sta_add(hapd, addr);
+ if (sta == NULL)
+ return -1;
+
+ hostapd_new_assoc_sta(hapd, sta, 0);
+ accounting_sta_get_id(hapd, sta);
+ return 0;
+}
+
+
+static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ char buf[256];
+ int res;
+ struct sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+ char *reply;
+ const int reply_size = 4096;
+ int reply_len;
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(ctrl_iface)");
+ return;
+ }
+ buf[res] = '\0';
+ wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
+
+ reply = os_malloc(reply_size);
+ if (reply == NULL) {
+ sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+ fromlen);
+ return;
+ }
+
+ os_memcpy(reply, "OK\n", 3);
+ reply_len = 3;
+
+ if (os_strcmp(buf, "PING") == 0) {
+ os_memcpy(reply, "PONG\n", 5);
+ reply_len = 5;
+ } else if (os_strcmp(buf, "MIB") == 0) {
+ reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
+ if (reply_len >= 0) {
+ res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
+ reply_size - reply_len);
+ if (res < 0)
+ reply_len = -1;
+ else
+ reply_len += res;
+ }
+ if (reply_len >= 0) {
+ res = ieee802_1x_get_mib(hapd, reply + reply_len,
+ reply_size - reply_len);
+ if (res < 0)
+ reply_len = -1;
+ else
+ reply_len += res;
+ }
+ if (reply_len >= 0) {
+ res = radius_client_get_mib(hapd->radius,
+ reply + reply_len,
+ reply_size - reply_len);
+ if (res < 0)
+ reply_len = -1;
+ else
+ reply_len += res;
+ }
+ } else if (os_strcmp(buf, "STA-FIRST") == 0) {
+ reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
+ reply_size);
+ } else if (os_strncmp(buf, "STA ", 4) == 0) {
+ reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
+ reply_size);
+ } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
+ reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
+ reply_size);
+ } else if (os_strcmp(buf, "ATTACH") == 0) {
+ if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DETACH") == 0) {
+ if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
+ if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
+ buf + 6))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
+ if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
+ reply_len = -1;
+ } else {
+ os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+ reply_len = 16;
+ }
+
+ if (reply_len < 0) {
+ os_memcpy(reply, "FAIL\n", 5);
+ reply_len = 5;
+ }
+ sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+ os_free(reply);
+}
+
+
+static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
+{
+ char *buf;
+ size_t len;
+
+ if (hapd->conf->ctrl_interface == NULL)
+ return NULL;
+
+ len = os_strlen(hapd->conf->ctrl_interface) +
+ os_strlen(hapd->conf->iface) + 2;
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return NULL;
+
+ os_snprintf(buf, len, "%s/%s",
+ hapd->conf->ctrl_interface, hapd->conf->iface);
+ buf[len - 1] = '\0';
+ return buf;
+}
+
+
+int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
+{
+ struct sockaddr_un addr;
+ int s = -1;
+ char *fname = NULL;
+
+ hapd->ctrl_sock = -1;
+
+ if (hapd->conf->ctrl_interface == NULL)
+ return 0;
+
+ if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
+ if (errno == EEXIST) {
+ wpa_printf(MSG_DEBUG, "Using existing control "
+ "interface directory.");
+ } else {
+ perror("mkdir[ctrl_interface]");
+ goto fail;
+ }
+ }
+
+ if (hapd->conf->ctrl_interface_gid_set &&
+ chown(hapd->conf->ctrl_interface, 0,
+ hapd->conf->ctrl_interface_gid) < 0) {
+ perror("chown[ctrl_interface]");
+ return -1;
+ }
+
+ if (os_strlen(hapd->conf->ctrl_interface) + 1 +
+ os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
+ goto fail;
+
+ s = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket(PF_UNIX)");
+ goto fail;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ fname = hostapd_ctrl_iface_path(hapd);
+ if (fname == NULL)
+ goto fail;
+ os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind(PF_UNIX)");
+ goto fail;
+ }
+
+ if (hapd->conf->ctrl_interface_gid_set &&
+ chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
+ perror("chown[ctrl_interface/ifname]");
+ goto fail;
+ }
+
+ if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+ perror("chmod[ctrl_interface/ifname]");
+ goto fail;
+ }
+ os_free(fname);
+
+ hapd->ctrl_sock = s;
+ eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
+ NULL);
+
+ return 0;
+
+fail:
+ if (s >= 0)
+ close(s);
+ if (fname) {
+ unlink(fname);
+ os_free(fname);
+ }
+ return -1;
+}
+
+
+void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
+{
+ struct wpa_ctrl_dst *dst, *prev;
+
+ if (hapd->ctrl_sock > -1) {
+ char *fname;
+ eloop_unregister_read_sock(hapd->ctrl_sock);
+ close(hapd->ctrl_sock);
+ hapd->ctrl_sock = -1;
+ fname = hostapd_ctrl_iface_path(hapd);
+ if (fname)
+ unlink(fname);
+ os_free(fname);
+
+ if (hapd->conf->ctrl_interface &&
+ rmdir(hapd->conf->ctrl_interface) < 0) {
+ if (errno == ENOTEMPTY) {
+ wpa_printf(MSG_DEBUG, "Control interface "
+ "directory not empty - leaving it "
+ "behind");
+ } else {
+ perror("rmdir[ctrl_interface]");
+ }
+ }
+ }
+
+ dst = hapd->ctrl_dst;
+ while (dst) {
+ prev = dst;
+ dst = dst->next;
+ os_free(prev);
+ }
+}
+
+
+void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+ char *buf, size_t len)
+{
+ struct wpa_ctrl_dst *dst, *next;
+ struct msghdr msg;
+ int idx;
+ struct iovec io[2];
+ char levelstr[10];
+
+ dst = hapd->ctrl_dst;
+ if (hapd->ctrl_sock < 0 || dst == NULL)
+ return;
+
+ os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+ io[0].iov_base = levelstr;
+ io[0].iov_len = os_strlen(levelstr);
+ io[1].iov_base = buf;
+ io[1].iov_len = len;
+ os_memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 2;
+
+ idx = 0;
+ while (dst) {
+ next = dst->next;
+ if (level >= dst->debug_level) {
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
+ (u8 *) dst->addr.sun_path, dst->addrlen);
+ msg.msg_name = &dst->addr;
+ msg.msg_namelen = dst->addrlen;
+ if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
+ fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
+ idx);
+ perror("sendmsg");
+ dst->errors++;
+ if (dst->errors > 10) {
+ hostapd_ctrl_iface_detach(
+ hapd, &dst->addr,
+ dst->addrlen);
+ }
+ } else
+ dst->errors = 0;
+ }
+ idx++;
+ dst = next;
+ }
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/hostapd/ctrl_iface.h b/hostapd/ctrl_iface.h
new file mode 100644
index 0000000..2ac2f3b
--- /dev/null
+++ b/hostapd/ctrl_iface.h
@@ -0,0 +1,23 @@
+/*
+ * hostapd / UNIX domain socket -based control interface
+ * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef CTRL_IFACE_H
+#define CTRL_IFACE_H
+
+int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
+void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
+void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+ char *buf, size_t len);
+
+#endif /* CTRL_IFACE_H */
diff --git a/hostapd/defconfig b/hostapd/defconfig
new file mode 100644
index 0000000..56ecfc6
--- /dev/null
+++ b/hostapd/defconfig
@@ -0,0 +1,119 @@
+# 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 madwifi driver
+#CONFIG_DRIVER_MADWIFI=y
+#CFLAGS += -I../head # change to reflect local setup; directory for madwifi src
+
+# Driver interface for Prism54 driver
+#CONFIG_DRIVER_PRISM54=y
+
+# Driver interface for drivers using the nl80211 kernel interface
+#CONFIG_DRIVER_NL80211=y
+# driver_nl80211.c requires a rather new libnl, probably not
+# shipped with your distribution yet
+#LIBNL=/usr/src/libnl
+#CFLAGS += -I$(LIBNL)/include
+#LIBS += -L$(LIBNL)/lib
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+
+# 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-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
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=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 802.11r/D4.1 (Fast BSS Transition)
+# This enables an experimental implementation of a draft version of
+# IEEE 802.11r. This draft is still subject to change, so it should be noted
+# that this version may not comply with the final standard.
+#CONFIG_IEEE80211R=y
diff --git a/hostapd/developer.txt b/hostapd/developer.txt
new file mode 100644
index 0000000..e1d3163
--- /dev/null
+++ b/hostapd/developer.txt
@@ -0,0 +1,219 @@
+Developer notes for hostapd
+===========================
+
+hostapd daemon setup, operations, and shutdown
+----------------------------------------------
+
+Files: hostapd.[ch]
+
+Externally called functions:
+ hostapd_new_assoc_sta() is called when a station associates with the AP
+
+Event loop functions:
+ handle_term() is called on SIGINT and SIGTERM to terminate hostapd process
+ handle_reload() is called on SIGHUP to reload configuration
+ handle_dump_state() is called on SIGUSR1 to dump station state data to a
+ text file
+ hostapd_rotate_wep() is called to periodically change WEP keys
+
+
+Configuration parsing
+---------------------
+
+Configuration file parsing and data structure definition.
+
+Files: config.[ch]
+
+Externally called functions:
+ hostapd_config_read() is called to read and parse a configuration file;
+ allocates and returns configuration data structure
+ hostapd_config_free() is called to free configuration data structure
+ hostapd_maclist_found() is called to check whether a given address is found
+ in a list of MAC addresses
+
+
+Kernel driver access
+--------------------
+
+Helper functions for configuring the Host AP kernel driver and
+accessing data from it.
+
+Files: driver.[ch]
+
+
+IEEE 802.11 frame handling (netdevice wlan#ap)
+----------------------------------------------
+
+Receive all incoming IEEE 802.11 frames from the kernel driver via
+wlan#ap interface.
+
+Files: receive.c
+
+Externally called functions:
+ hostapd_init_sockets() is called to initialize sockets for receiving and
+ sending IEEE 802.11 frames via wlan#ap interface
+
+Event loop functions:
+ handle_read() is called for each incoming packet from wlan#ap net device
+
+
+Station table
+-------------
+
+Files: sta_info.[ch], ap.h
+
+Event loop functions:
+ ap_handle_timer() is called to check station activity and to remove
+ inactive stations
+
+
+IEEE 802.11 management
+----------------------
+
+IEEE 802.11 management frame sending and processing (mainly,
+authentication and association). IEEE 802.11 station functionality
+(authenticate and associate with another AP as an station).
+
+Files: ieee802_11.[ch]
+
+Externally called functions:
+ ieee802_11_mgmt() is called for each received IEEE 802.11 management frame
+ (from handle_frame() in hostapd.c)
+ ieee802_11_mgmt_cb() is called for each received TX callback of IEEE 802.11
+ management frame (from handle_tx_callback() in hostapd.c)
+ ieee802_11_send_deauth() is called to send deauthentication frame
+ ieee802_11_send_disassoc() is called to send disassociation frame
+ ieee802_11_parse_elems() is used to parse information elements in
+ IEEE 802.11 management frames
+
+Event loop functions:
+ ieee802_11_sta_authenticate() called to retry authentication (with another
+ AP)
+ ieee802_11_sta_associate() called to retry association (with another AP)
+
+
+IEEE 802.11 authentication
+--------------------------
+
+Access control list for IEEE 802.11 authentication. Uses staticly
+configured ACL from configuration files or an external RADIUS
+server. Results from external RADIUS queries are cached to allow
+faster authentication frame processing.
+
+Files: ieee802_11_auth.[ch]
+
+Externally called functions:
+ hostapd_acl_init() called once during hostapd startup
+ hostapd_acl_deinit() called once during hostapd shutdown
+ hostapd_acl_recv_radius() called by IEEE 802.1X code for incoming RADIUS
+ Authentication messages (returns 0 if message was processed)
+ hostapd_allowed_address() called to check whether a specified station can be
+ authenticated
+
+Event loop functions:
+ hostapd_acl_expire() is called to expire ACL cache entries
+
+
+IEEE 802.1X Authenticator
+-------------------------
+
+Files: ieee802_1x.[ch]
+
+
+Externally called functions:
+ ieee802_1x_receive() is called for each incoming EAPOL frame from the
+ wireless interface
+ ieee802_1x_new_station() is called to start IEEE 802.1X authentication when
+ a new station completes IEEE 802.11 association
+
+Event loop functions:
+ ieee802_1x_receive_auth() called for each incoming RADIUS Authentication
+ message
+
+
+EAPOL state machine
+-------------------
+
+IEEE 802.1X state machine for EAPOL.
+
+Files: eapol_sm.[ch]
+
+Externally called functions:
+ eapol_sm_step() is called to advance EAPOL state machines after any change
+ that could affect their state
+
+Event loop functions:
+ eapol_port_timers_tick() called once per second to advance Port Timers state
+ machine
+
+
+IEEE 802.11f (IAPP)
+-------------------
+
+Files: iapp.[ch]
+
+Externally called functions:
+ iapp_new_station() is called to start accounting session when a new station
+ completes IEEE 802.11 association or IEEE 802.1X authentication
+
+Event loop functions:
+ iapp_receive_udp() is called for incoming IAPP frames over UDP
+
+
+Per station accounting
+----------------------
+
+Send RADIUS Accounting start and stop messages to a RADIUS Accounting
+server. Process incoming RADIUS Accounting messages.
+
+Files: accounting.[ch]
+
+Externally called functions:
+ accounting_init() called once during hostapd startup
+ accounting_deinit() called once during hostapd shutdown
+ accounting_sta_start() called when a station starts new session
+ accounting_sta_stop() called when a station session is terminated
+
+Event loop functions:
+ accounting_receive() called for each incoming RADIUS Accounting message
+ accounting_list_timer() called to retransmit accounting messages and to
+ remove expired entries
+
+
+RADIUS messages
+---------------
+
+RADIUS message generation and parsing functions.
+
+Files: radius.[ch]
+
+
+Event loop
+----------
+
+Event loop for registering timeout calls, signal handlers, and socket
+read events.
+
+Files: eloop.[ch]
+
+
+RC4
+---
+
+RC4 encryption
+
+Files: rc4.[ch]
+
+
+MD5
+---
+
+MD5 hash and HMAC-MD5.
+
+Files: md5.[ch]
+
+
+Miscellaneous helper functions
+------------------------------
+
+Files: common.[ch]
diff --git a/hostapd/doc/.gitignore b/hostapd/doc/.gitignore
new file mode 100644
index 0000000..987a5e9
--- /dev/null
+++ b/hostapd/doc/.gitignore
@@ -0,0 +1,4 @@
+html
+latex
+hostapd.eps
+hostapd.png
diff --git a/hostapd/doc/code_structure.doxygen b/hostapd/doc/code_structure.doxygen
new file mode 100644
index 0000000..fdcf725
--- /dev/null
+++ b/hostapd/doc/code_structure.doxygen
@@ -0,0 +1,5 @@
+/**
+\page code_structure Structure of the source code
+
+
+*/
diff --git a/hostapd/doc/ctrl_iface.doxygen b/hostapd/doc/ctrl_iface.doxygen
new file mode 100644
index 0000000..76cfc6a
--- /dev/null
+++ b/hostapd/doc/ctrl_iface.doxygen
@@ -0,0 +1,66 @@
+/**
+\page ctrl_iface_page Control interface
+
+hostapd implements a control interface that can be used by
+external programs to control the operations of the hostapd
+daemon and to get status information and event notifications. There is
+a small C library, in a form of a single C file, wpa_ctrl.c, that
+provides helper functions to facilitate the use of the control
+interface. External programs can link this file into them and then use
+the library functions documented in wpa_ctrl.h to interact with
+%wpa_supplicant. This library can also be used with C++. hostapd_cli.c
+is an example program using this library.
+
+There are multiple mechanisms for inter-process communication. For
+example, Linux version of hostapd is using UNIX domain sockets for the
+control interface. The use of the functions defined in wpa_ctrl.h can
+be used to hide the details of the used IPC from external programs.
+
+
+\section using_ctrl_iface Using the control interface
+
+External programs, e.g., a GUI or a configuration utility, that need to
+communicate with hostapd should link in wpa_ctrl.c. This
+allows them to use helper functions to open connection to the control
+interface with wpa_ctrl_open() and to send commands with
+wpa_ctrl_request().
+
+hostapd uses the control interface for two types of communication:
+commands and unsolicited event messages. Commands are a pair of
+messages, a request from the external program and a response from
+hostapd. These can be executed using wpa_ctrl_request().
+Unsolicited event messages are sent by hostapd to the control
+interface connection without specific request from the external program
+for receiving each message. However, the external program needs to
+attach to the control interface with wpa_ctrl_attach() to receive these
+unsolicited messages.
+
+If the control interface connection is used both for commands and
+unsolicited event messages, there is potential for receiving an
+unsolicited message between the command request and response.
+wpa_ctrl_request() caller will need to supply a callback, msg_cb,
+for processing these messages. Often it is easier to open two
+control interface connections by calling wpa_ctrl_open() twice and
+then use one of the connections for commands and the other one for
+unsolicited messages. This way command request/response pairs will
+not be broken by unsolicited messages. wpa_cli is an example of how
+to use only one connection for both purposes and wpa_gui demonstrates
+how to use two separate connections.
+
+Once the control interface connection is not needed anymore, it should
+be closed by calling wpa_ctrl_close(). If the connection was used for
+unsolicited event messages, it should be first detached by calling
+wpa_ctrl_detach().
+
+
+\section ctrl_iface_cmds Control interface commands
+
+Following commands can be used with wpa_ctrl_request():
+
+\subsection ctrl_iface_PING PING
+
+This command can be used to test whether hostapd is replying
+to the control interface commands. The expected reply is \c PONG if the
+connection is open and hostapd is processing commands.
+
+*/
diff --git a/hostapd/doc/doxygen.fast b/hostapd/doc/doxygen.fast
new file mode 100644
index 0000000..44760f4
--- /dev/null
+++ b/hostapd/doc/doxygen.fast
@@ -0,0 +1,233 @@
+# Doxyfile 1.4.4
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = hostapd
+PROJECT_NUMBER = 0.5.x
+OUTPUT_DIRECTORY = doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = . \
+ ../wpa_supplicant/eap_sim_common.c \
+ ../wpa_supplicant/eap_sim_common.h
+FILE_PATTERNS = *.c *.h *.doxygen
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH = doc
+INPUT_FILTER = doc/kerneldoc2doxygen.pl
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = YES
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 3
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED = RADIUS_SERVER EAP_SERVER EAP_SIM
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = NO
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/hostapd/doc/doxygen.full b/hostapd/doc/doxygen.full
new file mode 100644
index 0000000..619f977
--- /dev/null
+++ b/hostapd/doc/doxygen.full
@@ -0,0 +1,230 @@
+# Doxyfile 1.4.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = hostapd
+PROJECT_NUMBER = 0.5.x
+OUTPUT_DIRECTORY = doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = .
+FILE_PATTERNS = *.c *.h *.doxygen
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH = doc
+INPUT_FILTER = kerneldoc2doxygen.pl
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = YES
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 3
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = YES
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED = RADIUS_SERVER EAP_SERVER EAP_SIM
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = NO
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = YES
diff --git a/hostapd/doc/driver_wrapper.doxygen b/hostapd/doc/driver_wrapper.doxygen
new file mode 100644
index 0000000..0ad196f
--- /dev/null
+++ b/hostapd/doc/driver_wrapper.doxygen
@@ -0,0 +1,20 @@
+/**
+\page driver_wrapper Driver wrapper implementation (driver.h, drivers.c)
+
+All hardware and driver dependent functionality is in separate C files
+that implement defined wrapper functions. Other parts
+of the hostapd are designed to be hardware, driver, and operating
+system independent.
+
+Driver wrappers need to implement whatever calls are used in the
+target operating system/driver for controlling wireless LAN
+devices. As an example, in case of Linux, these are mostly some glue
+code and ioctl() calls and netlink message parsing for Linux Wireless
+Extensions (WE). Since features required for WPA were added only recently to
+Linux Wireless Extensions (in version 18), some driver specific code is used
+in number of driver interface implementations. These driver dependent parts
+can be replaced with generic code in driver_wext.c once the target driver
+includes full support for WE-18. After that, all Linux drivers, at
+least in theory, could use the same driver wrapper code.
+
+*/
diff --git a/hostapd/doc/eap.doxygen b/hostapd/doc/eap.doxygen
new file mode 100644
index 0000000..f0f135a
--- /dev/null
+++ b/hostapd/doc/eap.doxygen
@@ -0,0 +1,56 @@
+/**
+\page eap_module EAP server implementation
+
+Extensible Authentication Protocol (EAP) is an authentication framework
+defined in RFC 3748. hostapd uses a separate code module for EAP server
+implementation. This module was designed to use only a minimal set of
+direct function calls (mainly, to debug/event functions) in order for
+it to be usable in other programs. The design of the EAP
+implementation is based loosely on RFC 4137. The state machine is
+defined in this RFC and so is the interface between the server state
+machine and methods. As such, this RFC provides useful information for
+understanding the EAP server implementation in hostapd.
+
+Some of the terminology used in EAP state machine is referring to
+EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
+layer being IEEE 802.1X if EAP module is built for other programs than
+%wpa_supplicant. These terms should be understood to refer to the
+lower layer as defined in RFC 4137.
+
+
+\section adding_eap_methods Adding EAP methods
+
+Each EAP method is implemented as a separate module, usually as one C
+file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
+methods use the same interface between the server state machine and
+method specific functions. This allows new EAP methods to be added
+without modifying the core EAP state machine implementation.
+
+New EAP methods need to be registered by adding them into the build
+(Makefile) and the EAP method registration list in the
+eap_server_register_methods() function of eap_methods.c. Each EAP
+method should use a build-time configuration option, e.g., EAP_TLS, in
+order to make it possible to select which of the methods are included
+in the build.
+
+EAP methods must implement the interface defined in eap_i.h. struct
+eap_method defines the needed function pointers that each EAP method
+must provide. In addition, the EAP type and name are registered using
+this structure. This interface is based on section 4.4 of RFC 4137.
+
+It is recommended that the EAP methods would use generic helper
+functions, eap_msg_alloc() and eap_hdr_validate() when processing
+messages. This allows code sharing and can avoid missing some of the
+needed validation steps for received packets. In addition, these
+functions make it easier to change between expanded and legacy EAP
+header, if needed.
+
+When adding an EAP method that uses a vendor specific EAP type
+(Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
+must be registered by passing vendor id instead of EAP_VENDOR_IETF to
+eap_server_method_alloc(). These methods must not try to emulate
+expanded types by registering a legacy EAP method for type 254. See
+eap_vendor_test.c for an example of an EAP method implementation that
+is implemented as an expanded type.
+
+*/
diff --git a/hostapd/doc/hostapd.fig b/hostapd/doc/hostapd.fig
new file mode 100644
index 0000000..af3f0be
--- /dev/null
+++ b/hostapd/doc/hostapd.fig
@@ -0,0 +1,264 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+6 1875 4050 2925 4350
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 1875 4050 2925 4050 2925 4350 1875 4350 1875 4050
+4 0 0 50 -1 0 12 0.0000 4 180 735 2025 4275 l2_packet\001
+-6
+6 4725 1200 5925 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4725 1200 5925 1200 5925 1500 4725 1500 4725 1200
+4 0 0 50 -1 0 12 0.0000 4 135 1005 4800 1425 GUI frontend\001
+-6
+6 6000 2700 7200 3225
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6000 2700 7200 2700 7200 3225 6000 3225 6000 2700
+4 0 0 50 -1 0 12 0.0000 4 135 975 6075 2925 WPA/WPA2\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 3150 state machine\001
+-6
+6 6000 4950 7200 5475
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6000 4950 7200 4950 7200 5475 6000 5475 6000 4950
+4 0 0 50 -1 0 12 0.0000 4 135 360 6075 5175 EAP\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 5400 state machine\001
+-6
+6 4350 3900 5025 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4350 3900 5025 3900 5025 4425 4350 4425 4350 3900
+4 0 0 50 -1 0 12 0.0000 4 105 420 4500 4125 event\001
+4 0 0 50 -1 0 12 0.0000 4 180 315 4500 4350 loop\001
+-6
+6 4275 2550 5100 2850
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4275 2550 5100 2550 5100 2850 4275 2850 4275 2550
+4 0 0 50 -1 0 12 0.0000 4 135 450 4425 2775 ctrl i/f\001
+-6
+6 6000 3900 7200 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6000 3900 7200 3900 7200 4425 6000 4425 6000 3900
+4 0 0 50 -1 0 12 0.0000 4 135 600 6075 4125 EAPOL\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 4350 state machine\001
+-6
+6 2775 3150 4050 3450
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 2775 3150 4050 3150 4050 3450 2775 3450 2775 3150
+4 0 0 50 -1 0 12 0.0000 4 180 990 2925 3375 configuration\001
+-6
+6 3450 1200 4575 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3450 1200 4575 1200 4575 1500 3450 1500 3450 1200
+4 0 0 50 -1 0 12 0.0000 4 180 870 3600 1425 hostapd_cli\001
+-6
+6 3525 7800 5775 8100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3525 7800 5775 7800 5775 8100 3525 8100 3525 7800
+4 0 0 50 -1 0 12 0.0000 4 135 2145 3600 8025 kernel network device driver\001
+-6
+6 4275 6000 5100 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4275 6000 5100 6000 5100 6300 4275 6300 4275 6000
+4 0 0 50 -1 0 12 0.0000 4 135 630 4350 6225 driver i/f\001
+-6
+6 8175 4725 9225 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 4725 9225 4725 9225 5025 8175 5025 8175 4725
+4 0 0 50 -1 0 12 0.0000 4 135 735 8250 4950 EAP-TLS\001
+-6
+6 9300 4725 10350 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 4725 10350 4725 10350 5025 9300 5025 9300 4725
+4 0 0 50 -1 0 12 0.0000 4 135 810 9375 4950 EAP-MD5\001
+-6
+6 8175 5100 9225 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 5100 9225 5100 9225 5400 8175 5400 8175 5100
+4 0 0 50 -1 0 12 0.0000 4 135 885 8250 5325 EAP-PEAP\001
+-6
+6 9300 5100 10350 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 5100 10350 5100 10350 5400 9300 5400 9300 5100
+4 0 0 50 -1 0 12 0.0000 4 135 840 9375 5325 EAP-TTLS\001
+-6
+6 8175 5475 9225 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 5475 9225 5475 9225 5775 8175 5775 8175 5475
+4 0 0 50 -1 0 12 0.0000 4 135 780 8250 5700 EAP-GTC\001
+-6
+6 8175 5850 9225 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 5850 9225 5850 9225 6150 8175 6150 8175 5850
+4 0 0 50 -1 0 12 0.0000 4 135 750 8250 6075 EAP-SIM\001
+-6
+6 8175 6225 9225 6525
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 6225 9225 6225 9225 6525 8175 6525 8175 6225
+4 0 0 50 -1 0 12 0.0000 4 135 765 8250 6450 EAP-PSK\001
+-6
+6 9300 5850 10350 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 5850 10350 5850 10350 6150 9300 6150 9300 5850
+4 0 0 50 -1 0 12 0.0000 4 135 825 9375 6075 EAP-AKA\001
+-6
+6 9300 5475 10350 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 5475 10350 5475 10350 5775 9300 5775 9300 5475
+4 0 0 50 -1 0 12 0.0000 4 135 795 9375 5700 EAP-PAX\001
+-6
+6 8175 6600 9675 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 6600 9675 6600 9675 6900 8175 6900 8175 6600
+4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 6825 EAP-MSCHAPv2\001
+-6
+6 8700 3450 9375 3750
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8700 3450 9375 3450 9375 3750 8700 3750 8700 3450
+4 0 0 50 -1 0 12 0.0000 4 150 480 8775 3675 crypto\001
+-6
+6 9600 3450 10275 3750
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9600 3450 10275 3450 10275 3750 9600 3750 9600 3450
+4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3675 TLS\001
+-6
+6 6000 5775 7200 6300
+6 6000 5775 7200 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6000 5775 7200 5775 7200 6300 6000 6300 6000 5775
+4 0 0 50 -1 0 12 0.0000 4 135 690 6075 6000 RADIUS\001
+-6
+4 0 0 50 -1 0 12 0.0000 4 90 480 6075 6225 server\001
+-6
+6 8100 2250 8925 2775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8100 2250 8925 2250 8925 2775 8100 2775 8100 2250
+4 0 0 50 -1 0 12 0.0000 4 135 690 8175 2475 RADIUS\001
+4 0 0 50 -1 0 12 0.0000 4 135 420 8175 2700 client\001
+-6
+6 3150 5475 4425 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3150 5475 4425 5475 4425 5775 3150 5775 3150 5475
+4 0 0 50 -1 0 12 0.0000 4 135 990 3300 5700 driver events\001
+-6
+6 1950 5550 2625 6075
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 1950 5550 2625 5550 2625 6075 1950 6075 1950 5550
+4 0 0 50 -1 0 12 0.0000 4 135 540 2025 5775 Station\001
+4 0 0 50 -1 0 12 0.0000 4 135 375 2025 6000 table\001
+-6
+6 1875 4725 2925 5250
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 1875 4725 2925 4725 2925 5250 1875 5250 1875 4725
+4 0 0 50 -1 0 12 0.0000 4 135 960 1950 4950 IEEE 802.11\001
+4 0 0 50 -1 0 12 0.0000 4 135 555 1950 5175 MLME\001
+-6
+2 1 1 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
+ 1275 4200 1875 4200
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+ 4500 2550 3900 1500
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+ 4800 2550 5400 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 2925 4200 4350 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 5025 3900 6000 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 5025 4200 6000 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4650 6000 4650 4425
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6600 4425 6600 4950
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6600 3225 6600 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 7200 5250 8100 5250
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 9075 4425 9075 3750
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 7200 3000 8700 3525
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4650 3900 4650 2850
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 7200 4125 8700 3675
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6000 4350 5025 6000
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6000 3150 4875 6000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 1500 2100 10800 2100 10800 7500 1500 7500 1500 2100
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 9900 4425 9900 3750
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 1
+ 4350 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4350 3900 4050 3450
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4350 4425 4050 5475
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+ 2250 7200 4200 7800
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+ 7200 7200 5100 7800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 2775 6900 3675 6900 3675 7200 2775 7200 2775 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3750 6900 4650 6900 4650 7200 3750 7200 3750 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4
+ 2250 6900 2250 6600 7200 6600 7200 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3225 6900 3225 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4200 6900 4200 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 5175 6900 5175 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6150 6900 6150 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4650 6600 4650 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 1800 6900 2700 6900 2700 7200 1800 7200 1800 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4725 6900 5625 6900 5625 7200 4725 7200 4725 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 5700 6900 6600 6900 6600 7200 5700 7200 5700 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6675 6900 7800 6900 7800 7200 6675 7200 6675 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8100 6975 10425 6975 10425 4425 8100 4425 8100 6975
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6600 5475 6600 5775
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 5025 4425 6000 5775
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
+ 4800 3900 5925 2550 8100 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 7200 3900 8475 2775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9450 2250 10425 2250 10425 2775 9450 2775 9450 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 8925 2475 9450 2475
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 2325 5550 2325 5250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 2925 4950 4350 4275
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
+ 2850 4725 5775 2400 8100 2400
+4 0 0 50 -1 0 12 0.0000 4 135 915 375 3975 EAPOL and\001
+4 0 0 50 -1 0 12 0.0000 4 180 630 375 4200 pre-auth\001
+4 0 0 50 -1 0 12 0.0000 4 180 810 375 4425 ethertypes\001
+4 0 0 50 -1 0 12 0.0000 4 135 1050 375 4650 from/to kernel\001
+4 0 0 50 -1 0 12 0.0000 4 135 1920 3675 1875 frontend control interface\001
+4 0 0 50 -1 2 14 0.0000 4 195 720 1637 2371 hostapd\001
+4 0 0 50 -1 0 12 0.0000 4 180 600 3825 7125 prism54\001
+4 0 0 50 -1 0 12 0.0000 4 180 510 1875 7125 hostap\001
+4 0 0 50 -1 0 12 0.0000 4 135 600 2850 7125 madwifi\001
+4 0 0 50 -1 0 12 0.0000 4 135 270 4800 7125 bsd\001
+4 0 0 50 -1 0 12 0.0000 4 105 300 6750 7125 test\001
+4 0 0 50 -1 0 12 0.0000 4 135 420 5775 7125 wired\001
+4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
+4 0 0 50 -1 0 12 0.0000 4 135 690 9525 2475 RADIUS\001
+4 0 0 50 -1 0 12 0.0000 4 180 825 9525 2700 accounting\001
diff --git a/hostapd/doc/kerneldoc2doxygen.pl b/hostapd/doc/kerneldoc2doxygen.pl
new file mode 100755
index 0000000..68835a1
--- /dev/null
+++ b/hostapd/doc/kerneldoc2doxygen.pl
@@ -0,0 +1,129 @@
+#!/usr/bin/perl -w
+#
+##########################################################################
+# Convert kernel-doc style comments to Doxygen comments.
+##########################################################################
+#
+# This script reads a C source file from stdin, and writes
+# to stdout. Normal usage:
+#
+# $ mv file.c file.c.gtkdoc
+# $ kerneldoc2doxygen.pl <file.c.gtkdoc >file.c
+#
+# Or to do the same thing with multiple files:
+# $ perl -i.gtkdoc kerneldoc2doxygen.pl *.c *.h
+#
+# This script may also be suitable for use as a Doxygen input filter,
+# but that has not been tested.
+#
+# Back up your source files before using this script!!
+#
+##########################################################################
+# Copyright (C) 2003 Jonathan Foster <jon@jon-foster.co.uk>
+# Copyright (C) 2005 Jouni Malinen <j@w1.fi>
+# (modified for kerneldoc format used in wpa_supplicant)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+# or look at http://www.gnu.org/licenses/gpl.html
+##########################################################################
+
+
+##########################################################################
+#
+# This function converts a single comment from gtk-doc to Doxygen format.
+# The parameter does not include the opening or closing lines
+# (i.e. given a comment like this:
+# "/**\n"
+# " * FunctionName:\n"
+# " * @foo: This describes the foo parameter\n"
+# " * @bar: This describes the bar parameter\n"
+# " * @Returns: This describes the return value\n"
+# " *\n"
+# " * This describes the function.\n"
+# " */\n"
+# This function gets:
+# " * FunctionName:\n"
+# " * @foo: This describes the foo parameter\n"
+# " * @bar: This describes the bar parameter\n"
+# " * @Returns: This describes the return value\n"
+# " *\n"
+# " * This describes the function.\n"
+# And it returns:
+# " * This describes the function.\n"
+# " *\n"
+# " * @param foo This describes the foo parameter\n"
+# " * @param bar This describes the bar parameter\n"
+# " * @return This describes the return value\n"
+# )
+#
+sub fixcomment {
+ $t = $_[0];
+
+ # " * func: foo" --> "\brief foo\n"
+ # " * struct bar: foo" --> "\brief foo\n"
+ # If this fails, not a kernel-doc comment ==> return unmodified.
+ ($t =~ s/^[\t ]*\*[\t ]*(struct )?([^ \t\n]*) - ([^\n]*)/\\brief $3\n/s)
+ or return $t;
+
+ # " * Returns: foo" --> "\return foo"
+ $t =~ s/\n[\t ]*\*[\t ]*Returns:/\n\\return/sig;
+
+ # " * @foo: bar" --> "\param foo bar"
+ # Handle two common typos: No ":", or "," instead of ":".
+ $t =~ s/\n[\t ]*\*[\t ]*\@([^ :,]*)[:,]?[\t ]*/\n\\param $1 /sg;
+
+ return $t;
+}
+
+##########################################################################
+# Start of main code
+
+# Read entire stdin into memory - one multi-line string.
+$_ = do { local $/; <> };
+
+s{^/\*\n \*}{/\*\* \\file\n\\brief};
+s{ \* Copyright}{\\par Copyright\nCopyright};
+
+# Fix any comments like "/*************" so they don't match.
+# "/***" ===> "/* *"
+s{/\*\*\*}{/\* \*}gs;
+
+# The main comment-detection code.
+s{
+ ( # $1 = Open comment
+ /\*\* # Open comment
+ (?!\*) # Do not match /*** (redundant due to fixup above).
+ [\t ]*\n? # If 1st line is whitespace, match the lot (including the newline).
+ )
+ (.*?) # $2 = Body of comment (multi-line)
+ ( # $3 = Close comment
+ ( # If possible, match the whitespace before the close-comment
+ (?<=\n) # This part only matches after a newline
+ [\t ]* # Eat whitespace
+ )?
+ \*/ # Close comment
+ )
+ }
+ {
+ $1 . fixcomment($2) . $3
+ }gesx;
+# ^^^^ Modes: g - Global, match all occurances.
+# e - Evaluate the replacement as an expression.
+# s - Single-line - allows the pattern to match across newlines.
+# x - eXtended pattern, ignore embedded whitespace
+# and allow comments.
+
+# Write results to stdout
+print $_;
+
diff --git a/hostapd/doc/mainpage.doxygen b/hostapd/doc/mainpage.doxygen
new file mode 100644
index 0000000..7cf95de
--- /dev/null
+++ b/hostapd/doc/mainpage.doxygen
@@ -0,0 +1,52 @@
+/**
+\mainpage Developers' documentation for hostapd
+
+hostapd includes IEEE 802.11 access point management (authentication /
+association), IEEE 802.1X/WPA/WPA2 Authenticator, EAP server, and
+RADIUS authentication server functionality. It can be build with
+various configuration option, e.g., a standalone AP management
+solution or a RADIUS authentication server with support for number of
+EAP methods.
+
+The goal of this documentation and comments in the source code is to
+give enough information for other developers to understand how hostapd
+has been implemented, how it can be modified, how new drivers can be
+supported, and how hostapd can be ported to other operating
+systems. If any information is missing, feel free to contact Jouni
+Malinen <j@w1.fi> for more information. Contributions as
+patch files are also very welcome at the same address. Please note
+that hostapd is licensed under dual license, GPLv2 or BSD at user's
+choice. All contributions to hostapd are expected to use compatible
+licensing terms.
+
+The source code and read-only access to hostapd CVS repository
+is available from the project home page at
+http://hostap.epitest.fi/hostapd/. This developers' documentation
+is also available as a PDF file from
+http://hostap.epitest.fi/hostapd/hostapd-devel.pdf .
+
+The design goal for hostapd was to use hardware, driver, and
+OS independent, portable C code for all WPA functionality. The source
+code is divided into separate C files as shown on the \ref
+code_structure "code structure page". All hardware/driver specific
+functionality is in separate files that implement a \ref
+driver_wrapper "well-defined driver API". Information about porting
+to different target boards and operating systems is available on
+the \ref porting "porting page".
+
+EAPOL (IEEE 802.1X) state machines are implemented as a separate
+module that interacts with \ref eap_module "EAP server implementation".
+Similarly, RADIUS authentication server is in its own separate module.
+Both IEEE 802.1X and RADIUS authentication server can use EAP server
+functionality.
+
+hostapd implements a \ref ctrl_iface_page "control interface" that can
+be used by external programs to control the operations of the hostapdt
+daemon and to get status information and event notifications. There is
+a small C library that provides helper functions to facilitate the use
+of the control interface. This library can also be used with C++.
+
+\image html hostapd.png "hostapd modules"
+\image latex hostapd.eps "hostapd modules" width=15cm
+
+*/
diff --git a/hostapd/doc/porting.doxygen b/hostapd/doc/porting.doxygen
new file mode 100644
index 0000000..0621791
--- /dev/null
+++ b/hostapd/doc/porting.doxygen
@@ -0,0 +1,5 @@
+/**
+\page porting Porting to different target boards and operating systems
+
+
+*/
diff --git a/hostapd/driver.h b/hostapd/driver.h
new file mode 100644
index 0000000..ffa28ac
--- /dev/null
+++ b/hostapd/driver.h
@@ -0,0 +1,681 @@
+/*
+ * hostapd - driver interface definition
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef DRIVER_H
+#define DRIVER_H
+
+enum hostapd_driver_if_type {
+ HOSTAPD_IF_VLAN, HOSTAPD_IF_WDS
+};
+
+struct wpa_driver_ops {
+ const char *name; /* as appears in the config file */
+
+ void * (*init)(struct hostapd_data *hapd);
+ void * (*init_bssid)(struct hostapd_data *hapd, const u8 *bssid);
+ void (*deinit)(void *priv);
+
+ int (*wireless_event_init)(void *priv);
+ void (*wireless_event_deinit)(void *priv);
+
+ /**
+ * set_8021x - enable/disable IEEE 802.1X support
+ * @ifname: Interface name (for multi-SSID/VLAN support)
+ * @priv: driver private data
+ * @enabled: 1 = enable, 0 = disable
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Configure the kernel driver to enable/disable 802.1X support.
+ * This may be an empty function if 802.1X support is always enabled.
+ */
+ int (*set_ieee8021x)(const char *ifname, void *priv, int enabled);
+
+ /**
+ * set_privacy - enable/disable privacy
+ * @priv: driver private data
+ * @enabled: 1 = privacy enabled, 0 = disabled
+ *
+ * Return: 0 on success, -1 on failure
+ *
+ * Configure privacy.
+ */
+ int (*set_privacy)(const char *ifname, void *priv, int enabled);
+
+ int (*set_encryption)(const char *ifname, void *priv, const char *alg,
+ const u8 *addr, int idx,
+ const u8 *key, size_t key_len, int txkey);
+ int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr,
+ int idx, u8 *seq);
+ int (*get_seqnum_igtk)(const char *ifname, void *priv, const u8 *addr,
+ int idx, u8 *seq);
+ int (*flush)(void *priv);
+ int (*set_generic_elem)(const char *ifname, void *priv, const u8 *elem,
+ size_t elem_len);
+
+ int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr);
+ int (*send_eapol)(void *priv, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt, const u8 *own_addr);
+ int (*sta_deauth)(void *priv, const u8 *addr, int reason);
+ int (*sta_disassoc)(void *priv, const u8 *addr, int reason);
+ int (*sta_remove)(void *priv, const u8 *addr);
+ int (*get_ssid)(const char *ifname, void *priv, u8 *buf, int len);
+ int (*set_ssid)(const char *ifname, void *priv, const u8 *buf,
+ int len);
+ int (*set_countermeasures)(void *priv, int enabled);
+ int (*send_mgmt_frame)(void *priv, const void *msg, size_t len,
+ int flags);
+ int (*set_assoc_ap)(void *priv, const u8 *addr);
+ int (*sta_add)(const char *ifname, void *priv, const u8 *addr, u16 aid,
+ u16 capability, u8 *supp_rates, size_t supp_rates_len,
+ int flags);
+ int (*get_inact_sec)(void *priv, const u8 *addr);
+ int (*sta_clear_stats)(void *priv, const u8 *addr);
+
+ int (*set_freq)(void *priv, int mode, int freq);
+ int (*set_rts)(void *priv, int rts);
+ int (*get_rts)(void *priv, int *rts);
+ int (*set_frag)(void *priv, int frag);
+ int (*get_frag)(void *priv, int *frag);
+ int (*set_retry)(void *priv, int short_retry, int long_retry);
+ int (*get_retry)(void *priv, int *short_retry, int *long_retry);
+
+ int (*sta_set_flags)(void *priv, const u8 *addr,
+ int total_flags, int flags_or, int flags_and);
+ int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates,
+ int mode);
+ int (*set_channel_flag)(void *priv, int mode, int chan, int flag,
+ unsigned char power_level,
+ unsigned char antenna_max);
+ int (*set_regulatory_domain)(void *priv, unsigned int rd);
+ int (*set_country)(void *priv, const char *country);
+ int (*set_ieee80211d)(void *priv, int enabled);
+ int (*set_beacon)(const char *ifname, void *priv,
+ u8 *head, size_t head_len,
+ u8 *tail, size_t tail_len);
+
+ /* Configure internal bridge:
+ * 0 = disabled, i.e., client separation is enabled (no bridging of
+ * packets between associated STAs
+ * 1 = enabled, i.e., bridge packets between associated STAs (default)
+ */
+ int (*set_internal_bridge)(void *priv, int value);
+ int (*set_beacon_int)(void *priv, int value);
+ int (*set_dtim_period)(const char *ifname, void *priv, int value);
+ /* Configure broadcast SSID mode:
+ * 0 = include SSID in Beacon frames and reply to Probe Request frames
+ * that use broadcast SSID
+ * 1 = hide SSID from Beacon frames and ignore Probe Request frames for
+ * broadcast SSID
+ */
+ int (*set_broadcast_ssid)(void *priv, int value);
+ int (*set_cts_protect)(void *priv, int value);
+ int (*set_key_tx_rx_threshold)(void *priv, int value);
+ int (*set_preamble)(void *priv, int value);
+ int (*set_short_slot_time)(void *priv, int value);
+ int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min,
+ int cw_max, int burst_time);
+ int (*bss_add)(void *priv, const char *ifname, const u8 *bssid);
+ int (*bss_remove)(void *priv, const char *ifname);
+ int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask);
+ int (*passive_scan)(void *priv, int now, int our_mode_only,
+ int interval, int _listen, int *channel,
+ int *last_rx);
+ struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
+ u16 *num_modes,
+ u16 *flags);
+ int (*if_add)(const char *iface, void *priv,
+ enum hostapd_driver_if_type type, char *ifname,
+ const u8 *addr);
+ int (*if_update)(void *priv, enum hostapd_driver_if_type type,
+ char *ifname, const u8 *addr);
+ int (*if_remove)(void *priv, enum hostapd_driver_if_type type,
+ const char *ifname, const u8 *addr);
+ int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname,
+ int vlan_id);
+ /**
+ * commit - Optional commit changes handler
+ * @priv: driver private data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This optional handler function can be registered if the driver
+ * interface implementation needs to commit changes (e.g., by setting
+ * network interface up) at the end of initial configuration. If set,
+ * this handler will be called after initial setup has been completed.
+ */
+ int (*commit)(void *priv);
+
+ int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto,
+ const u8 *data, size_t data_len);
+};
+
+static inline void *
+hostapd_driver_init(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->driver->init == NULL)
+ return NULL;
+ return hapd->driver->init(hapd);
+}
+
+static inline void *
+hostapd_driver_init_bssid(struct hostapd_data *hapd, const u8 *bssid)
+{
+ if (hapd->driver == NULL || hapd->driver->init_bssid == NULL)
+ return NULL;
+ return hapd->driver->init_bssid(hapd, bssid);
+}
+
+static inline void
+hostapd_driver_deinit(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->driver->deinit == NULL)
+ return;
+ hapd->driver->deinit(hapd->drv_priv);
+}
+
+static inline int
+hostapd_wireless_event_init(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->wireless_event_init == NULL)
+ return 0;
+ return hapd->driver->wireless_event_init(hapd->drv_priv);
+}
+
+static inline void
+hostapd_wireless_event_deinit(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->wireless_event_deinit == NULL)
+ return;
+ hapd->driver->wireless_event_deinit(hapd->drv_priv);
+}
+
+static inline int
+hostapd_set_ieee8021x(const char *ifname, struct hostapd_data *hapd,
+ int enabled)
+{
+ if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL)
+ return 0;
+ return hapd->driver->set_ieee8021x(ifname, hapd->drv_priv, enabled);
+}
+
+static inline int
+hostapd_set_privacy(struct hostapd_data *hapd, int enabled)
+{
+ if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
+ return 0;
+ return hapd->driver->set_privacy(hapd->conf->iface, hapd->drv_priv,
+ enabled);
+}
+
+static inline int
+hostapd_set_encryption(const char *ifname, struct hostapd_data *hapd,
+ const char *alg, const u8 *addr, int idx,
+ u8 *key, size_t key_len, int txkey)
+{
+ if (hapd->driver == NULL || hapd->driver->set_encryption == NULL)
+ return 0;
+ return hapd->driver->set_encryption(ifname, hapd->drv_priv, alg, addr,
+ idx, key, key_len, txkey);
+}
+
+static inline int
+hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
+ const u8 *addr, int idx, u8 *seq)
+{
+ if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL)
+ return 0;
+ return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx,
+ seq);
+}
+
+static inline int
+hostapd_get_seqnum_igtk(const char *ifname, struct hostapd_data *hapd,
+ const u8 *addr, int idx, u8 *seq)
+{
+ if (hapd->driver == NULL || hapd->driver->get_seqnum_igtk == NULL)
+ return -1;
+ return hapd->driver->get_seqnum_igtk(ifname, hapd->drv_priv, addr, idx,
+ seq);
+}
+
+static inline int
+hostapd_flush(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->driver->flush == NULL)
+ return 0;
+ return hapd->driver->flush(hapd->drv_priv);
+}
+
+static inline int
+hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
+ size_t elem_len)
+{
+ if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL)
+ return 0;
+ return hapd->driver->set_generic_elem(hapd->conf->iface,
+ hapd->drv_priv, elem, elem_len);
+}
+
+static inline int
+hostapd_read_sta_data(struct hostapd_data *hapd,
+ struct hostap_sta_driver_data *data, const u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
+ return -1;
+ return hapd->driver->read_sta_data(hapd->drv_priv, data, addr);
+}
+
+static inline int
+hostapd_send_eapol(struct hostapd_data *hapd, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt)
+{
+ if (hapd->driver == NULL || hapd->driver->send_eapol == NULL)
+ return 0;
+ return hapd->driver->send_eapol(hapd->drv_priv, addr, data, data_len,
+ encrypt, hapd->own_addr);
+}
+
+static inline int
+hostapd_sta_deauth(struct hostapd_data *hapd, const u8 *addr, int reason)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
+ return 0;
+ return hapd->driver->sta_deauth(hapd->drv_priv, addr, reason);
+}
+
+static inline int
+hostapd_sta_disassoc(struct hostapd_data *hapd, const u8 *addr, int reason)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
+ return 0;
+ return hapd->driver->sta_disassoc(hapd->drv_priv, addr, reason);
+}
+
+static inline int
+hostapd_sta_remove(struct hostapd_data *hapd, const u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
+ return 0;
+ return hapd->driver->sta_remove(hapd->drv_priv, addr);
+}
+
+static inline int
+hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
+{
+ if (hapd->driver == NULL || hapd->driver->get_ssid == NULL)
+ return 0;
+ return hapd->driver->get_ssid(hapd->conf->iface, hapd->drv_priv, buf,
+ len);
+}
+
+static inline int
+hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
+{
+ if (hapd->driver == NULL || hapd->driver->set_ssid == NULL)
+ return 0;
+ return hapd->driver->set_ssid(hapd->conf->iface, hapd->drv_priv, buf,
+ len);
+}
+
+static inline int
+hostapd_send_mgmt_frame(struct hostapd_data *hapd, const void *msg, size_t len,
+ int flags)
+{
+ if (hapd->driver == NULL || hapd->driver->send_mgmt_frame == NULL)
+ return 0;
+ return hapd->driver->send_mgmt_frame(hapd->drv_priv, msg, len, flags);
+}
+
+static inline int
+hostapd_set_assoc_ap(struct hostapd_data *hapd, const u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->set_assoc_ap == NULL)
+ return 0;
+ return hapd->driver->set_assoc_ap(hapd->drv_priv, addr);
+}
+
+static inline int
+hostapd_set_countermeasures(struct hostapd_data *hapd, int enabled)
+{
+ if (hapd->driver == NULL || hapd->driver->set_countermeasures == NULL)
+ return 0;
+ return hapd->driver->set_countermeasures(hapd->drv_priv, enabled);
+}
+
+static inline int
+hostapd_sta_add(const char *ifname, struct hostapd_data *hapd, const u8 *addr,
+ u16 aid, u16 capability, u8 *supp_rates, size_t supp_rates_len,
+ int flags)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_add == NULL)
+ return 0;
+ return hapd->driver->sta_add(ifname, hapd->drv_priv, addr, aid,
+ capability, supp_rates, supp_rates_len,
+ flags);
+}
+
+static inline int
+hostapd_get_inact_sec(struct hostapd_data *hapd, const u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
+ return 0;
+ return hapd->driver->get_inact_sec(hapd->drv_priv, addr);
+}
+
+static inline int
+hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq)
+{
+ if (hapd->driver == NULL || hapd->driver->set_freq == NULL)
+ return 0;
+ return hapd->driver->set_freq(hapd->drv_priv, mode, freq);
+}
+
+static inline int
+hostapd_set_rts(struct hostapd_data *hapd, int rts)
+{
+ if (hapd->driver == NULL || hapd->driver->set_rts == NULL)
+ return 0;
+ return hapd->driver->set_rts(hapd->drv_priv, rts);
+}
+
+static inline int
+hostapd_get_rts(struct hostapd_data *hapd, int *rts)
+{
+ if (hapd->driver == NULL || hapd->driver->get_rts == NULL)
+ return 0;
+ return hapd->driver->get_rts(hapd->drv_priv, rts);
+}
+
+static inline int
+hostapd_set_frag(struct hostapd_data *hapd, int frag)
+{
+ if (hapd->driver == NULL || hapd->driver->set_frag == NULL)
+ return 0;
+ return hapd->driver->set_frag(hapd->drv_priv, frag);
+}
+
+static inline int
+hostapd_get_frag(struct hostapd_data *hapd, int *frag)
+{
+ if (hapd->driver == NULL || hapd->driver->get_frag == NULL)
+ return 0;
+ return hapd->driver->get_frag(hapd->drv_priv, frag);
+}
+
+static inline int
+hostapd_set_retry(struct hostapd_data *hapd, int short_retry, int long_retry)
+{
+ if (hapd->driver == NULL || hapd->driver->set_retry == NULL)
+ return 0;
+ return hapd->driver->set_retry(hapd->drv_priv, short_retry,
+ long_retry);
+}
+
+static inline int
+hostapd_get_retry(struct hostapd_data *hapd, int *short_retry, int *long_retry)
+{
+ if (hapd->driver == NULL || hapd->driver->get_retry == NULL)
+ return 0;
+ return hapd->driver->get_retry(hapd->drv_priv, short_retry,
+ long_retry);
+}
+
+static inline int
+hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
+ int total_flags, int flags_or, int flags_and)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
+ return 0;
+ return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
+ flags_or, flags_and);
+}
+
+static inline int
+hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
+ int *basic_rates, int mode)
+{
+ if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL)
+ return 0;
+ return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates,
+ basic_rates, mode);
+}
+
+static inline int
+hostapd_set_channel_flag(struct hostapd_data *hapd, int mode, int chan,
+ int flag, unsigned char power_level,
+ unsigned char antenna_max)
+{
+ if (hapd->driver == NULL || hapd->driver->set_channel_flag == NULL)
+ return 0;
+ return hapd->driver->set_channel_flag(hapd->drv_priv, mode, chan, flag,
+ power_level, antenna_max);
+}
+
+static inline int
+hostapd_set_regulatory_domain(struct hostapd_data *hapd, unsigned int rd)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->set_regulatory_domain == NULL)
+ return 0;
+ return hapd->driver->set_regulatory_domain(hapd->drv_priv, rd);
+}
+
+static inline int
+hostapd_set_country(struct hostapd_data *hapd, const char *country)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->set_country == NULL)
+ return 0;
+ return hapd->driver->set_country(hapd->drv_priv, country);
+}
+
+static inline int
+hostapd_set_ieee80211d(struct hostapd_data *hapd, int enabled)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->set_ieee80211d == NULL)
+ return 0;
+ return hapd->driver->set_ieee80211d(hapd->drv_priv, enabled);
+}
+
+static inline int
+hostapd_sta_clear_stats(struct hostapd_data *hapd, const u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
+ return 0;
+ return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
+}
+
+static inline int
+hostapd_set_beacon(const char *ifname, struct hostapd_data *hapd,
+ u8 *head, size_t head_len,
+ u8 *tail, size_t tail_len)
+{
+ if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
+ return 0;
+ return hapd->driver->set_beacon(ifname, hapd->drv_priv, head, head_len,
+ tail, tail_len);
+}
+
+static inline int
+hostapd_set_internal_bridge(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_internal_bridge == NULL)
+ return 0;
+ return hapd->driver->set_internal_bridge(hapd->drv_priv, value);
+}
+
+static inline int
+hostapd_set_beacon_int(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_beacon_int == NULL)
+ return 0;
+ return hapd->driver->set_beacon_int(hapd->drv_priv, value);
+}
+
+static inline int
+hostapd_set_dtim_period(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_dtim_period == NULL)
+ return 0;
+ return hapd->driver->set_dtim_period(hapd->conf->iface, hapd->drv_priv,
+ value);
+}
+
+static inline int
+hostapd_set_broadcast_ssid(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_broadcast_ssid == NULL)
+ return 0;
+ return hapd->driver->set_broadcast_ssid(hapd->drv_priv, value);
+}
+
+static inline int
+hostapd_set_cts_protect(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL)
+ return 0;
+ return hapd->driver->set_cts_protect(hapd->drv_priv, value);
+}
+
+static inline int
+hostapd_set_key_tx_rx_threshold(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->set_key_tx_rx_threshold == NULL)
+ return 0;
+ return hapd->driver->set_key_tx_rx_threshold(hapd->drv_priv, value);
+}
+
+static inline int
+hostapd_set_preamble(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_preamble == NULL)
+ return 0;
+ return hapd->driver->set_preamble(hapd->drv_priv, value);
+}
+
+static inline int
+hostapd_set_short_slot_time(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL)
+ return 0;
+ return hapd->driver->set_short_slot_time(hapd->drv_priv, value);
+}
+
+static inline int
+hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
+ int cw_min, int cw_max, int burst_time)
+{
+ if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL)
+ return 0;
+ return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs,
+ cw_min, cw_max, burst_time);
+}
+
+static inline int
+hostapd_bss_add(struct hostapd_data *hapd, const char *ifname, const u8 *bssid)
+{
+ if (hapd->driver == NULL || hapd->driver->bss_add == NULL)
+ return 0;
+ return hapd->driver->bss_add(hapd->drv_priv, ifname, bssid);
+}
+
+static inline int
+hostapd_bss_remove(struct hostapd_data *hapd, const char *ifname)
+{
+ if (hapd->driver == NULL || hapd->driver->bss_remove == NULL)
+ return 0;
+ return hapd->driver->bss_remove(hapd->drv_priv, ifname);
+}
+
+static inline int
+hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *mask)
+{
+ if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL)
+ return 1;
+ return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask);
+}
+
+static inline int
+hostapd_if_add(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
+ char *ifname, const u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->if_add == NULL)
+ return -1;
+ return hapd->driver->if_add(hapd->conf->iface, hapd->drv_priv, type,
+ ifname, addr);
+}
+
+static inline int
+hostapd_if_update(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
+ char *ifname, const u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->if_update == NULL)
+ return -1;
+ return hapd->driver->if_update(hapd->drv_priv, type, ifname, addr);
+}
+
+static inline int
+hostapd_if_remove(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
+ char *ifname, const u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
+ return -1;
+ return hapd->driver->if_remove(hapd->drv_priv, type, ifname, addr);
+}
+
+static inline int
+hostapd_passive_scan(struct hostapd_data *hapd, int now, int our_mode_only,
+ int interval, int _listen, int *channel,
+ int *last_rx)
+{
+ if (hapd->driver == NULL || hapd->driver->passive_scan == NULL)
+ return -1;
+ return hapd->driver->passive_scan(hapd->drv_priv, now, our_mode_only,
+ interval, _listen, channel, last_rx);
+}
+
+static inline struct hostapd_hw_modes *
+hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
+ u16 *flags)
+{
+ if (hapd->driver == NULL || hapd->driver->get_hw_feature_data == NULL)
+ return NULL;
+ return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes,
+ flags);
+}
+
+static inline int
+hostapd_set_sta_vlan(const char *ifname, struct hostapd_data *hapd,
+ const u8 *addr, int vlan_id)
+{
+ if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
+ return 0;
+ return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname, vlan_id);
+}
+
+static inline int
+hostapd_driver_commit(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->driver->commit == NULL)
+ return 0;
+ return hapd->driver->commit(hapd->drv_priv);
+}
+
+#endif /* DRIVER_H */
diff --git a/hostapd/driver_bsd.c b/hostapd/driver_bsd.c
new file mode 100644
index 0000000..14c3662
--- /dev/null
+++ b/hostapd/driver_bsd.c
@@ -0,0 +1,838 @@
+/*
+ * hostapd / Driver interaction with BSD net80211 layer
+ * Copyright (c) 2004, Sam Leffler <sam@errno.com>
+ * Copyright (c) 2004, 2Wire, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+
+/*
+ * Avoid conflicts with hostapd definitions by undefining couple of defines
+ * from net80211 header files.
+ */
+#undef RSN_VERSION
+#undef WPA_VERSION
+#undef WPA_OUI_TYPE
+
+#include "hostapd.h"
+#include "driver.h"
+#include "ieee802_1x.h"
+#include "eloop.h"
+#include "sta_info.h"
+#include "l2_packet/l2_packet.h"
+
+#include "eapol_sm.h"
+#include "wpa.h"
+#include "radius/radius.h"
+#include "ieee802_11.h"
+#include "common.h"
+
+struct bsd_driver_data {
+ struct hostapd_data *hapd; /* back pointer */
+
+ char iface[IFNAMSIZ + 1];
+ struct l2_packet_data *sock_xmit; /* raw packet xmit socket */
+ int ioctl_sock; /* socket for ioctl() use */
+ int wext_sock; /* socket for wireless events */
+};
+
+static int bsd_sta_deauth(void *priv, const u8 *addr, int reason_code);
+
+static int
+set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len)
+{
+ struct ieee80211req ireq;
+
+ memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ);
+ ireq.i_type = op;
+ ireq.i_len = arg_len;
+ ireq.i_data = (void *) arg;
+
+ if (ioctl(drv->ioctl_sock, SIOCS80211, &ireq) < 0) {
+ perror("ioctl[SIOCS80211]");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len)
+{
+ struct ieee80211req ireq;
+
+ memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ);
+ ireq.i_type = op;
+ ireq.i_len = arg_len;
+ ireq.i_data = arg;
+
+ if (ioctl(drv->ioctl_sock, SIOCG80211, &ireq) < 0) {
+ perror("ioctl[SIOCG80211]");
+ return -1;
+ }
+ return ireq.i_len;
+}
+
+static int
+set80211param(struct bsd_driver_data *drv, int op, int arg)
+{
+ struct ieee80211req ireq;
+
+ memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ);
+ ireq.i_type = op;
+ ireq.i_val = arg;
+
+ if (ioctl(drv->ioctl_sock, SIOCS80211, &ireq) < 0) {
+ perror("ioctl[SIOCS80211]");
+ return -1;
+ }
+ return 0;
+}
+
+static const char *
+ether_sprintf(const u8 *addr)
+{
+ static char buf[sizeof(MACSTR)];
+
+ if (addr != NULL)
+ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+ else
+ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
+ return buf;
+}
+
+/*
+ * Configure WPA parameters.
+ */
+static int
+bsd_configure_wpa(struct bsd_driver_data *drv)
+{
+ static const char *ciphernames[] =
+ { "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" };
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+ int v;
+
+ switch (conf->wpa_group) {
+ case WPA_CIPHER_CCMP:
+ v = IEEE80211_CIPHER_AES_CCM;
+ break;
+ case WPA_CIPHER_TKIP:
+ v = IEEE80211_CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_WEP104:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_WEP40:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_NONE:
+ v = IEEE80211_CIPHER_NONE;
+ break;
+ default:
+ printf("Unknown group key cipher %u\n",
+ conf->wpa_group);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)",
+ __func__, ciphernames[v], v);
+ if (set80211param(drv, IEEE80211_IOC_MCASTCIPHER, v)) {
+ printf("Unable to set group key cipher to %u (%s)\n",
+ v, ciphernames[v]);
+ return -1;
+ }
+ if (v == IEEE80211_CIPHER_WEP) {
+ /* key length is done only for specific ciphers */
+ v = (conf->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
+ if (set80211param(drv, IEEE80211_IOC_MCASTKEYLEN, v)) {
+ printf("Unable to set group key length to %u\n", v);
+ return -1;
+ }
+ }
+
+ v = 0;
+ if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
+ v |= 1<<IEEE80211_CIPHER_AES_CCM;
+ if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
+ v |= 1<<IEEE80211_CIPHER_TKIP;
+ if (conf->wpa_pairwise & WPA_CIPHER_NONE)
+ v |= 1<<IEEE80211_CIPHER_NONE;
+ wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
+ if (set80211param(drv, IEEE80211_IOC_UCASTCIPHERS, v)) {
+ printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
+ __func__, conf->wpa_key_mgmt);
+ if (set80211param(drv, IEEE80211_IOC_KEYMGTALGS, conf->wpa_key_mgmt)) {
+ printf("Unable to set key management algorithms to 0x%x\n",
+ conf->wpa_key_mgmt);
+ return -1;
+ }
+
+ v = 0;
+ if (conf->rsn_preauth)
+ v |= BIT(0);
+ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
+ __func__, conf->rsn_preauth);
+ if (set80211param(drv, IEEE80211_IOC_RSNCAPS, v)) {
+ printf("Unable to set RSN capabilities to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, conf->wpa);
+ if (set80211param(drv, IEEE80211_IOC_WPA, conf->wpa)) {
+ printf("Unable to set WPA to %u\n", conf->wpa);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int
+bsd_set_iface_flags(void *priv, int dev_up)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ifreq ifr;
+
+ wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up);
+
+ if (drv->ioctl_sock < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up) {
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
+ ifr.ifr_mtu = HOSTAPD_MTU;
+ if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
+ perror("ioctl[SIOCSIFMTU]");
+ printf("Setting MTU failed - trying to survive with "
+ "current value\n");
+ }
+ }
+
+ return 0;
+}
+
+static int
+bsd_set_ieee8021x(const char *ifname, void *priv, int enabled)
+{
+ struct bsd_driver_data *drv = priv;
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+ if (!enabled) {
+ /* XXX restore state */
+ return set80211param(priv, IEEE80211_IOC_AUTHMODE,
+ IEEE80211_AUTH_AUTO);
+ }
+ if (!conf->wpa && !conf->ieee802_1x) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
+ return -1;
+ }
+ if (conf->wpa && bsd_configure_wpa(drv) != 0) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
+ return -1;
+ }
+ if (set80211param(priv, IEEE80211_IOC_AUTHMODE,
+ (conf->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
+ return -1;
+ }
+ return bsd_set_iface_flags(priv, 1);
+}
+
+static int
+bsd_set_privacy(const char *ifname, void *priv, int enabled)
+{
+ struct bsd_driver_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+ return set80211param(drv, IEEE80211_IOC_PRIVACY, enabled);
+}
+
+static int
+bsd_set_sta_authorized(void *priv, const u8 *addr, int authorized)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
+ __func__, ether_sprintf(addr), authorized);
+
+ if (authorized)
+ mlme.im_op = IEEE80211_MLME_AUTHORIZE;
+ else
+ mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
+ mlme.im_reason = 0;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
+}
+
+static int
+bsd_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or,
+ int flags_and)
+{
+ /* For now, only support setting Authorized flag */
+ if (flags_or & WLAN_STA_AUTHORIZED)
+ return bsd_set_sta_authorized(priv, addr, 1);
+ if (!(flags_and & WLAN_STA_AUTHORIZED))
+ return bsd_set_sta_authorized(priv, addr, 0);
+ return 0;
+}
+
+static int
+bsd_del_key(void *priv, const u8 *addr, int key_idx)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_del_key wk;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
+ __func__, ether_sprintf(addr), key_idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr != NULL) {
+ memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */
+ } else {
+ wk.idk_keyix = key_idx;
+ }
+
+ return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
+}
+
+static int
+bsd_set_key(const char *ifname, void *priv, const char *alg,
+ const u8 *addr, int key_idx,
+ const u8 *key, size_t key_len, int txkey)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+ u_int8_t cipher;
+
+ if (strcmp(alg, "none") == 0)
+ return bsd_del_key(drv, addr, key_idx);
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s addr=%s key_idx=%d",
+ __func__, alg, ether_sprintf(addr), key_idx);
+
+ if (strcmp(alg, "WEP") == 0)
+ cipher = IEEE80211_CIPHER_WEP;
+ else if (strcmp(alg, "TKIP") == 0)
+ cipher = IEEE80211_CIPHER_TKIP;
+ else if (strcmp(alg, "CCMP") == 0)
+ cipher = IEEE80211_CIPHER_AES_CCM;
+ else {
+ printf("%s: unknown/unsupported algorithm %s\n",
+ __func__, alg);
+ return -1;
+ }
+
+ if (key_len > sizeof(wk.ik_keydata)) {
+ printf("%s: key length %d too big\n", __func__, key_len);
+ return -3;
+ }
+
+ memset(&wk, 0, sizeof(wk));
+ wk.ik_type = cipher;
+ wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
+ if (addr == NULL) {
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = key_idx;
+ wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+ } else {
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = IEEE80211_KEYIX_NONE;
+ }
+ wk.ik_keylen = key_len;
+ memcpy(wk.ik_keydata, key, key_len);
+
+ return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
+}
+
+
+static int
+bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
+ u8 *seq)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
+ __func__, ether_sprintf(addr), idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr == NULL)
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ else
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = idx;
+
+ if (get80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) {
+ printf("Failed to get encryption.\n");
+ return -1;
+ }
+
+#ifdef WORDS_BIGENDIAN
+ {
+ /*
+ * wk.ik_keytsc is in host byte order (big endian), need to
+ * swap it to match with the byte order used in WPA.
+ */
+ int i;
+ u8 tmp[WPA_KEY_RSC_LEN];
+ memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+ for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
+ seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
+ }
+ }
+#else /* WORDS_BIGENDIAN */
+ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+#endif /* WORDS_BIGENDIAN */
+ return 0;
+}
+
+
+static int
+bsd_flush(void *priv)
+{
+ u8 allsta[IEEE80211_ADDR_LEN];
+
+ memset(allsta, 0xff, IEEE80211_ADDR_LEN);
+ return bsd_sta_deauth(priv, allsta, IEEE80211_REASON_AUTH_LEAVE);
+}
+
+
+static int
+bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_sta_stats stats;
+
+ memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
+ if (get80211var(drv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) > 0) {
+ /* XXX? do packets counts include non-data frames? */
+ data->rx_packets = stats.is_stats.ns_rx_data;
+ data->rx_bytes = stats.is_stats.ns_rx_bytes;
+ data->tx_packets = stats.is_stats.ns_tx_data;
+ data->tx_bytes = stats.is_stats.ns_tx_bytes;
+ }
+ return 0;
+}
+
+static int
+bsd_set_opt_ie(const char *ifname, void *priv, const u8 *ie, size_t ie_len)
+{
+ /*
+ * Do nothing; we setup parameters at startup that define the
+ * contents of the beacon information element.
+ */
+ return 0;
+}
+
+static int
+bsd_sta_deauth(void *priv, const u8 *addr, int reason_code)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
+}
+
+static int
+bsd_sta_disassoc(void *priv, const u8 *addr, int reason_code)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DISASSOC;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
+}
+
+static int
+bsd_del_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+ struct sta_info *sta;
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "deassociated");
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta != NULL) {
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ if (conf->wpa)
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ ap_free_sta(hapd, sta);
+ }
+ return 0;
+}
+
+static int
+bsd_new_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+ struct sta_info *sta;
+ struct ieee80211req_wpaie ie;
+ int new_assoc, ielen, res;
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "associated");
+
+ sta = ap_sta_add(hapd, addr);
+ if (sta == NULL)
+ return -1;
+ /*
+ * Fetch and validate any negotiated WPA/RSN parameters.
+ */
+ if (conf->wpa) {
+ memset(&ie, 0, sizeof(ie));
+ memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
+ if (get80211var(drv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) {
+ printf("Failed to get WPA/RSN information element.\n");
+ return -1; /* XXX not right */
+ }
+ ielen = ie.wpa_ie[1];
+ if (ielen == 0) {
+ printf("No WPA/RSN information element for station!\n");
+ return -1; /* XXX not right */
+ }
+ ielen += 2;
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr);
+ if (sta->wpa_sm == NULL) {
+ printf("Failed to initialize WPA state machine\n");
+ return -1;
+ }
+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ ie.wpa_ie, ielen, NULL, 0);
+ if (res != WPA_IE_OK) {
+ printf("WPA/RSN information element rejected? "
+ "(res %u)\n", res);
+ return -1;
+ }
+ }
+
+ /*
+ * Now that the internal station state is setup
+ * kick the authenticator into action.
+ */
+ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
+ hostapd_new_assoc_sta(hapd, sta, !new_assoc);
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+ return 0;
+}
+
+#include <net/route.h>
+#include <net80211/ieee80211_freebsd.h>
+
+static void
+bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
+{
+ struct bsd_driver_data *drv = ctx;
+ struct hostapd_data *hapd = drv->hapd;
+ char buf[2048];
+ struct if_announcemsghdr *ifan;
+ struct rt_msghdr *rtm;
+ struct ieee80211_michael_event *mic;
+ struct ieee80211_join_event *join;
+ struct ieee80211_leave_event *leave;
+ int n;
+
+ n = read(sock, buf, sizeof(buf));
+ if (n < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("read(PF_ROUTE)");
+ return;
+ }
+
+ rtm = (struct rt_msghdr *) buf;
+ if (rtm->rtm_version != RTM_VERSION) {
+ wpa_printf(MSG_DEBUG, "Routing message version %d not "
+ "understood\n", rtm->rtm_version);
+ return;
+ }
+ ifan = (struct if_announcemsghdr *) rtm;
+ switch (rtm->rtm_type) {
+ case RTM_IEEE80211:
+ switch (ifan->ifan_what) {
+ case RTM_IEEE80211_ASSOC:
+ case RTM_IEEE80211_REASSOC:
+ case RTM_IEEE80211_DISASSOC:
+ case RTM_IEEE80211_SCAN:
+ break;
+ case RTM_IEEE80211_LEAVE:
+ leave = (struct ieee80211_leave_event *) &ifan[1];
+ bsd_del_sta(drv, leave->iev_addr);
+ break;
+ case RTM_IEEE80211_JOIN:
+#ifdef RTM_IEEE80211_REJOIN
+ case RTM_IEEE80211_REJOIN:
+#endif
+ join = (struct ieee80211_join_event *) &ifan[1];
+ bsd_new_sta(drv, join->iev_addr);
+ break;
+ case RTM_IEEE80211_REPLAY:
+ /* ignore */
+ break;
+ case RTM_IEEE80211_MICHAEL:
+ mic = (struct ieee80211_michael_event *) &ifan[1];
+ wpa_printf(MSG_DEBUG,
+ "Michael MIC failure wireless event: "
+ "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
+ MAC2STR(mic->iev_src));
+ ieee80211_michael_mic_failure(hapd, mic->iev_src, 1);
+ break;
+ }
+ break;
+ }
+}
+
+static int
+bsd_wireless_event_init(void *priv)
+{
+ struct bsd_driver_data *drv = priv;
+ int s;
+
+ drv->wext_sock = -1;
+
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0) {
+ perror("socket(PF_ROUTE,SOCK_RAW)");
+ return -1;
+ }
+ eloop_register_read_sock(s, bsd_wireless_event_receive, drv, NULL);
+ drv->wext_sock = s;
+
+ return 0;
+}
+
+static void
+bsd_wireless_event_deinit(void *priv)
+{
+ struct bsd_driver_data *drv = priv;
+
+ if (drv != NULL) {
+ if (drv->wext_sock < 0)
+ return;
+ eloop_unregister_read_sock(drv->wext_sock);
+ close(drv->wext_sock);
+ }
+}
+
+
+static int
+bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
+ int encrypt, const u8 *own_addr)
+{
+ struct bsd_driver_data *drv = priv;
+ unsigned char buf[3000];
+ unsigned char *bp = buf;
+ struct l2_ethhdr *eth;
+ size_t len;
+ int status;
+
+ /*
+ * Prepend the Etherent header. If the caller left us
+ * space at the front we could just insert it but since
+ * we don't know we copy to a local buffer. Given the frequency
+ * and size of frames this probably doesn't matter.
+ */
+ len = data_len + sizeof(struct l2_ethhdr);
+ if (len > sizeof(buf)) {
+ bp = malloc(len);
+ if (bp == NULL) {
+ printf("EAPOL frame discarded, cannot malloc temp "
+ "buffer of size %u!\n", len);
+ return -1;
+ }
+ }
+ eth = (struct l2_ethhdr *) bp;
+ memcpy(eth->h_dest, addr, ETH_ALEN);
+ memcpy(eth->h_source, own_addr, ETH_ALEN);
+ eth->h_proto = htons(ETH_P_EAPOL);
+ memcpy(eth+1, data, data_len);
+
+ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
+
+ status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
+
+ if (bp != buf)
+ free(bp);
+ return status;
+}
+
+static void
+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+ struct bsd_driver_data *drv = ctx;
+ struct hostapd_data *hapd = drv->hapd;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, src_addr);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+ printf("Data frame from not associated STA %s\n",
+ ether_sprintf(src_addr));
+ /* XXX cannot happen */
+ return;
+ }
+ ieee802_1x_receive(hapd, src_addr, buf + sizeof(struct l2_ethhdr),
+ len - sizeof(struct l2_ethhdr));
+}
+
+static int
+bsd_get_ssid(const char *ifname, void *priv, u8 *buf, int len)
+{
+ struct bsd_driver_data *drv = priv;
+ int ssid_len = get80211var(drv, IEEE80211_IOC_SSID, buf, len);
+
+ wpa_printf(MSG_DEBUG, "%s: ssid=\"%.*s\"", __func__, ssid_len, buf);
+
+ return ssid_len;
+}
+
+static int
+bsd_set_ssid(const char *ifname, void *priv, const u8 *buf, int len)
+{
+ struct bsd_driver_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: ssid=\"%.*s\"", __func__, len, buf);
+
+ return set80211var(drv, IEEE80211_IOC_SSID, buf, len);
+}
+
+static void *
+bsd_init(struct hostapd_data *hapd)
+{
+ struct bsd_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct bsd_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for bsd driver data\n");
+ goto bad;
+ }
+
+ drv->hapd = hapd;
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ goto bad;
+ }
+ memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
+
+ drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
+ handle_read, drv, 1);
+ if (drv->sock_xmit == NULL)
+ goto bad;
+ if (l2_packet_get_own_addr(drv->sock_xmit, hapd->own_addr))
+ goto bad;
+
+ bsd_set_iface_flags(drv, 0); /* mark down during setup */
+
+ return drv;
+bad:
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv != NULL)
+ free(drv);
+ return NULL;
+}
+
+
+static void
+bsd_deinit(void *priv)
+{
+ struct bsd_driver_data *drv = priv;
+
+ (void) bsd_set_iface_flags(drv, 0);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ free(drv);
+}
+
+const struct wpa_driver_ops wpa_driver_bsd_ops = {
+ .name = "bsd",
+ .init = bsd_init,
+ .deinit = bsd_deinit,
+ .set_ieee8021x = bsd_set_ieee8021x,
+ .set_privacy = bsd_set_privacy,
+ .set_encryption = bsd_set_key,
+ .get_seqnum = bsd_get_seqnum,
+ .flush = bsd_flush,
+ .set_generic_elem = bsd_set_opt_ie,
+ .wireless_event_init = bsd_wireless_event_init,
+ .wireless_event_deinit = bsd_wireless_event_deinit,
+ .sta_set_flags = bsd_sta_set_flags,
+ .read_sta_data = bsd_read_sta_driver_data,
+ .send_eapol = bsd_send_eapol,
+ .sta_disassoc = bsd_sta_disassoc,
+ .sta_deauth = bsd_sta_deauth,
+ .set_ssid = bsd_set_ssid,
+ .get_ssid = bsd_get_ssid,
+};
diff --git a/hostapd/driver_hostap.c b/hostapd/driver_hostap.c
new file mode 100644
index 0000000..7817143
--- /dev/null
+++ b/hostapd/driver_hostap.c
@@ -0,0 +1,1235 @@
+/*
+ * hostapd / Kernel driver communication with Linux Host AP driver
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#ifdef USE_KERNEL_HEADERS
+#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h> /* The L2 protocols */
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#else /* USE_KERNEL_HEADERS */
+#include <net/if_arp.h>
+#include <netpacket/packet.h>
+#include "wireless_copy.h"
+#endif /* USE_KERNEL_HEADERS */
+
+#include "hostapd.h"
+#include "driver.h"
+#include "ieee802_1x.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "hostap_common.h"
+#include "hw_features.h"
+
+
+struct hostap_driver_data {
+ struct hostapd_data *hapd;
+
+ char iface[IFNAMSIZ + 1];
+ int sock; /* raw packet socket for driver access */
+ int ioctl_sock; /* socket for ioctl() use */
+ int wext_sock; /* socket for wireless events */
+
+ int we_version;
+
+ u8 *generic_ie;
+ size_t generic_ie_len;
+};
+
+
+static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param,
+ int len);
+static int hostap_set_iface_flags(void *priv, int dev_up);
+
+static void handle_data(struct hostapd_data *hapd, u8 *buf, size_t len,
+ u16 stype)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc, ethertype;
+ u8 *pos, *sa;
+ size_t left;
+ struct sta_info *sta;
+
+ if (len < sizeof(struct ieee80211_hdr))
+ return;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ if ((fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) != WLAN_FC_TODS) {
+ printf("Not ToDS data frame (fc=0x%04x)\n", fc);
+ return;
+ }
+
+ sa = hdr->addr2;
+ sta = ap_get_sta(hapd, sa);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+ printf("Data frame from not associated STA " MACSTR "\n",
+ MAC2STR(sa));
+ if (sta && (sta->flags & WLAN_STA_AUTH))
+ hostapd_sta_disassoc(
+ hapd, sa,
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+ else
+ hostapd_sta_deauth(
+ hapd, sa,
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+ return;
+ }
+
+ pos = (u8 *) (hdr + 1);
+ left = len - sizeof(*hdr);
+
+ if (left < sizeof(rfc1042_header)) {
+ printf("Too short data frame\n");
+ return;
+ }
+
+ if (memcmp(pos, rfc1042_header, sizeof(rfc1042_header)) != 0) {
+ printf("Data frame with no RFC1042 header\n");
+ return;
+ }
+ pos += sizeof(rfc1042_header);
+ left -= sizeof(rfc1042_header);
+
+ if (left < 2) {
+ printf("No ethertype in data frame\n");
+ return;
+ }
+
+ ethertype = WPA_GET_BE16(pos);
+ pos += 2;
+ left -= 2;
+ switch (ethertype) {
+ case ETH_P_PAE:
+ ieee802_1x_receive(hapd, sa, pos, left);
+ break;
+
+ default:
+ printf("Unknown ethertype 0x%04x in data frame\n", ethertype);
+ break;
+ }
+}
+
+
+static void handle_tx_callback(struct hostapd_data *hapd, u8 *buf, size_t len,
+ int ok)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc, type, stype;
+ struct sta_info *sta;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ switch (type) {
+ case WLAN_FC_TYPE_MGMT:
+ wpa_printf(MSG_DEBUG, "MGMT (TX callback) %s",
+ ok ? "ACK" : "fail");
+ ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ wpa_printf(MSG_DEBUG, "CTRL (TX callback) %s",
+ ok ? "ACK" : "fail");
+ break;
+ case WLAN_FC_TYPE_DATA:
+ wpa_printf(MSG_DEBUG, "DATA (TX callback) %s",
+ ok ? "ACK" : "fail");
+ sta = ap_get_sta(hapd, hdr->addr1);
+ if (sta && sta->flags & WLAN_STA_PENDING_POLL) {
+ wpa_printf(MSG_DEBUG, "STA " MACSTR
+ " %s pending activity poll",
+ MAC2STR(sta->addr),
+ ok ? "ACKed" : "did not ACK");
+ if (ok)
+ sta->flags &= ~WLAN_STA_PENDING_POLL;
+ }
+ if (sta)
+ ieee802_1x_tx_status(hapd, sta, buf, len, ok);
+ break;
+ default:
+ printf("unknown TX callback frame type %d\n", type);
+ break;
+ }
+}
+
+
+static void handle_frame(struct hostapd_data *hapd, u8 *buf, size_t len)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc, extra_len, type, stype;
+ unsigned char *extra = NULL;
+ size_t data_len = len;
+ int ver;
+
+ /* PSPOLL is only 16 bytes, but driver does not (at least yet) pass
+ * these to user space */
+ if (len < 24) {
+ wpa_printf(MSG_MSGDUMP, "handle_frame: too short (%lu)",
+ (unsigned long) len);
+ return;
+ }
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ if (type != WLAN_FC_TYPE_MGMT || stype != WLAN_FC_STYPE_BEACON) {
+ wpa_hexdump(MSG_MSGDUMP, "Received management frame",
+ buf, len);
+ }
+
+ ver = fc & WLAN_FC_PVER;
+
+ /* protocol version 3 is reserved for indicating extra data after the
+ * payload, version 2 for indicating ACKed frame (TX callbacks), and
+ * version 1 for indicating failed frame (no ACK, TX callbacks) */
+ if (ver == 3) {
+ u8 *pos = buf + len - 2;
+ extra_len = WPA_GET_LE16(pos);
+ printf("extra data in frame (elen=%d)\n", extra_len);
+ if ((size_t) extra_len + 2 > len) {
+ printf(" extra data overflow\n");
+ return;
+ }
+ len -= extra_len + 2;
+ extra = buf + len;
+ } else if (ver == 1 || ver == 2) {
+ handle_tx_callback(hapd, buf, data_len, ver == 2 ? 1 : 0);
+ return;
+ } else if (ver != 0) {
+ printf("unknown protocol version %d\n", ver);
+ return;
+ }
+
+ switch (type) {
+ case WLAN_FC_TYPE_MGMT:
+ if (stype != WLAN_FC_STYPE_BEACON)
+ wpa_printf(MSG_MSGDUMP, "MGMT");
+ ieee802_11_mgmt(hapd, buf, data_len, stype, NULL);
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ wpa_printf(MSG_DEBUG, "CTRL");
+ break;
+ case WLAN_FC_TYPE_DATA:
+ wpa_printf(MSG_DEBUG, "DATA");
+ handle_data(hapd, buf, data_len, stype);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "unknown frame type %d", type);
+ break;
+ }
+}
+
+
+static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ handle_frame(hapd, buf, len);
+}
+
+
+static int hostap_init_sockets(struct hostap_driver_data *drv)
+{
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+
+ drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (drv->sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->sock, handle_read, drv->hapd, NULL))
+ {
+ printf("Could not register read socket\n");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface);
+ if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ return -1;
+ }
+
+ if (hostap_set_iface_flags(drv, 1)) {
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifr.ifr_ifindex;
+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
+ addr.sll_ifindex);
+
+ if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+ if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
+ perror("ioctl(SIOCGIFHWADDR)");
+ return -1;
+ }
+
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ printf("Invalid HW-addr family 0x%04x\n",
+ ifr.ifr_hwaddr.sa_family);
+ return -1;
+ }
+ memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ return 0;
+}
+
+
+static int hostap_send_mgmt_frame(void *priv, const void *msg, size_t len,
+ int flags)
+{
+ struct hostap_driver_data *drv = priv;
+
+ return send(drv->sock, msg, len, flags);
+}
+
+
+static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt, const u8 *own_addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ieee80211_hdr *hdr;
+ size_t len;
+ u8 *pos;
+ int res;
+
+ len = sizeof(*hdr) + sizeof(rfc1042_header) + 2 + data_len;
+ hdr = os_zalloc(len);
+ if (hdr == NULL) {
+ printf("malloc() failed for hostapd_send_data(len=%lu)\n",
+ (unsigned long) len);
+ return -1;
+ }
+
+ hdr->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
+ hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
+ /* Request TX callback */
+ hdr->frame_control |= host_to_le16(BIT(1));
+ if (encrypt)
+ hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+ memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+ pos = (u8 *) (hdr + 1);
+ memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
+ pos += sizeof(rfc1042_header);
+ *((u16 *) pos) = htons(ETH_P_PAE);
+ pos += 2;
+ memcpy(pos, data, data_len);
+
+ res = hostap_send_mgmt_frame(drv, (u8 *) hdr, len, 0);
+ free(hdr);
+
+ if (res < 0) {
+ perror("hostapd_send_eapol: send");
+ printf("hostapd_send_eapol - packet len: %lu - failed\n",
+ (unsigned long) len);
+ }
+
+ return res;
+}
+
+
+static int hostap_sta_set_flags(void *priv, const u8 *addr,
+ int total_flags, int flags_or, int flags_and)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ param.u.set_flags_sta.flags_or = flags_or;
+ param.u.set_flags_sta.flags_and = flags_and;
+ return hostapd_ioctl(drv, &param, sizeof(param));
+}
+
+
+static int hostap_set_iface_flags(void *priv, int dev_up)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ifreq ifr;
+
+ if (drv->ioctl_sock < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, IFNAMSIZ, "%sap", drv->iface);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up) {
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, IFNAMSIZ, "%sap", drv->iface);
+ ifr.ifr_mtu = HOSTAPD_MTU;
+ if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
+ perror("ioctl[SIOCSIFMTU]");
+ printf("Setting MTU failed - trying to survive with "
+ "current value\n");
+ }
+ }
+
+ return 0;
+}
+
+
+static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param,
+ int len)
+{
+ struct hostap_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) param;
+ iwr.u.data.length = len;
+
+ if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
+ perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostap_set_encryption(const char *ifname, void *priv,
+ const char *alg, const u8 *addr,
+ int idx, const u8 *key, size_t key_len,
+ int txkey)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ u8 *buf;
+ size_t blen;
+ int ret = 0;
+
+ blen = sizeof(*param) + key_len;
+ buf = os_zalloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ param = (struct prism2_hostapd_param *) buf;
+ param->cmd = PRISM2_SET_ENCRYPTION;
+ if (addr == NULL)
+ memset(param->sta_addr, 0xff, ETH_ALEN);
+ else
+ memcpy(param->sta_addr, addr, ETH_ALEN);
+ os_strlcpy((char *) param->u.crypt.alg, alg,
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ param->u.crypt.flags = txkey ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
+ param->u.crypt.idx = idx;
+ param->u.crypt.key_len = key_len;
+ memcpy((u8 *) (param + 1), key, key_len);
+
+ if (hostapd_ioctl(drv, param, blen)) {
+ printf("Failed to set encryption.\n");
+ ret = -1;
+ }
+ free(buf);
+
+ return ret;
+}
+
+
+static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr,
+ int idx, u8 *seq)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ u8 *buf;
+ size_t blen;
+ int ret = 0;
+
+ blen = sizeof(*param) + 32;
+ buf = os_zalloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ param = (struct prism2_hostapd_param *) buf;
+ param->cmd = PRISM2_GET_ENCRYPTION;
+ if (addr == NULL)
+ memset(param->sta_addr, 0xff, ETH_ALEN);
+ else
+ memcpy(param->sta_addr, addr, ETH_ALEN);
+ param->u.crypt.idx = idx;
+
+ if (hostapd_ioctl(drv, param, blen)) {
+ printf("Failed to get encryption.\n");
+ ret = -1;
+ } else {
+ memcpy(seq, param->u.crypt.seq, 8);
+ }
+ free(buf);
+
+ return ret;
+}
+
+
+static int hostap_ioctl_prism2param(void *priv, int param, int value)
+{
+ struct hostap_driver_data *drv = priv;
+ struct iwreq iwr;
+ int *i;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ i = (int *) iwr.u.name;
+ *i++ = param;
+ *i++ = value;
+
+ if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
+ perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostap_set_ieee8021x(const char *ifname, void *priv, int enabled)
+{
+ struct hostap_driver_data *drv = priv;
+
+ /* enable kernel driver support for IEEE 802.1X */
+ if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_IEEE_802_1X, enabled)) {
+ printf("Could not setup IEEE 802.1X support in kernel driver."
+ "\n");
+ return -1;
+ }
+
+ if (!enabled)
+ return 0;
+
+ /* use host driver implementation of encryption to allow
+ * individual keys and passing plaintext EAPOL frames */
+ if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_DECRYPT, 1) ||
+ hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_ENCRYPT, 1)) {
+ printf("Could not setup host-based encryption in kernel "
+ "driver.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostap_set_privacy(const char *ifname, void *priv, int enabled)
+{
+ struct hostap_drvier_data *drv = priv;
+
+ return hostap_ioctl_prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
+ enabled);
+}
+
+
+static int hostap_set_ssid(const char *ifname, void *priv, const u8 *buf,
+ int len)
+{
+ struct hostap_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.flags = 1; /* SSID active */
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len + 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ printf("len=%d\n", len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostap_flush(void *priv)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_FLUSH;
+ return hostapd_ioctl(drv, &param, sizeof(param));
+}
+
+
+static int hostap_read_sta_data(void *priv,
+ struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ char buf[1024], line[128], *pos;
+ FILE *f;
+ unsigned long val;
+
+ memset(data, 0, sizeof(*data));
+ snprintf(buf, sizeof(buf), "/proc/net/hostap/%s/" MACSTR,
+ drv->iface, MAC2STR(addr));
+
+ f = fopen(buf, "r");
+ if (!f)
+ return -1;
+ /* Need to read proc file with in one piece, so use large enough
+ * buffer. */
+ setbuffer(f, buf, sizeof(buf));
+
+ while (fgets(line, sizeof(line), f)) {
+ pos = strchr(line, '=');
+ if (!pos)
+ continue;
+ *pos++ = '\0';
+ val = strtoul(pos, NULL, 10);
+ if (strcmp(line, "rx_packets") == 0)
+ data->rx_packets = val;
+ else if (strcmp(line, "tx_packets") == 0)
+ data->tx_packets = val;
+ else if (strcmp(line, "rx_bytes") == 0)
+ data->rx_bytes = val;
+ else if (strcmp(line, "tx_bytes") == 0)
+ data->tx_bytes = val;
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+
+static int hostap_sta_add(const char *ifname, void *priv, const u8 *addr,
+ u16 aid, u16 capability, u8 *supp_rates,
+ size_t supp_rates_len, int flags)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+ int tx_supp_rates = 0;
+ size_t i;
+
+#define WLAN_RATE_1M BIT(0)
+#define WLAN_RATE_2M BIT(1)
+#define WLAN_RATE_5M5 BIT(2)
+#define WLAN_RATE_11M BIT(3)
+
+ for (i = 0; i < supp_rates_len; i++) {
+ if ((supp_rates[i] & 0x7f) == 2)
+ tx_supp_rates |= WLAN_RATE_1M;
+ if ((supp_rates[i] & 0x7f) == 4)
+ tx_supp_rates |= WLAN_RATE_2M;
+ if ((supp_rates[i] & 0x7f) == 11)
+ tx_supp_rates |= WLAN_RATE_5M5;
+ if ((supp_rates[i] & 0x7f) == 22)
+ tx_supp_rates |= WLAN_RATE_11M;
+ }
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_ADD_STA;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ param.u.add_sta.aid = aid;
+ param.u.add_sta.capability = capability;
+ param.u.add_sta.tx_supp_rates = tx_supp_rates;
+ return hostapd_ioctl(drv, &param, sizeof(param));
+}
+
+
+static int hostap_sta_remove(void *priv, const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ hostap_sta_set_flags(drv, addr, 0, 0, ~WLAN_STA_AUTHORIZED);
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_REMOVE_STA;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ if (hostapd_ioctl(drv, &param, sizeof(param))) {
+ printf("Could not remove station from kernel driver.\n");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int hostap_get_inact_sec(void *priv, const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_GET_INFO_STA;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ if (hostapd_ioctl(drv, &param, sizeof(param))) {
+ return -1;
+ }
+
+ return param.u.get_info_sta.inactive_sec;
+}
+
+
+static int hostap_sta_clear_stats(void *priv, const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_STA_CLEAR_STATS;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ if (hostapd_ioctl(drv, &param, sizeof(param))) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostap_set_assoc_ap(void *priv, const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ if (hostapd_ioctl(drv, &param, sizeof(param)))
+ return -1;
+
+ return 0;
+}
+
+
+static int hostapd_ioctl_set_generic_elem(struct hostap_driver_data *drv)
+{
+ struct prism2_hostapd_param *param;
+ int res;
+ size_t blen, elem_len;
+
+ elem_len = drv->generic_ie_len;
+ blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + elem_len;
+ if (blen < sizeof(*param))
+ blen = sizeof(*param);
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
+ param->u.generic_elem.len = elem_len;
+ if (drv->generic_ie) {
+ os_memcpy(param->u.generic_elem.data, drv->generic_ie,
+ drv->generic_ie_len);
+ }
+ wpa_hexdump(MSG_DEBUG, "hostap: Set generic IE",
+ param->u.generic_elem.data, elem_len);
+ res = hostapd_ioctl(drv, param, blen);
+
+ os_free(param);
+
+ return res;
+}
+
+
+static int hostap_set_generic_elem(const char *ifname, void *priv,
+ const u8 *elem, size_t elem_len)
+{
+ struct hostap_driver_data *drv = priv;
+
+ os_free(drv->generic_ie);
+ drv->generic_ie = NULL;
+ drv->generic_ie_len = 0;
+ if (elem) {
+ drv->generic_ie = os_malloc(elem_len);
+ if (drv->generic_ie == NULL)
+ return -1;
+ os_memcpy(drv->generic_ie, elem, elem_len);
+ drv->generic_ie_len = elem_len;
+ }
+
+ return hostapd_ioctl_set_generic_elem(drv);
+}
+
+
+static void
+hostapd_wireless_event_wireless_custom(struct hostap_driver_data *drv,
+ char *custom)
+{
+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ char *pos;
+ u8 addr[ETH_ALEN];
+ pos = strstr(custom, "addr=");
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "without sender address ignored");
+ return;
+ }
+ pos += 5;
+ if (hwaddr_aton(pos, addr) == 0) {
+ ieee80211_michael_mic_failure(drv->hapd, addr, 1);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "with invalid MAC address");
+ }
+ }
+}
+
+
+static void hostapd_wireless_event_wireless(struct hostap_driver_data *drv,
+ char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (drv->we_version > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ iwe->cmd == IWEVCUSTOM)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return;
+ memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ hostapd_wireless_event_wireless_custom(drv, buf);
+ free(buf);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void hostapd_wireless_event_rtm_newlink(struct hostap_driver_data *drv,
+ struct nlmsghdr *h, int len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < (int) sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ /* TODO: use ifi->ifi_index to filter out wireless events from other
+ * interfaces */
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ hostapd_wireless_event_wireless(
+ drv, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void hostapd_wireless_event_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ char buf[256];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ struct hostap_driver_data *drv = eloop_ctx;
+
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (left >= (int) sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ printf("Malformed netlink message: "
+ "len=%d left=%d plen=%d\n",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ hostapd_wireless_event_rtm_newlink(drv, h, plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ printf("%d extra bytes in the end of netlink message\n", left);
+ }
+}
+
+
+static int hostap_get_we_version(struct hostap_driver_data *drv)
+{
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ drv->we_version = 0;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->we_version = range->we_version_compiled;
+ }
+
+ free(range);
+ return 0;
+}
+
+
+static int hostap_wireless_event_init(void *priv)
+{
+ struct hostap_driver_data *drv = priv;
+ int s;
+ struct sockaddr_nl local;
+
+ hostap_get_we_version(drv);
+
+ drv->wext_sock = -1;
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ return -1;
+ }
+
+ memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ return -1;
+ }
+
+ eloop_register_read_sock(s, hostapd_wireless_event_receive, drv,
+ NULL);
+ drv->wext_sock = s;
+
+ return 0;
+}
+
+
+static void hostap_wireless_event_deinit(void *priv)
+{
+ struct hostap_driver_data *drv = priv;
+ if (drv->wext_sock < 0)
+ return;
+ eloop_unregister_read_sock(drv->wext_sock);
+ close(drv->wext_sock);
+}
+
+
+static void * hostap_init(struct hostapd_data *hapd)
+{
+ struct hostap_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct hostap_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for hostapd driver data\n");
+ return NULL;
+ }
+
+ drv->hapd = hapd;
+ drv->ioctl_sock = drv->sock = -1;
+ memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
+
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ free(drv);
+ return NULL;
+ }
+
+ if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 1)) {
+ printf("Could not enable hostapd mode for interface %s\n",
+ drv->iface);
+ close(drv->ioctl_sock);
+ free(drv);
+ return NULL;
+ }
+
+ if (hapd->conf->assoc_ap &&
+ hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD_STA, 1)) {
+ printf("Could not enable hostapd STA mode for interface %s\n",
+ drv->iface);
+ close(drv->ioctl_sock);
+ free(drv);
+ return NULL;
+ }
+
+ if (hostap_init_sockets(drv)) {
+ close(drv->ioctl_sock);
+ free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void hostap_driver_deinit(void *priv)
+{
+ struct hostap_driver_data *drv = priv;
+
+ (void) hostap_set_iface_flags(drv, 0);
+ (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 0);
+ (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD_STA, 0);
+
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+
+ if (drv->sock >= 0)
+ close(drv->sock);
+
+ os_free(drv->generic_ie);
+
+ free(drv);
+}
+
+
+static int hostap_sta_deauth(void *priv, const u8 *addr, int reason)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ieee80211_mgmt mgmt;
+
+ memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DEAUTH);
+ memcpy(mgmt.da, addr, ETH_ALEN);
+ memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN);
+ memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN);
+ mgmt.u.deauth.reason_code = host_to_le16(reason);
+ return hostap_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth), 0);
+}
+
+
+static int hostap_sta_disassoc(void *priv, const u8 *addr, int reason)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ieee80211_mgmt mgmt;
+
+ memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DISASSOC);
+ memcpy(mgmt.da, addr, ETH_ALEN);
+ memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN);
+ memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN);
+ mgmt.u.disassoc.reason_code = host_to_le16(reason);
+ return hostap_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN +
+ sizeof(mgmt.u.disassoc), 0);
+}
+
+
+static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv,
+ u16 *num_modes,
+ u16 *flags)
+{
+ struct hostapd_hw_modes *mode;
+ int i, clen, rlen;
+ const short chan2freq[14] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+ 2447, 2452, 2457, 2462, 2467, 2472, 2484
+ };
+
+ mode = os_zalloc(sizeof(struct hostapd_hw_modes));
+ if (mode == NULL)
+ return NULL;
+
+ *num_modes = 1;
+ *flags = 0;
+
+ mode->mode = HOSTAPD_MODE_IEEE80211B;
+ mode->num_channels = 14;
+ mode->num_rates = 4;
+
+ clen = mode->num_channels * sizeof(struct hostapd_channel_data);
+ rlen = mode->num_rates * sizeof(struct hostapd_rate_data);
+
+ mode->channels = os_zalloc(clen);
+ mode->rates = os_zalloc(rlen);
+ if (mode->channels == NULL || mode->rates == NULL) {
+ hostapd_free_hw_features(mode, *num_modes);
+ return NULL;
+ }
+
+ for (i = 0; i < 14; i++) {
+ mode->channels[i].chan = i + 1;
+ mode->channels[i].freq = chan2freq[i];
+ }
+
+ mode->rates[0].rate = 10;
+ mode->rates[0].flags = HOSTAPD_RATE_CCK;
+ mode->rates[1].rate = 20;
+ mode->rates[1].flags = HOSTAPD_RATE_CCK;
+ mode->rates[2].rate = 55;
+ mode->rates[2].flags = HOSTAPD_RATE_CCK;
+ mode->rates[3].rate = 110;
+ mode->rates[3].flags = HOSTAPD_RATE_CCK;
+
+ return mode;
+}
+
+
+const struct wpa_driver_ops wpa_driver_hostap_ops = {
+ .name = "hostap",
+ .init = hostap_init,
+ .deinit = hostap_driver_deinit,
+ .wireless_event_init = hostap_wireless_event_init,
+ .wireless_event_deinit = hostap_wireless_event_deinit,
+ .set_ieee8021x = hostap_set_ieee8021x,
+ .set_privacy = hostap_set_privacy,
+ .set_encryption = hostap_set_encryption,
+ .get_seqnum = hostap_get_seqnum,
+ .flush = hostap_flush,
+ .set_generic_elem = hostap_set_generic_elem,
+ .read_sta_data = hostap_read_sta_data,
+ .send_eapol = hostap_send_eapol,
+ .sta_set_flags = hostap_sta_set_flags,
+ .sta_deauth = hostap_sta_deauth,
+ .sta_disassoc = hostap_sta_disassoc,
+ .sta_remove = hostap_sta_remove,
+ .set_ssid = hostap_set_ssid,
+ .send_mgmt_frame = hostap_send_mgmt_frame,
+ .set_assoc_ap = hostap_set_assoc_ap,
+ .sta_add = hostap_sta_add,
+ .get_inact_sec = hostap_get_inact_sec,
+ .sta_clear_stats = hostap_sta_clear_stats,
+ .get_hw_feature_data = hostap_get_hw_feature_data,
+};
diff --git a/hostapd/driver_madwifi.c b/hostapd/driver_madwifi.c
new file mode 100644
index 0000000..9c3ebff
--- /dev/null
+++ b/hostapd/driver_madwifi.c
@@ -0,0 +1,1363 @@
+/*
+ * hostapd / Driver interaction with MADWIFI 802.11 driver
+ * Copyright (c) 2004, Sam Leffler <sam@errno.com>
+ * Copyright (c) 2004, Video54 Technologies
+ * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include <include/compat.h>
+#include <net80211/ieee80211.h>
+#ifdef WME_NUM_AC
+/* Assume this is built against BSD branch of madwifi driver. */
+#define MADWIFI_BSD
+#include <net80211/_ieee80211.h>
+#endif /* WME_NUM_AC */
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+
+/*
+ * Avoid conflicts with hostapd definitions by undefining couple of defines
+ * from madwifi header files.
+ */
+#undef RSN_VERSION
+#undef WPA_VERSION
+#undef WPA_OUI_TYPE
+
+
+#ifdef IEEE80211_IOCTL_SETWMMPARAMS
+/* Assume this is built against madwifi-ng */
+#define MADWIFI_NG
+#endif /* IEEE80211_IOCTL_SETWMMPARAMS */
+
+#include "wireless_copy.h"
+
+#include "hostapd.h"
+#include "driver.h"
+#include "ieee802_1x.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "sta_info.h"
+#include "l2_packet/l2_packet.h"
+
+#include "wpa.h"
+#include "radius/radius.h"
+#include "ieee802_11.h"
+#include "accounting.h"
+#include "common.h"
+
+
+struct madwifi_driver_data {
+ struct hostapd_data *hapd; /* back pointer */
+
+ char iface[IFNAMSIZ + 1];
+ int ifindex;
+ struct l2_packet_data *sock_xmit; /* raw packet xmit socket */
+ struct l2_packet_data *sock_recv; /* raw packet recv socket */
+ int ioctl_sock; /* socket for ioctl() use */
+ int wext_sock; /* socket for wireless events */
+ int we_version;
+ u8 acct_mac[ETH_ALEN];
+ struct hostap_sta_driver_data acct_data;
+
+ struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
+};
+
+static int madwifi_sta_deauth(void *priv, const u8 *addr, int reason_code);
+
+static int
+set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
+{
+ struct iwreq iwr;
+ int do_inline = len < IFNAMSIZ;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+ /* FILTERFRAME must be NOT inline, regardless of size. */
+ if (op == IEEE80211_IOCTL_FILTERFRAME)
+ do_inline = 0;
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+ if (do_inline) {
+ /*
+ * Argument data fits inline; put it there.
+ */
+ memcpy(iwr.u.name, data, len);
+ } else {
+ /*
+ * Argument data too big for inline transfer; setup a
+ * parameter block instead; the kernel will transfer
+ * the data for the driver.
+ */
+ iwr.u.data.pointer = data;
+ iwr.u.data.length = len;
+ }
+
+ if (ioctl(drv->ioctl_sock, op, &iwr) < 0) {
+#ifdef MADWIFI_NG
+ int first = IEEE80211_IOCTL_SETPARAM;
+ static const char *opnames[] = {
+ "ioctl[IEEE80211_IOCTL_SETPARAM]",
+ "ioctl[IEEE80211_IOCTL_GETPARAM]",
+ "ioctl[IEEE80211_IOCTL_SETMODE]",
+ "ioctl[IEEE80211_IOCTL_GETMODE]",
+ "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
+ "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
+ "ioctl[IEEE80211_IOCTL_SETCHANLIST]",
+ "ioctl[IEEE80211_IOCTL_GETCHANLIST]",
+ "ioctl[IEEE80211_IOCTL_CHANSWITCH]",
+ "ioctl[IEEE80211_IOCTL_GET_APPIEBUF]",
+ "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
+ "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
+ "ioctl[IEEE80211_IOCTL_FILTERFRAME]",
+ "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
+ "ioctl[IEEE80211_IOCTL_SETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_GETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_SETMLME]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_SETKEY]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_DELKEY]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_ADDMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_DELMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_WDSMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_WDSDELMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_KICKMAC]",
+ };
+#else /* MADWIFI_NG */
+ int first = IEEE80211_IOCTL_SETPARAM;
+ static const char *opnames[] = {
+ "ioctl[IEEE80211_IOCTL_SETPARAM]",
+ "ioctl[IEEE80211_IOCTL_GETPARAM]",
+ "ioctl[IEEE80211_IOCTL_SETKEY]",
+ "ioctl[SIOCIWFIRSTPRIV+3]",
+ "ioctl[IEEE80211_IOCTL_DELKEY]",
+ "ioctl[SIOCIWFIRSTPRIV+5]",
+ "ioctl[IEEE80211_IOCTL_SETMLME]",
+ "ioctl[SIOCIWFIRSTPRIV+7]",
+ "ioctl[IEEE80211_IOCTL_SETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_GETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_ADDMAC]",
+ "ioctl[SIOCIWFIRSTPRIV+11]",
+ "ioctl[IEEE80211_IOCTL_DELMAC]",
+ "ioctl[SIOCIWFIRSTPRIV+13]",
+ "ioctl[IEEE80211_IOCTL_CHANLIST]",
+ "ioctl[SIOCIWFIRSTPRIV+15]",
+ "ioctl[IEEE80211_IOCTL_GETRSN]",
+ "ioctl[SIOCIWFIRSTPRIV+17]",
+ "ioctl[IEEE80211_IOCTL_GETKEY]",
+ };
+#endif /* MADWIFI_NG */
+ int idx = op - first;
+ if (first <= op &&
+ idx < (int) (sizeof(opnames) / sizeof(opnames[0])) &&
+ opnames[idx])
+ perror(opnames[idx]);
+ else
+ perror("ioctl[unknown???]");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+set80211param(struct madwifi_driver_data *drv, int op, int arg)
+{
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.mode = op;
+ memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));
+
+ if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
+ perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
+ wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d "
+ "arg %d)", __func__, op, arg);
+ return -1;
+ }
+ return 0;
+}
+
+static const char *
+ether_sprintf(const u8 *addr)
+{
+ static char buf[sizeof(MACSTR)];
+
+ if (addr != NULL)
+ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+ else
+ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
+ return buf;
+}
+
+/*
+ * Configure WPA parameters.
+ */
+static int
+madwifi_configure_wpa(struct madwifi_driver_data *drv)
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+ int v;
+
+ switch (conf->wpa_group) {
+ case WPA_CIPHER_CCMP:
+ v = IEEE80211_CIPHER_AES_CCM;
+ break;
+ case WPA_CIPHER_TKIP:
+ v = IEEE80211_CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_WEP104:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_WEP40:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_NONE:
+ v = IEEE80211_CIPHER_NONE;
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "Unknown group key cipher %u",
+ conf->wpa_group);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
+ if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
+ printf("Unable to set group key cipher to %u\n", v);
+ return -1;
+ }
+ if (v == IEEE80211_CIPHER_WEP) {
+ /* key length is done only for specific ciphers */
+ v = (conf->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
+ if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
+ printf("Unable to set group key length to %u\n", v);
+ return -1;
+ }
+ }
+
+ v = 0;
+ if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
+ v |= 1<<IEEE80211_CIPHER_AES_CCM;
+ if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
+ v |= 1<<IEEE80211_CIPHER_TKIP;
+ if (conf->wpa_pairwise & WPA_CIPHER_NONE)
+ v |= 1<<IEEE80211_CIPHER_NONE;
+ wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
+ if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
+ printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
+ __func__, conf->wpa_key_mgmt);
+ if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, conf->wpa_key_mgmt)) {
+ printf("Unable to set key management algorithms to 0x%x\n",
+ conf->wpa_key_mgmt);
+ return -1;
+ }
+
+ v = 0;
+ if (conf->rsn_preauth)
+ v |= BIT(0);
+ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
+ __func__, conf->rsn_preauth);
+ if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
+ printf("Unable to set RSN capabilities to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, conf->wpa);
+ if (set80211param(drv, IEEE80211_PARAM_WPA, conf->wpa)) {
+ printf("Unable to set WPA to %u\n", conf->wpa);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int
+madwifi_set_iface_flags(void *priv, int dev_up)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ifreq ifr;
+
+ wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up);
+
+ if (drv->ioctl_sock < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up) {
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
+ ifr.ifr_mtu = HOSTAPD_MTU;
+ if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
+ perror("ioctl[SIOCSIFMTU]");
+ printf("Setting MTU failed - trying to survive with "
+ "current value\n");
+ }
+ }
+
+ return 0;
+}
+
+static int
+madwifi_set_ieee8021x(const char *ifname, void *priv, int enabled)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+ if (!enabled) {
+ /* XXX restore state */
+ return set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+ IEEE80211_AUTH_AUTO);
+ }
+ if (!conf->wpa && !conf->ieee802_1x) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
+ return -1;
+ }
+ if (conf->wpa && madwifi_configure_wpa(drv) != 0) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
+ return -1;
+ }
+ if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+ (conf->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+madwifi_set_privacy(const char *ifname, void *priv, int enabled)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+ return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled);
+}
+
+static int
+madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
+ __func__, ether_sprintf(addr), authorized);
+
+ if (authorized)
+ mlme.im_op = IEEE80211_MLME_AUTHORIZE;
+ else
+ mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
+ mlme.im_reason = 0;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR,
+ __func__, authorized ? "" : "un", MAC2STR(addr));
+ }
+
+ return ret;
+}
+
+static int
+madwifi_sta_set_flags(void *priv, const u8 *addr, int total_flags,
+ int flags_or, int flags_and)
+{
+ /* For now, only support setting Authorized flag */
+ if (flags_or & WLAN_STA_AUTHORIZED)
+ return madwifi_set_sta_authorized(priv, addr, 1);
+ if (!(flags_and & WLAN_STA_AUTHORIZED))
+ return madwifi_set_sta_authorized(priv, addr, 0);
+ return 0;
+}
+
+static int
+madwifi_del_key(void *priv, const u8 *addr, int key_idx)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_del_key wk;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
+ __func__, ether_sprintf(addr), key_idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr != NULL) {
+ memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
+ } else {
+ wk.idk_keyix = key_idx;
+ }
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s"
+ " key_idx %d)", __func__, ether_sprintf(addr),
+ key_idx);
+ }
+
+ return ret;
+}
+
+static int
+madwifi_set_key(const char *ifname, void *priv, const char *alg,
+ const u8 *addr, int key_idx,
+ const u8 *key, size_t key_len, int txkey)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+ u_int8_t cipher;
+ int ret;
+
+ if (strcmp(alg, "none") == 0)
+ return madwifi_del_key(drv, addr, key_idx);
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s addr=%s key_idx=%d",
+ __func__, alg, ether_sprintf(addr), key_idx);
+
+ if (strcmp(alg, "WEP") == 0)
+ cipher = IEEE80211_CIPHER_WEP;
+ else if (strcmp(alg, "TKIP") == 0)
+ cipher = IEEE80211_CIPHER_TKIP;
+ else if (strcmp(alg, "CCMP") == 0)
+ cipher = IEEE80211_CIPHER_AES_CCM;
+ else {
+ printf("%s: unknown/unsupported algorithm %s\n",
+ __func__, alg);
+ return -1;
+ }
+
+ if (key_len > sizeof(wk.ik_keydata)) {
+ printf("%s: key length %lu too big\n", __func__,
+ (unsigned long) key_len);
+ return -3;
+ }
+
+ memset(&wk, 0, sizeof(wk));
+ wk.ik_type = cipher;
+ wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
+ if (addr == NULL) {
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = key_idx;
+ wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+ } else {
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = IEEE80211_KEYIX_NONE;
+ }
+ wk.ik_keylen = key_len;
+ memcpy(wk.ik_keydata, key, key_len);
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
+ " key_idx %d alg '%s' key_len %lu txkey %d)",
+ __func__, ether_sprintf(wk.ik_macaddr), key_idx,
+ alg, (unsigned long) key_len, txkey);
+ }
+
+ return ret;
+}
+
+
+static int
+madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
+ u8 *seq)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
+ __func__, ether_sprintf(addr), idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr == NULL)
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ else
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = idx;
+
+ if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data "
+ "(addr " MACSTR " key_idx %d)",
+ __func__, MAC2STR(wk.ik_macaddr), idx);
+ return -1;
+ }
+
+#ifdef WORDS_BIGENDIAN
+ {
+ /*
+ * wk.ik_keytsc is in host byte order (big endian), need to
+ * swap it to match with the byte order used in WPA.
+ */
+ int i;
+ u8 tmp[WPA_KEY_RSC_LEN];
+ memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+ for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
+ seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
+ }
+ }
+#else /* WORDS_BIGENDIAN */
+ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+#endif /* WORDS_BIGENDIAN */
+ return 0;
+}
+
+
+static int
+madwifi_flush(void *priv)
+{
+#ifdef MADWIFI_BSD
+ u8 allsta[IEEE80211_ADDR_LEN];
+ memset(allsta, 0xff, IEEE80211_ADDR_LEN);
+ return madwifi_sta_deauth(priv, allsta, IEEE80211_REASON_AUTH_LEAVE);
+#else /* MADWIFI_BSD */
+ return 0; /* XXX */
+#endif /* MADWIFI_BSD */
+}
+
+
+static int
+madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct madwifi_driver_data *drv = priv;
+
+#ifdef MADWIFI_BSD
+ struct ieee80211req_sta_stats stats;
+
+ memset(data, 0, sizeof(*data));
+
+ /*
+ * Fetch statistics for station from the system.
+ */
+ memset(&stats, 0, sizeof(stats));
+ memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
+ if (set80211priv(drv,
+#ifdef MADWIFI_NG
+ IEEE80211_IOCTL_STA_STATS,
+#else /* MADWIFI_NG */
+ IEEE80211_IOCTL_GETSTASTATS,
+#endif /* MADWIFI_NG */
+ &stats, sizeof(stats))) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr "
+ MACSTR ")", __func__, MAC2STR(addr));
+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+ memcpy(data, &drv->acct_data, sizeof(*data));
+ return 0;
+ }
+
+ printf("Failed to get station stats information element.\n");
+ return -1;
+ }
+
+ data->rx_packets = stats.is_stats.ns_rx_data;
+ data->rx_bytes = stats.is_stats.ns_rx_bytes;
+ data->tx_packets = stats.is_stats.ns_tx_data;
+ data->tx_bytes = stats.is_stats.ns_tx_bytes;
+ return 0;
+
+#else /* MADWIFI_BSD */
+
+ char buf[1024], line[128], *pos;
+ FILE *f;
+ unsigned long val;
+
+ memset(data, 0, sizeof(*data));
+ snprintf(buf, sizeof(buf), "/proc/net/madwifi/%s/" MACSTR,
+ drv->iface, MAC2STR(addr));
+
+ f = fopen(buf, "r");
+ if (!f) {
+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) != 0)
+ return -1;
+ memcpy(data, &drv->acct_data, sizeof(*data));
+ return 0;
+ }
+ /* Need to read proc file with in one piece, so use large enough
+ * buffer. */
+ setbuffer(f, buf, sizeof(buf));
+
+ while (fgets(line, sizeof(line), f)) {
+ pos = strchr(line, '=');
+ if (!pos)
+ continue;
+ *pos++ = '\0';
+ val = strtoul(pos, NULL, 10);
+ if (strcmp(line, "rx_packets") == 0)
+ data->rx_packets = val;
+ else if (strcmp(line, "tx_packets") == 0)
+ data->tx_packets = val;
+ else if (strcmp(line, "rx_bytes") == 0)
+ data->rx_bytes = val;
+ else if (strcmp(line, "tx_bytes") == 0)
+ data->tx_bytes = val;
+ }
+
+ fclose(f);
+
+ return 0;
+#endif /* MADWIFI_BSD */
+}
+
+
+static int
+madwifi_sta_clear_stats(void *priv, const u8 *addr)
+{
+#if defined(MADWIFI_BSD) && defined(IEEE80211_MLME_CLEAR_STATS)
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr));
+
+ mlme.im_op = IEEE80211_MLME_CLEAR_STATS;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
+ sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr "
+ MACSTR ")", __func__, MAC2STR(addr));
+ }
+
+ return ret;
+#else /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
+ return 0; /* FIX */
+#endif /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
+}
+
+
+static int
+madwifi_set_opt_ie(const char *ifname, void *priv, const u8 *ie, size_t ie_len)
+{
+ /*
+ * Do nothing; we setup parameters at startup that define the
+ * contents of the beacon information element.
+ */
+ return 0;
+}
+
+static int
+madwifi_sta_deauth(void *priv, const u8 *addr, int reason_code)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR
+ " reason %d)",
+ __func__, MAC2STR(addr), reason_code);
+ }
+
+ return ret;
+}
+
+static int
+madwifi_sta_disassoc(void *priv, const u8 *addr, int reason_code)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DISASSOC;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr "
+ MACSTR " reason %d)",
+ __func__, MAC2STR(addr), reason_code);
+ }
+
+ return ret;
+}
+
+static int
+madwifi_del_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct sta_info *sta;
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "disassociated");
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta != NULL) {
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ ap_free_sta(hapd, sta);
+ }
+ return 0;
+}
+
+static int
+madwifi_process_wpa_ie(struct madwifi_driver_data *drv, struct sta_info *sta)
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct ieee80211req_wpaie ie;
+ int ielen, res;
+ u8 *iebuf;
+
+ /*
+ * Fetch negotiated WPA/RSN parameters from the system.
+ */
+ memset(&ie, 0, sizeof(ie));
+ memcpy(ie.wpa_macaddr, sta->addr, IEEE80211_ADDR_LEN);
+ if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) {
+ wpa_printf(MSG_ERROR, "%s: Failed to get WPA/RSN IE",
+ __func__);
+ printf("Failed to get WPA/RSN information element.\n");
+ return -1; /* XXX not right */
+ }
+ wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE",
+ ie.wpa_ie, IEEE80211_MAX_OPT_IE);
+ wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE",
+ ie.rsn_ie, IEEE80211_MAX_OPT_IE);
+ iebuf = ie.wpa_ie;
+ /* madwifi seems to return some random data if WPA/RSN IE is not set.
+ * Assume the IE was not included if the IE type is unknown. */
+ if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
+ iebuf[1] = 0;
+#ifdef MADWIFI_NG
+ if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
+ /* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
+ * set. This is needed for WPA2. */
+ iebuf = ie.rsn_ie;
+ if (iebuf[0] != WLAN_EID_RSN)
+ iebuf[1] = 0;
+ }
+#endif /* MADWIFI_NG */
+ ielen = iebuf[1];
+ if (ielen == 0) {
+ printf("No WPA/RSN information element for station!?\n");
+ return -1; /* XXX not right */
+ }
+ ielen += 2;
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr);
+ if (sta->wpa_sm == NULL) {
+ printf("Failed to initialize WPA state machine\n");
+ return -1;
+ }
+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ iebuf, ielen, NULL, 0);
+ if (res != WPA_IE_OK) {
+ printf("WPA/RSN information element rejected? (res %u)\n", res);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct sta_info *sta;
+ int new_assoc;
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "associated");
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta) {
+ accounting_sta_stop(hapd, sta);
+ } else {
+ sta = ap_sta_add(hapd, addr);
+ if (sta == NULL)
+ return -1;
+ }
+
+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+ /* Cached accounting data is not valid anymore. */
+ memset(drv->acct_mac, 0, ETH_ALEN);
+ memset(&drv->acct_data, 0, sizeof(drv->acct_data));
+ }
+ accounting_sta_get_id(hapd, sta);
+
+ if (hapd->conf->wpa) {
+ if (madwifi_process_wpa_ie(drv, sta))
+ return -1;
+ }
+
+ /*
+ * Now that the internal station state is setup
+ * kick the authenticator into action.
+ */
+ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
+ hostapd_new_assoc_sta(hapd, sta, !new_assoc);
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+ return 0;
+}
+
+static void
+madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv,
+ char *custom)
+{
+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ char *pos;
+ u8 addr[ETH_ALEN];
+ pos = strstr(custom, "addr=");
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "without sender address ignored");
+ return;
+ }
+ pos += 5;
+ if (hwaddr_aton(pos, addr) == 0) {
+ ieee80211_michael_mic_failure(drv->hapd, addr, 1);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "with invalid MAC address");
+ }
+ } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) {
+ char *key, *value;
+ u32 val;
+ key = custom;
+ while ((key = strchr(key, '\n')) != NULL) {
+ key++;
+ value = strchr(key, '=');
+ if (value == NULL)
+ continue;
+ *value++ = '\0';
+ val = strtoul(value, NULL, 10);
+ if (strcmp(key, "mac") == 0)
+ hwaddr_aton(value, drv->acct_mac);
+ else if (strcmp(key, "rx_packets") == 0)
+ drv->acct_data.rx_packets = val;
+ else if (strcmp(key, "tx_packets") == 0)
+ drv->acct_data.tx_packets = val;
+ else if (strcmp(key, "rx_bytes") == 0)
+ drv->acct_data.rx_bytes = val;
+ else if (strcmp(key, "tx_bytes") == 0)
+ drv->acct_data.tx_bytes = val;
+ key = value;
+ }
+ }
+}
+
+static void
+madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
+ char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (drv->we_version > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ iwe->cmd == IWEVCUSTOM)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case IWEVEXPIRED:
+ madwifi_del_sta(drv, (u8 *) iwe->u.addr.sa_data);
+ break;
+ case IWEVREGISTERED:
+ madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
+ break;
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return; /* XXX */
+ memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ madwifi_wireless_event_wireless_custom(drv, buf);
+ free(buf);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void
+madwifi_wireless_event_rtm_newlink(struct madwifi_driver_data *drv,
+ struct nlmsghdr *h, int len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < (int) sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ if (ifi->ifi_index != drv->ifindex)
+ return;
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ madwifi_wireless_event_wireless(
+ drv, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void
+madwifi_wireless_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ char buf[256];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ struct madwifi_driver_data *drv = eloop_ctx;
+
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (left >= (int) sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ printf("Malformed netlink message: "
+ "len=%d left=%d plen=%d\n",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ madwifi_wireless_event_rtm_newlink(drv, h, plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ printf("%d extra bytes in the end of netlink message\n", left);
+ }
+}
+
+
+static int
+madwifi_get_we_version(struct madwifi_driver_data *drv)
+{
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ drv->we_version = 0;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->we_version = range->we_version_compiled;
+ }
+
+ free(range);
+ return 0;
+}
+
+
+static int
+madwifi_wireless_event_init(void *priv)
+{
+ struct madwifi_driver_data *drv = priv;
+ int s;
+ struct sockaddr_nl local;
+
+ madwifi_get_we_version(drv);
+
+ drv->wext_sock = -1;
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ return -1;
+ }
+
+ memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ return -1;
+ }
+
+ eloop_register_read_sock(s, madwifi_wireless_event_receive, drv, NULL);
+ drv->wext_sock = s;
+
+ return 0;
+}
+
+
+static void
+madwifi_wireless_event_deinit(void *priv)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ if (drv != NULL) {
+ if (drv->wext_sock < 0)
+ return;
+ eloop_unregister_read_sock(drv->wext_sock);
+ close(drv->wext_sock);
+ }
+}
+
+
+static int
+madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
+ int encrypt, const u8 *own_addr)
+{
+ struct madwifi_driver_data *drv = priv;
+ unsigned char buf[3000];
+ unsigned char *bp = buf;
+ struct l2_ethhdr *eth;
+ size_t len;
+ int status;
+
+ /*
+ * Prepend the Ethernet header. If the caller left us
+ * space at the front we could just insert it but since
+ * we don't know we copy to a local buffer. Given the frequency
+ * and size of frames this probably doesn't matter.
+ */
+ len = data_len + sizeof(struct l2_ethhdr);
+ if (len > sizeof(buf)) {
+ bp = malloc(len);
+ if (bp == NULL) {
+ printf("EAPOL frame discarded, cannot malloc temp "
+ "buffer of size %lu!\n", (unsigned long) len);
+ return -1;
+ }
+ }
+ eth = (struct l2_ethhdr *) bp;
+ memcpy(eth->h_dest, addr, ETH_ALEN);
+ memcpy(eth->h_source, own_addr, ETH_ALEN);
+ eth->h_proto = htons(ETH_P_EAPOL);
+ memcpy(eth+1, data, data_len);
+
+ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
+
+ status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
+
+ if (bp != buf)
+ free(bp);
+ return status;
+}
+
+static void
+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+ struct madwifi_driver_data *drv = ctx;
+ struct hostapd_data *hapd = drv->hapd;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, src_addr);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+ printf("Data frame from not associated STA %s\n",
+ ether_sprintf(src_addr));
+ /* XXX cannot happen */
+ return;
+ }
+ ieee802_1x_receive(hapd, src_addr, buf + sizeof(struct l2_ethhdr),
+ len - sizeof(struct l2_ethhdr));
+}
+
+static void *
+madwifi_init(struct hostapd_data *hapd)
+{
+ struct madwifi_driver_data *drv;
+ struct ifreq ifr;
+ struct iwreq iwr;
+
+ drv = os_zalloc(sizeof(struct madwifi_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for madwifi driver data\n");
+ goto bad;
+ }
+
+ drv->hapd = hapd;
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ goto bad;
+ }
+ memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+ if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ goto bad;
+ }
+ drv->ifindex = ifr.ifr_ifindex;
+
+ drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
+ handle_read, drv, 1);
+ if (drv->sock_xmit == NULL)
+ goto bad;
+ if (l2_packet_get_own_addr(drv->sock_xmit, hapd->own_addr))
+ goto bad;
+ if (hapd->conf->bridge[0] != '\0') {
+ wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
+ hapd->conf->bridge);
+ drv->sock_recv = l2_packet_init(hapd->conf->bridge, NULL,
+ ETH_P_EAPOL, handle_read, drv,
+ 1);
+ if (drv->sock_recv == NULL)
+ goto bad;
+ } else
+ drv->sock_recv = drv->sock_xmit;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+ iwr.u.mode = IW_MODE_MASTER;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWMODE]");
+ printf("Could not set interface to master mode!\n");
+ goto bad;
+ }
+
+ madwifi_set_iface_flags(drv, 0); /* mark down during setup */
+ madwifi_set_privacy(drv->iface, drv, 0); /* default to no privacy */
+
+ return drv;
+bad:
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv != NULL)
+ free(drv);
+ return NULL;
+}
+
+
+static void
+madwifi_deinit(void *priv)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ (void) madwifi_set_iface_flags(drv, 0);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
+ l2_packet_deinit(drv->sock_recv);
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ if (drv->sock_raw)
+ l2_packet_deinit(drv->sock_raw);
+ free(drv);
+}
+
+static int
+madwifi_set_ssid(const char *ifname, void *priv, const u8 *buf, int len)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.flags = 1; /* SSID active */
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len + 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ printf("len=%d\n", len);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+madwifi_get_ssid(const char *ifname, void *priv, u8 *buf, int len)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCGIWESSID]");
+ ret = -1;
+ } else
+ ret = iwr.u.essid.length;
+
+ return ret;
+}
+
+static int
+madwifi_set_countermeasures(void *priv, int enabled)
+{
+ struct madwifi_driver_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
+}
+
+static int
+madwifi_commit(void *priv)
+{
+ return madwifi_set_iface_flags(priv, 1);
+}
+
+const struct wpa_driver_ops wpa_driver_madwifi_ops = {
+ .name = "madwifi",
+ .init = madwifi_init,
+ .deinit = madwifi_deinit,
+ .set_ieee8021x = madwifi_set_ieee8021x,
+ .set_privacy = madwifi_set_privacy,
+ .set_encryption = madwifi_set_key,
+ .get_seqnum = madwifi_get_seqnum,
+ .flush = madwifi_flush,
+ .set_generic_elem = madwifi_set_opt_ie,
+ .wireless_event_init = madwifi_wireless_event_init,
+ .wireless_event_deinit = madwifi_wireless_event_deinit,
+ .sta_set_flags = madwifi_sta_set_flags,
+ .read_sta_data = madwifi_read_sta_driver_data,
+ .send_eapol = madwifi_send_eapol,
+ .sta_disassoc = madwifi_sta_disassoc,
+ .sta_deauth = madwifi_sta_deauth,
+ .set_ssid = madwifi_set_ssid,
+ .get_ssid = madwifi_get_ssid,
+ .set_countermeasures = madwifi_set_countermeasures,
+ .sta_clear_stats = madwifi_sta_clear_stats,
+ .commit = madwifi_commit,
+};
diff --git a/hostapd/driver_nl80211.c b/hostapd/driver_nl80211.c
new file mode 100644
index 0000000..bf00624
--- /dev/null
+++ b/hostapd/driver_nl80211.c
@@ -0,0 +1,2382 @@
+/*
+ * hostapd / Kernel driver communication via nl80211
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include <sys/ioctl.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+#include <linux/nl80211.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h> /* The L2 protocols */
+#include <linux/wireless.h>
+#include <net/if_arp.h>
+
+#include "hostapd.h"
+#include "driver.h"
+#include "ieee802_1x.h"
+#include "eloop.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "hw_features.h"
+#include "mlme.h"
+#include "radiotap.h"
+#include "radiotap_iter.h"
+
+enum ieee80211_msg_type {
+ ieee80211_msg_normal = 0,
+ ieee80211_msg_tx_callback_ack = 1,
+ ieee80211_msg_tx_callback_fail = 2,
+};
+
+struct i802_driver_data {
+ struct hostapd_data *hapd;
+
+ char iface[IFNAMSIZ + 1];
+ int ioctl_sock; /* socket for ioctl() use */
+ int wext_sock; /* socket for wireless events */
+ int eapol_sock; /* socket for EAPOL frames */
+ int monitor_sock; /* socket for monitor */
+ int monitor_ifidx;
+
+ int default_if_indices[16];
+ int *if_indices;
+ int num_if_indices;
+
+ int we_version;
+ struct nl_handle *nl_handle;
+ struct nl_cache *nl_cache;
+ struct genl_family *nl80211;
+ int dtim_period;
+ unsigned int beacon_set:1;
+ unsigned int ieee802_1x_active:1;
+};
+
+
+static void add_ifidx(struct i802_driver_data *drv, int ifidx)
+{
+ int i;
+ int *old;
+
+ for (i = 0; i < drv->num_if_indices; i++) {
+ if (drv->if_indices[i] == 0) {
+ drv->if_indices[i] = ifidx;
+ return;
+ }
+ }
+
+ if (drv->if_indices != drv->default_if_indices)
+ old = drv->if_indices;
+ else
+ old = NULL;
+
+ drv->if_indices = realloc(old,
+ sizeof(int) * (drv->num_if_indices + 1));
+ if (!drv->if_indices) {
+ if (!old)
+ drv->if_indices = drv->default_if_indices;
+ else
+ drv->if_indices = old;
+ wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
+ "interfaces");
+ wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
+ return;
+ }
+ drv->if_indices[drv->num_if_indices] = ifidx;
+ drv->num_if_indices++;
+}
+
+
+static void del_ifidx(struct i802_driver_data *drv, int ifidx)
+{
+ int i;
+
+ for (i = 0; i < drv->num_if_indices; i++) {
+ if (drv->if_indices[i] == ifidx) {
+ drv->if_indices[i] = 0;
+ break;
+ }
+ }
+}
+
+
+static int have_ifidx(struct i802_driver_data *drv, int ifidx)
+{
+ int i;
+
+ for (i = 0; i < drv->num_if_indices; i++)
+ if (drv->if_indices[i] == ifidx)
+ return 1;
+
+ return 0;
+}
+
+
+/* helper for netlink get routines */
+static int ack_wait_handler(struct nl_msg *msg, void *arg)
+{
+ int *finished = arg;
+
+ *finished = 1;
+ return NL_STOP;
+}
+
+
+static int hostapd_set_iface_flags(struct i802_driver_data *drv,
+ const char *ifname, int dev_up)
+{
+ struct ifreq ifr;
+
+ if (drv->ioctl_sock < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ wpa_printf(MSG_DEBUG, "Could not read interface flags (%s)",
+ drv->iface);
+ return -1;
+ }
+
+ if (dev_up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int i802_set_encryption(const char *iface, void *priv, const char *alg,
+ const u8 *addr, int idx, const u8 *key,
+ size_t key_len, int txkey)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+ int err = 0;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ if (strcmp(alg, "none") == 0) {
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_KEY, 0);
+ } else {
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_KEY, 0);
+ NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
+ if (strcmp(alg, "WEP") == 0) {
+ if (key_len == 5)
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ 0x000FAC01);
+ else
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ 0x000FAC05);
+ } else if (strcmp(alg, "TKIP") == 0)
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02);
+ else if (strcmp(alg, "CCMP") == 0)
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);
+ else
+ goto out;
+ }
+
+ if (addr)
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ (err = nl_wait_for_ack(drv->nl_handle)) < 0) {
+ if (err != -ENOENT) {
+ err = 0;
+ goto out;
+ }
+ }
+
+ /*
+ * If we need to set the default TX key we do that below,
+ * otherwise we're done here.
+ */
+ if (!txkey || addr) {
+ ret = 0;
+ goto out;
+ }
+
+ nlmsg_free(msg);
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_KEY, 0);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ (err = nl_wait_for_ack(drv->nl_handle)) < 0) {
+ if (err != -ENOENT) {
+ err = 0;
+ goto out;
+ }
+ }
+
+ ret = 0;
+
+ out:
+ nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static inline int min_int(int a, int b)
+{
+ if (a < b)
+ return a;
+ return b;
+}
+
+
+static int get_key_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ /*
+ * TODO: validate the key index and mac address!
+ * Otherwise, there's a race condition as soon as
+ * the kernel starts sending key notifications.
+ */
+
+ if (tb[NL80211_ATTR_KEY_SEQ])
+ memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
+ min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
+ return NL_SKIP;
+}
+
+
+static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
+ int idx, u8 *seq)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ struct nl_cb *cb = NULL;
+ int ret = -1;
+ int err = 0;
+ int finished = 0;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_GET_KEY, 0);
+
+ if (addr)
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+
+ cb = nl_cb_alloc(NL_CB_CUSTOM);
+ if (!cb)
+ goto out;
+
+ memset(seq, 0, 6);
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0)
+ goto out;
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_key_handler, seq);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished);
+
+ err = nl_recvmsgs(drv->nl_handle, cb);
+
+ if (!finished)
+ err = nl_wait_for_ack(drv->nl_handle);
+
+ if (err < 0)
+ goto out;
+
+ ret = 0;
+
+ out:
+ nl_cb_put(cb);
+ nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,
+ int mode)
+{
+ return -1;
+}
+
+
+static int i802_set_ssid(const char *ifname, void *priv, const u8 *buf,
+ int len)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ);
+ iwr.u.essid.flags = 1; /* SSID active */
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ printf("len=%d\n", len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int i802_send_mgmt_frame(void *priv, const void *data, size_t len,
+ int flags)
+{
+ struct ieee80211_hdr *hdr = (void*) data;
+ __u8 rtap_hdr[] = {
+ 0x00, 0x00, /* radiotap version */
+ 0x0e, 0x00, /* radiotap length */
+ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
+ 0x0c, /* F_WEP | F_FRAG (encrypt/fragment if required) */
+ 0x00, /* padding */
+ 0x00, 0x00, /* RX and TX flags to indicate that */
+ 0x00, 0x00, /* this is the injected frame directly */
+ };
+ struct i802_driver_data *drv = priv;
+ struct iovec iov[2] = {
+ {
+ .iov_base = &rtap_hdr,
+ .iov_len = sizeof(rtap_hdr),
+ },
+ {
+ .iov_base = (void*)data,
+ .iov_len = len,
+ }
+ };
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = iov,
+ .msg_iovlen = 2,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0,
+ };
+
+ /*
+ * ugh, guess what, the generic code sets one of the version
+ * bits to request tx callback
+ */
+ hdr->frame_control &= ~host_to_le16(BIT(1));
+ return sendmsg(drv->monitor_sock, &msg, flags);
+}
+
+
+/* Set kernel driver on given frequency (MHz) */
+static int i802_set_freq(void *priv, int mode, int freq)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
+ iwr.u.freq.m = freq;
+ iwr.u.freq.e = 6;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+ perror("ioctl[SIOCSIWFREQ]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int i802_set_rts(void *priv, int rts)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
+ iwr.u.rts.value = rts;
+ iwr.u.rts.fixed = 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWRTS, &iwr) < 0) {
+ perror("ioctl[SIOCSIWRTS]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int i802_get_rts(void *priv, int *rts)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRTS, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRTS]");
+ return -1;
+ }
+
+ *rts = iwr.u.rts.value;
+
+ return 0;
+}
+
+
+static int i802_set_frag(void *priv, int frag)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
+ iwr.u.frag.value = frag;
+ iwr.u.frag.fixed = 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) {
+ perror("ioctl[SIOCSIWFRAG]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int i802_get_frag(void *priv, int *frag)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWFRAG, &iwr) < 0) {
+ perror("ioctl[SIOCGIWFRAG]");
+ return -1;
+ }
+
+ *frag = iwr.u.frag.value;
+
+ return 0;
+}
+
+
+static int i802_set_retry(void *priv, int short_retry, int long_retry)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
+
+ iwr.u.retry.value = short_retry;
+ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+ if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) {
+ perror("ioctl[SIOCSIWRETRY(short)]");
+ return -1;
+ }
+
+ iwr.u.retry.value = long_retry;
+ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) {
+ perror("ioctl[SIOCSIWRETRY(long)]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int i802_get_retry(void *priv, int *short_retry, int *long_retry)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
+
+ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+ if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) {
+ perror("ioctl[SIOCGIWFRAG(short)]");
+ return -1;
+ }
+ *short_retry = iwr.u.retry.value;
+
+ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) {
+ perror("ioctl[SIOCGIWFRAG(long)]");
+ return -1;
+ }
+ *long_retry = iwr.u.retry.value;
+
+ return 0;
+}
+
+
+static int i802_flush(void *priv)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_STATION, 0);
+
+ /*
+ * XXX: FIX! this needs to flush all VLANs too
+ */
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+
+ ret = 0;
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0) {
+ ret = -1;
+ }
+
+ nla_put_failure:
+ nlmsg_free(msg);
+
+ out:
+ return ret;
+}
+
+
+static int get_sta_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct hostap_sta_driver_data *data = arg;
+ struct nlattr *stats[NL80211_STA_STAT_MAX + 1];
+ static struct nla_policy stats_policy[NL80211_STA_STAT_MAX + 1] = {
+ [NL80211_STA_STAT_INACTIVE_TIME] = { .type = NLA_U32 },
+ [NL80211_STA_STAT_RX_BYTES] = { .type = NLA_U32 },
+ [NL80211_STA_STAT_TX_BYTES] = { .type = NLA_U32 },
+ };
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ /*
+ * TODO: validate the interface and mac address!
+ * Otherwise, there's a race condition as soon as
+ * the kernel starts sending station notifications.
+ */
+
+ if (!tb[NL80211_ATTR_STA_STATS]) {
+ wpa_printf(MSG_DEBUG, "sta stats missing!");
+ return NL_SKIP;
+ }
+ if (nla_parse_nested(stats, NL80211_STA_STAT_MAX,
+ tb[NL80211_ATTR_STA_STATS],
+ stats_policy)) {
+ wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
+ return NL_SKIP;
+ }
+
+ if (stats[NL80211_STA_STAT_INACTIVE_TIME])
+ data->inactive_msec =
+ nla_get_u32(stats[NL80211_STA_STAT_INACTIVE_TIME]);
+ if (stats[NL80211_STA_STAT_RX_BYTES])
+ data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_RX_BYTES]);
+ if (stats[NL80211_STA_STAT_TX_BYTES])
+ data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_TX_BYTES]);
+
+ return NL_SKIP;
+}
+
+static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ struct nl_cb *cb = NULL;
+ int ret = -1;
+ int err = 0;
+ int finished = 0;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_GET_STATION, 0);
+
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+
+ cb = nl_cb_alloc(NL_CB_CUSTOM);
+ if (!cb)
+ goto out;
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0)
+ goto out;
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_sta_handler, data);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished);
+
+ err = nl_recvmsgs(drv->nl_handle, cb);
+
+ if (!finished)
+ err = nl_wait_for_ack(drv->nl_handle);
+
+ if (err < 0)
+ goto out;
+
+ ret = 0;
+
+ out:
+ nl_cb_put(cb);
+ nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+
+}
+
+
+static int i802_send_eapol(void *priv, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt, const u8 *own_addr)
+{
+ struct i802_driver_data *drv = priv;
+ struct ieee80211_hdr *hdr;
+ size_t len;
+ u8 *pos;
+ int res;
+#if 0 /* FIX */
+ int qos = sta->flags & WLAN_STA_WME;
+#else
+ int qos = 0;
+#endif
+
+ len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
+ data_len;
+ hdr = os_zalloc(len);
+ if (hdr == NULL) {
+ printf("malloc() failed for i802_send_data(len=%lu)\n",
+ (unsigned long) len);
+ return -1;
+ }
+
+ hdr->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
+ hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
+ if (encrypt)
+ hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+#if 0 /* To be enabled if qos determination is added above */
+ if (qos) {
+ hdr->frame_control |=
+ host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
+ }
+#endif
+
+ memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+ pos = (u8 *) (hdr + 1);
+
+#if 0 /* To be enabled if qos determination is added above */
+ if (qos) {
+ /* add an empty QoS header if needed */
+ pos[0] = 0;
+ pos[1] = 0;
+ pos += 2;
+ }
+#endif
+
+ memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
+ pos += sizeof(rfc1042_header);
+ WPA_PUT_BE16(pos, ETH_P_PAE);
+ pos += 2;
+ memcpy(pos, data, data_len);
+
+ res = i802_send_mgmt_frame(drv, (u8 *) hdr, len, 0);
+ free(hdr);
+
+ if (res < 0) {
+ perror("i802_send_eapol: send");
+ printf("i802_send_eapol - packet len: %lu - failed\n",
+ (unsigned long) len);
+ }
+
+ return res;
+}
+
+
+static int i802_sta_add(const char *ifname, void *priv, const u8 *addr,
+ u16 aid, u16 capability, u8 *supp_rates,
+ size_t supp_rates_len, int flags)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, aid);
+ NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, supp_rates_len,
+ supp_rates);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 0);
+
+ ret = nl_send_auto_complete(drv->nl_handle, msg);
+ if (ret < 0)
+ goto nla_put_failure;
+
+ ret = nl_wait_for_ack(drv->nl_handle);
+ /* ignore EEXIST, this happens if a STA associates while associated */
+ if (ret == -EEXIST || ret >= 0)
+ ret = 0;
+
+ nla_put_failure:
+ nlmsg_free(msg);
+
+ out:
+ return ret;
+}
+
+
+static int i802_sta_remove(void *priv, const u8 *addr)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ ret = 0;
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0) {
+ ret = -1;
+ }
+
+ nla_put_failure:
+ nlmsg_free(msg);
+
+ out:
+ return ret;
+}
+
+
+static int i802_sta_set_flags(void *priv, const u8 *addr,
+ int total_flags, int flags_or, int flags_and)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg, *flags = NULL;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ flags = nlmsg_alloc();
+ if (!flags)
+ goto free_msg;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ if (total_flags & WLAN_STA_AUTHORIZED || !drv->ieee802_1x_active)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+
+ if (total_flags & WLAN_STA_WME)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
+
+ if (total_flags & WLAN_STA_SHORT_PREAMBLE)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
+
+ if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
+ goto nla_put_failure;
+
+ ret = 0;
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0) {
+ ret = -1;
+ }
+
+ nla_put_failure:
+ nlmsg_free(flags);
+
+ free_msg:
+ nlmsg_free(msg);
+
+ out:
+ return ret;
+}
+
+
+static int i802_set_channel_flag(void *priv, int mode, int chan, int flag,
+ unsigned char power_level,
+ unsigned char antenna_max)
+{
+ return -1;
+}
+
+
+static int i802_set_regulatory_domain(void *priv, unsigned int rd)
+{
+ return -1;
+}
+
+
+static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
+ int cw_min, int cw_max, int burst_time)
+{
+ return -1;
+}
+
+
+static void nl80211_remove_iface(struct i802_driver_data *drv, int ifidx)
+{
+ struct nl_msg *msg;
+
+ /* stop listening for EAPOL on this interface */
+ del_ifidx(drv, ifidx);
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0)
+ nla_put_failure:
+ printf("Failed to remove interface.\n");
+ nlmsg_free(msg);
+}
+
+
+static int nl80211_create_iface(struct i802_driver_data *drv,
+ const char *ifname,
+ enum nl80211_iftype iftype,
+ const u8 *addr)
+{
+ struct nl_msg *msg, *flags = NULL;
+ int ifidx;
+ struct ifreq ifreq;
+ struct iwreq iwr;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->hapd->conf->iface));
+ NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
+
+ if (iftype == NL80211_IFTYPE_MONITOR) {
+ int err;
+
+ flags = nlmsg_alloc();
+ if (!flags)
+ goto nla_put_failure;
+
+ NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
+
+ err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
+
+ nlmsg_free(flags);
+
+ if (err)
+ goto nla_put_failure;
+ }
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0) {
+ nla_put_failure:
+ printf("Failed to create interface %s.\n", ifname);
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ nlmsg_free(msg);
+
+ ifidx = if_nametoindex(ifname);
+
+ if (ifidx <= 0)
+ return -1;
+
+ /* start listening for EAPOL on this interface */
+ add_ifidx(drv, ifidx);
+
+ if (addr) {
+ switch (iftype) {
+ case NL80211_IFTYPE_AP:
+ os_strlcpy(ifreq.ifr_name, ifname, IFNAMSIZ);
+ memcpy(ifreq.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+ ifreq.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifreq)) {
+ nl80211_remove_iface(drv, ifidx);
+ return -1;
+ }
+ break;
+ case NL80211_IFTYPE_WDS:
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ);
+ iwr.u.addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwr.u.addr.sa_data, addr, ETH_ALEN);
+ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr))
+ return -1;
+ break;
+ default:
+ /* nothing */
+ break;
+ }
+ }
+
+ return ifidx;
+}
+
+
+static int i802_bss_add(void *priv, const char *ifname, const u8 *bssid)
+{
+ int ifidx;
+
+ /*
+ * The kernel supports that when the low-level driver does,
+ * but we currently don't because we need per-BSS data that
+ * currently we can't handle easily.
+ */
+ return -1;
+
+ ifidx = nl80211_create_iface(priv, ifname, NL80211_IFTYPE_AP, bssid);
+ if (ifidx < 0)
+ return -1;
+ if (hostapd_set_iface_flags(priv, ifname, 1)) {
+ nl80211_remove_iface(priv, ifidx);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int i802_bss_remove(void *priv, const char *ifname)
+{
+ nl80211_remove_iface(priv, if_nametoindex(ifname));
+ return 0;
+}
+
+
+static int i802_set_beacon(const char *iface, void *priv,
+ u8 *head, size_t head_len,
+ u8 *tail, size_t tail_len)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ u8 cmd = NL80211_CMD_NEW_BEACON;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ if (drv->beacon_set)
+ cmd = NL80211_CMD_SET_BEACON;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, cmd, 0);
+ NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head);
+ NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, 1000);
+
+ if (!drv->dtim_period)
+ drv->dtim_period = 2;
+ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period);
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0)
+ goto out;
+
+ ret = 0;
+
+ drv->beacon_set = 1;
+
+ out:
+ nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int i802_del_beacon(struct i802_driver_data *drv)
+{
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_BEACON, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0)
+ goto out;
+
+ ret = 0;
+
+ out:
+ nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int i802_set_ieee8021x(const char *ifname, void *priv, int enabled)
+{
+ struct i802_driver_data *drv = priv;
+
+ /*
+ * FIXME: This needs to be per interface (BSS)
+ */
+ drv->ieee802_1x_active = enabled;
+ return 0;
+}
+
+
+static int i802_set_privacy(const char *ifname, void *priv, int enabled)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+
+ os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ);
+ iwr.u.param.flags = IW_AUTH_PRIVACY_INVOKED;
+ iwr.u.param.value = enabled;
+
+ ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr);
+
+ /* ignore errors, the kernel/driver might not care */
+ return 0;
+}
+
+
+static int i802_set_internal_bridge(void *priv, int value)
+{
+ return -1;
+}
+
+
+static int i802_set_beacon_int(void *priv, int value)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_BEACON, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+
+ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, value);
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0)
+ goto out;
+
+ ret = 0;
+
+ out:
+ nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int i802_set_dtim_period(const char *iface, void *priv, int value)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_BEACON, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+
+ drv->dtim_period = value;
+ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period);
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0)
+ goto out;
+
+ ret = 0;
+
+ out:
+ nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int i802_set_cts_protect(void *priv, int value)
+{
+ return -1;
+}
+
+
+static int i802_set_preamble(void *priv, int value)
+{
+ return -1;
+}
+
+
+static int i802_set_short_slot_time(void *priv, int value)
+{
+ return -1;
+}
+
+
+static enum nl80211_iftype i802_if_type(enum hostapd_driver_if_type type)
+{
+ switch (type) {
+ case HOSTAPD_IF_VLAN:
+ return NL80211_IFTYPE_AP_VLAN;
+ case HOSTAPD_IF_WDS:
+ return NL80211_IFTYPE_WDS;
+ }
+ return -1;
+}
+
+
+static int i802_if_add(const char *iface, void *priv,
+ enum hostapd_driver_if_type type, char *ifname,
+ const u8 *addr)
+{
+ if (nl80211_create_iface(priv, ifname, i802_if_type(type), addr) < 0)
+ return -1;
+ return 0;
+}
+
+
+static int i802_if_update(void *priv, enum hostapd_driver_if_type type,
+ char *ifname, const u8 *addr)
+{
+ /* unused at the moment */
+ return -1;
+}
+
+
+static int i802_if_remove(void *priv, enum hostapd_driver_if_type type,
+ const char *ifname, const u8 *addr)
+{
+ nl80211_remove_iface(priv, if_nametoindex(ifname));
+ return 0;
+}
+
+
+struct phy_info_arg {
+ u16 *num_modes;
+ struct hostapd_hw_modes *modes;
+ int error;
+};
+
+static int phy_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct phy_info_arg *phy_info = arg;
+
+ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+
+ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+ [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+ };
+
+ struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
+ static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
+ [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
+ [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG },
+ };
+
+ struct nlattr *nl_band;
+ struct nlattr *nl_freq;
+ struct nlattr *nl_rate;
+ int rem_band, rem_freq, rem_rate;
+ struct hostapd_hw_modes *mode;
+ int idx, mode_is_set;
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+ return NL_SKIP;
+
+ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
+ mode = realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode));
+ if (!mode)
+ return NL_SKIP;
+ phy_info->modes = mode;
+
+ mode_is_set = 0;
+
+ mode = &phy_info->modes[*(phy_info->num_modes)];
+ memset(mode, 0, sizeof(*mode));
+ *(phy_info->num_modes) += 1;
+
+ nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+ nla_len(nl_band), NULL);
+
+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
+ nla_len(nl_freq), freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+ mode->num_channels++;
+ }
+
+ mode->channels = calloc(mode->num_channels, sizeof(struct hostapd_channel_data));
+ if (!mode->channels)
+ return NL_SKIP;
+
+ idx = 0;
+
+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
+ nla_len(nl_freq), freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+
+ mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+ mode->channels[idx].flag |= HOSTAPD_CHAN_W_SCAN |
+ HOSTAPD_CHAN_W_ACTIVE_SCAN |
+ HOSTAPD_CHAN_W_IBSS;
+
+ if (!mode_is_set) {
+ /* crude heuristic */
+ if (mode->channels[idx].freq < 4000)
+ mode->mode = HOSTAPD_MODE_IEEE80211B;
+ else
+ mode->mode = HOSTAPD_MODE_IEEE80211A;
+ mode_is_set = 1;
+ }
+
+ /* crude heuristic */
+ if (mode->channels[idx].freq < 4000)
+ if (mode->channels[idx].freq == 2848)
+ mode->channels[idx].chan = 14;
+ else
+ mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5;
+ else
+ mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ mode->channels[idx].flag &= ~HOSTAPD_CHAN_W_SCAN;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
+ mode->channels[idx].flag &= ~HOSTAPD_CHAN_W_ACTIVE_SCAN;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
+ mode->channels[idx].flag &= ~HOSTAPD_CHAN_W_IBSS;
+ idx++;
+ }
+
+ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
+ nla_len(nl_rate), rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->num_rates++;
+ }
+
+ mode->rates = calloc(mode->num_rates, sizeof(struct hostapd_rate_data));
+ if (!mode->rates)
+ return NL_SKIP;
+
+ idx = 0;
+
+ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
+ nla_len(nl_rate), rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->rates[idx].rate = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]);
+
+ /* crude heuristic */
+ if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
+ mode->rates[idx].rate > 200)
+ mode->mode = HOSTAPD_MODE_IEEE80211G;
+
+ if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE])
+ mode->rates[idx].flags |= HOSTAPD_RATE_PREAMBLE2;
+
+ idx++;
+ }
+ }
+
+ phy_info->error = 0;
+
+ return NL_SKIP;
+}
+
+static struct hostapd_hw_modes *i802_get_hw_feature_data(void *priv,
+ u16 *num_modes,
+ u16 *flags)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ int err = -1;
+ struct nl_cb *cb = NULL;
+ int finished;
+ struct phy_info_arg result = {
+ .num_modes = num_modes,
+ .modes = NULL,
+ .error = 1,
+ };
+
+ *num_modes = 0;
+ *flags = 0;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return NULL;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_GET_WIPHY, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+
+ cb = nl_cb_alloc(NL_CB_CUSTOM);
+ if (!cb)
+ goto out;
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0)
+ goto out;
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, phy_info_handler, &result);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished);
+
+ err = nl_recvmsgs(drv->nl_handle, cb);
+
+ if (!finished)
+ err = nl_wait_for_ack(drv->nl_handle);
+
+ if (err < 0 || result.error) {
+ hostapd_free_hw_features(result.modes, *num_modes);
+ result.modes = NULL;
+ }
+
+ out:
+ nl_cb_put(cb);
+ nla_put_failure:
+ if (err)
+ fprintf(stderr, "failed to get information: %d\n", err);
+ nlmsg_free(msg);
+ return result.modes;
+}
+
+
+static int i802_set_sta_vlan(void *priv, const u8 *addr,
+ const char *ifname, int vlan_id)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto out;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(ifname));
+
+ ret = 0;
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ (errno = nl_wait_for_ack(drv->nl_handle) < 0)) {
+ ret = -1;
+ }
+
+ nla_put_failure:
+ nlmsg_free(msg);
+
+ out:
+ return ret;
+}
+
+
+static void handle_unknown_sta(struct hostapd_data *hapd, u8 *ta)
+{
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, ta);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+ printf("Data/PS-poll frame from not associated STA "
+ MACSTR "\n", MAC2STR(ta));
+ if (sta && (sta->flags & WLAN_STA_AUTH))
+ hostapd_sta_disassoc(
+ hapd, ta,
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+ else
+ hostapd_sta_deauth(
+ hapd, ta,
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+ }
+}
+
+
+static void handle_tx_callback(struct hostapd_data *hapd, u8 *buf, size_t len,
+ int ok)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc, type, stype;
+ struct sta_info *sta;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ switch (type) {
+ case WLAN_FC_TYPE_MGMT:
+ wpa_printf(MSG_DEBUG, "MGMT (TX callback) %s",
+ ok ? "ACK" : "fail");
+ ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ wpa_printf(MSG_DEBUG, "CTRL (TX callback) %s",
+ ok ? "ACK" : "fail");
+ break;
+ case WLAN_FC_TYPE_DATA:
+ wpa_printf(MSG_DEBUG, "DATA (TX callback) %s",
+ ok ? "ACK" : "fail");
+ sta = ap_get_sta(hapd, hdr->addr1);
+ if (sta && sta->flags & WLAN_STA_PENDING_POLL) {
+ wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
+ "activity poll", MAC2STR(sta->addr),
+ ok ? "ACKed" : "did not ACK");
+ if (ok)
+ sta->flags &= ~WLAN_STA_PENDING_POLL;
+ }
+ if (sta)
+ ieee802_1x_tx_status(hapd, sta, buf, len, ok);
+ break;
+ default:
+ printf("unknown TX callback frame type %d\n", type);
+ break;
+ }
+}
+
+
+static void handle_frame(struct hostapd_iface *iface, u8 *buf, size_t len,
+ struct hostapd_frame_info *hfi,
+ enum ieee80211_msg_type msg_type)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc, type, stype;
+ size_t data_len = len;
+ struct hostapd_data *hapd = NULL;
+ int broadcast_bssid = 0;
+ size_t i;
+ u8 *bssid;
+
+ /*
+ * PS-Poll frames are 16 bytes. All other frames are
+ * 24 bytes or longer.
+ */
+ if (len < 16)
+ return;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ switch (type) {
+ case WLAN_FC_TYPE_DATA:
+ if (len < 24)
+ return;
+ switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
+ case WLAN_FC_TODS:
+ bssid = hdr->addr1;
+ break;
+ default:
+ /* discard */
+ return;
+ }
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ /* discard non-ps-poll frames */
+ if (stype != WLAN_FC_STYPE_PSPOLL)
+ return;
+ bssid = hdr->addr1;
+ break;
+ case WLAN_FC_TYPE_MGMT:
+ bssid = hdr->addr3;
+ break;
+ default:
+ /* discard */
+ return;
+ }
+
+ /* find interface frame belongs to */
+ for (i = 0; i < iface->num_bss; i++) {
+ if (memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) {
+ hapd = iface->bss[i];
+ break;
+ }
+ }
+
+ if (hapd == NULL) {
+ hapd = iface->bss[0];
+
+ if (bssid[0] != 0xff || bssid[1] != 0xff ||
+ bssid[2] != 0xff || bssid[3] != 0xff ||
+ bssid[4] != 0xff || bssid[5] != 0xff) {
+ /*
+ * Unknown BSSID - drop frame if this is not from
+ * passive scanning or a beacon (at least ProbeReq
+ * frames to other APs may be allowed through RX
+ * filtering in the wlan hw/driver)
+ */
+ if ((type != WLAN_FC_TYPE_MGMT ||
+ stype != WLAN_FC_STYPE_BEACON))
+ return;
+ } else
+ broadcast_bssid = 1;
+ }
+
+ switch (msg_type) {
+ case ieee80211_msg_normal:
+ /* continue processing */
+ break;
+ case ieee80211_msg_tx_callback_ack:
+ handle_tx_callback(hapd, buf, data_len, 1);
+ return;
+ case ieee80211_msg_tx_callback_fail:
+ handle_tx_callback(hapd, buf, data_len, 0);
+ return;
+ }
+
+ switch (type) {
+ case WLAN_FC_TYPE_MGMT:
+ if (stype != WLAN_FC_STYPE_BEACON &&
+ stype != WLAN_FC_STYPE_PROBE_REQ)
+ wpa_printf(MSG_MSGDUMP, "MGMT");
+ if (broadcast_bssid) {
+ for (i = 0; i < iface->num_bss; i++)
+ ieee802_11_mgmt(iface->bss[i], buf, data_len,
+ stype, hfi);
+ } else
+ ieee802_11_mgmt(hapd, buf, data_len, stype, hfi);
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ /* can only get here with PS-Poll frames */
+ wpa_printf(MSG_DEBUG, "CTRL");
+ handle_unknown_sta(hapd, hdr->addr2);
+ break;
+ case WLAN_FC_TYPE_DATA:
+ wpa_printf(MSG_DEBUG, "DATA");
+ handle_unknown_sta(hapd, hdr->addr2);
+ break;
+ }
+}
+
+
+static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct i802_driver_data *drv = eloop_ctx;
+ struct hostapd_data *hapd = drv->hapd;
+ struct sockaddr_ll lladdr;
+ unsigned char buf[3000];
+ int len;
+ socklen_t fromlen = sizeof(lladdr);
+
+ len = recvfrom(sock, buf, sizeof(buf), 0,
+ (struct sockaddr *)&lladdr, &fromlen);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ if (have_ifidx(drv, lladdr.sll_ifindex))
+ ieee802_1x_receive(hapd, lladdr.sll_addr, buf, len);
+}
+
+
+static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct i802_driver_data *drv = eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+ struct hostapd_data *hapd = drv->hapd;
+ struct ieee80211_radiotap_iterator iter;
+ int ret;
+ struct hostapd_frame_info hfi;
+ int injected = 0, failed = 0, msg_type, rxflags = 0;
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
+ printf("received invalid radiotap frame\n");
+ return;
+ }
+
+ memset(&hfi, 0, sizeof(hfi));
+
+ while (1) {
+ ret = ieee80211_radiotap_iterator_next(&iter);
+ if (ret == -ENOENT)
+ break;
+ if (ret) {
+ printf("received invalid radiotap frame (%d)\n", ret);
+ return;
+ }
+ switch (iter.this_arg_index) {
+ case IEEE80211_RADIOTAP_FLAGS:
+ if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
+ len -= 4;
+ break;
+ case IEEE80211_RADIOTAP_RX_FLAGS:
+ rxflags = 1;
+ break;
+ case IEEE80211_RADIOTAP_TX_FLAGS:
+ injected = 1;
+ failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
+ IEEE80211_RADIOTAP_F_TX_FAIL;
+ break;
+ case IEEE80211_RADIOTAP_DATA_RETRIES:
+ break;
+ case IEEE80211_RADIOTAP_CHANNEL:
+ /* TODO convert from freq/flags to channel number
+ hfi.channel = XXX;
+ hfi.phytype = XXX;
+ */
+ break;
+ case IEEE80211_RADIOTAP_RATE:
+ hfi.datarate = *iter.this_arg * 5;
+ break;
+ case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
+ hfi.ssi_signal = *iter.this_arg;
+ break;
+ }
+ }
+
+ if (rxflags && injected)
+ return;
+
+ if (!injected)
+ msg_type = ieee80211_msg_normal;
+ else if (failed)
+ msg_type = ieee80211_msg_tx_callback_fail;
+ else
+ msg_type = ieee80211_msg_tx_callback_ack;
+
+ handle_frame(hapd->iface, buf + iter.max_length,
+ len - iter.max_length, &hfi, msg_type);
+}
+
+
+static int nl80211_create_monitor_interface(struct i802_driver_data *drv)
+{
+ char buf[IFNAMSIZ];
+ struct sockaddr_ll ll;
+ int optval;
+ socklen_t optlen;
+
+ snprintf(buf, IFNAMSIZ, "mon.%s", drv->iface);
+ buf[IFNAMSIZ - 1] = '\0';
+
+ drv->monitor_ifidx =
+ nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL);
+
+ if (drv->monitor_ifidx < 0)
+ return -1;
+
+ if (hostapd_set_iface_flags(drv, buf, 1))
+ goto error;
+
+ memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = drv->monitor_ifidx;
+ drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (drv->monitor_sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ goto error;
+ }
+
+ if (bind(drv->monitor_sock, (struct sockaddr *) &ll,
+ sizeof(ll)) < 0) {
+ perror("monitor socket bind");
+ goto error;
+ }
+
+ optlen = sizeof(optval);
+ optval = 20;
+ if (setsockopt
+ (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
+ perror("Failed to set socket priority");
+ goto error;
+ }
+
+ if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
+ drv, NULL)) {
+ printf("Could not register monitor read socket\n");
+ goto error;
+ }
+
+ return 0;
+ error:
+ nl80211_remove_iface(drv, drv->monitor_ifidx);
+ return -1;
+}
+
+
+static int nl80211_set_master_mode(struct i802_driver_data *drv,
+ const char *ifname)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(ifname));
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP);
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0) {
+ nla_put_failure:
+ wpa_printf(MSG_ERROR, "Failed to set interface %s to master "
+ "mode.", ifname);
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ nlmsg_free(msg);
+
+ return 0;
+}
+
+
+static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid)
+{
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+
+ drv->ioctl_sock = -1;
+
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ return -1;
+ }
+
+ /* start listening for EAPOL on the default AP interface */
+ add_ifidx(drv, if_nametoindex(drv->iface));
+
+ if (hostapd_set_iface_flags(drv, drv->iface, 0))
+ return -1;
+
+ if (bssid) {
+ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
+ memcpy(ifr.ifr_hwaddr.sa_data, bssid, ETH_ALEN);
+ ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifr)) {
+ perror("ioctl(SIOCSIFHWADDR)");
+ return -1;
+ }
+ }
+
+ /*
+ * initialise generic netlink and nl80211
+ */
+ drv->nl_handle = nl_handle_alloc();
+ if (!drv->nl_handle) {
+ printf("Failed to allocate netlink handle.\n");
+ return -1;
+ }
+
+ if (genl_connect(drv->nl_handle)) {
+ printf("Failed to connect to generic netlink.\n");
+ return -1;
+ }
+
+ drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
+ if (!drv->nl_cache) {
+ printf("Failed to allocate generic netlink cache.\n");
+ return -1;
+ }
+
+ drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
+ if (!drv->nl80211) {
+ printf("nl80211 not found.\n");
+ return -1;
+ }
+
+ /* Initialise a monitor interface */
+ if (nl80211_create_monitor_interface(drv))
+ return -1;
+
+ if (nl80211_set_master_mode(drv, drv->iface))
+ return -1;
+
+ if (hostapd_set_iface_flags(drv, drv->iface, 1))
+ return -1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifr.ifr_ifindex;
+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
+ addr.sll_ifindex);
+
+ drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
+ if (drv->eapol_sock < 0) {
+ perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
+ {
+ printf("Could not register read socket for eapol\n");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+ if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) != 0) {
+ perror("ioctl(SIOCGIFHWADDR)");
+ return -1;
+ }
+
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ printf("Invalid HW-addr family 0x%04x\n",
+ ifr.ifr_hwaddr.sa_family);
+ return -1;
+ }
+ memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ return 0;
+}
+
+
+static int i802_get_inact_sec(void *priv, const u8 *addr)
+{
+ struct hostap_sta_driver_data data;
+ int ret;
+
+ data.inactive_msec = (unsigned long) -1;
+ ret = i802_read_sta_data(priv, &data, addr);
+ if (ret || data.inactive_msec == (unsigned long) -1)
+ return -1;
+ return data.inactive_msec / 1000;
+}
+
+
+static int i802_sta_clear_stats(void *priv, const u8 *addr)
+{
+#if 0
+ /* TODO */
+#endif
+ return 0;
+}
+
+
+static void
+hostapd_wireless_event_wireless_custom(struct i802_driver_data *drv,
+ char *custom)
+{
+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ char *pos;
+ u8 addr[ETH_ALEN];
+ pos = strstr(custom, "addr=");
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "without sender address ignored");
+ return;
+ }
+ pos += 5;
+ if (hwaddr_aton(pos, addr) == 0) {
+ ieee80211_michael_mic_failure(drv->hapd, addr, 1);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "with invalid MAC address");
+ }
+ }
+}
+
+
+static void hostapd_wireless_event_wireless(struct i802_driver_data *drv,